9번째 문제인 vampire다.
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/\'/i', $_GET[id])) exit("No Hack ~_~");
$_GET[id] = strtolower($_GET[id]);
$_GET[id] = str_replace("admin","",$_GET[id]);
$query = "select id from prob_vampire where id='{$_GET[id]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id'] == 'admin') solve("vampire");
highlight_file(__FILE__);
?>
이번 문제부터는 따옴표를 필터링함으로써 조금씩 어려워지고 있다. 사용자가 입력할 수 있는 파라미터는 id인데 여기서 admin이란 단어를 필터링하고 있기 때문에 admin을 입력할 수는 없다. 하지만 이 문제를 풀기 위해서는 결과 데이터의 id 컬럼에 "admin"이란 값이 포함되어 있어야 하는데 그렇다면 어떻게 문자열 필터링을 우회해서 "admin"을 입력할 수 있을까?
일단 지난번처럼 쿼리 내부의 파라미터가 따옴표에 둘러싸여 있기 때문에 어떤 함수를 사용하거나 16진수 값으로 입력할 수는 없다. 그리고 strtolower() 함수를 이용해서 문자열을 모두 소문자로 변환시키고 있어 지난번처럼 "ADMIN"같은 문자열로 우회할 수 없다. 즉 문자열만 입력해서 이를 우회해야 한다는 것인데 여기서 눈여겨 볼 것은 str_replace() 함수가 단 한번만 호출되고 있다는 것이다.
이 함수는 주어진 변수에서 치환할 문자열을 탐색하고 치환한 다음에는 더 탐색하지 않는다. 즉 처음 탐색했을때 발견한 문자열들에 대해서는 치환하지만 이제 치환되고 난 결과 문자열에도 치환 대상 문자열이 포함되어 있을 경우 이를 치환하지 않는다는 것이다. 확인을 위해 아래 코드를 예시로 들 수 있다.
$text = "Hello World\n";
echo $text; // Hello World
$text = str_replace("Hello", "Cruel", $text);
echo $text; // Cruel World
$text = "CruCruelel World\n";
echo $text; // CruCruelel World
$text = str_replace("Cruel", "", $text);
echo $text; // Cruel World
"CruCruelel World"에서 "Cruel"을 빈 문자열로 치환하면서 "Cruel World"가 됐지만 이 문자열의 "Cruel"은 지워지지 않고 그대로 출력되는 것을 볼 수 있다. 그렇다면 이를 응용해서 "admin" 문자열을 치환하는 것도 "adadminmin"처럼 가운데에 사라질 "admin" 문자열을 집어넣은 "admin" 문자열을 전달하면 되지 않을까?
어렵지 않게 통과할 수 있었다.
이번 문제의 중요한 점은 특정 문자열을 빈 문자열로 바꾸는 식으로 필터링할 시 꼭 반복문을 통해 모든 문자열이 사라졌는지 확인해야 한다는 것이다. 이를테면 str_contains() 메소드를 사용해서 문자열을 치환한 결과에도 또 해당 문자열이 들어있다면 다시한번 문자열을 치환하도록 구현해야 할 것이다.
'챌린지 > los.rubiya.kr' 카테고리의 다른 글
Lord of SQLInjection - golem (0) | 2020.12.31 |
---|---|
Lord of SQLInjection - skeleton (0) | 2020.12.30 |
Lord of SQLInjection - troll (0) | 2020.12.28 |
Lord of SQLInjection - orge (0) | 2020.12.27 |
Lord of SQLInjection - darkelf (0) | 2020.12.27 |