HTTP Version Negotiation
Los servidores web puede ofrecer al cliente varias versiones de protocolo HTTP en un solo puerto. Esto es útil ya que no puedes garantizar que los usuarios tendrán un navegador que cumpla con HTTP/2. De esta forma, el servidor puede ofrecer al cliente ambos (HTTP/1.1 y HTTP/2), y el cliente puede seleccionar la versión que quiere usar. Este proceso se conoce como negociación y es manejado completamente por el navegador.
La especificación HTTP/2 original definió dos maneras de negociar HTTP/2, dependiendo de si las comunicaciones eran o no encriptadas. Los dos métodos usaban identificadores de protocolo:
- h2: Protocolo usado al correr HTTP/2 sobre un canal TLS encriptado. Recae en el mecanismo de la negociación de protocolo de capa de aplicación (ALPN) de TLS para ofrecer HTTP/2.
- h2c: HTTP/2 sobre canales de texto plano. Esto sería usado cuando la encriptación no está disponible. Como ALPN es una funcionalidad de TLS, no puedes usarla en canales de texto plano. En este caso, el cliente manda la petición inicial HTTP/1.1 con un par de headers añadidos para pedir un upgrade a HTTP/2. Si el servidor reconoce los headers adicionales, la conexión se eleva a HTTP/2.
El protocolo h2 es la forma usual de implementar HTTP/2 ya que se considera más segura. De hecho, la especificación h2c está catalogada ahora como obsoleta hasta el punto de que los navegadores más modernos ni siquiera la soportan. Muchas implementaciones de servidores, sin embargo, todavía lo soportan por motivos de compatibilidad, permitiendo otra forma de contrabandear peticiones.
h2c Upgrades
Al negociar una conexión HTTP/2 en texto plano, el cliente mandará una petición HTTP/1.1 regular con el header Upgrade: h2c para hacer saber al servidor que soporta h2c. La petición debe incluir también un header adicional HTTP"-Settings con algunos parámetros de negociación que no veremos en detalle. Un servidor compatible aceptará el upgrade con una respuesta 101 Switching Protocols. Desde ese punto, la conexión cambia a HTTP/2.

Tunneling Requests vía h2c Smuggling
Cuando un upgrade de conexión HTTP/1.1 se intenta vía algunos reverse proxies, estos redireccionarán los headers de upgrade al servidor backend en lugar de manejarlos por ellos mismos. El servidor backend realizará el upgrade y manejará las comunicaciones en el nuevo protocolo después. El proxy tuneleará cualquier comunicación entre el cliente y el servidor pero no comprobará su contenido más, ya que asume que el protocolo ha cambiado.

Como las conexiones en HTTP/2 son persistentes por defecto, deberíamos ser capaces de mandar otras peticiones HTTP/2, lo que irá directamente al servidor backend a través del túnel HTTP/2. Esta técnica se conoce como h2c smuggling.
Para que h2c smuggling funcione, el proxy debe redireccionar el upgrade h2c al backend. Si no, acabaremos con una conexión elevada a HTTP/2 en el propio frontend en lugar de un túnel al backend, lo que no tiene mucho uso.
Al encontrarse con un proxy consciente de h2c, todavía hay una oportunidad de conseguir que h2c smuggling funcione bajo un escenario específico. Si el proxy del frontend soporta HTTP/1.1 sobre TLS, podemos tratar de realizar la upgrade sobre el canal TLS. Esto es una petición inusual, ya que h2c está definido para funcionar bajo canales en texto plano sólo. El proxy puede redireccionar los headers de upgrade en lugar de manejar el upgrade directamente, ya que no tendría mucho sentido tener un h2c sobre un canal encriptado.
Date cuenta de que h2c smuggling sólo permite hacer request tunneling. Contaminar las conexiones de otros usuarios no será posible. Pero como ya hemos visto, esto podría seguir siendo usado para bypassear restricciones en el frontend o incluso realizar contaminación de caché.
Sobrepasando Restricciones del Frontend con h2csmuggler
Para este escenario, estaremos atacando la aplicación en el puerto 8200. La aplicación es servida mediante una instancia HAProxy con configuración por defecto. La aplicación expone dos endpoints:
- El endpoint
/contiene una página web simple y está permitida a través del proxy. - El endpoint
/privateno está permitido a través del proxy. Puede intentar acceder y deberías obtener403 Forbidden.
Nuestro objetivo será usar h2c smuggling para obtener los contenidos de /private mediante el proxy. Usaremos la herramienta h2csmuggler para conseguirlo. La herramienta realizará el ataque completo por nosotros ya que hacerlo manualmente es bastante complicado.
El siguiente comando primero intenta una upgrade h2c pidiendo /. Como ese recurso está permitido por el proxy, la conexión será elevada exitosamente a HTTP/2. El túnel HTTP/2 sería entonces usado para hacer una petición a /private, bypasseando las restricciones del frontend.
user@attackbox$ python3 h2csmuggler.py -x https://10.114.129.77:8200/ https://10.114.129.77:8200/private
Debes ejecutar el comando varias veces si falla.
