17번째 문제인 zombie_assassin이다.
<?php
include "./config.php";
login_chk();
$db = dbconnect();
$_GET['id'] = strrev(addslashes($_GET['id']));
$_GET['pw'] = strrev(addslashes($_GET['pw']));
if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~");
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
$query = "select id from prob_zombie_assassin 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("zombie_assassin");
highlight_file(__FILE__);
?>
이번 문제에서는 id, pw 파라미터를 addslashes() 함수를 이용하여 필터링하고 있는데 strrev()란 함수가 한번 더 적용되어 있다. 이는 문자열을 반대로 뒤집는 php 함수로 만약 'abcd'란 문자열을 strrev() 함수에 전달하면 'dcba'란 문자열이 반환된다. 이 함수를 addslashes()된 GET으로 얻은 id, pw 파라미터에 적용하기 때문에 특수문자에 '\'가 추가된 문자열이 뒤집히게 된다. 예를 들어 따옴표를 입력하면 다음과 같다.
id 파라미터에 따옴표, pw 파라미터에 쌍따옴표를 입력했더니 쿼리에 '\, "\ 처럼 삽입되었다. 원래는 역슬래시로 필터링되면서 \', \" 처럼 삽입되어야 하지만 strrev() 함수가 이를 뒤집었기 때문에 위처럼 필터링이 이상하게 되는 것이다. 현재 문제에서는 쿼리 결과에 특정 계정을 명시하고 있지 않기 때문에 어떤 계정이든 쿼리에 선택되기만 하면 문제를 풀 수 있다. 그렇다면 pw 파라미터를 조작해서 쿼리 맨 마지막에 "or true" 같은 조건을 삽입할 수 있도록 해보자.
2021/01/06 - [챌린지/los.rubiya.kr] - Lord of SQLInjection - succubus
우선 위와 같은 쿼리에서 착안할 수 있는 해결방법은 이전 문제에서 따옴표가 필터링됐을 때 역슬래시는 필터링되지 않았을 경우 파라미터를 감싸는 따옴표를 이스케이프하여 쿼리문을 잡아먹는 방식이었다. 그러나 지금은 모든 특수문자가 역슬래시로 필터링되고 역순으로 나열되기 때문에 약간 생각을 한번 더 해야했는데 일단 맨 뒤에 있는 pw 파라미터를 '#eurt||'(따옴표 제외) 처럼 채우고 시작했다.
'#' 문자는 URL에서 앵커로 취급되니 %23으로 인코딩해서 넣어줘야한다. 위처럼 전달했을 경우 이제 id 파라미터를 닫는 따옴표를 이스케이프하면 이전 문제처럼 id 파라미터가 "1' and pw=" 인 경우 또는 그냥 true를 조건으로 하는 쿼리가 완성된다. 그렇다면 id 파라미터의 닫는 따옴표를 어떻게 이스케이프할 수 있을까?
이전처럼 그냥 역슬래시만 삽입하면 역슬래시 문자가 두 개 삽입된다. 이는 addslashes()에 의해 필터링되기 때문이다. 그런데 strrev() 함수에 의해 문자열은 반전되기 때문에 두 역슬래시 문자 중 뒤에 있는 역슬래시를 다른 따옴표와 끼워 맞출 수 있지 않을까? 생각의 전환은 익숙하지 않지만 strrev() 함수가 '\"'를 '"\'로 바꾼다는 점이었다. 따옴표 자체가 역슬래시보다 먼저 나오기 때문에 두 문자가 각각 다른 따옴표나 역슬래시와 상호작용할 수 있는 것이다.
이런저런 시도를 해보던 도중 쌍따옴표를 역슬래시 앞에 넣음으로써 문제를 해결할 수 있었다. 약간 얻어걸린 감도 없지않아 있긴 한데 역슬래시 뒤에 따라오는 쌍따옴표가 strrev()에 의해 거꾸로 배치되었기 때문에 필터링된 역슬래시 문자 두 개중 하나를 쌍따옴표가 차지하게 된다. 그리고 쌍따옴표가 받은 역슬래시는 id 파라미터를 닫는 따옴표를 차지하게 되어 두 따옴표가 모두 이스케이프 될 수 있었다. 이 경우 쿼리는 id가 \"' and pw= 인 데이터나 그냥 true 조건인 데이터를 찾게 되며 테이블이 비어있지 않는 이상 어떻게든 쿼리에 결과가 포함되기 때문에 문제를 해결할 수 있다.
이번 문제는 id 파라미터를 무시하고 pw 파라미터에만 이것저것 시도하다가 굉장히 애를 먹었다. 다행히 이전에 따옴표를 이스케이프시키는 문제를 생각해내서 id 파라미터도 활용하면서 조금 해결책이 보이나 싶었지만 strrev() 함수 때문에 쿼리가 헷갈려서 힘들었던 것 같다. 실제로 쿼리에 삽입되는 파라미터를 뒤집을 일은 없을 테니 SQL Injection 보다는 퍼즐게임같은 느낌이었다.
'챌린지 > los.rubiya.kr' 카테고리의 다른 글
Lord of SQLInjection - xavis (0) | 2021.01.15 |
---|---|
Lord of SQLInjection - nightmare (0) | 2021.01.13 |
Lord of SQLInjection - succubus (0) | 2021.01.06 |
Lord of SQLInjection - assassin (0) | 2021.01.05 |
Lord of SQLInjection - giant (0) | 2021.01.04 |