В знаменитом форумном движке phpBB обнаружилась уязвимость, связанная с PHP-десериализацией. В результате некорректной проверки настроек атакующий может сохранить файл с произвольным содержимым на целевой системе и таким образом получить выполнение произвольных команд и скомпрометировать сервер. Здесь я детально разберу каждый аспект обнаруженной проблемы и покажу способ ее эксплуатации.

INFO

Уязвимость связана с техникой PHAR-десериализации, которую мы недавно освещали. Баг актуален для phpBB версии 3.2.3.

Думаю, что phpBB в представлении не нуждается. Он существует аж с 16 декабря 2000 года. Поднимем бокалы за его совершеннолетие! За это время движок повидал множество уязвимостей самого разного рода. Одна из самых известных — CVE-2004-1315, или в миру viewtopic highlight PHP injection. Этот баг был одним из первых, который я изучил.

Впрочем, вернемся к современным реалиям. Сейчас phpBB, конечно, растерял былую популярность, но все еще огромное количество площадок выбирает его как основную платформу общения пользователей.

Уязвимость нашел исследователь из RIPS Technologies, воспользовавшись сканером исходных кодов производства своей компании. Можно даже заценить его отчет.

 

Стенд

Начнем с привычного — поднятия среды для тестирования уязвимости. Форум работает со многими базами данных, но я буду использовать старый добрый MySQL в виде контейнера Docker. Рекомендую использовать версии из ветки 5.х, так как в последних бранчах (8.х) изменился протокол авторизации по умолчанию и клиентские библиотеки текущих репозиториев PHP не работают с ним. Такое поведение можно поменять в конфигурационном файле MySQL, но зачем лишние телодвижения для тестового стенда, верно?

$ docker run -e MYSQL_USER="phpbb" -e MYSQL_PASSWORD="JaLdqX5on0" -e MYSQL_DATABASE="phpbb" -d --rm --name=mysql --hostname=mysql mysql/mysql-server:5.7

Теперь можно приступать к разворачиванию самого сервера. По традиции использую Debian.

$ docker run --rm -p80:80 -ti --name=phpbb --hostname=phpbb --link=mysql debian /bin/bash

Обновляем репозитории и ставим нужные пакеты.

$ apt update && apt install -y zip wget nano apache2 php php-mysql php-xml php-mbstring php-gd

Скачиваем архив с уязвимой версией форума phpBB (3.2.3) и распаковываем его.

$ cd /var/www/html
$ wget https://www.phpbb.com/files/release/phpBB-3.2.3.zip
$ unzip phpBB-3.2.3.zip
$ chown www-data:root -R phpBB3

Если хочется побаловаться с отладкой, то дополнительно ставим xdebug.

$ apt install -y php-xdebug

Настраиваем модуль и включаем его. Не забывай изменить IP под свои реалии.

$ echo "xdebug.remote_enable=1" >> /etc/php/7.0/mods-available/xdebug.ini
$ echo "xdebug.remote_host=192.168.99.1" >> /etc/php/7.0/mods-available/xdebug.ini
$ phpenmod xdebug

Далее правим конфиги веб-сервера и запускаем его.

$ sed 's/html/html\/phpBB3/' -i /etc/apache2/sites-enabled/000-default.conf
$ service apache2 start

Теперь переходим в браузере по адресу контейнера и устанавливаем и настраиваем форум.

Установка форума phpBB
Установка форума phpBB

После завершения инсталляции не забудь снести папку install.

$ rm -rf /var/www/html/phpBB3/install

Стенд готов.

 

Часть первая: внедряем враппер phar

Начнем с просмотра исходников. Если ты внимательно изучал мою прошлую статью про PHAR-десериализацию, то знаешь, на вызовы каких функций стоит обратить особое внимание при поиске потенциально уязвимых мест. Конкретно в этом случае нужно поискать file_exists. Код phpBB объемный (~300 тысяч строк), и вызовов этой функции там предостаточно. Но нас интересуют только те, которым в качестве аргумента можно пропихнуть юзердату. Не буду тянуть и скажу, что интересующий нас вызов находится в файле functions_acp.php.

