Skip to content

Commit 687de95

Browse files
authored
Merge pull request #1104 from HackTricks-wiki/research_update_src_pentesting-web_http-request-smuggling_request-smuggling-in-http-2-downgrades_20250712_013912
Research Update Enhanced src/pentesting-web/http-request-smu...
2 parents f6d9768 + 2d9a4ac commit 687de95

File tree

2 files changed

+94
-3
lines changed

2 files changed

+94
-3
lines changed

src/mobile-pentesting/ios-pentesting/ios-pentesting-without-jailbreak.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ Recent Frida releases (>=16) automatically handle pointer authentication and oth
106106

107107
### Automated dynamic analysis with MobSF (no jailbreak)
108108

109-
[MobSF](https://mobsf.github.io/Mobile-Security-Framework-MobSF/) can instrument a dev-signed IPA on a real device using the same technique (`get_task_allow`) and provides a web UI with filesystem browser, traffic capture and Frida console【】. The quickest way is to run MobSF in Docker and then plug your iPhone via USB:
109+
[MobSF](https://mobsf.github.io/Mobile-Security-Framework-MobSF/) can instrument a dev-signed IPA on a real device using the same technique (`get_task_allow`) and provides a web UI with filesystem browser, traffic capture and Frida console【†L2-L3】. The quickest way is to run MobSF in Docker and then plug your iPhone via USB:
110110

111111
```bash
112112
docker pull opensecurity/mobile-security-framework-mobsf:latest

src/pentesting-web/http-request-smuggling/request-smuggling-in-http-2-downgrades.md

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,100 @@
22

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

5-
**Check the post [https://portswigger.net/research/http-2-downgrades](https://portswigger.net/research/http-2-downgrades)**
5+
HTTP/2 is generally considered immune to classic request-smuggling because the length of each DATA frame is explicit. **That protection disappears as soon as a front-end proxy “downgrades” the request to HTTP/1.x before forwarding it to a back-end**. The moment two different parsers (the HTTP/2 front-end and the HTTP/1 back-end) try to agree on where one request ends and the next begins, all the old desync tricks come back – plus a few new ones.
66

7-
{{#include ../../banners/hacktricks-training.md}}
7+
---
8+
## Why downgrades happen
9+
10+
1. Browsers already speak HTTP/2, but much legacy origin infrastructure still only understands HTTP/1.1.
11+
2. Reverse-proxies (CDNs, WAFs, load-balancers) therefore terminate TLS + HTTP/2 at the edge and **rewrite every request as HTTP/1.1** for the origin.
12+
3. The translation step has to create *both* `Content-Length` **and/or** `Transfer-Encoding: chunked` headers so that the origin can determine body length.
13+
14+
Whenever the front-end trusts the HTTP/2 frame length **but** the back-end trusts CL or TE, an attacker can force them to disagree.
15+
16+
---
17+
## Two dominant primitive classes
18+
19+
| Variant | Front-end length | Back-end length | Typical payload |
20+
|---------|-----------------|-----------------|-----------------|
21+
| **H2.TE** | HTTP/2 frame | `Transfer-Encoding: chunked` | Embed an extra chunked message body whose final `0\r\n\r\n` is *not* sent, so the back-end waits for the attacker-supplied “next” request. |
22+
| **H2.CL** | HTTP/2 frame | `Content-Length` | Send a *smaller* CL than the real body, so the back-end reads past the boundary into the following request. |
23+
24+
> These are identical in spirit to classic TE.CL / CL.TE, just with HTTP/2 replacing one of the parsers.
25+
26+
---
27+
## Identifying a downgrade chain
28+
29+
1. Use **ALPN** in a TLS handshake (`openssl s_client -alpn h2 -connect host:443`) or **curl**:
30+
```bash
31+
curl -v --http2 https://target
32+
```
33+
If `* Using HTTP2` appears, the edge speaks H2.
34+
2. Send a deliberately malformed CL/TE request *over* HTTP/2 (Burp Repeater now has a dropdown to force HTTP/2). If the response is an HTTP/1.1 error such as `400 Bad chunk`, you have proof the edge converted the traffic for a HTTP/1 parser downstream.
35+
36+
---
37+
## Exploitation workflow (H2.TE example)
38+
39+
```http
40+
:method: POST
41+
:path: /login
42+
:scheme: https
43+
:authority: example.com
44+
content-length: 13 # ignored by the edge
45+
transfer-encoding: chunked
46+
47+
5;ext=1\r\nHELLO\r\n
48+
0\r\n\r\nGET /admin HTTP/1.1\r\nHost: internal\r\nX: X
49+
```
50+
1. The **front-end** reads exactly 13 bytes (`HELLO\r\n0\r\n\r\nGE`), thinks the request is finished and forwards that much to the origin.
51+
2. The **back-end** trusts the TE header, keeps reading until it sees the *second* `0\r\n\r\n`, thereby consuming the prefix of the attacker’s second request (`GET /admin …`).
52+
3. The remainder (`GET /admin …`) is treated as a *new* request queued behind the victim’s.
53+
54+
Replace the smuggled request with:
55+
* `POST /api/logout` to force session fixation
56+
* `GET /users/1234` to steal a victim-specific resource
857

58+
---
59+
## h2c smuggling (clear-text upgrades)
960

61+
A 2023 study showed that if a front-end passes the HTTP/1.1 `Upgrade: h2c` header to a back-end that supports clear-text HTTP/2, an attacker can tunnel *raw* HTTP/2 frames through an edge that only validated HTTP/1.1. This bypasses header normalisation, WAF rules and even TLS termination.
1062

63+
Key requirements:
64+
* Edge forwards **both** `Connection: Upgrade` and `Upgrade: h2c` unchanged.
65+
* Origin increments to HTTP/2 and keeps the connection-reuse semantics that enable request queueing.
66+
67+
Mitigation is simple – strip or hard-code the `Upgrade` header at the edge except for WebSockets.
68+
69+
---
70+
## Notable real-world CVEs (2022-2025)
71+
72+
* **CVE-2023-25690** – Apache HTTP Server mod_proxy rewrite rules could be chained for request splitting and smuggling. (fixed in 2.4.56)
73+
* **CVE-2023-25950** – HAProxy 2.7/2.6 request/response smuggling when HTX parser mishandled pipelined requests.
74+
* **CVE-2022-41721** – Go `MaxBytesHandler` caused left-over body bytes to be parsed as **HTTP/2** frames, enabling cross-protocol smuggling.
75+
76+
---
77+
## Tooling
78+
79+
* **Burp Request Smuggler** – since v1.26 it automatically tests H2.TE/H2.CL and hidden ALPN support. Enable “HTTP/2 probing” in the extension options.
80+
* **h2cSmuggler** – Python PoC by Bishop Fox to automate the clear-text upgrade attack:
81+
```bash
82+
python3 h2csmuggler.py -u https://target -x 'GET /admin HTTP/1.1\r\nHost: target\r\n\r\n'
83+
```
84+
* **curl**/`hyper` – crafting manual payloads: `curl --http2-prior-knowledge -X POST --data-binary @payload.raw https://target`.
85+
86+
---
87+
## Defensive measures
88+
89+
1. **End-to-end HTTP/2** – eliminate the downgrade translation completely.
90+
2. **Single source of length truth** – when downgrading, *always* generate a valid `Content-Length` **and** **strip** any user-supplied `Content-Length`/`Transfer-Encoding` headers.
91+
3. **Normalize before route** – apply header-sanitisation *before* routing/rewrite logic.
92+
4. **Connection isolation** – do not reuse back-end TCP connections across users; “one request per connection” defeats queue-based exploits.
93+
5. **Strip `Upgrade` unless WebSocket** – prevents h2c tunnelling.
94+
95+
---
96+
## References
97+
98+
* PortSwigger Research – “HTTP/2: The Sequel is Always Worse” <https://portswigger.net/research/http2>
99+
* Bishop Fox – “h2c Smuggling: request smuggling via HTTP/2 clear-text” <https://bishopfox.com/blog/h2c-smuggling-request>
100+
101+
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)