Отчет о безопасности для приложения Tuleap версии <= 8.18

Отчет о безопасности для приложения Tuleap версии <= 8.18

Tuleap полностью бесплатен и с открытым исходным кодом. Предназначен для управления жизненным циклом приложения.

Автор: Mehmet Ince

Введение

Tuleap полностью бесплатен и с открытым исходным кодом. Предназначен для управления жизненным циклом приложения. Сюда входит традиционная и гибкая разработка, управление потребностями и IT-службами и т. д. Tuleap позволяет увеличить продуктивность работы внутри проекта, делает участников более сплоченными и повышает уровень индустриализации.

Краткий отчет о найденных брешах:

Уязвимость A: SQL-инъекция

Подтверждено и воспроизведено
Критичность: высокая
Базовая оценка системой CVSS v3: 8.8 (CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
Текущее состояние: исправления добавлены в Tuleap 8.19.99.2 (коммит 7333184217e2dd880259d3bb2c42af6541ed8737)

Уязвимость С: Отраженный межсайтовый скриптинг

Подтверждено и воспроизведено
Критичность: средняя
Базовая оценка системой CVSS v3: 6.1 (CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)
Текущее состояние: исправления добавлены в Tuleap 8.19.99.5 (коммит 38d20046d9796a987168b4fccafae9ef2725ed6e)

Уязвимость D: Отраженный межсайтовый скриптинг

Подтверждено и воспроизведено
Критичность: средняя
Базовая оценка системой CVSS v3: 6.1 (CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)
Текущее состояние: исправления добавлены в Tuleap 8.19.99.1 (коммит b07641eda8e98acf896fce2304d771848ef1451a)

A – SQL-инъекция

На рисунке ниже показана часть файла tuleap-8.18/src/www/widgets/updatelayout.php, который доступен обычным пользователям.

Файл updatelayout.php отвечает за конфигурацию пользовательской панели управления. Есть возможность использовать различные схемы разделения рабочего пространства (на 2 или 3 колонки) или меню слева.


Рисунок 1: Часть файла updatelayout.php

Код из строки 94 будет выполнен при условии, что пользовательский input action = layout. Функция updateLayout(), принадлежащая классу LayoutManager, принимает 5 различных параметров.

Первый параметр $owner_id целочисленного типа и приходит из сессии.

Второй параметр $owner_type появляется по результатам работы функции substr($request->get('owner'), 0, 1). Даже если бы содержимое приходило после ввода пользователя, Tuleap берет только первый символ. То есть первые две переменные ($owner_id и $owner_type) защищены от SQL-инъекций.

Четвертый и пятый параметры поступают напрямую от клиента без проверки.

Код ниже принадлежит функции updateLayout(), являющейся членом класса WidgetLayoutManager.


Рисунок 2: Часть функции updateLayout()

Вначале функция выполняет sql запрос, а во время построения запроса используются переменные $owner_id и $owner_type.

Строки 350 – 458 будут выполняться в случае, если функция возвращает какую-либо информацию. Между этими строками приложение Tuleap проверяет привилегии пользователя, чтобы удостовериться, что операция может выполняться от имени пользователя, отсылающего HTTP-запрос. Затем поток выполнения идет в определенном направлении в зависимости от содержимого переменных $layout и $new_layout_id.

Переменная $layout является параметром функции и находится под полным контролем клиента. Кроме того, эта переменная при передаче в функцию не проверяется. В строке 354 говорится, что если переменная $layout не равна -1, тогда $new_layout_id = $layout. Сей факт означает, что мы можем получить управление над параметром $new_layout_id в том случае, если переменная $layout не равна -1.

На рисунке ниже показано, что произойдет, если переменная $new_layout_id – не пустая (или, другими словами, переменная $layout не равна -1).


Рисунок 3: Ветвь кода, выполняемая при условии, что переменная $layout не равна -1

Здесь мы видим два вызова функций. В первом вызове один из параметров - $old_layout_id, второй - $new_layout_id. В строке 352 (см. Рисунок 2) переменная $old_layout_id будет определена в том случае, если $layout = -1, и присваиваемое значение будет взято из базы данных. На первый взгляд, получить управление над переменной $old_layout_id невозможно.

В итоге мы остановились на переменной $new_layout_id. Теперь посмотрим на содержимое функции _retrieveStructureOfLayout().


Рисунок 4: Содержимое функции _retrieveStructureOfLayout()

В запросе переменная $layout_id используется для построения запроса без PDO (PHP Data Objects) и экранирования. Соответственно, мы имеем уязвимость, связанную с SQL-инъекцией.

Общий алгоритм использования уязвимости

  1. Регистрируем пользователя. Только зарегистрированные пользователи могут изменять структуру колонок.
  2. Устанавливаем в поле action значение layout.
  3. Помещаем полезную нагрузку SQLi в layout_id. Таким образом, переменная $layout в функции updateLayout() не будет равна -1. Когда это условие вернет значение, сработает вторая ветвь, и переменная $layout станет $new_layout_id.
  4. Переменная $new_layout_id будет использована в качестве параметра функции _retrieveStructureOfLayout().
  5. SQL-инъекция.

Практическая реализация

  1. Чтобы добраться до уязвимого модуля выполните следующие шаги:
    1. Зайдите на домашнюю страницу (https://10.0.0.134/my/).
    2. Нажмите на кнопку “Customize widgets” в левом верхнем углу страницы.
    3. Выберите раздел “Cusomize layout”
  2. Поменяйте структуру колонок.
  3. Перехватите HTTP-запрос и установите в параметр layout_id значение 1 or sleep(50) # или 1 or sleep(50) — . #, либо двойное тире, используемое для отключения операции сортировки ' ORDER BY rank’ , которая добавляется в коде во время построения запроса.
  4. Запрос возвратится через 1 минуту.


Рисунок 5: Практическая реализация sql-инъекции

B – Небезопасная прямая ссылка на объект

Файл plugins/docman/www/sendmessage.php используется в том случае, если у пользователя нет прав для просмотра модуля docman запрашиваемого объекта ($group_id). Когда пользователь пытается открыть http://10.0.0.134/plugins/docman/?group_id=104, приложение Tuleap проверяет привилегии. Если прав не достаточно, то пользователь может отправить сообщение при помощи файла sendmessage.php для запроса авторизации.
Ниже показан исходный текст, принадлежащий файлу sendmessage.php.


Рисунок 6: Часто исходного кода файла sendmessage.php

В строке 48 сообщение пользователя отсылается администратору посредством электронной почты. На скриншоте ниже показан исходный код функции processMail().

В строке 172 определена переменная $user, которая используется в качестве второго параметра в функции sendMail() (строка 180).


Рисунок 7: Функция processMail()

Главная проблема – строка 172. Tuleap создает переменную $user через пользовательский ввод. Значение пересылается с параметром userId в запросе HTTP POST. Соответственно, мы можем поставить фальшивый userId. Этот параметр следует брать из сессии вместо HTTP-запроса.

На рисунке ниже показана функция sendMail(), которая вызывается в строке 180.


Рисунок 8: Функция sendMail()

Из рисунка выше видно, что второй параметр функции находится под контролем клиента. Все важные операции внутри функции sendMail(), такие как $user->getRealName() или $user->getEmail(), зависят от поддельного параметра.
В итоге мы можем отправить запрос администратору на доступ от имени любого пользователя, у которого мы знаем userId. Все значения userId получается посредством автоувеличения.

C – Отраженный межсайтовы скриптинг
Код на рисунке ниже взят из файла src/www/svn/index.php:

Рисунок 9: Часть файла index.php

Параметр func находится под контролем клиента. Когда этот параметр равен значение browse, приложение Tuleap подключает файл browse_revision.php.
На рисунке ниже показан код из файла browse_revision.php. Обратите внимание на строки 237 и 238. Переменные $_path и $_srch используются во время генерации HTML-кода при помощи функции purify().

Рисунок 10: Часть файла browse_revision.php

Известно, что функция purify отвечает за кодирование переменных для избежания проблем с XSS. Но здесь есть одна маленькая ошибка, которая приводит к очень большой проблеме.
Допустим, переменная $_srch равна INVICTUS. В строке 238 будет сгенерировать следующий HTML-код:

Рисунок 11: HTML-код, сгенерированный на базе строки 238

У атрибута VALUE нет кавычек. Эту проблему чрезвычайно сложно обнаружить в тех случаях, когда перемешаны php и html код.
В библиотеках обычно кодируются символы ‘ или “ или < и т. д. Однако когда кавычки не используются в HTML-атрибутах, браузеры в качестве разделителя используют пробел. Допустим:

$_srch = X onmouseover=alert(1)
Результат генерации будет следующим:


Рисунок 12: HTML-код, сгенерированный на базе переменной $_srch

Практическая реализация

https://10.0.0.134/svn/?func=browse&group_id=104&_srch=x%20onmouseover=alert(9)

Рисунок 13: Использование уязвимости на практике

D – Отраженный межсайтовый скриптинг

Код на рисунке ниже принадлежит файлу src/www/admin/grouplist.php. Данные для пользовательского контроллера берутся от клиента через параметр status, которые затем присваиваются в переменную $export. Далее переменная $export используется при генерации HTML-кода без кодирования.


Рисунок 14: Часть файла grouplist.php

Практическая реализация

https://10.0.0.134/admin/grouplist.php?status=%22%3E%3Cscript%3Ealert(1)%3C/script%3E

Рисунок 14: Использование уязвимости на практике

Хронология событий

16 сентября 2016 года: выход на связь с разработчиком.
16 сентября 2016 года: разработчик подтвердил наличие уязвимостей.
19 сентября 2016 года: разработчик передал план действий и даты выхода новой версии.
14 октября 2016 года: разработчик выпустил новую версию.
15 октября 2016 года: обнародование уязвимости.

Не ждите, пока хакеры вас взломают - подпишитесь на наш канал и станьте неприступной крепостью!

Подписаться