/phpBB3.2.3/includes/functions_acp.php
420: function validate_config_vars($config_vars, &$cfg_array, &$error)
421: {
...
428:    foreach ($config_vars as $config_name => $config_definition)
429:    {
...
443:        switch ($validator[$type])
444:        {
...
544:            case 'rpath':
545:            case 'rwpath':
...
568:            case 'absolute_path':
569:            case 'absolute_path_writable':
570:            // Path being relative (still prefixed by phpbb_root_path), but with the ability to escape the root dir...
571:            case 'path':
572:            case 'wpath':
...
588:                $path = in_array($config_definition['validate'], array('wpath', 'path', 'rpath', 'rwpath')) ? $phpbb_root_path . $cfg_array[$config_name] : $cfg_array[$config_name];
589:
590:                if (!file_exists($path))
591:                {
592:                    $error[] = sprintf($user->lang['DIRECTORY_DOES_NOT_EXIST'], $cfg_array[$config_name]);
593:                }
594:
595:                if (file_exists($path) && !is_dir($path))
596:                {
597:                    $error[] = sprintf($user->lang['DIRECTORY_NOT_DIR'], $cfg_array[$config_name]);
598:                }
599:
600:                // Check if the path is writable
601:                if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath' || $config_definition['validate'] === 'absolute_path_writable')
602:                {
603:                    if (file_exists($path) && !$phpbb_filesystem->is_writable($path))
604:                    {
605:                        $error[] = sprintf($user->lang['DIRECTORY_NOT_WRITABLE'], $cfg_array[$config_name]);
606:                    }
607:                }

Из названия файла можно понять, что функция валидации конфигурационных переменных (validate_config_vars) заходит в нужную нам ветку, когда выполняется проверка путей в панели администратора (в терминологии phpBB ACP — Administrator Control Panel).

Проверим это. Откроем админку и найдем любой раздел, где можно указать путь.

Раздел настроек прикрепляемых файлов
Раздел настроек прикрепляемых файлов

Как видишь, я открыл настройки прикрепленных файлов. Там есть опция Upload directory — папка, в которую они будут загружаться. Теперь поставим бряк где-нибудь в начале тела case и нажмем Submit.

Отладки функции validate_config_vars в phpBB
Отладки функции validate_config_vars в phpBB

Брейк-пойнт сработал, так как валидатором переменной upload_path служит wpath.

/phpBB3.2.3/includes/acp/acp_attachments.php
138:                $display_vars = array(
...
150:                        'upload_path'           => array('lang' => 'UPLOAD_DIR',            'validate' => 'wpath',  'type' => 'text:25:100', 'explain' => true),

Никаких дополнительных проверок переменной $path не производится, и указанное пользователем значение попадает в качестве аргумента в функцию file_exists.

Передача пользовательских данных в функцию file_exists
Передача пользовательских данных в функцию file_exists

Обрати внимание на добавленный префикс ./../. Он появляется, потому что мы имеем дело с настройкой, которая подразумевает относительные пути. Но для выполнения атаки нам нужен полный контроль над всей переменной, поскольку требуется передать значение, начинающееся с враппера phar://. Для этих целей отлично подойдут те настройки, у которых есть валидатор absolute_path.

Одна из таких — это img_imagick. Путь до бинарника утилиты ImageMagick для манипуляции с загруженными изображениями. Находится она там же, в разделе настройки аттачей.

/phpBB3.2.3/includes/acp/acp_attachments.php
138:                $display_vars = array(
...
167:                        'img_imagick'               => array('lang' => 'IMAGICK_PATH',          'validate' => 'absolute_path',  'type' => 'text:20:200', 'explain' => true, 'append' => '&nbsp;&nbsp;<span>[ <a href="' . $this->u_action . '&amp;action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'),
Использование враппера phar в качестве пути к ImageMagick
Использование враппера phar в качестве пути к ImageMagick

Вот теперь получается настоящее внедрение, и первая часть атаки успешно выполнена.

Внедрение враппера phar в аргумент функции file_exists
Внедрение враппера phar в аргумент функции file_exists

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии