Write-Up
<?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");
}
?>
처음 페이지 접근 시, Access Denied 가 출력되는 것을 볼 수 있다. 그 이유는 if(!is_numeric($_COOKIE['PHPSESSID']) 의 조건에 걸리면서, 접근이 거부되기 때문이다. 접근 거부를 해결하기 위해서, Cookie 값을 숫자로 구성 후, 재 로그인을 하니, 아래와 같은 페이지가 출력되었다.
이제 위 코드에 따라 /?mode=auth 요청을 보내본다. 그 결과는 아래 그림 2와 같다.
idx 값에 따라 /readme/61946.txt 요청을 하니, NOT FOUND 에러 페이지가 반환된다. 아래와 같은 조건 때문이다.
if($_SERVER['REMOTE_ADDR']!="127.0.0.1"){
sleep(1);
unlink("./readme/{$_SESSION['idx']}.txt");
REMOTE_ADDR이 127.0.0.1이 아니기 때문에 sleep(1) 초 후에, unlink() 함수에 의해 해당 경로의 파일이 삭제되어 볼 수가 없다. 하지만 문제 해결을 위해서는 아래 조건을 만족 시켜야한다.
$result = file_get_contents("./readme/{$_SESSION['idx']}.txt");
if(preg_match("/{$_SESSION['idx']}/",$result)){
echo("Done!");
file_get_contents() 함수로, 해당 파일 내용을 불러와 $result에 담고, preg_match() 로 일치 여부를 확인한뒤, 일치하면 문제를 해결할 수 있다.
문제 해결에 대한 결론을 내리자면, 해당 문제는 Race Condition을 이용한 문제이며, 파일이 삭제되기 전 읽어 옴에 성공하면 된다! 브라우저 2개를 준비한 뒤 요청( /?mode=auth ) 을 빠르게, 1초안에 보낸다. 그러면 아래 그림 3과 같이 문제를 해결할 수 있다.
참고
https://codingeverybody.kr/php-is_numeric-%ED%95%A8%EC%88%98/