2026 年 3 月 19 日,一起震惊安全社区的事件再次验证了供应链攻击的致命威胁。Aqua Security 旗下的知名开源漏洞扫描工具 Trivy 遭到入侵,攻击者不仅成功窃取了大量 CI/CD 环境中的敏感凭证,还在开发者终端部署了持久化后门,并实现了自传播的 npm 供应链蠕虫。这起事件被安全研究人员命名为「Trivy 供应链攻击」,其攻击链的复杂程度和破坏力堪称近年来供应链安全领域的教科书级案例。

攻击背景与初始渗透

Trivy 作为 Aqua Security 维护的开源漏洞扫描工具,在全球范围内拥有数百万次下载量,广泛应用于 CI/CD 管道的安全检测环节。攻击者 TeamPCP(代号包括 DeadCatx3、PCPcat、ShellForce、CipherForce)采用了典型的「初始渗透 — 权限维持 — 横向移动 — 数据窃取」五阶段攻击链。值得注意的是,这起事件并非凭空出现,而是建立在一次前期渗透的基础之上。

在主攻击发生前三周,一个名为 hackerbot-claw 的自动化攻击程序利用了 Trivy 项目 GitHub Actions 工作流中 pull_request_target 的误配置,成功窃取了维护者的 Personal Access Token。这次初始渗透虽然被 Aqua Security 的安全团队发现并进行了凭证轮换,但轮换工作存在疏漏 —— 部分长期访问凭证并未被彻底撤销。攻击者正是利用了这一安全缺口,在为期三周的潜伏期内完成了后续攻击的准备和实施工作。

这种「不完全轮换」的安全失误在真实攻击场景中极为常见。许多组织在发现凭证泄露后,往往只轮换最明显的 API 密钥或访问令牌,却忽视了那些通过 OAuth 授予、跨服务共享或硬编码在 CI/CD 环境变量中的长期凭证。安全团队应在每次凭证泄露事件后建立完整的凭证清单,并执行「全部轮换」策略,而非仅针对已知泄露的凭证进行更换。

标签投毒与恶意代码分发

攻击链的第二阶段展现了供应链攻击的核心特征 —— 利用开发者对上游工具的信任进行恶意代码分发。攻击者使用窃取的凭证成功入侵了 aqua-bot 服务账户,并开始冒充合法的项目维护者进行提交操作。他们向 Trivy 仓库推送了经过篡改的 v0.69.4 版本标签,该标签触发了自动化的发布流水线,将植入后门的二进制文件分发至 GitHub Releases、Docker Hub、GHCR 以及 Amazon ECR 等多个分发渠道。

更具破坏性的是,攻击者对 aquasecurity/trivy-action 仓库中的 75 个版本标签进行了 force-push 操作,将这些标签指向包含恶意代码的提交。由于 GitHub Actions 工作流通常使用类似uses: aquasecurity/trivy-action@v0.28.0的版本标签引用方式,这意味着任何使用这些标签的工作流都会在运行时自动执行攻击者植入的恶意代码,而无需修改工作流配置文件本身。攻击者甚至巧妙地保留了原始作者的元数据和提交时间戳,使恶意提交在 Git 历史中看起来与正常的维护者提交无异。

这种标签投毒技术的危险性在于其「不可见性」—— 开发者并未主动修改工作流文件,CI/CD 配置表面上与原来完全一致,但运行时的实际行为已经发生了根本变化。安全团队应强制要求所有 GitHub Actions 引用完整的安全哈希值而非可变标签,例如将uses: action@v1.0改为uses: action@a1b2c3d4e5f6...的形式。Palo Alto Networks 的安全分析指出,如果 Trivy 的下游用户事先采取了这一最佳实践,这次攻击的传播范围将大幅缩小。

内存级凭证窃取技术

攻击链的第三阶段是整个事件中技术含量最高、危害最大的环节。恶意 GitHub Action 执行后,攻击代码并未简单地搜索环境变量或日志文件,而是直接读取 GitHub Actions Runner 进程的内存空间(通过/proc/<pid>/mem接口)。这种技术的关键优势在于:它绕过了所有基于日志脱敏或环境变量过滤的安全防护措施。

具体而言,攻击代码从 Runner 内存中提取了多种类型的敏感凭证,包括 SSH 私钥、主要云服务商的访问密钥(AWS、GCP、Azure)、Kubernetes 服务账户令牌、Docker 注册表凭据、数据库连接密码、TLS 私钥以及加密货币钱包文件等。这种「全谱式」凭证收集策略意味着攻击者能够在单一攻击事件中获得目标环境中最有价值的全部访问凭证。

