10번째 문제인 skeleton이다.
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
$query = "select id from prob_skeleton where id='guest' and pw='{$_GET[pw]}' and 1=0";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id'] == 'admin') solve("skeleton");
highlight_file(__FILE__);
?>
별다른 필터링은 없는데 쿼리에서는 guest의 id로 조회하고 있지만 결과에서 요구되는 id는 admin이다. 그리고 특이하게 쿼리 마지막에 1=0이라는 조건이 AND 연산으로 들어가 있다. 즉 이 구문이 존재하는 한 앞에서 무슨 쿼리를 해도 무조건 거짓으로 만들어서 결과가 아무것도 나오지 않게 되는데 이를 우회하려면 어떻게 해야 할까?
이전 문제들처럼 뒤의 쿼리를 주석으로 없애버릴 수도 있지만 다른 조건을 줘서 이 1=0이라는 거짓 조건이 다른 조건에 합산되게 만들 수도 있다. mysql에서 AND, OR 연산자는 프로그래밍 언어처럼 AND가 OR에 우선한다. 그렇기 때문에 <conditionA> AND <conditionB> OR <conditionC>는 (<conditionA> AND <conditionB>) OR <conditionC>처럼 동작한다. 아래 예를 보자.
select "CORRECT" where 1=1 AND 1=2 OR 2=2 // CORRECT
select "CORRECT" where 1=1 AND 1=2 OR 2=1
위의 쿼리에서 1=1 AND 1=2는 하나로 묶였기 때문에 1=2 조건에 의해 항상 거짓이 된다. 그래서 OR 조건의 2=2, 2=1에 의해 쿼리의 성공과 실패가 결정된다. 이를 문제에 적용해보면 다음과 같이 작성할 수 있다.
select id from prob_skeleton where id='guest' and pw='1' or id='admin' or id='guest' and 1=0
이 쿼리는 OR 연산으로 묶인 "id='guest' and pw='1'"과 "id='admin'", 그리고 "id='guest' and 1=0"으로 나눌 수 있다. 첫번째의 경우 guest 계정의 비밀번호는 1이 아닐것이기 때문에 거짓이 되며 세번째는 1=0때문에 거짓이 되기 때문에 남은 "id='admin'" 조건만이 참이 되며 이에 의해서 admin 계정의 id가 쿼리 결과에 포함되기 때문에 문제를 풀 수 있다.
아니면 그냥 이전처럼 주석으로 없애버릴 수도 있다.
딱히 필터링되는 게 없기 때문에 쉽게 풀 수 있다.
이번 문제는 mysql에서 AND, OR 연산자의 우선순위를 좀 알아보게 되는 문제인 것 같다.
'챌린지 > los.rubiya.kr' 카테고리의 다른 글
Lord of SQLInjection - darkknight (0) | 2021.01.01 |
---|---|
Lord of SQLInjection - golem (0) | 2020.12.31 |
Lord of SQLInjection - vampire (0) | 2020.12.30 |
Lord of SQLInjection - troll (0) | 2020.12.28 |
Lord of SQLInjection - orge (0) | 2020.12.27 |