hacktricks/pentesting-web/h2c-smuggling.md
2023-06-06 18:56:34 +00:00

9.4 KiB

Upgrade de Header Smuggling

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

H2C Smuggling

HTTP2 Sobre Texto Claro (H2C)

Uma conexão HTTP normalmente dura apenas durante a duração de uma única solicitação. No entanto, H2C ou "http2 sobre texto claro" é onde uma conexão http normal transitória é atualizada para uma conexão persistente que usa o protocolo binário http2 para se comunicar continuamente em vez de uma solicitação usando o protocolo http em texto simples.

A segunda parte do smuggling ocorre quando um proxy reverso é usado. Normalmente, quando solicitações http são feitas a um proxy reverso, o proxy lidará com a solicitação, processará uma série de regras de roteamento, encaminhará a solicitação para o backend e, em seguida, retornará a resposta. Quando uma solicitação http inclui um cabeçalho Connection: Upgrade, como para uma conexão websocket, o proxy reverso manterá a conexão persistente entre o cliente e o servidor, permitindo a comunicação contínua necessária para esses protocolos. Para uma conexão H2C, o RFC requer que 3 cabeçalhos estejam presentes:

Upgrade: h2c
HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
Connection: Upgrade, HTTP2-Settings

Então, onde está o bug? Ao atualizar uma conexão, o proxy reverso frequentemente deixará de lidar com solicitações individuais, assumindo que, uma vez estabelecida a conexão, seu trabalho de roteamento está concluído. Usando o H2C Smuggling, podemos contornar as regras que um proxy reverso usa ao processar solicitações, como roteamento baseado em caminho, autenticação ou processamento WAF, desde que possamos estabelecer uma conexão H2C primeiro.

Proxies Vulneráveis

Observe a explicação da vulnerabilidade que o servidor proxy precisa encaminhar o cabeçalho Upgrade, e às vezes o cabeçalho Connection também precisa ser encaminhado com sucesso.

Por padrão, os seguintes serviços encaminham o Upgrade e os cabeçalhos Connection durante o proxy-pass, permitindo assim o h2c smuggling out-of-the-box:

  • HAProxy
  • Traefik
  • Nuster

Por padrão, esses serviços não encaminham ambos os cabeçalhos Upgrade e Connection durante o proxy-pass, mas podem ser configurados de maneira insegura (passando cabeçalhos Upgrade e Connection não filtrados):

  • AWS ALB/CLB
  • NGINX
  • Apache
  • Squid
  • Varnish
  • Kong
  • Envoy
  • Apache Traffic Server

Exploração

A postagem original do blog aponta que nem todos os servidores encaminharão os cabeçalhos necessários para uma atualização de conexão H2C compatível. Isso significa que balanceadores de carga como AWS ALB/CLB, NGINX e Apache Traffic Server, entre outros, impedirão uma conexão H2C por padrão. No entanto, no final da postagem do blog, ele menciona que "nem todos os back-ends eram compatíveis, e poderíamos testar com a variante não compatível Connection: Upgrade, em que o valor HTTP2-Settings é omitido do cabeçalho Connection".

{% hint style="danger" %} Observe que, mesmo que a URL de proxy_pass (o ponto final para o qual o proxy encaminha a conexão) aponte para um caminho específico, como http://backend:9999/socket.io, a conexão será estabelecida com http://backend:9999, para que você possa acessar qualquer outro caminho dentro desse endpoint interno abusando dessa técnica. Portanto, não importa se um caminho é especificado na URL de proxy_pass. {% endhint %}

Usando as ferramentas https://github.com/BishopFox/h2csmuggler e https://github.com/assetnote/h2csmuggler, você pode tentar contornar as proteções impostas pelo proxy estabelecendo uma conexão H2C e acessar recursos protegidos pelo proxy.

Siga este link para mais informações sobre essa vulnerabilidade no Nginx.

Smuggling de Websocket

Semelhante à técnica anterior, esta em vez disso de criar um túnel HTTP2 para um endpoint acessível por meio de um proxy, criará um túnel Websocket para o mesmo propósito, contornando as limitações potenciais dos proxies e falando diretamente com o endpoint:

Cenário 1

Temos um backend que expõe uma API WebSocket pública e também tem uma API REST interna não disponível externamente. Um cliente mal-intencionado deseja acessar a API REST interna.

No primeiro passo, o cliente envia uma solicitação de atualização para o proxy reverso, mas com uma versão de protocolo incorreta dentro do cabeçalho Sec-WebSocket-Version. O proxy não valida o cabeçalho Sec-WebSocket-Version e pensa que a solicitação de atualização está correta. Além disso, ele traduz a solicitação para o backend.

No segundo passo, o backend envia resposta com o código de status 426 porque a versão do protocolo está incorreta dentro do cabeçalho Sec-WebSocket-Version. No entanto, o proxy reverso não verifica a resposta suficiente do backend (incluindo o código de status) e pensa que o backend está pronto para a comunicação WebSocket. Além disso, ele traduz a solicitação para o cliente.

Finalmente, o proxy reverso pensa que a conexão WebSocket está estabelecida entre o cliente e o backend. Na realidade, não há conexão WebSocket - o backend recusou a solicitação de atualização. Ao mesmo tempo, o proxy mantém a conexão TCP ou TLS entre o cliente e o backend em estado aberto. O cliente pode facilmente acessar a API REST privada enviando uma solicitação HTTP sobre a conexão.

Foi descoberto que os seguintes proxies reversos são afetados:

  • Varnish - a equipe se recusou a corrigir o problema descrito.
  • Envoy proxy 1.8.0 (ou mais antigo) - em versões mais recentes, o mecanismo de atualização foi alterado.
  • Outros - TBA.

Cenário 2

A maioria dos proxies reversos (por exemplo, NGINX) verifica o código de status do backend durante a parte de handshake. Isso torna o ataque mais difícil, mas não impossível.

Vamos observar o segundo cenário. Temos um backend que expõe uma API WebSocket pública e uma API REST pública para verificação de integridade e também tem uma API REST interna não disponível externamente. Um cliente mal-intencionado deseja acessar a API REST interna. O NGINX é usado como proxy reverso. A API WebSocket está disponível no caminho /api/socket.io/ e a API de verificação de integridade no caminho /api/health.

A API de verificação de integridade é invocada enviando uma solicitação POST, o parâmetro com o nome u controla a URL. O backend alcança o recurso externo e retorna o código de status de volta ao cliente.

No primeiro passo, o cliente envia uma solicitação POST para invocar a API de verificação de integridade, mas com um cabeçalho HTTP adicional Upgrade: websocket. O NGINX pensa que é uma solicitação de atualização normal, ele procura apenas o cabeçalho Upgrade, ignorando outras partes da solicitação. Além disso, o proxy traduz a solicitação para o backend.

No segundo passo, o backend invoca a API de verificação de integridade. Ele alcança o recurso externo controlado por usuários mal-intencionados que retorna a resposta HTTP com o código de status 101. O backend traduz essa resposta para o proxy reverso. Como o NGINX valida apenas o código de status, ele pensará que o backend está pronto para a comunicação WebSocket.