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-инъекцией.
Общий алгоритм использования уязвимости
Практическая реализация
Рисунок 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 года: обнародование уязвимости.