문제 코드

<?php
  include "./config.php";
  login_chk();
  $db = dbconnect("zombie");
  if(preg_match('/rollup|join|ace|@/i', $_GET['pw'])) exit("No Hack ~_~");
  $query = "select pw from prob_zombie where pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['pw']) echo "<h2>Pw : {$result[pw]}</h2>";
  if(($result['pw']) && ($result['pw'] === $_GET['pw'])) solve("zombie");
  highlight_file(__FILE__);
?>

공격 백터

Get 메소드

  • pw

공격 백터의 검증

  • pw : rollup, join, ace, @ 필터링
if(preg_match('/rollup|join|ace|@/i', $_GET['pw'])) exit("No Hack ~_~");

코드 설명

if(preg_match('/rollup|join|ace|@/i', $_GET['pw'])) exit("No Hack ~_~");
$query = "select pw from prob_zombie where pw='{$_GET[pw]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";

pw에 대한 검증 후 select pw from prob_zombie where pw='{$_GET[pw]}' 에 pw가 들어가게 된다. 그 후 pw가 들어간 쿼리문을 페이지에 출력한다.

 

$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['pw']) echo "<h2>Pw : {$result[pw]}</h2>";
if(($result['pw']) && ($result['pw'] === $_GET['pw'])) solve("zombie");

쿼리문에 대한 결과값이 있으면 페이지에 출력되고, 그 후 쿼리문의 결과값과 공격 백터 pw와 같은지 비교를 한다.
만약 같으면 문제를 클리어하게 된다.


문제 풀이

코드를 본 결과 전 문제인 ouroboros 문제와 유사하다고 생각이 든다.
그러므로 Quine SQLi 문제로 생각하면 될 듯 싶었다.

 

확인을 위해 '1'='1' 을 이용하여 모든 pw을 출력하여 맨 위에 있는 pw을 페이지에 출력하려고 시도하였지만, ouroboros 문제처럼 테이블 안에 데이터는 아무것도 없는 것으로 추측됐다.
예상한 대로 Quine SQLi 문제였다.

 

하지만 pw의 필러링 중 ace가 있어서 replace 함수는 사용이 불가능이다.
이를 위해 replace 함수를 사용하지 않는 방법을 검색한 결과 los를 만드신 rubiya님이 쓰신 글을 찾을 수 있었다. 그 글 속엔 아주 큰 힌트가 있었다.

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=withrubiya&logNo=220449067274

 

직접해보니 내가 사용한 쿼리문이 INFO 컬럼에 들어있었다.

 

이를 Union에 적용시키면, 내가 쓴 쿼리문이 그대로 출력된다.
전체 쿼리문이 나오므로, substr()로 나눠서 사용하면 될 듯 싶다.

 

위와 같이 문제를 클리어할 수 있었다.

복사했습니다!