본문 바로가기

Wargame(hacking)/webhacking.kr

Webhacking.kr : old-60

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 값을 숫자로 구성 후, 재 로그인을 하니, 아래와 같은 페이지가 출력되었다. 

 

그림 1

 

이제 위 코드에 따라 /?mode=auth 요청을 보내본다. 그 결과는 아래 그림 2와 같다. 

 

그림 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과 같이 문제를 해결할 수 있다. 

 

그림 3

 

 

 

 

참고

 

https://zetawiki.com/wiki/PHP_%ED%8C%8C%EC%9D%BC%EC%82%AD%EC%A0%9C_%ED%95%A8%EC%88%98_unlink()#google_vignette

 

PHP 파일삭제 함수 unlink() - 제타위키

다음 문자열 포함...

zetawiki.com

 

https://codingeverybody.kr/php-is_numeric-%ED%95%A8%EC%88%98/

 

PHP is_numeric() 함수 – 변수의 값이 숫자 또는 숫자 문자열인지 확인 - 코딩에브리바디

is_numeric() 함수는 주어진 값이 숫자 또는 숫자 문자열인지 확인하는 함수입니다. 이 함수는 매개변수로 전달된 값이 숫자이거나 숫자 문자열이면 true를 반환하고, 그렇지 않으면 false를 반환합니

codingeverybody.kr