http-response-smuggling-desync.md (18031B)
1 --- 2 title: "HTTP Response Smuggling / Desync" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/http-response-smuggling-desync.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/http-response-smuggling-desync.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # HTTP Response Smuggling / Desync 14 15 **The technique of this post was taken from the video:** [**https://www.youtube.com/watch?v=suxDcYViwao\&t=1343s**](https://www.youtube.com/watch?v=suxDcYViwao&t=1343s)<sup>[[3]](#references)[[4]](#references)</sup> 16 17 ## HTTP Request Queue Desynchronisation 18 19 First of all, this technique **abuses a HTTP Request Smuggling vulnerability**, so you need to know what that is: 20 21 The **main** **difference** between this technique and a common HTTP Request smuggling is that **instead** of **attacking** the **request** of the **victim** **by adding a prefix to it**, we are going to **leak or modify the response the victim receives**. This is done by, instead of sending 1 request and a half to abuse the HTTP Request smuggling, **send 2 complete requests to desynchronise the proxies responses queue**. 22 23 This is because we are going to be able to **desynchronise the response queue** so the **response** from the **legit** **request** of the **victim is sent to the attacker**, or by **injecting attackers controlled content in the response to the victim**. 24 25 ### HTTP Pipeline Desync 26 27 HTTP/1.1 allows to ask for **different resources without needing to wait for previous ones**. Therefore, if there is a **proxy** in the **middle**, it's the proxies task to **maintain a synchronised match of requests sent to the backend and responses coming from it**. 28 29 However, there is a problem desynchronising the responses queue. If an attacker send a HTTP Response smuggling attack and the responses to the **initial request and the smuggled one are responded immediately**, the smuggled response won't be inserted inside the queue of the victim response but will **just be discarded as an error**. 30 31  32 33 Therefore, it's needed that the **smuggled** **request** **takes more time to be processed** inside the back-end server. Therefore, by the time the smuggled request is processed, the communication with the attacker will be over. 34 35 If in this specific situation a **victim has sent a request** and the **smuggled request is responded before** the legitimate request, the **smuggled response will be sent to the victim**. Therefore, the attacker will be **controlling the request "performed" by the victim**. 36 37 Moreover, is the **attacker then perform a request** and the **legitimate response** to the **victim** request is **answered** **before** the attackers request. The **response to the victim is going to be sent to the attacker**, **stealing** the response to the victim (which can contains for example the header **Set-Cookie**). 38 39  40 41  42 43 ### Multiple Nested Injections 44 45 Another **interesting difference** with common **HTTP Request Smuggling** is that, in a common smuggling attack, the **goal** is to **modify the beginning of the victims request** so it perform an unexpected action. In a **HTTP Response smuggling attack**, as you are **sending full requests**, you can **inject in one payload tens of responses** that will be **desynchronising tens of users** that will be **receiving** the **injected** **responses**. 46 47 Apart from being able to **distribute more easily tens of exploits** across legitimate users, this could also be used to cause a **DoS** in the server. 48 49 ### Exploit Organisation 50 51 As explained previously, in order to abuse this technique, it's needed that the **first smuggled message** into the server **requires a lot of time to be processed**. 52 53 This **time consuming request is enough** if we just want to **try to steal the victims response.** But if you want to perform a more complex exploit this will be a common structure for the exploit. 54 55 First of all the **initial** request abusing **HTTP** **Request** **smuggling**, then the **time consuming request** and then **1 or more payload requests** that whose responses will be sent to the victims. 56 57 ### Modern testing notes 58 59 A common pitfall when testing this nowadays is to confuse **real response queue poisoning** with harmless **client-side pipelining / connection reuse artifacts**. If your PoC only works with `requestsPerConnection > 1`, Repeater groups over a single socket, or explicit connection reuse, re-test with connection reuse disabled before claiming a server-side desync. Otherwise you may have only desynchronised **your client** from the server, not the front-end from the back-end. 60 61 Legitimate reuse-required cases still exist: **connection-locked request smuggling**, **connection-state attacks**, and **client-side desync**. A good confirmation trick is to retry the same primitive over an HTTP/2 downgrade path and look for a **nested HTTP/1 response** inside a single response. If you can do that, you are likely looking at a real parser discrepancy instead of a pure pipelining illusion. 62 63 For the generic methodology and browser-powered variants, check [the main HTTP request smuggling page](/hacktricks/pentesting-web/http-request-smuggling/overview) and [Browser HTTP Request Smuggling](/hacktricks/pentesting-web/http-request-smuggling/browser-http-request-smuggling). 64 65 ## Abusing HTTP Response Queue Desynchronisation 66 67 ### Capturing other users' requests <a href="#capturing-other-users-requests" id="capturing-other-users-requests"></a> 68 69 As with HTTP Request Smuggling known payloads, you can **steal the victims request** with one important difference: In this case you just need the **send content to be reflected in the response**, **no persistent storage** is needed. 70 71 First, the attacker send a payload containing a **final POST request with the reflected parameter** at the end and a large Content-Length 72 73  74 75 Then, once the **initial request** (blue) was **processed** and **while** the **sleepy** one is being processed (yellow) the **next request that arrives from a victim** is going to be **appended in the queue just after the reflected parameter**: 76 77  78 79 Then, the **victim** will **receive** the **response to the sleepy** request and if in the meantime the **attacker** **sent** **another** **request**, the **response from the reflected content request will be sent to him**. 80 81 ## Response Desynchronisation 82 83 Up to this point, we have learned how to abuse HTTP Request Smuggling attacks to **control** the **request** **whose** **response** a **client** is going to **receive** and how you can then **steal the response that was meant for the victim**. 84 85 But it's still possible to **desynchronise even** more the responses. 86 87 There are interesting requests like **HEAD** request that are specified to not have **any content inside the responses body** and that should (must) **contain the Content-Length** of the request like **if it was a GET request**. 88 89 Therefore, if an attacker **injects** a **HEAD** request, like in this images: 90 91  92 93 Then, **once the blue one is responded to the attacker**, the next victims request is going to be introduced in the queue: 94 95  96 97 Then, the **victim** will **receive** the **response** from the **HEAD** request, which is **going to contain a Content-Length but no content at all**. Therefore, the proxy **won't send this response** to the victim, but will **wait** for some **content**, which actually is going to be **response to the yellow request** (also injected by the attacker): 98 99  100 101 ### Content Confusion 102 103 Following the previous example, knowing that you can **control the body** of the request whose response is going to receive the victim and that a **HEAD** **response** usually contains in its headers the **Content-Type and the Content-Length**, you can **send a request like the following** one to **cause XSS** in the victim without the page being vulnerable to XSS: 104 105  106 107 ### TRACE as a reflection gadget 108 109 A very practical update is to use a **smuggled `TRACE` request** as the response-body generator when the target has no obvious reflection endpoint. `TRACE` reflects the request received by the backend, often including proxy-added headers (`X-Forwarded-For`, downgraded `HTTP/1.1` start-lines, etc.), so it can be combined with a smuggled `HEAD` to turn a queue desync into **attacker-controlled reflected bytes** in the victim response.<sup>[[1]](#references)</sup> 110 111 Typical pattern: 112 113 1. Smuggle a `HEAD` so the proxy expects a response body length but the backend only sends headers. 114 2. Immediately smuggle `TRACE /...` with attacker-controlled headers and enough padding. 115 3. The `TRACE` response becomes the missing body of the `HEAD` response. 116 4. Reuse it for **content confusion**, **response splitting**, **cache poisoning**, or simply to learn how the proxy rewrites requests before they reach the backend. 117 118 ```http 119 GET / HTTP/1.1 120 Host: target 121 Content-Length: 150 122 123 HEAD / HTTP/1.1 124 Host: target 125 126 TRACE / HTTP/1.1 127 Host: target 128 X-Pad: ...padding... 129 X: <script>alert(1)</script> 130 ``` 131 132 Even if the edge blocks `TRACE`, smuggling can hide it from the front-end/WAF and deliver it directly to the backend. This is especially interesting in HTTP/2→HTTP/1 downgrade scenarios where the downgraded request line and injected proxy headers are reflected back in the `TRACE` body. 133 134 ### Cache Poisoning 135 136 Abusing the previously commented response desynchronisation Content Confusion attack, i**f the cache stores the response to the request performed by the victim and this response is an injected one causing a XSS, then the cache is poisoned**. 137 138 Malicious request containing the XSS payload: 139 140  141 142 Malicious response to the victim that contains the header that indicates to the cache to store the response: 143 144  145 146 > [!WARNING] 147 > Note that in this case if the **"victim" is the attacker** he can now perform **cache poisoning in arbitrary URLs** as he can **control the URL that is going to be cached** with the malicious response. 148 149 ### Web Cache Deception 150 151 This attack is similar to the previous one, but **instead of injecting a payload inside the cache, the attacker will be caching victim information inside of the cache:** 152 153  154 155 ### Response Splitting 156 157 The **goal** of this attack is to abuse again the **response** **desynchronisation** in order to **make the proxy send a 100% attacker generated response**. 158 159 In order to achieve this, the attacker needs to find an endpoint of the web application that is **reflecting some values inside the response** and **know the content length of the HEAD response**. 160 161 He will send a **exploit** like: 162 163  164 165 After the first request is resolved and sent back to the attacker, the **victims request is added into the queue**: 166 167  168 169 The victim will receive as response the **HEAD response + the content of the second request response (containing part of the reflected data):** 170 171  172 173 However, note how the **reflected data had a size according to the Content-Length** of the **HEAD** response that **generated a valid HTTP response in the response queue**. 174 175 Therefore, the **next request of the second victim** will be **receiving** as **response something completely crafted by the attacker**. As the response is completely crafted by the attacker he can also **make the proxy cache the response**. 176 177 ## New response-side discrepancies worth testing (2024-2025) 178 179 Recent research shows that response desync is **not limited to HEAD-only tricks**. When auditing modern stacks, also test response translation layers and not just classic CL.TE / TE.CL ambiguities in requests:<sup>[[2]](#references)</sup> 180 181 - **Response TE.CL / dechunk-vs-length mismatches**: one hop dechunks a backend response or strips `Transfer-Encoding`, while another hop still trusts `Content-Length`. This can transform backend bytes into a forged follow-up response. 182 - **Response-order bugs**: some multi-endpoint frameworks can map responses to the wrong request even without a textbook CL.TE primitive, enabling **response stealing**. 183 - **CGI / gateway conversion issues**: when a CGI/FastCGI/uWSGI-style gateway converts backend output into HTTP, headers emitted by the CGI response can leak into the final HTTP response and create fresh response-side desync gadgets. 184 185 From an offensive point of view, this means it is worth testing **legacy methods** (`HEAD`, `TRACE`), **response rewriting intermediaries**, and **CGI/proxy adapters** even when the classic request-side smuggling checks look clean. 186 187 ## Tooling notes 188 189 - **Burp HTTP Request Smuggler** remains the most practical day-to-day option to probe these bugs, especially when you need to chain a desync into response stealing or cache poisoning. 190 - If you are reviewing implementations from source code, **gray-box differential fuzzing** is now practical enough to find discrepancies in **HTTP requests, HTTP responses, and CGI responses**, not only in front-end request parsing.<sup>[[2]](#references)</sup> 191 192 ## References 193 194 - [1] [PortSwigger - Making desync attacks easy with TRACE](https://portswigger.net/research/trace-desync-attack) 195 - [2] [USENIX Security 2025 - The Silent Danger in HTTP: Identifying HTTP Desync Vulnerabilities with Gray-box Testing](https://www.usenix.org/system/files/usenixsecurity25-mu.pdf) 196 - [3] [DEF CON 29 - Martin Doyhenard - Response Smuggling: Pwning HTTP/1.1 Connections](https://www.youtube.com/watch?v=suxDcYViwao&t=1343s) 197 - [4] [youtube.com - Watch](https://www.youtube.com/watch?v=suxDcYViwao)