21일차

●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을 배열로 만들어 저장해 서버에서 추적하여 여러페이지 간에 상태유지를 해준다