웹 해킹 & 시큐어 코딩

웹 해킹 & 시큐어 코딩 (24)

홍시뗄레 2025. 2. 6. 13:24

[실습6-3] Ajax를 활용한 Stealth CSRF 공격

<script>var xhp = new XMLHttpRequest();xhp.open("POST","/insecure_website/index.php?page=mypage",true);xhp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");xhp.send("gubun=action&name=희생자&password=test&email=victim&company=(주)희생자");</script>
 
true: 비동기화. 요청이 올 때까지 기다리는 게 아니라 다른 작업도 가능하게끔 만들기. 효율적이다.

챗지피티 참고.

해커 계정으로 이렇게 글을 작성한다.
관리자 계정으로 이 글을 클릭하면 어떻게 되는지 실습해보자.

변화를 알 수 없다. 그런데 요청이 이루어졌을 것이다.

이렇게 마이페이지도 바뀌어졌고
패스워드도 바뀌었는지 확인해보면 바뀌었음을 확인할 수 있다.
 

참고. 게시글을 모두 삭제하고 싶을 때 이렇게 삭제하면 된다.
mysql 부르는 건 mysql -u root -p 입력하고 패스워드를 입력하면 된다.
use pentest;
delete from insecure_board;
 

대응 방안

1. Referer 값 검증
회원 정보 수정 요청을 홈페이지 내에서 요청했는지, 아니면 게시물에서 요청했는지 검증해야 된다.
2. CSRF TOKEN 사용
form 페이지와 action 페이지가 있다. csrf token은 매번 달라지기 때문에 공격자가 예측할 수 없다. 세션에 주입된 토큰값과 csrf 토큰값을 알아야 공격을 할 수 있어져서 어려워진다.
3. 인증 로직 사용/CAPTCHA 사용
수정, 삭제할 때 패스워드를 받는다. 공격자가 페이로드를 작성할 때 패스워드를 알아야 하기 때문에 공격하기 어려워진다. 
많은 웹 사이트에서 CAPTCHA를 사용한다. 주로 게시글 작성할 때 사용한다. 

CAPTCHA 예시.
4. SameSite Cookie
사이트 간 요청되는 경우. 정상적으로 이루어지지 않는다. 쿠키가 실리지 않기 때문이다.
 

CSRF Token 동작 상세 원리

폼 페이지 (Form Page)가 있을 것이다. 우리가 요청하고 액션이 이루어지는 페이지는 액션 페이지. (Action Page). 실질적인 행위를 한다.
CSRF Token을 발급하고 전달하는 곳은 폼 페이지. 그 토큰을 액션 페이지로 전달하고, 액션 페이지에서 토큰을 검증한다. 
 

토큰을 발급할 때 세션에 토큰을 넣어주고, 파라미터에 토큰을 넣어준다. 파라미터에 전달하기 위해 Hidden 값으로 전달될 것이다. 그리고 액션 페이지에서는 세션과 파라미터에서 토큰을 받아 온다. 요청을 하면 파라미터에 토큰이 담겨져서 올 텐데, 이 두 개를 비교한다. 정상적인 폼 페이지에서 액션 페이지로 요청한다면, 세션과 파라미터의 토큰이 일치하기 때문에 유효성이 검증될 것이다.
만약 공격자가 CSRF 공격을 한다면 폼 페이지에서 세션 토큰이 발생하지 않기 때문에 액션 페이지에서 검증이 실패할 것이다. 
 

[실습6-4] 취약 환경 시큐어 코딩 적용 실습-1

게시글 작성 / 수정 / 삭제 기능에 대한 시큐어 코딩 적용
* 공통 - common.php
* Form Page - (작성) write.php / (수정) modify.php / (삭제) view.php 
* Action Page - action.php 
토큰에 대한 유효성 검증을 action.php에서 하면 된다.

우선 common.php에 토큰을 만드는 함수를 추가해준다. 가장 마지막에 추가해주면 된다.

원래 write.php 등 다 설정해줘야 하지만, 이 사이트는 index.php에서 일괄적으로 처리하므로 index.php를 수정해주면 더 편리하게 시큐어 코딩을 적용할 수 있다.

이렇게 함수를 추가해주고

