Summary

HTTP Request Smuggling is one of those vulnerabilities that sounds complicated, but the core idea is actually simple. Let’s Understand it in simplest way possible. When your browser sends a request to a server there are generally two types of servers through which your request goes through -

  1. Front end server (like a load balancer, reverse proxy, or CDN)
  2. Back end Server (Actual web application server) The Front end Server uses a single TCP Connection and sends many requests at once to save computation time and costs. The Question arises here is when a request comes to the Front end server how does it know that the request has ended here and the next request has been started, actually this is identified by the server using either of the two types of headers mentioned below-
  3. Content-Length (CL)
  4. Transfer-Encoding (TE) Suppose there is a request as Follows :- Here as you can see the Content-Length Header has value set to 13, you might wonder why it’s 13 and what are those \r\n actually these are non printable characters and \r\n is known as CRLF (Carraige return Line feed) it is used to represent a new line. These are non printable characters but they are counted in Content-Length calculation and \r is 1 byte and \n is also 1 byte so \r\n together counted as 2 bytes. Again now also if you count the full length of the body it should be 15 bytes right ? Nopes, the first \r\n is used to seprate header and body and body starts behind it so the content length will be 13 only. So the front end server will read the Content-Length and would know that after 13 bytes the request will be finished and next request will be started from there. Now what if the server is using Transfer-Encoding to know where the request gets Terminated ? Suppose there is a request as Follows :- There is slight difference in how size calculation is done in Content-Length and in Transfer-Encoding: chunked :- How Chunked Encoding Length Works :- In HTTP/1.1 chunked encoding, each chunk consists of:
  • Chunk size in hexadecimal followed by \r\n
  • Chunk data (exact byte count specified by the size) followed by \r\n
  • A final chunk size of 0 followed by\r\n to end the message The chunk size specifies only the length of the data content, excluding the \r\n line breaks. So as you can see the chunk size in the request is 5 and in next line “Hello” which is of length 5 and in last line there is a 0 to tell the server that the request has been terminated. All GOOD, but where is the Vulnerability ? The Vulnerability arises when one of the servers from the front end server and the back end server is using either of the one technique to check for request termination. Types of Vulnerabilities :-
  1. CL.TE (Frontend uses Content-Length , backend uses Transfer-Encoding )
  2. TE.CL (Frontend uses Transfer-Encoding , backend uses Content-Length ) Get Kuldeep Choudhary’s stories in your inbox Join Medium for free to get updates from this writer.
  3. TE.TE (Both use Transfer-Encoding , but one parses it differently) But you might wonder how do attackers actually exploit this vulnerability ? The answer is very simple they just add both the headers into the request and there is a desync created between the servers as both of them are relying on different headers. Practical Example of a CL.TE Exploit - Front-end trusts Content-Length & Back-end trusts Transfer-Encoding What happens:
  • Front-end reads Content-Length: 13 , so it thinks the body is”0\r\n\r\nSMUGGLED” (13 bytes) — the request ends there. It forwards everything as one request. - Back-end ignores Content-Length and instead trustsTransfer-Encoding: chunked . It sees the chunk0 , which means “end of chunked body” — so it treats the request as ending right there. - That leaves SMUGGLED sitting unconsumed in the connection buffer. The back-end now treatsSMUGGLED as the start of the next request on that same connection. If another legitimate user’s request comes in right after on that same reused connection, the back-end may accidentally glue the attacker’s leftover text onto the front of that innocent request — corrupting it, redirecting it, or letting the attacker read/manipulate parts of someone else’s traffic. The attacker can also add a full new mallicious request at the place of SMUGGLED For example :- What happens:
  • Front-end trusts Content-Length so it thinks everything inside those 43 bytes belongs to ONE request so forwards all of it. - Back-end trusts Transfer-Encoding It sees0 which means request finished. So the remaning data remains in the request Pipeline and now the server thinks Ohhhhh a new request has just arrived. Classic HTTP Request Smuggling primarily affects only HTTP/1.1 because HTTP/1.1 has ambiguous ways to determine where a request ends. This ambiguity is what makes request smuggling possible. Why Request Smuggling Matters (real-world impact)
  • Bypassing front-end security filters (WAF rules)
  • Stealing session tokens / hijacking other users’ requests
  • Cache poisoning
  • Gaining access to internal-only endpoints The Fix
  • Reject requests that specify both Content-Length andTransfer-Encoding
  • Normalize/reject ambiguous requests at the front-end
  • Use HTTP/2 end-to-end where possible (removes this ambiguity)
  • Keep front-end and back-end parsers consistent, or use the same software stack HTTP/2 HTTP/2 does not use: Content-Length to delimit framesTransfer-Encoding: chunked Instead, HTTP/2 sends data in binary frames, and each frame has its own explicit length. There is no ambiguity about where one request ends.

By Kuldeep Choudhary

Original Article