Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion src/pentesting-web/http-request-smuggling/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,58 @@ def handleResponse(req, interesting):
table.add(req)
```

## Chunked extension line-terminator desync (TERM.EXT/EXT.TERM) – Kestrel/.NET CVE-2025-55315

A modern HTTP/1.x smuggling primitive arises when front-ends and back-ends disagree on how to terminate the first chunk header when it contains an extension. RFC 9112 requires chunk headers to end with a strict CRLF (`\r\n`). Some front-ends tolerate a lone LF (`\n`) as a line terminator inside the chunk extension and proceed, while some back-ends correctly keep scanning for CRLF. If the FE accepts LF but the BE ignores it, their message boundaries desynchronize and the tail can be parsed as a second, hidden request.

Background
- Chunk syntax: size-hex[;extensions]`\r\n` + [size bytes] + `\r\n`, ending with `0\r\n\r\n`.
- Chunk extensions: optional metadata after a semicolon (`;foo=bar`). Most servers ignore them, but how they are ignored matters.
- Variants (per w4ke): TERM.EXT vs EXT.TERM depending on whether the FE treats LF as a terminator while the BE treats it as extension data, or vice versa.

Example payload (LF in first chunk extension)
```http
POST /example HTTP/1.1\r\n
Host: victim\r\n
Transfer-Encoding: chunked\r\n
\r\n
2;foo=bar\n
xx\r\n
47\r\n
GET /admin HTTP/1.1\r\n
Host: victim\r\n
X-SSL-CLIENT-CN: administrator\r\n
\r\n
0\r\n\r\n
```

Parsing behavior
- Front-end (tolerates LF): parses a single chunked request. It consumes `2;foo=bar\n` as the first chunk header, then `xx` as the body, then sees the next header (`47`). Only one response is sent.
- Back-end (pre-fix Kestrel): ignores the lone LF within the extension and keeps scanning for CRLF, so it can realign early and interpret part of the stream as a second pipelined request (for example, `GET /admin`) with attacker-controlled headers such as `X-SSL-CLIENT-CN`.

Impacts (depends on FE/BE/app)
- Proxy header spoofing/auth bypass: inject headers normally added by the FE (for example, `X-SSL-CLIENT-CN`) and bypass authn/authz.
- SSRF/internal routing: smuggle requests to internal-only paths behind the FE.
- CSRF/cache poisoning/data exfil: desync request/response boundaries to leak or poison without XSS.

Scope/notes
- Affects HTTP/1.0–1.1 only. HTTP/2/3 are not affected (binary framing; no chunked TE).
- Even without an external proxy, any proxy-like code that reads/forwards raw request streams can introduce a second parser layer and the same ambiguity.

Patch behavior and detection
- Fixed Kestrel rejects any non-CRLF line ending while parsing chunk extensions and returns HTTP 400 (`KestrelBadHttpRequestException`).
- Unpatched Kestrel often hangs awaiting more data on LF-terminated chunk headers.

Quick probe
```bash
# Expect hang if vulnerable; 400 if fixed
echo -e "GET / HTTP/1.1\\r\\nHost:\\r\\nTransfer-Encoding: chunked\\r\\n\\r\\n1;\\n" | nc <host> <port>
```

Notes
- Many front-ends normalize or reject malformed chunked bodies; the primitive requires an FE that accepts lone LF in the extension while a BE insists on CRLF.
- For automated verification across framework versions, see the public repro tool that replays ASP.NET Core functional tests.

## Tools

- HTTP Hacker (Burp BApp Store) – visualize concatenation/framing and low‑level HTTP behavior
Expand All @@ -915,6 +967,7 @@ def handleResponse(req, interesting):
- [https://github.com/defparam/smuggler](https://github.com/defparam/smuggler)
- [https://github.com/Moopinger/smugglefuzz](https://github.com/Moopinger/smugglefuzz)
- [https://github.com/bahruzjabiyev/t-reqs-http-fuzzer](https://github.com/bahruzjabiyev/t-reqs-http-fuzzer): This tool is a grammar-based HTTP Fuzzer useful to find weird request smuggling discrepancies.
- [Repro/verification for Kestrel LF-in-extension desync](https://github.com/sirredbeard/CVE-2025-55315-repro)

## References

Expand All @@ -932,6 +985,10 @@ def handleResponse(req, interesting):
- Browser‑Powered Desync Attacks – [https://portswigger.net/research/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](https://portswigger.net/web-security/request-smuggling/browser/client-side-desync)
- [https://portswigger.net/research/http1-must-die](https://portswigger.net/research/http1-must-die)
- [Understanding the .NET/Kestrel LF-in-extension desync (CVE-2025-55315)](https://andrewlock.net/understanding-the-worst-dotnet-vulnerability-request-smuggling-and-cve-2025-55315/)
- [Kestrel fix PR (strict CRLF in chunk extensions)](https://github.com/dotnet/aspnetcore/pull/64037)
- [Microsoft advisory/issue for CVE-2025-55315](https://github.com/dotnet/aspnetcore/issues/64033)
- [Chunked-extension line-terminator research (TERM.EXT/EXT.TERM)](https://w4ke.info/2025/06/18/funky-chunks.html)


{{#include ../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}