
Mautic < 5.2.3 Аутентифицированное RCE
Плохая санитизация содержимого, типа и расширения загружаемого файла в функции редактирования Asset позволяет аутентифицированному злоумышленнику записать произвольный PHP-код в веб-каталог и определить, куда этот файл записан. Это приводит к удаленному выполнению кода.
Обход пути также позволяет использовать эту функцию для рекурсивного удаления любого каталога в файловой системе, к которому веб-пользователь имеет права на изменение.

При редактировании Asset через маршрут /assets/view/{assetID} предоставляется возможность изменить файл актива.
Загрузка нового файла в конечном итоге вызывает следующую функцию внутри app/Bundles/AssetBundle/Controller/AssetController.php:
public function editAction(Request $request, UploaderHelper $uploaderHelper, AssetModel $model, $objectId, $ignorePost = false)
Логика загрузки находится здесь:
if (!$ignorePost && 'POST' == $method) {
$valid = false;
if (!$cancelled = $this->isFormCancelled($form)) {
if ($valid = $this->isFormValid($form)) {
$entity->setUploadDir($this->coreParametersHelper->get('upload_dir'));
$entity->preUpload();
$entity->upload();
Более конкретно, нас интересуют методы preUpload() и upload(), так как они обрабатывают фактическую запись файла на диск.
Первый дефект находится в preUpload() в app/Bundles/AssetBundle/Entity/Asset.php, так как реализация позволяет нам указать произвольное расширение файла (тем самым обходя защиту, обычно обеспечиваемую массивом allowed_extensions):
$filename = sha1(uniqid(mt_rand(), true));
$extension = $this->getFile()->guessExtension();
if (empty($extension)) {
// get it from the original name
$extension = pathinfo($this->originalFileName, PATHINFO_EXTENSION);
}
$this->path = $filename.'.'.$extension;
Строка $extension = $this->getFile()->guessExtension(); вернет NULL, если мы предоставим имя файла, заканчивающееся на .php, и содержимое, начинающееся с тега <?php.
Проверка empty($extension) поэтому будет истинной, и расширение файла затем будет извлечено через вызов pathinfo(), что позволит нам загружать временные файлы с произвольным содержимым и расширением. Мы не можем контролировать фактическое имя файла, так как оно генерируется с помощью sha1().
Затем внутри последующего метода upload() файл фактически будет записан на диск в веб-каталог через следующий вызов:
$this->getFile()->move($this->getUploadDir(), $this->path);
Он использует наше произвольное расширение (содержащееся в переменной $this->path).
Имя файла затем можно получить, обновив страницу деталей Asset (/assets/view/{assetId}), в записи таблицы Local filename.
Примечание: Это также работает при изменении запросов, отправляемых при создании нового Asset. Будет вызвана функция newAction(), но логика идентична, и дефекты все еще находятся в методах preUpload() и upload().
PoC не будет опубликован еще примерно месяц.
Это делается для того, чтобы дать время организациям, которые полагаются на это программное обеспечение, исправить его, не опасаясь, что скрипт-кидди все испортят.
После этого этот репозиторий будет обновлен полным скриптом эксплуатации и доказательствами. На этой странице и так уже достаточно информации.
При проверке временной загрузки (через /s/assets/new или /s/assets/edit/{assetId}) каталог, в котором хранится временный файл, рекурсивно удаляется в конце запроса.
Параметр, отвечающий за хранение имени временного каталога, подвержен атакам с обходом пути, что позволяет аутентифицированному злоумышленнику удалить любой каталог в системе, при условии, что веб-пользователь имеет на это права.
Это может привести к потере данных или даже уничтожению всей файловой системы, если сервер случайно выполняется от имени пользователя root.
Укажите любой файл, существующий в системе, через конечную точку, используемую ниже. Если файл существует, сервер попытается удалить каталог, в котором он хранится.

Захват сервера Отказ в обслуживании Потеря данных