窃取的凭证数据经过双重加密处理:首先使用 AES-256-CBC 算法进行对称加密,随后使用 RSA-4096 非对称加密算法对密钥进行包装。这种两层加密结构使得网络层面的流量检测工具无法识别攻击载荷的实质内容 —— 网络监控设备只能看到发往外部服务器的加密数据流,而无法解密并分析其内容。攻击者还将数据发送至一个仿冒域名scan.aquasecurtiy[.]org(故意拼写错误以模仿 aquasecurity.org),作为主要外传通道;同时设置了备用方案 —— 利用窃取的 GitHub Personal Access Token 在受害者账户下创建名为tpcp-docs的公开仓库,用于暂存和转移窃取的凭证数据。

从防御角度看,这种内存级攻击暴露了 CI/CD 环境的一个根本性安全盲点:运行时的进程内存数据往往被视为可信的,因为它们来自于组织自身启动的合法进程。安全团队应在 CI/CD Runner 上实施进程内存访问限制策略,禁用或审计对/proc/敏感路径的读取操作;同时对出站网络连接实施严格的域名白名单和 DNS 解析验证。

终端持久化与区块链 C2

攻击的第四阶段将威胁从 CI/CD 管道延伸到了开发者的工作站。当带有后门的 Trivy 二进制文件在开发者机器上运行时,它会部署一个伪装成系统监控服务的 systemd 守护进程(文件名为 sysmon.py,但实际上与 PostgreSQL 监控无关)。该守护进程每 50 分钟主动连接一个 Internet Computer(ICP)区块链 canister,获取指令并进行命令与控制通信。

使用区块链作为 C2 基础设施是近年来攻击者的创新尝试。相比传统的域名型 C2 服务器,区块链 canister 具有更高的弹性和抗摧毁性 —— 传统的 C2 域名可以被注册商封禁、IP 地址可以被 ISP 加入黑名单,但区块链 canister 的地址嵌入在智能合约中,理论上只有在区块链协议层面进行干预才能将其移除。这种去中心化特性使得传统的 C2 takedown 手段对这类攻击几乎无效。

安全团队应在开发者工作站上部署端点检测与响应(EDR)解决方案,重点监控非标准父进程创建 systemd 服务的行为、周期性外部网络连接模式以及从互联网下载并执行的动态行为。开发者的终端安全策略不应仅关注传统的恶意软件特征,还应具备对异常进程树和可疑网络行为的检测能力。

自传播供应链蠕虫

攻击的第五阶段是 CanisterWorm 蠕虫的实现。攻击者利用前期窃取的凭证突破了 npm 生态系统的多个包作用域,在极短时间内(少于 60 秒) compromis 了 47 个以上的 npm 包。这些被植入恶意代码的包随后在 postinstall 钩子中加入了凭证窃取和自传播逻辑,使得任何安装受影响包的开发者或 CI/CD 管道都可能在不知情的情况下成为攻击传播的载体。

这种自传播机制将供应链攻击的破坏力推向了新高度 —— 传统供应链攻击通常是一次性的「供应链投毒」,而 CanisterWorm 实现了攻击载荷的指数级扩散。28 个包在不足一分钟内被攻陷的事实表明,攻击者已经建立了高度自动化的攻击流程,能够在获取凭证后快速定位并入侵高价值的 npm 包。

针对此类风险,安全团队应在 CI/CD 管道中强制使用npm ci --ignore-scripts命令,阻止未知包的 postinstall 钩子执行;同时实施 npm 包的签名验证和完整性检查,确保安装的包与其声明的校验和一致。

检测与防御建议

综合这起事件的经验教训,安全团队应在以下方面立即采取行动:首先,验证当前使用的 Trivy 版本是否安全,官方建议使用 v0.69.3 版本,同时确认 trivy-action 和 setup-trivy 的版本分别为 v0.35.0 和 v0.2.6。其次,对所有 GitHub Actions 进行审计,将版本标签引用全部替换为完整的 SHA 哈希值。第三,在组织内搜索名为tpcp-docs的 GitHub 仓库 —— 如果发现此类仓库,表明凭证可能已经外泄。第四,在网络边界阻断对scan.aquasecurtiy[.]org域名和45.148.10.212IP 地址的访问。第五,检查开发者工作站上是否存在名为 sysmon.py 或 pgmon 的 systemd 服务。

从更宏观的视角来看,Trivy 供应链攻击代表了现代软件供应链威胁的进化方向 —— 攻击者不再满足于单一环节的入侵,而是追求从代码仓库到 CI/CD、从构建系统到开发者终端的完整攻击路径。安全团队需要建立覆盖软件生命全周期的供应链安全治理体系,从依赖项管理、工作流配置、凭证生命周期、终端行为监控等多个维度构建纵深防御。


参考资料