## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-SOTA70-CVE-2023-41564-RESEARCH
# Обзор уязвимости CVE-2023-41564
CVE-2023-415641 — это уязвимость типа Stored XSS в CMS Cockpit (<= v2.6.3).
Если при загрузке файла загрузить HTML-файл с расширением .shtml, то в момент открытия загруженного файла выполнится JavaScript.
1: https://nvd.nist.gov/vuln/detail/CVE-2023-41564
# Порядок проведения атаки
Сначала рассмотрим метод атаки на основе PoC2, опубликованного, предположительно, автором отчета об уязвимости.
Сначала войдите на сайт под учетной записью, имеющей права на загрузку файлов.


Затем загрузите shtml-файл следующего содержания:
```html
root@kitploit:~
Скопируйте URL загруженного файла (Asset).<br /><br />При переходе по скопированной ссылке выполнится скрипт, описанный в HTML выше.<br /><br /><br />2: https://github.com/LongHair00/Mitre_opensource_report/blob/main/CockpitCMS-StoredXSS.md
# Конкретная причина возникновения
Теперь я объясню результаты моего более глубокого исследования.<br />Обработка загрузки Assets начинается с POST-запроса к пути /assets/upload.<br />Обработка запроса на загрузку определена в строке 51 файла modules/Assets/bootstrap.php<sup>3</sup>.<br />Ниже приведен код.
```php
// assets api
$this->module('assets')->extend([
// 省略
'upload' => function(string|array $param = 'files', array $meta = [], bool $isUpload = true) {
$files = [];
if (is_string($param) && isset($this->app->request->files[$param])) {
$files = $this->app->request->files[$param];
} elseif (is_array($param) && isset($param['name'], $param['error'], $param['tmp_name'])) {
$files = $param;
}
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$uploaded = [];
$failed = [];
$_files = [];
$assets = [];
$allowed = $this->app->retrieve('assets/allowed_uploads', '*');
$allowed = $allowed == '*' ? true : str_replace([' ', ','], ['', '|'], preg_quote(is_array($allowed) ? implode(',', $allowed) : $allowed));
$max_size = $this->app->retrieve('assets/max_upload_size', 0);
$forbiddenExtension = ['bat', 'exe', 'sh', 'php', 'phar', 'phtml', 'phps', 'htm', 'html', 'xhtml', 'htaccess'];
$forbiddenMime = [
'application/x-httpd-php', 'application/x-php', 'text/x-php',
'text/html', 'application/xhtml+xml'
];
if (isset($files['name']) && is_array($files['name'])) {
$cnt = count($files['name']);
for ($i = 0; $i < $cnt; $i++) {
$_file = $this->app->path('#tmp:').'/'.$files['name'][$i];
$_mime = $finfo->file($files['tmp_name'][$i]);
$_isAllowed = $allowed === true ? true : preg_match("/\.({$allowed})$/i", $_file);
$_sizeAllowed = $max_size ? filesize($files['tmp_name'][$i]) < $max_size : true;
$extension = strtolower(pathinfo(parse_url($_file, PHP_URL_PATH), PATHINFO_EXTENSION));
if (!$extension) {
$_isAllowed = false;
}
// prevent uploading php / html files
if ($_isAllowed && (
in_array($extension, $forbiddenExtension) ||
in_array(strtolower($_mime), $forbiddenMime)
)) {
$_isAllowed = false;
}
if (!$files['error'][$i] && $_isAllowed && $_sizeAllowed && ($isUpload ? move_uploaded_file($files['tmp_name'][$i], $_file) : rename($files['tmp_name'][$i], $_file))) {
$_files[] = $_file;
$uploaded[] = $files['name'][$i];
if (\preg_match('/\.(svg|xml)$/i', $_file)) {
file_put_contents($_file, \SVGSanitizer::clean(\file_get_contents($_file)));
}
} else {
$failed[] = $files['name'][$i];
}
}
}
if (count($_files)) {
$assets = $this->add($_files, $meta, isset($meta['_id']));
foreach ($_files as $file) {
unlink($file);
}
}
return ['uploaded' => $uploaded, 'failed' => $failed, 'assets' => $assets];
},
// 省略
]);