Joomla — вторая по популярности система управления сайтами после WordPress. Уязвимость, о которой мы поговорим в этой статье, позволяет атакующему без особых проблем одним запросом поднять свои привилегии в CMS до суперпользователя, от которого до выполнения кода один шаг.

Проблема затрагивает все существующие версии Joomla вплоть до 3.8.3. О деталях сообщил исследователь из компании RIPS Technologies. Уязвимость получила идентификатор CVE-2018-6376. В версии 3.8.4 она была исправлена разработчиками CMS, о чем сообщается в анонсе от 30 января.

Проэксплуатировать уязвимость можно, обладая привилегиями менеджера в системе или выше. Сам баг довольно интересный, и его изучение позволит нам поговорить о технике инъекций second order SQL.

 

Стенд

Для тестирования эксплоита первым делом готовим стенд. Разумеется, у Joomla есть официальный репозиторий на сайте Docker Hub, где ты можешь найти всевозможные версии CMS. Но использовать их я не буду и подготовлю свой контейнер, поскольку делается это всего несколькими командами.

Сначала запускаем контейнер с Debian 9.

docker run -ti -p80:80 --rm --name=joomlavh --hostname=joomlavh debian /bin/bash

Ставим все необходимое: MySQL, Apache 2 и PHP 7.0.

apt-get update && apt-get install -y mysql-server apache2 php php7.0-xml php7.0-mysqli nano wget

Теперь сама CMS. Нам нужна версия 3.8.3.

cd /var/www/html/
wget https://downloads.joomla.org/cms/joomla3/3-8-3/Joomla_3-8-3-Stable-Full_Package.tar.gz?format=gz
tar xzf Joomla*
chown -R www-data:www-data .

И последнее: стартуем нужные сервисы и создаем базу данных для будущей установки приложения.

service mysql start && service apache2 start
mysql -u root -e "CREATE DATABASE joomla; GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY 'megapass';"

После этого необходимо перейти на свежеподнятый веб-сервер и установить CMS.

Установка Joomla 3.8.3
Установка Joomla 3.8.3

Создай аккаунт с правами Manager, через него будем тестировать эксплоит.

 

Подробнее об уязвимости

Сколько всего порядков SQL-инъекций существует?

Загрузка ... Загрузка ...

Из анонса уязвимости можно узнать, что корень проблемы — в отсутствии приведения типов переменной в информационных сообщениях темплейта Hathor (Hathor postinstall message).

Анонс уязвимости в Developer Network
Анонс уязвимости в Developer Network

Hathor — это название одного из предустановленных бэкенд-шаблонов административной панели, с которым поставляется Joomla.

Настройка шаблонов панели администрирования в Joomla
Настройка шаблонов панели администрирования в Joomla

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

/administrator/index.php?option=com_admin&view=profile&layout=edit
Настройка профиля текущего пользователя
Настройка профиля текущего пользователя

Теперь настало время зарыться в дебри исходников. Но где искать? Отправную точку, как обычно, ищем в коммите, который решает проблему.

Коммит с патчем для SQLi
Коммит с патчем для SQLi

Как видишь, нам необходимо заглянуть в файл hathormessage.php.

/administrator/templates/hathor/postinstall/hathormessage.php
19: function hathormessage_postinstall_condition()
20: {
...
22:     $user           = JFactory::getUser();
...
39:     // Get the current user admin style
40:     $adminstyle = $user->getParam('admin_style', '');
41:
42:     if ($adminstyle != '')
43:     {
44:         $query = $db->getQuery(true)
45:             ->select('template')
46:             ->from($db->quoteName('#__template_styles'))
47:             ->where($db->quoteName('id') . ' = ' . $adminstyle[0])
48:             ->where($db->quoteName('client_id') . ' = 1');
...
50:         // Get the template name associated to the admin style
51:         $template = $db->setquery($query)->loadResult();

После патча переменная $adminstyle приводится к int, значит, она нам и нужна. Строка 40 говорит нам о том, что значение переменной — это результат работы метода getParam из класса User.

/libraries/src/User/User.php
024: class User extends \JObject
025: {
...
318:    public function getParam($key, $default = null)
319:    {
320:        return $this->_params->get($key, $default);
321:    }

Параметры ($this->_params) текущего пользователя — это экземпляр класса Registry.

/libraries/src/User/User.php
233:    public function __construct($identifier = 0, UserWrapper $userHelper = null)
234:    {
...
242:        // Create the user parameters object
243:        $this->_params = new Registry;

При инициализации пользователя, сохранении данных профиля и прочих манипуляциях с пользовательскими настройками данные попадают в эту переменную. В том числе и нужный нам admin_styles. Нам остается лишь задать ему значение. Выше я уже писал, где находится редактирование профиля текущего юзера.

Давай включим сниффер и сохраним данные профиля. В пойманном пакете будет атрибут с названием jform[params][admin_style]. Так как в запрос попадает первый элемент массива, то добавляем каноничную кавычку.

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

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

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

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

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


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

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

    Подписаться

  • Подписаться
    Уведомить о
    4 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии