文章总结: 本文通过五个实战案例复盘SQL注入高级利用链,强调挖掘Header、Cookie、XML及数组参数等非常规入口。核心是建立稳定时间盲注信号,解决WAF与缓存干扰,通过入口可达、执行可控、观测稳定及影响可证四阶段形成闭环。建议扩展测试面并设立对照组以确保证据可靠。 综合评分: 95 文章分类: 渗透测试,漏洞分析,WEB安全,实战经验,SRC活动
5个SQL注入案例里的信号建模与利用链闭环总结
原创
Zacarx Zacarx
Zacarx随笔
2026年2月11日 10:35 西藏
说明:本文根据公开披露报告进行技术复盘,定位为安全研究与防守理解。文中仅讨论利用思路与技术原理,不提供针对真实系统的未授权攻击指导。
案例背景
做 SQL 注入测试时,很多人会陷入一个固定动作:改 URL 参数、丢几组 payload、看有没有报错。
但真实世界里的高质量案例,几乎都不是这么“直线型”地打出来的。研究员真正拉开差距的能力是:
- 能从非常规输入面找到入口(XML 节点、Header、Cookie、数组参数);
- 能在噪声环境下建立稳定的验证信号(报错、时间差、条件对照);
- 能把“可能有漏洞”推进成“完整利用链证据”。
背景知识
什么是“利用链思维”
SQL 注入不只是“拼接字符串导致报错”这么简单。真正的利用链通常包含四段:
- 入口可达:输入能否进入数据库查询语境;
- 执行可控:能否通过布尔/时间差控制执行分支;
- 观测稳定:能否在缓存、网关、WAF 干扰下重复验证;
- 影响可证:能否证明读取能力或敏感数据接触能力。
常见误区
- 只测 Query 参数,不测 Header/Cookie;
- 只看单次响应,不做对照组;
- 遇到不稳定结果就判“漏洞不存在”;
- 把缓存命中、CDN 抖动误当成“payload失效”。
为什么“时间盲注”在这5案里反复出现
因为很多现代系统不会直接回显 SQL 错误。研究员就需要一个可重复的 side-channel(侧信道)。
时间盲注的核心就是构造一个逻辑门:
- 条件成立 -> 响应明显变慢;
- 条件不成立 -> 响应明显变快。
只要这个差异稳定且可重复,就说明攻击者影响到了数据库执行路径。
案例1:Starbucks(Report 531051)
- 报告链接:https://hackerone.com/reports/531051
- 目标:Starbucks
- 严重性:Critical (9.3)
- 赏金:隐藏
案例背景
这个案例的经典之处在于:入口表面看起来像文件上传,但研究员最终走出的主链路是“XML业务字段 -> SQL 语境 -> 时间盲注”。
漏洞发现过程
Step 1:先从“上传”入手,但很快发现方向不对
研究员最初按常规上传漏洞思路测试,发现文件虽然传到了服务端,但并不会按“文件落盘”方式保留,而是被解析处理。
这一步很关键:它把问题从“文件上传漏洞”转成了“结构化数据处理漏洞”。
Step 2:尝试 XXE,收益有限
由于是 XML 通道,研究员先怀疑 XXE,这很合理。但实际结果并没有形成高价值、稳定的利用链。
Step 3:反向推理——字段既然被解析,很可能进入数据库
他开始把焦点转到 XML 节点字段本身,思路是:业务字段最终若参与数据库查询,就可能存在 SQL 注入。
Step 4:解决“语法到达”问题,触发数据库信号
在 XML 场景里,输入不是原样直达数据库,先要经过 XML 语法层。研究员处理了编码与实体表达后,成功触发了数据库相关异常和时间差行为。
例如后端如果是下面这种拼接方式,XML 字段一旦可控,就会直接进入 SQL 语境:
原理伪代码(PHP)
<?php
$xml = simplexml_load_string($rawBody);
$mainAccount = (string)$xml->MainAccount;
// 危险写法:直接拼接 XML 字段
$sql = "SELECT id, amount FROM ledger WHERE main_account = '$mainAccount'";
$result = $db->query($sql);
公开信息没有完整原始请求包,但请求形态可抽象为:
请求样本(抽象脱敏)
POST /<target_path> HTTP/1.1
Host: <target_host>
Content-Type: application/xml
<LedgerEntry>
<MainAccount>123456<payload></MainAccount>
<Credit>100</Credit>
<Debit>0</Debit>
</LedgerEntry>
这也是为什么该案例里“先解决 XML 语法可达,再验证 SQL 可控”是关键路径。
Step 5:从“可疑”推进到“可证”
后续通过时间盲注建立稳定观测,确认数据库信息,并评估到高价值业务数据面。
完整利用过程(技术链)
- 资产发现到 XML 接口;
- 识别上传并非落盘逻辑;
- 从 XXE 转向 SQLi;
- 处理 XML 实体编码使输入可达 SQL 语境;
- 先用异常信号确认路径,再用时间信号确认条件可控;
- 逐步证明数据库读取风险。
技术原理拆解
- 双解释器问题:输入先过 XML 解析器,再进入 SQL 执行器;
- 语法可达性先于漏洞验证:如果第一层语法不过,SQL payload 再“强”也无意义;
- 时间盲注价值:当报错不稳定或回显不足时,时间差是最可靠的控制信号。
案例2:GSA Bounty(Report 297478)
- 报告链接:https://hackerone.com/reports/297478
- 目标:GSA Bounty
- 严重性:Critical (9.1)
- 赏金:隐藏
案例背景
这是一个典型“你不测就永远发现不了”的注入面:入口不在参数,而在 User-Agent 请求头。
漏洞发现过程
Step 1:优先扫描非常规输入面
研究员没有把注意力局限在 Query 或 Body,而是把 Header 也纳入主测试面。
Step 2:在 User-Agent 中构造条件表达式
核心不是“让页面报错”,而是让后端查询执行分支发生可观察变化。
在不少系统里,Header 会被写入数据库或参与查询条件,原理上常见于下面这种代码:
原理伪代码(PHP)
<?php
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
// 危险写法:把 User-Agent 直接拼接进 SQL
$sql = "INSERT INTO request_log(user_agent, ip) VALUES ('$ua', '$ip')";
$db->query($sql);
只要存在这种拼接链路,User-Agent 就不再是“普通头部信息”,而是可被利用的输入面。
公开报告中的请求形态(脱敏)大致如下:
请求样本(报告脱敏)
GET /dashboard/datagov/csv_to_json HTTP/1.1
Host: labs.data.gov
Referer: 1
X-Forwarded-For: 1
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 ...'XOR(IF(<boolean_condition>,SLEEP(25),0))OR'
Accept: */*
研究员就是通过改变 <boolean_condition> 真假,持续观察 25s 与快速返回之间的差异来固化证据。
Step 3:用时间差替代回显
由于很多场景不会直出 SQL 错误,研究员使用时间盲注信号作为验证依据。
Step 4:建立对照实验,避免误判
同类请求仅改变一个条件变量,重复多轮观察:
- 条件成立:延迟明显;
- 条件不成立:快速返回。
这一步把“感觉像注入”变成“统计上可重复的注入证据”。
完整利用过程(技术链)
- 识别 Header 为潜在注入面;
- 注入条件表达式;
- 观察时间差;
- 建立真/假条件对照;
- 多轮复验排除网络抖动;
- 输出稳定可复现结论。
技术原理拆解
- Header 不是元数据,而是输入数据:只要进入拼接查询链路,就具备注入可能;
- 盲注验证本质是实验设计:必须有对照组,且只变一个变量;
- 稳定性高于花哨 payload:真实复盘里,稳定证据链比复杂语句更有价值。
案例3:Valve(Report 383127)
- 报告链接:https://hackerone.com/reports/383127
- 目标:Valve
- 严重性:Critical (9.9)
- 赏金:$25,000
案例背景
该案例公开摘要虽短,但信息很典型:countryFilter[] 数组参数、盲注、并涉及 WAF 场景。它代表的是“动态筛选接口”这类高风险形态。
漏洞发现过程
Step 1:把数组参数当成结构化攻击面
countryFilter[] 往往会参与 IN (...) 或动态筛选拼装,其风险高于普通单值参数。
对应到后端,很多接口会这样处理数组参数:
原理伪代码(PHP)
<?php
$filters = $_GET['countryFilter'] ?? [];
// 危险写法:数组元素直接拼接为 IN 列表
$in = "'" . implode("','", $filters) . "'";
$sql = "SELECT report_id, clicks FROM partner_report WHERE country IN ($in)";
$rows = $db->query($sql)->fetchAll();
这类拼装方式会把“数组输入”变成“查询结构的一部分”,风险通常高于单值参数。
公开摘要未披露完整请求体,但可抽象为以下形态:
请求样本(抽象脱敏)
GET /report_xml.php?countryFilter[]=US&countryFilter[]=CA&countryFilter[]=<sqli_payload> HTTP/1.1
Host: <target_host>
当数组元素直接参与拼接时,攻击者就有机会影响动态筛选逻辑。
Step 2:验证是否能影响查询结构
研究员通过盲注路径测试参数是否改变执行分支,而不是依赖直接报错。
Step 3:识别边缘防护的观测干扰
在 WAF/网关存在时,单次失败不能直接判定“无漏洞”,因为可能是请求在前层被改写、拦截或限速。
Step 4:调整表达形态后复测
核心思想是“保持 SQL 语义目标不变,调整输入形态”,最终得到稳定的盲注执行信号。
完整利用过程(技术链)
- 识别数组参数为主入口;
- 测试参数结构对查询逻辑影响;
- 通过盲注行为验证可控性;
- 拆分分析 WAF 与后端执行路径;
- 调整请求表达并复测;
- 固化可读风险证据。
技术原理拆解
- 结构注入风险:数组参数常用于拼接条件集合,容易形成结构层注入;
- 多层解释差异:WAF 对输入的“理解”不等于数据库最终解释;
- 盲注价值:当直接回显不可靠时,行为侧信道仍可证明执行控制权。
案例4:Eternal / Zomato(Report 403616)
- 报告链接:https://hackerone.com/reports/403616
- 目标:Eternal / Zomato
- 严重性:Critical
- 赏金:$4,500
案例背景
这个案例最有启发的点不是“有注入”,而是研究员识别并处理了缓存干扰。很多盲注失败,其实失败在观测层,不在注入层。
漏洞发现过程
Step 1:锁定 item_id 为入口
POST 参数进入复杂业务路径,初测存在可疑时间差。
Step 2:结果不稳定,先判断观测污染
同类请求表现忽快忽慢,研究员没有马上否定漏洞,而是怀疑缓存策略在干扰。
Step 3:主动构造“去缓存”测试
通过对关键前缀做微小变化,使请求穿透缓存,重新回到数据库真实执行路径。
这个现象经常来自“缓存键与 SQL 参数复用”,例如:
原理伪代码(PHP)
<?php
$itemId = $_POST['item_id'] ?? '';
$prefix = explode('-', $itemId)[0] ?? $itemId;
$cacheKey = 'menu:item:' . $prefix;
if ($cache->has($cacheKey)) {
return $cache->get($cacheKey);
}
// 危险写法:命中不了缓存时,仍是字符串拼接查询
$sql = "SELECT * FROM menu_item WHERE item_id = '$itemId'";
$data = $db->query($sql)->fetchAll();
$cache->set($cacheKey, $data, 60);
所以研究员才会先做“去缓存扰动”,再做盲注对照,不然观测信号会被缓存噪声覆盖。
公开报告中的请求形态(脱敏)如下,重点是 item_id 参数承担了注入语义:
请求样本(报告脱敏)
POST /php/██████████ HTTP/1.1
Host: www.zomato.com
Content-Type: application/x-www-form-urlencoded
res_id=1111&method=add_menu_item_tags&item_id=1111-if(<boolean_condition>,sleep(5),0)&new_tags[]=3&menu_id=1111
当 <boolean_condition> 成立时响应明显变慢,不成立时响应恢复正常,这就是盲注可控性的关键观测点。
Step 4:重建条件对照,确认盲注
去噪后,条件成立与不成立的时间差开始稳定,说明可控执行成立。
Step 5:位级验证读取能力
继续通过条件判断方式验证可读能力,而非追求大量数据导出。
完整利用过程(技术链)
- 锁定
item_id; - 观察不稳定响应;
- 识别缓存噪声;
- 变更请求特征去缓存;
- 建立真/假条件对照;
- 固化时间盲注可控性;
- 证明读取能力。
技术原理拆解
- 缓存假阴性:payload 可能有效,但缓存命中掩盖了结果;
- 盲注前置条件:先净化观测链路,再谈时间判断;
- 位级条件验证:在低扰动下证明读取可能性,是高质量复盘常见做法。
案例5:MTN Group(Report 761304)
- 报告链接:https://hackerone.com/reports/761304
- 目标:MTN Group
- 严重性:High
- 赏金:隐藏
案例背景
这是一类非常容易被忽略但命中率很高的场景:Cookie 参数注入。测试者如果只盯 URL 和 Body,通常会漏掉这种入口。
漏洞发现过程
Step 1:将 Cookie 纳入主测试面
研究员定位到 lang 字段,而不是把它当“普通客户端状态值”。
Step 2:语法扰动确认异常相关性
先做最小扰动观察异常,再做平衡输入看异常是否消失,判断是否与 SQL 解析相关。
在 Cookie 场景里,后端常见风险点通常像这样:
原理伪代码(PHP)
<?php
$lang = $_COOKIE['lang'] ?? 'en';
// 危险写法:Cookie 直接进入查询条件
$sql = "SELECT id, title FROM article WHERE lang = '$lang' ORDER BY publish_time DESC";
$list = $db->query($sql)->fetchAll();
只要 Cookie 值参与了拼接 SQL,lang 这类“看起来 harmless 的字段”也会变成注入入口。
公开报告中的请求形态(脱敏)可抽象为:
请求样本(报告脱敏)
GET /index.php/search/default?t=1&x=0&y=0 HTTP/1.1
Host: mtn.com.ye
User-Agent: Mozilla/5.0 ...
Cookie: PHPSESSID=<session_id>; lang=en'<sqli_payload>; _ga=...; _gid=...
研究员先用引号扰动确认语法相关性,再用延时表达式确认数据库执行路径受控。
Step 3:引入时间盲注建立强信号
在异常相关性已确认后,进一步使用时间差验证执行可控性。
Step 4:多轮复测收敛结论
通过重复实验确认该现象可稳定重现,最终形成闭环证据。
完整利用过程(技术链)
- Cookie 字段扫描;
- 锁定
lang; - 扰动与平衡测试;
- 时间盲注验证;
- 多轮复测;
- 形成“入口-信号-结论”闭环。
技术原理拆解
- Cookie 与 Query/Body 地位相同:本质都是客户端可控输入;
- 两阶段验证法:先用错误行为判断相关性,再用时间信号确认可控性;
- 可复现是关键:单次异常不算证据,重复一致才是利用链基础。
五案共性:高命中率利用链框架
把 5 个案例放在一起看,可以提炼一套通用策略:
1) 入口扩展
不要只测 URL 参数。优先覆盖:
- Header
- Cookie
- 数组参数
- XML/JSON 结构字段
2) 验证分层
- 先验证“是否可达 SQL 语境”;
- 再验证“是否可控执行分支”;
- 最后验证“是否可稳定复现”。
3) 对照优先
任何时间盲注结论都要有真/假条件对照组,且只改变一个变量。
4) 噪声先行
缓存、CDN、网关限速、WAF 策略都会污染观测。先处理噪声,再看延时。
5) 证据闭环
高质量复盘的底层结构是:
入口发现 -> 语法可达 -> 行为可控 -> 多轮复现 -> 风险确认
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Zacarx随笔 Zacarx Zacarx《5个SQL注入案例里的信号建模与利用链闭环总结》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论