write.php에서 hidden 값으로 토큰을 추가해주면 된다.
정상적으로 되는지 확인해보자.

관리자모드(F12)를 눌러주면 이렇게 적용된 것을 확인할 수 있다. (Ctrl+F를 누르고 csrf를 눌러 있는지 검색해보면 됨)
우리 이제 토큰을 발급했으니 세션에 넣어주어야 한다.

다시 common.php에 들어가서 세션이 있으면 토큰을 받도록 하고 없으면 못 받게 로직을 만들어주면 된다.

수정: 10번째 줄 코드에 empty 앞에 있는 !를 둘다 지워줘야 된다. 깜빡하고 사진 수정을 못했다.

작성, 수정, 삭제 모두 검증 로직을 적용시켜야 하므로 아예 맨 위에 검증 로직 코드를 작성해준다. 세션과 파라미터가 일치하는지 아닌지 확인해주는 코드를 작성해주면 된다.
 
해커 계정으로 아래 내용을 담은 게시글을 작성하고 관리자 계정으로 그 게시글을 클릭해보자.
 
<form action="http://127.0.0.1/insecure_website/action.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="title" value="해커가 무단으로 작성!">
<input type="hidden" name="password" value="test">
<input type="hidden" name="content" value="해커">
<input type="hidden" name="mode" value="write">
<input type="submit">
</form>
 
 

이렇게 작성하였고, 이제 관리자 계정으로 이 게시글을 클릭해보자.

정상적인 접근이 아니라고 뜨면서, 게시글이 작성되지 않는다.
 
이제 수정 페이지에도 적용해보자.
modify.php 열어서 적용시키면 된다.

마찬가지로 modify.php에서도 write.php에서 작성한 것과 동일한 코드를 작성해주면 된다.

index.php도 똑같이 적용해주면 된다.
정상적으로 수정이 되는지 확인해주고, 공격도 가능한지 확인해주자.
 
저번에 csrf 공격을 할 때 사용했던 코드를 그대로 가져와서 게시글을 작성해주자.
<body onload="document.forms[0].submit()">
<form action="http://127.0.0.1/insecure_website/action.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="title" value="계좌정보 정보입니다.">
<input type="hidden" name="content" value="* 은행: 홍시은행
* 예금주: 해커
* 계좌번호: 2222222222

모든 상품에 대한 입금은 해당 계좌로 진행하시면 됩니다.">
<input type="hidden" name="password" value="a">
<input type="hidden" name="idx" value="26">
<input type="hidden" name="mode" value="modify">
<input type="submit">
</form>
</body>
참고. 
해커 계정으로 게시글을 작성한 후 관리자 계정으로 이걸 클릭해보자.
실습해보면 마찬가지로 정상적인 접근이 아니라고 팝업창이 뜨며 수정되지 않는다.
 
마지막으로 삭제 부분도 해주면 된다.

마찬가지로 view 부분에다가도 이렇게 추가해준다.
 

        <div class="text-right">
            <? if($_SESSION["id"] == $row["id"]) { ?>
            <button type="button" class="btn btn-outline-secondary" onclick="location.href='index.php?page=modify&idx=<?=$row["idx"]?>'">Modify</button>
            <button type="button" class="btn btn-outline-danger" onclick="location.href='action.php?mode=delete&idx=<?=$row["idx"]?>&csrf_token=<?=$csrf_token?>'">Delete</button>
            <? } ?>
            <button type="button" class="btn btn-outline-warning" onclick="location.href='index.php'">List</button>
        </div>

view.php에서는 이렇게 바꿔준다. 길이가 길어서 복사해서 붙였다.

수정할 부분만 표시해주면 위와 같다.

그리고 원래 POST 방식으로 삭제하던 방식을 GET 방식으로 바꿔주겠다.
 
그리고 정상적으로 삭제되는 것을 확인해보고 이상이 없는지 확인한다.
이제 관리자 계정으로 글을 작성해보고, 해커 계정으로 게시글을 작성하여 삭제하는 공격을 수행해보자.
<body onload="document.forms[0].submit()">
<form action="http://127.0.0.1/insecure_website/action.php" method="POST">
<input type="hidden" name="password" value="a">
<input type="hidden" name="idx" value="43">
<input type="hidden" name="mode" value="delete">
<input type="submit">
</form>
</body>
 
