http-connection-request-smuggling.md (9129B)
1 --- 2 title: "HTTP Connection Request Smuggling" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/http-connection-request-smuggling.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/http-connection-request-smuggling.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # HTTP Connection Request Smuggling 14 15 **HTTP connection request smuggling** is a **connection-state / routing** problem rather than a classic CL.TE/TE.CL parser discrepancy. The bug appears when a front-end decides **where a connection is allowed to go only once**, then silently reuses that same TCP/TLS connection for later requests with a different `Host` or `:authority`.<sup>[[1]](#references)[[2]](#references)</sup> 16 17 If you need the classic length-confusion variants, see [HTTP Request Smuggling / HTTP Desync Attack](/hacktricks/pentesting-web/http-request-smuggling/overview) and [Request Smuggling in HTTP/2 Downgrades](/hacktricks/pentesting-web/http-request-smuggling/request-smuggling-in-http-2-downgrades). 18 19 ## Connection-State Attacks <a href="#state" id="state"></a> 20 21 ### First-request Validation 22 23 When routing requests, reverse proxies often depend on the **Host** header (or **`:authority`** in HTTP/2) to decide the destination back-end server and whether that destination is allowed. A recurring bug class is that this whitelist is **only enforced on the first request on a connection**. After that, the front-end trusts the connection itself instead of re-validating each request: 24 25 ```http 26 GET / HTTP/1.1 27 Host: allowed-external-host.example 28 29 GET /admin HTTP/1.1 30 Host: internal-only.example 31 ``` 32 33 This turns connection reuse into an SSRF-like primitive against **internal virtual hosts**, admin panels, debug routes, and alternate tenants sharing the same edge.<sup>[[1]](#references)</sup> 34 35 ### First-request Routing 36 37 Some reverse proxies map the **entire back-end connection** to a destination pool based only on the **first request** they forward. Every later request on that client connection is then sent to the same upstream, even if the `Host` header changes. This is especially useful when combined with [Host header attacks](https://portswigger.net/web-security/host-header) such as password-reset poisoning, cache poisoning, or virtual-host brute forcing: 38 39 ```http 40 GET / HTTP/1.1 41 Host: public.example 42 43 POST /pwreset HTTP/1.1 44 Host: private.internal 45 ``` 46 47 > [!TIP] 48 > PortSwigger's **HTTP Request Smuggler** extension includes a **connection-state probe** specifically for these cases. They are easy to dismiss as “just connection reuse” or “just pipelining”, so always confirm with a fresh-connection control request. 49 50 ### Why this is different from classic desyncs 51 52 - **No CL/TE ambiguity is required.** The dangerous behavior is the **routing/authorization decision being cached per connection**. 53 - **Reuse is mandatory.** If the front-end or browser opens a new connection for the second request, the attack dies. 54 - **False positives are common.** Ordinary HTTP pipelining/reuse can look suspicious, so re-test the same request on a brand-new connection and compare the response origin, headers, and status code. 55 56 --- 57 58 ## Browser-Powered Connection-State Abuse (2022-2025) 59 60 The most practical modern variant is **browser-powered** exploitation. A victim first opens a legitimate connection to an attacker-controlled or attacker-triggered origin, and the browser later **reuses or coalesces** that connection for a different authority.<sup>[[1]](#references)</sup> 61 62 ### Coalescing preconditions worth checking 63 64 For HTTP/2 and HTTP/3, prioritize targets where several hostnames share the same edge infrastructure: 65 66 - The certificate presented on the existing connection is valid for **both** the attacker-controlled hostname and the target hostname. 67 - For classic HTTP/2 coalescing, browsers commonly require the hostnames to resolve to the **same edge / overlapping IP set**. 68 - **ORIGIN frames** can further expand which authorities are considered reusable on an existing HTTP/2 connection, so “same IP” is **not** the whole story anymore. 69 - Shared **CDNs, API gateways, WAFs, service meshes, Alt-Svc / HTTP/3 endpoints**, and wildcard certificates increase the odds of cross-origin reuse. 70 - The front-end performs **routing or host validation only once** instead of per request / per stream. 71 72 ### Exploitation scenario 73 74 1. The attacker controls `evil.com`, which terminates on the same shared edge as `internal.company`. 75 2. The victim opens `https://evil.com/` and the browser establishes an HTTP/2 or HTTP/3 connection. 76 3. The attacker causes the victim to request `https://internal.company/...` (for example via an `<img>`, `fetch()`, or redirect chain). 77 4. The browser reuses the **existing** connection because the endpoint looks authoritative for both origins. 78 5. If the edge only validated the **first** request, the later request to `internal.company` is routed or authorized using stale connection state. 79 80 > [!NOTE] 81 > A hardened deployment may respond with **`421 Misdirected Request`** when a reused connection is not valid for the new authority. Seeing `421` is usually a good sign: the server noticed the connection was coalesced but refused to trust it. 82 83 ### Practical testing workflow 84 85 #### HTTP/1.1 manual probe 86 87 ```bash 88 printf 'GET / HTTP/1.1\r\nHost: public.example\r\nConnection: keep-alive\r\n\r\nGET /admin HTTP/1.1\r\nHost: internal.example\r\nConnection: close\r\n\r\n' \ 89 | openssl s_client -quiet -connect target:443 90 ``` 91 92 If the second response clearly belongs to `internal.example`, or if back-end behavior changes only when both requests share one socket, investigate further. 93 94 #### HTTP/2 workflow 95 96 1. In **Burp Repeater**, enable **Allow HTTP/2 ALPN override** so you can test **hidden HTTP/2** support even when the server does not advertise it. 97 2. Send an initial request to an allowed host / authority. 98 3. Reuse the **same Repeater tab / same connection** and change only `:authority` (or the target path) for the next request or stream. 99 4. Repeat the exact same second request from a **fresh connection** as a control. 100 5. A genuine issue normally shows a routing / authorization difference that exists **only** on the reused connection. 101 102 ### High-value chains 103 104 Connection-state flaws combine particularly well with: 105 106 - **Internal virtual-host enumeration** and access to admin panels or preview environments. 107 - **Host header attacks** such as password-reset poisoning or cache poisoning on an internal / alternate vhost. 108 - **Client-side desync** and browser-assisted queue poisoning techniques from [Browser HTTP Request Smuggling](/hacktricks/pentesting-web/http-request-smuggling/browser-http-request-smuggling). 109 - **HTTP/2 downgrade gadgets** from [Request Smuggling in HTTP/2 Downgrades](/hacktricks/pentesting-web/http-request-smuggling/request-smuggling-in-http-2-downgrades) when you need a second primitive to poison a shared back-end connection. 110 111 --- 112 113 ## Related State-Transition Abuse: `h2c` Upgrade Tunnelling 114 115 A closely related bug appears when a front-end forwards **`Upgrade: h2c`** and, after the `101 Switching Protocols`, stops inspecting the traffic and simply tunnels bytes to the back end. In practice, the proxy may enforce routing / ACLs only on the **initial HTTP/1.1 request**, after which the attacker speaks raw clear-text HTTP/2 directly to the internal service. 116 117 ```http 118 GET / HTTP/1.1 119 Host: public.example 120 Connection: Upgrade, HTTP2-Settings 121 Upgrade: h2c 122 HTTP2-Settings: AAMAAABkAAQCAAAAAAIAAAAA 123 ``` 124 125 This is worth testing on reverse proxies that support upgrade-style tunnelling or permissive `proxy_pass` rules. 126 127 --- 128 129 ## Tooling 130 131 - **HTTP Request Smuggler** (Burp) – useful for **connection-state probes**, hidden-HTTP/2 testing, browser-powered desync work, and modern parser-discrepancy detection. 132 - **`http2smugl`** – purpose-built for finding **HTTP/2 → HTTP/1.1 downgrade** smuggling paths and related request poisoning opportunities. 133 - **`smugglefuzz`** – a **Go-based** downgrade smuggling scanner with customizable gadget lists and fast bulk probing. 134 - **`h2cSmuggler`** – focuses on `Upgrade: h2c` tunnelling mistakes that bypass front-end ACLs. 135 136 --- 137 138 ## Mitigations 139 140 - Re-validate **`Host` / `:authority` on every request and every HTTP/2 stream**, not just once per socket. 141 - Keep **internal and external hostnames** on separate certificates / origin sets / Alt-Svc advertisements when possible. 142 - Return **`421 Misdirected Request`** when a reused connection is not authoritative for the new origin. 143 - Strip or hard-code **`Upgrade: h2c`** at the edge unless it is explicitly required. 144 - Where feasible, avoid reusing a single privileged upstream connection across unrelated tenants or trust zones. 145 146 --- 147 148 ## References 149 150 - [1] [PortSwigger Research - Browser-Powered Desync Attacks](https://portswigger.net/research/browser-powered-desync-attacks) 151 - [2] [PortSwigger Research - HTTP/1.1 must die: the desync endgame](https://portswigger.net/research/http1-must-die)