문제 링크
https://webhacking.kr/challenge/web-37/
https://webhacking.kr/challenge/web-37/
webhacking.kr
문제 풀이
문제 링크로 들어가보면 다음과 같은 화면이 나온다.
user의 idx 값(71006)과 'Access Denied'라는 문자열 그리고 view-source라는 링크가 보였다.
드림핵처럼 문제 파일이 따로 있는게 아니라서 바로 view-source 링크에 들어가 보았다.
<?php
include "../../config.php";
if($_GET['view_source']) view_source();
login_chk();
echo "Your idx is {$_SESSION['idx']}<hr>";
if(!is_numeric($_COOKIE['PHPSESSID'])) exit("Access Denied<br><a href=./?view_source=1>view-source</a>");
sleep(1);
if($_GET['mode']=="auth"){
echo("Auth~<br>");
$result = file_get_contents("./readme/{$_SESSION['idx']}.txt");
if(preg_match("/{$_SESSION['idx']}/",$result)){
echo("Done!");
unlink("./readme/{$_SESSION['idx']}.txt");
solve(60);
exit();
}
}
$p = fopen("./readme/{$_SESSION['idx']}.txt","w");
fwrite($p,$_SESSION['idx']);
fclose($p);
if($_SERVER['REMOTE_ADDR']!="127.0.0.1"){
sleep(1);
unlink("./readme/{$_SESSION['idx']}.txt");
}
?>
<html><head><title>Challenge 60</title></head><body><a href=./?view_source=1>view-source</a></body></html>
링크에 들어가보니 위와 같은 코드만 덩그러니 나왔다. 이전 페이지에서 알수있는 정보가 하나도 없었기 때문에 이 코드만을 가지고 접근할 수 있는 엔드포인트들을 알아보려고 했다.
먼저 PHP 코드를 분석해보자.
코드 분석
0. 설정 파일을 include 시킴
1. /?view_source에 GET요청을 보내면 위 코드들을 보여줌
2. 내부 동작을 알 수 없는 login_chk()가 이루어짐
3. 사용자의 세션 아이디를 출력함
4. 쿠키 안에 들어있는 PHPSESSID를 가져오고 만약 숫자로 이루어진 문자열이 아니라면 Access Denied를 띄움
5. sleep(1)을 통해 1초동안 코드의 실행을 지연시킴(Brute Force 공격을 방지하려는 의도인듯)
6. /?mode=auth에 GET요청을 보내면 'Auth~'라는 문자열을 출력시키고 ./readme/ 경로에 있는 {$_SESSION['idx']}.txt 파일을 읽어옴
7. 파일 내용에 $_SESSION['idx']가 포함되어 있는지 확인
8. 파일 내용이 일치하면 'Done!' 문자열 출력, unlink("./readme/{$_SESSION['idx']}.txt") 를 통해 파일을 삭제
9. solve(60) -> 정답 처리로 유추
10. 특정 url로 접근하는 api가 아닌경우, ./readme/{$_SESSION['idx']}.txt 파일을 생성하고 idx 값을 기록
11. 만약 사용자의 IP가 127.0.0.1이 아니라면 sleep(1)을 통해 1초 대기 후 파일을 삭제
코드를 분석해보니 문제를 풀기 위한 궁극적인 목표는 ./readme/ 경로에 있는 {$_SESSION['idx']}.txt 파일을 읽는 것이라고 보았다.
파일을 읽기 위해서는 먼저 특정 url로 접근하지 않는 api 요청이 이루어져야 한다.
그래야 ./readme/{$_SESSION['idx']}.txt 파일이 생성된다.
그 다음에는 /?mode=auth에 GET 요청을 보내어 ./readme/{$_SESSION['idx']}.txt 파일을 읽도록 해야한다.
만약, Race Condition이 발생하지 않는다면 파일을 읽기도 전에 {$_SESSION['idx']}.txt 파일이 사라진다. 하지만 분석한 코드에 따르면 브루트포스 공격을 막기 위한 sleep(1)이 오히려 Race Condition을 일으킨다.
두개의 요청을 동시에 보내어 파일을 읽는건 알겠는데... 문제가 하나 남아있었다.
쿠키 안에 들어 있는 PHPSESSID가 숫자로 이루어져야 목표한 바를 이룰 수 있었다.
먼저, 개발자 도구를 사용하여 쿠키에 어떤 문자열이 들어있는지 확인해보았다.
확인해보니 '9ollvh0qd94ambhq5p4oq8k001'라는 문자 / 숫자가 섞여진 형태의 문자열이 들어있었다.
나는 임의의 숫자값인 '12345'로 바꾸었다.
새로 고침을 하니 다시 로그인을 하라고 했다.(어라... 다시 로그인을 하면 쿠키값이 초기화되는 건 아닐까..?)
로그인을 하고 old-60 문제를 들어가보니 PHPSESSID가 '12345'로 잘 남아있었다. 그리고 더이상 Access Denied라는 것도 뜨지 않았다.
그러면 이제 파이썬 코드를 통해 두 개의 요청을 보내면 문제가 풀릴까? Race Condition을 일으키기 위해서는 서로 다른 프로세스끼리 경쟁을 하게 만들어야 하는데 그러기 위해서는 두개의 브라우저가 필요하다. (나는 Chrome과 Chromium을 사용했다.)
PHPSESSID를 '12345'로 해두었던 브라우저는 Chrome이었기 때문에 Chromium에서도 PHPSESSID를 임의의 숫자인 '11111'로 바꿔두었다.(Race Condition을 일으키는 것과 Access Denied를 막기 위함)
마지막으로 두개의 요청을 동시에 날리기 위해 파이썬 코드를 작성하였다. 총 두 개의 파일로 나누어 작성을 했는데 그 이유는 Race Condition을 유발하기 위함이 있지만, {$_SESSION['idx']}.txt 파일을 읽어오기 위해서는 요청을 날리는 순서도 중요했기 때문이다.
파일 하나를 실행시키고 다른 파일을 실행시키면 결국 순차적으로 api 요청이 이루어질 것이기 때문에 무한 루프를 사용하여 요청 간의 텀을 줄이고자 하였다.
Python 코드 1
import requests
url = 'https://webhacking.kr/challenge/web-37/'
cookie1 = {'PHPSESSID': '12345'}
while True:
request1 = requests.get(url, cookies=cookie1)
print(request1.text)
Python 코드 2
import requests
url = 'https://webhacking.kr/challenge/web-37/'
cookie2 = {'PHPSESSID': '11111'}
while True:
request2 = requests.get(url + '?mode=auth', cookies=cookie2)
print(request2.text)
두 코드를 작성한 뒤, 하나는 PyCharm 터미널을 통해 실행하였고 나머지 하나는 iTerm 터미널을 통해 실행하였다.
실행 명령어1 : python3 main.py
실행 명령어2 : python3 main2.py
시간이 좀 지나고 나니
'already solved'라고 뜨며 정답처리 되었다!!!
근데 굳이 코드로 안짜고 꼼수..?를 사용할 수 있다.
두 개의 브라우저를 띄우는 것 까지는 동일하다. 쿠키의 SESESSID도 숫자로 바꾸는 것도 동일하다.
그냥 주소창에 각각
https://webhacking.kr/challenge/web-37/
https://webhacking.kr/challenge/web-37/?mode=auth
을 넣고 순서에 맞춰 빠르게 요청(한 브라우저에서 엔터, 한 브라우저에서 엔터)을 보내면 된다...🥲
'Security > Web Hacking' 카테고리의 다른 글
Simple Login 풀이 (0) | 2025.04.18 |
---|---|
KeyCat 풀이 (0) | 2025.04.10 |
login-1 풀이 (0) | 2025.04.03 |
Find The Lost Flag 풀이 (0) | 2025.02.19 |
XSS Filtering Bypass 풀이 (0) | 2025.02.19 |