본문 바로가기

챌린지/los.rubiya.kr

Lord of SQLInjection - succubus

16번째 문제인 succubus다.

<?php
  include "./config.php"; 
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/\'/',$_GET[id])) exit("HeHe");
  if(preg_match('/\'/',$_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 = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if($result['id']) solve("succubus"); 
  highlight_file(__FILE__); 
?>

id, pw 파라미터 모두 따옴표 필터링이 적용되어 있다. 그런데 두 파라미터 모두 따옴표로 감싸져 있다. 그래서 따옴표를 닫아주는 방식으로는 이를 탈출할 수 없는데 이 문제를 어떻게 풀 수 있는 것일까? 그 해답은 바로 이스케이프 문자였다.

echo "quote is '"."\n"; // quote is '
// echo 'quote is ''."\n"; << ERROR!
echo 'double quote is "'."\n"; // double quote is "
// echo "double quote is ""."\n"; << ERROR!

위의 PHP 예제에서 보면 알겠지만 ''이나 ""으로 묶인 문자열 내부에서 동일한 따옴표를 한번 더 사용하면 해당 리터럴의 끝을 의미하기 때문에 남은 따옴표가 혼자 남아서 구문 에러를 발생시킨다. 그래서 따옴표가 몇번 사용되지 않는다면 "I'm happy."나 '"World" should be followed.'처럼 해당 문자열의 따옴표와 반대되는 따옴표로 묶어준다. 그렇지만 불가피하게 같은 따옴표를 사용해야 한다면 어떻게 할까? C언어에서 봤던 것처럼 '\''처럼 '\' 문자를 붙여서 이스케이프 시퀀스로 만들어 줌으로써 따옴표가 리터럴의 끝으로 처리되는 것을 방지할 수 있다.

 

Escape sequences in C - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search escape characters and related in the C programming language Escape sequences are used in the programming languages C and C++, and their design was copied in many other languages such a

en.wikipedia.org

그런데 이 이스케이프 시퀀스가 무슨 의미란 말인가? 어차피 '\''처럼 입력해도 따옴표가 필터링되는 이상 불가능하지 않을까? 이는 현재 쿼리에서 사용자 입력값을 파라미터로 문자열에 그대로 집어넣고 있다는 점을 활용할 수 있다.

 

위의 "select id from prob_succubus where id='{$_GET[id]}' and pw='{$_GET[pw]}'" 쿼리에서 {$_GET[id]}나 {$_GET[pw]} 부분에 그냥 '\' 문자만 들어간다면 어떨까? 이는 필터링되지 않기 때문에 '\'가 그대로 쿼리에 입력될 수 있다. 그런데 지금 각 파라미터는 따옴표로 감싸져 있기 때문에 만약 파라미터 값이 '\'라면 "select id from prob_succubus where id='\' and pw='12345'" 처럼 쿼리가 생성된다. 그럼 이 쿼리는 id가 '\'이고 pw가 '12345'인 id를 찾는 쿼리일까? 그렇지 않다. 이 쿼리는 id가 "' and pw="인 값을 찾는 쿼리가 되며 pw 파라미터 값인 12345와 마지막 따옴표는 그냥 쿼리에 뜬금없이 붙어있는 이상한 값이 된다. 왜 그럴까?

이는 위처럼 '\' 문자에 의해 쿼리 내부의 따옴표가 이스케이프 시퀀스로 치환되었기 때문이다. 그래서 pw 파라미터를 감싸던 따옴표 중 여는 따옴표는 id 파라미터의 닫는 따옴표로 인식되고 pw 파라미터의 닫는 따옴표까지 나머지 문자열은 불완전한 쿼리로 인식됀다. 하지만 pw 파라미터는 사용자가 입력할 수 있는 부분이기 때문에 이곳에 추가적인 쿼리를 삽입하면 되는데 아무런 값이나 결과 쿼리에 포함되면 되기 때문에 적절한 값을 통해 조건을 true로 만들어주면 풀 수 있다.

위와 같은 쿼리의 경우 id 파라미터에 '\', pw 파라미터에 'or true%23'을 입력한 경우다. 그래서 id의 닫는 따옴표가 이스케이프 시퀀스로 처리되어 pw 파라미터 문자열까지 먹어버린 것을 알 수 있다. 이는 pw 파라미터가 쌍따옴표로 닫혀있거나 '\' 문자가 필터링된다면 불가능한 해결책이다.

 

 

LoS 문제를 풀면 풀수록 온갖 신기하고 창의적인 SQL Injection 기법들을 알게되는 것 같다. 이스케이프 시퀀스로 따옴표를 무시하는 방법은 생각지도 못했는데 웹해킹 SQLI 우회기법 정리에서 나온 내용이라 풀 수 있었던 것 같다.

'챌린지 > los.rubiya.kr' 카테고리의 다른 글

Lord of SQLInjection - nightmare  (0) 2021.01.13
Lord of SQLInjection - zombie_assassin  (0) 2021.01.11
Lord of SQLInjection - assassin  (0) 2021.01.05
Lord of SQLInjection - giant  (0) 2021.01.04
Lord of SQLInjection - bugbear  (0) 2021.01.03