Взлом

Старый сарай, новые грабли. Эксплуатируем PHAR-десериализацию в phpBB


В знаменитом форумном движке 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

После завершения инсталляции не забудь снести папку 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

Брейк-пойнт сработал, так как валидатором переменной 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

Обрати внимание на добавленный префикс ./../. Он появляется, потому что мы имеем дело с настройкой, которая подразумевает относительные пути. Но для выполнения атаки нам нужен полный контроль над всей переменной, поскольку требуется передать значение, начинающееся с враппера 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 в аргумент функции file_exists

Источник: xakep.ru

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *