●21일차(20250116)
[web2.st.kr editplus 수정]
+) public_html 아래에 static 만들어서 bootstrap 넣어줌
> 서버 > cd /home/web2/public_html > chmod 755 static/
workbench에 본래 users drop하고
---------------------------------------------------------------------------
CREATE TABLE users (
idx int(6),
id_param varchar(15),
pw_param varchar(32),
last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
failed_login INT(3),
PRIMARY KEY (idx)
);
---------------------------------------------------------------------------
> 번개모양 클릭 table users가 생김
오른쪽마우스 select 클릭 후
1 admin 123456 2025-01-16 00:00:00 0 추가
apply
> workbench의 failed_login의 횟수를 올려가며 테스트해줬다
[login_ok.php 수정]
> php.net에서 함수 사용방법 찾아가면서 해줌
#시간이 안맞는 문제
find / -name php.ini
> apache2, fpm에 있음
nano /etc/php/8.3/apache2/php.ini
nano /etc/php/8.3/fpm/php.ini
> crtl + w > timezone
> ; 주석제거, "Asia/Seoul" 추가
systemctl restart apache2
systemctl restart php8.3-fpm
> 현재시간으로 맞춰짐
> 로그인을 했는데 시간이 안보이는거면 코드 if문에서 timenow > timeout으로 바꿔줘야 보인다(잘 맞춰졌다는 뜻)
#로그인 할때만 사용되는 쿠키, 세션
> 로그인 유지 > 로그인이 남아있는 이유는 쿠키가 남아있긴 때문("/" > 모든 페이지의 쿠키를 cid_param이라는 변수에 저장)
> 우리는 60초로 설정 > 로그인 하면 로그아웃, 마이페이지 > 60초 이후에 새로고침을 하면 회원가입과 로그인이 뜨게 수정
쿠키는 데이터가 내 컴퓨터에 저장
세션을 내컴에 저장이 안됨(서버에 저장)
> 훔쳐가기가 힘들다
> 세션 start 걸어줘야함 맨위에(header에도 세션을 써야해서 header.php에도 넣어줘야함)
#함수
mysqli_num_rows($result)
> 변수 result(데이터베이스)에 데이터가 있는지 물어보는것
public_html 아래에
[index.html]
<script>location.href='./index.php';</script>
[index.php]
<?php
include __DIR__. "/includes/header.php";
?>
<?php
include __DIR__. "/main.php";
?>
<?php
include __DIR__. "/includes/footer.php";
?>
[main.php]
<div class="container mt-3">
<h2>나는 보안인이다</h2>
</div>
[profile.php]
<!DOCTYPE html>
<html lang="en">
<head>
<title>소개</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/static/bootstrap.min.css" rel="stylesheet">
<script src="/static/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container mt-3">
<h2>소개</h2>
<div class="card">
<div class="card-body">
<strong>산대특 결과물 웹 해킹 훈련장</strong><br>
서버버전: 24.10 (kelnel : 6.11.0-13.generic)<br>
APM버전 : 2.4.62<br>
웹취약점<br>
<hr>
서버 관리자 및 개발 : 문소희(4기)<br>
본 사이트 DVWA를 기반으로 재구성 되었습니다<br>
궁금한 사항은 web2@web2.st.kr로 질문 하시면 됩니다.<br>
</div>
</div>
</div>
</body>
</html>
includes 아래에
[db.php]
<?php
$host="localhost";
$user="web2";
$pw="123456";
$db="web2";
$conn = mysqli_connect($host,$user,$pw,$db);
if ($conn == false) {
echo mysqli_connect_error();
} else {
echo "연결성공";
}
?>
[footer.php]
X
[header.php]
<?php
session_start();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>웹해킹훈련장</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/static/bootstrap.min.css" rel="stylesheet">
<script src="/static/bootstrap.bundle.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">웹해킹훈련장</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mynavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="mynavbar">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link" href="/profile.php">소개</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/upload.php">자료올리기</a>
</li>
<li class="nav-item">
<a class="nav-link" href="javascript:void(0)">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">관리</a>
<ul class="dropdown-menu">
<?php
//echo $_COOKIE["cid_param"]
if(!isset($_SESSION["sid_param"])) {
?>
<li><a class="dropdown-item" href="/auth/signup.php">회원가입</a></li>
<li><a class="dropdown-item" href="/auth/login.php">로그인</a></li>
<?php
} else {
?>
<li><a class="dropdown-item" href="/auth/mypage.php">마이페이지</a></li>
<li><a class="dropdown-item" href="/auth/logout.php">로그아웃</a></li>
<?php
}
?>
</ul>
</li>
</ul>
<form class="d-flex">
<input class="form-control me-2" type="text" placeholder="Search">
<button class="btn btn-primary" type="button">Search</button>
</form>
</div>
</div>
</nav>
auth 아래에
[login.php]
<?php
include __DIR__. "/../includes/header.php";
?>
<div class="container mt-3">
<h2>로그인</h2>
<form action="/auth/login_ok.php">
<div class="mb-3 mt-3">
<label for="id_param">아이디</label>
<input type="text" class="form-control" id="id_param" placeholder="아이디입력" name="id_param">
</div>
<div class="mb-3">
<label for="pw_param">비밀번호</label>
<input type="password" class="form-control" id="pw_param" placeholder="암호입력" name="pw_param">
</div>
<div class="form-check mb-3">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="remember"> Remember me
</label>
</div>
<button type="submit" class="btn btn-primary" name="Login" value="Login"> 로그인</button>
</form>
</div>
[login_ok.php]
<?php
session_start(); #session은 맨처음에 start를 해줘야함
include __DIR__ . "/../includes/db.php";
$id_param = $_GET['id_param'];
$pw_param = $_GET['pw_param'];
//디폴트 변수 선언
$total_failed_login=3;
$lockout_time=3; #분을 의미함
$account_locked=false;
//기본틀(mysqli_를 이용한 함수 구현 : SQL 인젝션 공격 가능)
//step1 : 사용자만 검색
$sql = "select failed_login, last_login from users where id_param='admin'";
#데이터베이스를 가져옴
#id가 admin인 데이터에서 failed와 last 로그인을 가져옴
echo $sql. "<br>";
$result = mysqli_query($conn,$sql);
#$conn: 데이터베이스 연결 리소스, $sql: 데이터베이스 가져옴
#mysqli_query: 데이터베이스 연결
if (mysqli_num_rows($result) > 0) {
echo "OK". "<br>"; #OK
} else {
echo "NO". "<br>";
}
$row = mysqli_fetch_assoc($result);
echo $row['failed_login']. "<br>"; #0
#if 데이터베이스에 데이터가 있다면 OK를 출력, 없다면 NO를 출력해라
//step2 : 사용자 검색과 실패횟수가 3이상이면 락 상태 유지
//step3 : 사용자와 비밀번호 검색
//step4 : 사용자 검색과 로그인 상태가 아니면 성공
//step5 : 실패횟수 증가시키기
//step6 : 초기화 하기
//기본틀
if ((mysqli_num_rows($result)) > 0 && $row['failed_login'] > $total_failed_login) {
$last_login= $row['last_login']; #데이터베이스 안에 있는 last_login을 따로 변수 지정(마지막 로그인 시점)
$timeout = strtotime($last_login) + ($lockout_time*60);
#마지막 로그인 시점 + 3분*60초(초로 나와야함)
#실패한 마지막 로그인 시점 + 3분동안 락 걸리게 할거임
$timenow = time(); #지금 시간 변수 지정
if ($timenow < $timeout) {
$account_locked = true;
//echo "타임아웃시간 : ". date("Y-m-d H:i:s",$timeout). "<br>";
//echo "현재시간 : " . date("Y-m-d H:i:s",$timenow). "<br>";
echo "<script>alert('락상태입니다');</script>";
exit;
} else {
$account_locked = false;
echo "<script>alert('락해제상태입니다');</script>";
}
}
#if 데이터베이스에 데이터가 있고 데이터베이스 안에 있는 failed_login이 내가 정한 $total_failed_login=3보다
크다면 아래문을 실행시켜라(로그인 4번 실패하면 락걸리게 할거임)
#지금 시간이 아직 락에 걸려있어야 할 시간보다 작다면 $accout_lock을 true로 둬서 락을 걸음
#상태창으로 락상태임을 알려줌
#else문 시간이 지났다면 락을 풀고(false) 락 해제상태임을 상태창으로 알려줌
$sql = "select * from users where id_param='admin' and pw_param='123456'";
#users라는 테이블에서 id admin과 password 123456을 가져와서
$result = mysqli_query($conn,$sql); #연결한 걸 result라는 변수에 넣어줌
if (mysqli_num_rows($result) > 0 && $account_locked == false) {
echo "로그인성공";
# 쿠키또는세션(로그인할때만 보인다)
# A cookie is often used to identify a user
/*
setcookie("cid_param","admin",time()+(60),"/");
echo $_COOKIE["cid_param"];
*/
#세션
# A session is a way to store information(in variable) to be used across mutilple pages
#Unlike a cookie, the information is not stored in the users computer
$row = mysqli_fetch_assoc($result);
$failed_login = $row['failed_login'];
$last_login = $row['last_login'];
if ($failed_login > $total_failed_login) {
echo "Brute Force 공격을 받았군요"."<br>";
echo $failed_login. "번의 공격시도가 있었습니다.";
}
#카운터 초기화
$sql="update users set failed_login=0 where id_param='admin'";
mysqli_query($conn,$sql);
$_SESSION['sid_param']="admin";
#echo "<script>location.href='/index.php';</script>";
} else {
#sleep(rand(2,4));
echo rand(2,4);
echo "로그인실패";
$sql="update users set failed_login=failed_login+1 where id_param='admin'";
mysqli_query($conn,$sql);
#failed_login 증가
}
$sql="update users set last_login=now() where id_param='admin'";
mysqli_query($conn,$sql);
mysqli_close($conn);
echo "<script>location.href='/index.php';</script>";
?>
#마지막 if문
if 데이터베이스에 데이터가 있고 락이 안걸려있다면 로그인 성공이라는 메세지와 함께 아래코드를 실행
둘중에 하나라도 되어있지 않다면 로그인 실패라는 문구와 함께 admin의 failed_login을 1 더하고 데이터베이스 연결시켜줌
그리고는 데이터베이스 연결을 종료하고 index.php 홈으로 돌아가게 해놨다.
1. 쿠키 코드
cid_param이라는 변수에 지금 시간 + 60초 동안 모든 페이지에 admin이라는 데이터를 저장
> strtotime : 지금까지의 시간을 초로 환산함
header에 if문 cid_param이라는 곳에 데이터가 설정되어있지 않다면 로그인 회원가입 바를 보여줘라
> 60초동안은 로그아웃 마이페이지 바가 보여진다
2. 세션 코드
행을 하나씩 가져와서 failed와 last를 따로 변수지정해준다
if 실패한 횟수가 내가 지정한 3번이라는 횟수를 넘어선다면 failed횟수만큼 공격시도가 있었다는 걸 알려준다
if문에서 나와 데이터베이스에 admin에 속하는 실패횟수를 0으로 업데이트한다
sid_param이라는 이름의 변수에 admin을 배열로 만들어 저장해 서버에서 추적하여 여러페이지 간에 상태유지를 해준다