[Перевод] CVE-2024-4577: Не может быть, PHP опять под атакой

Orange Tsai недавно запостил про «Одну из уязвимостей PHP, которая влияет на XAMPP, развернутый по умолчанию», и нам было интересно рассказать немного об этом. XAMPP — очень популярный способ администраторов и разработчиков развернуть Apache, PHP и множество других инструментов, и любая ошибка, которая может быть RCE в установке этого набора по умолчанию, звучит очень заманчиво.

Изображение к статье от коллег из WatchTowr

Изображение к статье от коллег из WatchTowr

К счастью, для защитников, ошибку смогли воспроизвести только на инсталляциях PHP для Windows (где PHP используется в режиме CGI), в некоторых локализациях (речь про локали Windows):

Однако, Orange предупреждает, что другие локали могут быть тоже затронуты, и настоятельно призывает обновиться до последней версии PHP, где эти ошибки были уже устранены (для деталей, смотрите его пост — тут автор приводит пример уязвимой конфигурации).

Хочется отметить, что мы не можем проверить наверняка, насколько распространена данная конфигурация или тип развертывания на самом деле.

Пост Orange’а, хоть и информативный, но не демонстрирует нам, что необходимо для реализации такой привлекательной RCE. К сожалению, большой набор конфигураций делает сложным доказательство, что система уязвима (или нет) при пассивном просмотре, это очевидно, потому что информация о локали Windows обычно не размещается в каких либо «отпечатках». Поэтому мы решили приступить к воспроизведению ошибки, если мы сможем её использовать, это ли не лучшее доказательство?

Абсолютно понятно, что уязвимость затрагивает только CGI режим PHP. В этом режиме веб-сервер разбирает HTTP-запросы и передает их в PHP скрипт, затем выполняет некоторую обработку над этим. Для примера, строка запроса парсится и передается в интерпретатор PHP в командной строке — такой запрос http://host/cgi.php?foo=bar, может быть выполнен как php.exe cgi.php foo=bar.

Это, конечно, может быть использовано для внедрения команд, поэтому ввод тщательно обрабатывается и очищается перед вызовом php.exe (после CVE-2012–1823). Однако, как оказалось есть один способ, который разработчики не учли, он позволяет злоумышленнику выйти за пределы командной строки и передать аргументы, которые интерпретируются самим PHP. Этот способ связан с тем, как именно символы unicode перекодируются в ASCII. Покажем это на примере.

Ниже представлены два вызова php.exe, один вредоносный, а второй нет. Вы сможете найти разницу между ними?

7fd96a3e67dd122f7ffe164bef3da00e.png

Нет, и я тоже не могу. Давайте взглянем на них через hex-редактор и попробуем найти подсказку.

1b4411452f700eff2a88c277d2324488.png

Здесь мы видим, что первый вызов использует обычное тире (0×2D), а вот второй вызов использует что-то другое (видимо «мягкий дефис»), с кодом 0xAD (на скриншоте он выделен). Хоть внешне они для нас с вами абсолютно одинаковые, для операционной системы — это разные значения.

Самое важное в этом всём, что Apache будет экранировать дефис — 0×2D, но не второй «дефис», 0xAD. Ведь это же не настоящий дефис, верно? Значит его и не надо экранировать…верно?

Да шутка старая, но всё ещё актуальная:-Давай посмотрим кто ты на самом деле!-Я знаю его!

Да шутка старая, но всё ещё актуальная:
-Давай посмотрим кто ты на самом деле!
-Я знаю его!

Получается, что в части обработки юникода, PHP будет применять так называемый маппинг «лучшего соответствия», и предположит, что когда пользователь вводит «мягкий дефис», он хотел на самом деле ввести обычный дефис, и он будет его интерпретировать именно так. В этом и заключается уязвимость, если мы предоставим обработчику CGI «мягкий дефис» (0xAD), обработчик не станет его экранировать и передаст PHP. PHP в свою очередь уже будет интерпретировать его как обычный дефис, благодаря этому, злоумышленники могут указывать дополнительные аргументы командной строки, начинающиеся с дефисов для PHP.

Это очень похоже на старую ошибку PHP в режиме CGI (CVE-2012–1823), поэтому мы можем позаимствовать некоторые методы эксплуатации, которые применялись в старой CVE, но адаптируем их для работы с новой ошибкой.

Реализация

В одном полезном writeup (решение для CTF), говорится, что нам понадобятся следующие аргументы для нашей RCE:

-d allow_url_include=1 -d auto_prepend_file=php://input

Благодаря этим аргументам тело нашего HTTP-запроса будет передано и обработано уже в PHP. Но давайте заменим обычные дефисы на ранее обсуждаемые (0xAD). Будут ли они пропущены?

Пример запроса после преобразования:

POST /test.php?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1
Host: {{host}}
User-Agent: curl/8.3.0
Accept: */*
Content-Length: 23
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive

У нас получилось! Мы действительно получили страницу phpinfo, доказывая, что мы достигли RCE.

903d9a7aad8f6c7e25749ccb4c4f0b7f.png

Выводы

Неприятная ошибка с очень простой эксплуатацией.

Для Windows с локалями на английском, корейском и других, из-за разнообразия сценариев использования PHP в настоящее время невозможно перечислить и исключить все потенциальные сценарии использования данной уязвимости.

К счастью, патчи уже доступны, и мы рекомендуем обновить PHP. Как всегда, фантастическая работа и респект — Orange Tsai.

Мы не будем дублировать здесь рекомендации, их можно найти в ранее упомянутой статье.

Данная статья является переводом публикации коллег из watchTowr (не рекламирую их, но статьи короткие и полезные, советую также в оригинале).

Дополню только информацией из других статей и новостей про уязвимые версии PHP, а именно:

  • с версии PHP 8.3 по 8.3.8;

  • с версии PHP 8.2 по 8.2.20;

  • с версии PHP 8.1 по 8.1.29.

Спасибо за прочтение, мой личный телеграм-канал: https://t.me/kirsecurity

© Habrahabr.ru