이것도 마찬가지로 저번에 실습 때 사용했던 삭제 코드이다.
게시글을 올린 후 관리자 계정으로 클릭하면 정상적인 접근이 되지 않는다고 뜨고, 삭제도 되지 않는다.
이로써 안전하게 시큐어 코딩을 마쳤다.
 

[실습6-5] 취약 환경 시큐어 코딩 적용 실습-2

회원 수정 / 패스워드 변 / 탈퇴 기능에 대한 시큐어 코딩 적용
회원 수정과 패스워드는 csrf token을 굳이 받지 않아도 된다. 세션 하이재킹을 통해 탈취되면 패스워드 변경이 가능하기 때문에 일반적인 웹페이지에서 적용되는 시큐어 코딩을 해보자.

우선 이건 mypage.php이다. 
기존 패스워드를 먼저 확인하고 패스워드를 변경할 수 있도록 만들어 보자.

이렇게 바꿔준다.

패스워드 검증 로직도 필요한데, action.php에 검증 로직이 있으므로 이것을 활용해주겠다.

바꾼 게 너무 많아서...
우선 password, password1, password2 변수들에 대한 시큐어 코딩을 한 줄씩 적용했고 ($db_conn->real_escape_string())
그리고 패스워드 검증 로직을 활용할 때 members 안에서 일어날 수 있도록 select from 절을 사용했다.
id와 password가 일치하는지도 확인해줘야 하고.
 
그리고 패스워드를 저장할 때 평문으로 저장하는 게 아니라 md5로 암호화해서 저장하므로 이를 다시 저장해서 비교해야 된다. 
 
거짓값이 리턴되면 패스워드가 일치하지 않는다는 메시지가 나오도록 하고
다시 새로 입력한 password1과 password2가 일치하는지 확인해주는 로직도 추가하고, 새 비밀번호로 바꾸는 로직도 추가해주면 된다.
 
이제 해커 계정으로 회원정보 수정하는 게시글을 작성해보자.
<body onload="document.forms[0].submit()">
<form action="http://127.0.0.1/insecure_website/index.php?page=mypage&id=hacker" method="POST">
<input type="hidden" name="gubun" value="action">
<input type="hidden" name="name" value="희생자">
<input type="hidden" name="email" value="victim">
<input type="hidden" name="company" value="(주)희생자">
<input type="submit">
</form>
</body>
저번에 사용했던 공격 페이로드를 그대로 복사해서 또 실습해보자.
 
이제 공격자가 쓴 게시글을 관리자가 클릭하면, 패스워드가 일치하지 않는다는 팝업창이 뜨면서 회원정보가 수정되지 않는다.
 
이제 회원 탈퇴 시큐어 코딩을 해보자.
csrf token을 통해 유효성 검증을 해보자.

우선 withdrawal.php에 들어가서 이렇게 코드를 추가해준다. 세션과 파라미터를 적용해주는 것이다.

action.php에서 아까 작성해뒀던 로직을 활용해주자.

index.php에서는 mypage 부분에 또 함수를 불러준다.

mypage.php에서도 이렇게 get 방식으로 token을 보낼 수 있도록 바꿔준다.
 
이제 다 바꿔줬고, 정상적인 탈퇴가 가능한지 한번 시도해보자.

임의로 이렇게 만들어줬고, 회원탈퇴하기 버튼을 누르면 정상적으로 탈퇴가 되는 모습이다.
 
이제 해커 계정으로 글을 작성해보자.
<script>location.href='http://127.0.0.1/insecure_website/withdrawal.php'</script>
게시글에 이걸 입력하면, 게시글을 누르는 순간 회원 탈퇴가 될 것이다.

이렇게 적어주었고
관리자 계정으로 이걸 눌러주면

이렇게 정상적인 접근이 아니라고 한다.
토큰값이 없기 때문에 접근이 되지 않을 것이다.
그리고, 관리자 계정도 탈퇴되지 않았다.

[실습6-6] 취약 환경 시큐어 코딩 적용 실습-3

 

세션을 하나 만들어줬으면 폐기해주자. 나중에 문제가 생길 수 있으므로.

여기도 코드를 하나 추가해준다.