[webhacking.kr] 37번 문제 풀이[Race Condition]

1 분 소요

💡 Webhacking.kr challenge(old) 37번 문제에 대한 풀이입니다.

문제

image

<?php
  $db = dbconnect();
  $query = "select flag from challenge where idx=37";
  $flag = mysqli_fetch_array(mysqli_query($db,$query))['flag'];
  $time = time();

  $p = fopen("./tmp/tmp-{$time}","w");
  fwrite($p,"127.0.0.1");
  fclose($p);

  $file_nm = $_FILES['upfile']['name'];
  $file_nm = str_replace("<","",$file_nm);
  $file_nm = str_replace(">","",$file_nm);
  $file_nm = str_replace(".","",$file_nm);
  $file_nm = str_replace("/","",$file_nm);
  $file_nm = str_replace(" ","",$file_nm);

  if($file_nm){
    $p = fopen("./tmp/{$file_nm}","w");
    fwrite($p,$_SERVER['REMOTE_ADDR']);
    fclose($p);
  }

  echo "<pre>";
  $dirList = scandir("./tmp");
  for($i=0;$i<=count($dirList);$i++){
    echo "{$dirList[$i]}\n";
  }
  echo "</pre>";

  $host = file_get_contents("tmp/tmp-{$time}");

  $request = "GET /?{$flag} HTTP/1.0\r\n";
  $request .= "Host: {$host}\r\n";
  $request .= "\r\n";

  $socket = fsockopen($host,7777,$errstr,$errno,1);
  fputs($socket,$request);
  fclose($socket);

  if(count($dirList) > 20) system("rm -rf ./tmp/*");
?>

문제 풀이

php 코드가 길기 때문에 핵심적인 부분만 요약을 하면 다음 부분들입니다.

#매번 요청을 할때마다 서버에서 tmp-$time 형식으로 파일을 생성하고, 파일 안에 127.0.0.1을 적는다
$p = fopen("./tmp/tmp-{$time}","w");
  fwrite($p,"127.0.0.1");
  fclose($p);

#사용자가 파일을 업로드 하면 해당 파일 안에는 사용자의 ip를 적는다.
$file_nm = $_FILES['upfile']['name'];
if($file_nm){
    $p = fopen("./tmp/{$file_nm}","w");
    fwrite($p,$_SERVER['REMOTE_ADDR']);
    fclose($p);
  }

#tmp-$time 파일에서 ip를 읽어와서 해당 파일에 쓰여진 ip로 플래그 정보가 포함된 get 요청을 한다.
$host = file_get_contents("tmp/tmp-{$time}");
$request = "GET /?{$flag} HTTP/1.0\r\n";
  $request .= "Host: {$host}\r\n";
  $request .= "\r\n";

  $socket = fsockopen($host,7777,$errstr,$errno,1);
  fputs($socket,$request);

이번 문제는 race condition의 개념을 이용하는 문제로, 서버가 먼저 생성한 tmp-{$time} 파일을 덮어써서 127.0.0.1이 아닌 나의 ip로 요청이 오도록 변경하는 것입니다.

결과

이를 파이썬 코드로 작성하면 다음과 같습니다.

위의 코드를 우분투 환경에서 실행하면 다음과 같이 플래그를 획득 할 수 있습니다.

image

댓글남기기