Баги в популярных CMS в последние месяцы стали настоящей напастью. Появление каждой такой уязвимости означает, что под угрозой оказываются сотни тысяч сайтов, и далеко не каждый владелец успевает вовремя обновиться до свежей версии. В этой статье мы изучим недавно обнаруженную дыру в CMS Joomla: из-за недостаточной фильтрации пользовательских данных система уязвима для SQL-инъекций.

Joomla 3.7.0, помимо множества улучшений и исправлений, принесла в ядро функцию пользовательских полей и, в частности, компонент com_fields. Как ты уже, наверное, догадался, этот новый компонент и стал причиной проблемы. Так что без лишних церемоний приступим к увлекательному путешествию в исходниках по следам уязвимости.

Детали уязвимости

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

/components/com_fields/controller.php

16: class FieldsController extends JControllerLegacy
17: {
...
27:     public function __construct($config = array())
28:     {
...
32:         if ($this->input->get('view') === 'fields' && $this->input->get('layout') === 'modal')
...
36:             $lang->load('com_fields', JPATH_ADMINISTRATOR);
37:
38:             $config['base_path'] = JPATH_COMPONENT_ADMINISTRATOR;

Сразу же бросается в глаза условие [32]: если view и layout принимают значения fields и modal соответственно, то CMS загружает администраторскую версию компонента com_fields. И все запросы от обычного пользователя будут проксироваться в него.

Что же нам это дает? Давай посмотрим.

Заглянем внутрь метода getListQuery, он занимается тем, что собирает запрос к базе данных. Нас интересует часть со строкой, в которой формируется сортировка (ORDER BY).

/administrator/components/com_fields/models/fields.php

124:    protected function getListQuery()
125:    {
...
304:        // Add the list ordering clause
305:        $listOrdering = $this->getState('list.fullordering', 'a.ordering');
306:        $orderDirn    = '';
307:
308:        if (empty($listOrdering))
309:        {
310:            $listOrdering  = $this->state->get('list.ordering', 'a.ordering');
311:            $orderDirn     = $this->state->get('list.direction', 'DESC');
312:        }
313:
314:        $query->order($db->escape($listOrdering) . ' ' . $db->escape($orderDirn));

Переменная $listOrdering — название поля в таблице, по которому требуется отсортировать запрос. Ее фильтрует функция escape, которая зависит от используемого на сервере драйвера для работы с БД. Она возвращает строку, в которой экранированы спецсимволы, в частности кавычки.

Рассмотрим исходный код этой функции для драйвера mysqli. Он встречается чаще всего, поскольку Joomla при установке предлагает именно его.

/libraries/joomla/database/driver/mysqli.php

242:    public function escape($text, $extra = false)
243:    {
244:        $this->connect();
245:
246:        $result = mysqli_real_escape_string($this->getConnection(), $text);
247:
248:        if ($extra)
249:        {
250:            $result = addcslashes($result, '%_');
251:        }
252:
253:        return $result;
254:    }

Для фильтрации используется функция mysqli_real_escape_string (строка 246), которая экранирует null-байты, переносы строк, одинарные и двойные кавычки. Однако в нашем случае это абсолютно бесполезные действия, так как в нашей переменной хранится название колонки для сортировки.

Давай посмотрим, как передать нужные нам значения в $listOrdering. Метод getState наследуется прямиком из абстрактного класса JModelLegacy, который является родителем для JModelList, а он, в свою очередь, наследуется нашим FieldsModelFields.

/administrator/components/com_fields/models/fields.php

019: class FieldsModelFields extends JModelList
...
305:        $listOrdering = $this->getState('list.fullordering', 'a.ordering');

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

Вариант 1. Оформи подписку на «Хакер», чтобы читать все статьи на сайте

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Вариант 2. Купи одну статью

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


Комментарии

Подпишитесь на ][, чтобы участвовать в обсуждении

Обсуждение этой статьи доступно только нашим подписчикам. Вы можете войти в свой аккаунт или зарегистрироваться и оплатить подписку, чтобы свободно участвовать в обсуждении.

Check Also

SHA 2017. Репортаж с самого яркого хакерского ивента этого лета

Still Hacking Anyway 2017 — это фестиваль, на котором собрались четыре тысячи хакеров со в…