就编译了一下代码,浏览器密码没了——Rust 生态遭遇史上最狠供应链攻击

我用 Rust 不多,但 cargo 这个包管理器的生态算是比较成熟的,社区对安全性也一直很自信。结果这次被打了个措手不及。

整个事件大概是这样:有人通过一个被入侵的维护者账号,往 crates.io(Rust 的 npm)上传了一个恶意版本的 arrayref crate。这个包可能你没听过,但如果你用了 egui、iced 这些 GUI 框架,或者 blake3 哈希库,甚至以太坊和 Solana 的某些组件------你的项目依赖树里大概率有它。 arrayref 累计下载 2.45 亿次,光过去 90 天就 5300 万。

攻击是怎么发生的

昨天凌晨(UTC 时间 8 月 20 日 01:17),攻击者先注册了一个 GitHub 账号 dtolney。 这个名字,你要是不仔细看,可能觉得就是 dtolnay------Rust 圈子里非常知名的开发者,proc-macro2serde 这些核心库的作者。注意区别:真的叫 dtolnay,假的叫 dtolne**y,最后两个字母反了。

注册完号,攻击者用这个身份发布了一个叫 proc-macro1 的 crate。注意,不是 proc-macro2,是 proc-macro1。而且这个包的源码,就是从真正的 proc-macro2 原封不动抄过去的------连文档里的链接和 issue 引用都一并复制了,build 不会有任何异常。 但 build script 里,藏着东西。 五个小时后,攻击者动手了。他们劫持了 arrayref 维护者 droundy(David Roundy,另一位资深 Rust 开发者)的 crates.io 账号,用他的权限发布了三个恶意版本:

  • arrayref@0.3.10
  • internment@0.8.7
  • append-only-vec@0.1.9

这三个包在 Cargo.toml 里各加了一行依赖,指向那个假的 proc-macro1。 然后,最骚的操作来了------攻击者在同一个账号下,把 arrayref 所有之前的正常版本(0.3.5 到 0.3.9)全部 yanked 了。 yanked 是 crates.io 的一个机制,类似于"标记为已撤回"。Cargo 在解析依赖时,会尽量不用 yanked 的版本,还会弹一句 "consider updating to a version that is not yanked"。

好家伙,这一手直接把升级路径给堵死了。旧版本全被标记,唯一没被 yanked 的就是恶意版本 0.3.10。Cargo 的"建议更新"提示,直接变成了攻击者的引流工具。发现这个漏洞的研究员 jhobern 自己就是被这个提示引过去的。

build.rs 里到底写了什么

Cargo 有个设计:每个 crate 可以有一个 build.rs 构建脚本,在编译之前自动执行。这个设计的初衷是做 C 库链接、代码生成之类的事情。 问题是,build.rs 的执行权限是完整的系统级,跟你手动跑一个 shell 脚本没区别。 proc-macro1build.rs 里,攻击者把 C2 服务器地址拆成了几段 base64 碎片:

less 复制代码
const SRC_URL_PARTS: &[&str] =
    &["aHR0cHM6Ly8=", "MjMuMjU0Lg==", "MTY1Lg==", "MTEyOg==", "OTA4OS8="];

拼起来解码后是 https://23.254.165.112:9089/。然后脚本禁用 TLS 证书校验(自定义了一个 AcceptAll 验证器,所有检查直接 return Ok),下载对应平台的二进制文件:

  • Linux x86_64 → rust-crate_0.1.0
  • Windows x86_64 → rust-crate_0.2.0
  • macOS x86_64 → rust-crate_0.3.0
  • macOS aarch64 → rust-crate_0.4.0

在 Unix 上,恶意文件写到 /tmp/rust-setup,chmod +x,然后 detached 启动。在 Windows 上更有意思------写了一个 PowerShell 脚本,再通过 VBScript 启动,故意绕过 Cargo 的进程树管理。源码里甚至写了一行注释解释为什么用 WScript:

arduino 复制代码
// ShellExecute via WScript escapes Cargo's job object; spawned children otherwise
// keep the build script (and `cargo build`) waiting until they exit.

然后还来了个 std::mem::forget(child),直接泄漏进程句柄,确保恶意进程完全脱离编译进程独立运行。 我读到这里的时候说实话有点发毛。这代码写得相当专业,不是随手糊的脚本小子。 恶意程序跑起来之后干什么呢?连接 C2 服务器,然后偷浏览器密码。Chrome、Brave、Edge 的 SQLite 登录数据库全部扫一遍。接着在系统里装持久化后门:Windows 写注册表 Run key,macOS 放 LaunchAgent,Linux 建 systemd 用户服务。 说白了,就是冲着你浏览器里存的那些密码来的。

这个攻击为什么这么阴

有几点我觉得值得说说。

第一,攻击者非常有耐心。他们没有直接搞一个 typosquat 碰运气,而是先准备了几乎以假乱真的 proc-macro1(源码直接复制 proc-macro2),然后等到维护者账号被拿下之后,通过正规渠道发布,再 yank 掉所有旧版本来"逼"用户升级。这整套操作至少提前了好几个小时开始准备。

第二,Rust 的 build.rs 机制在生态内一直被视为"安全的"。不像 npm 的 postinstall 脚本大家都默认可能有猫腻,Rust 开发者普遍不会去怀疑一个构建脚本。但 build.rs 本质上就是一个有完整系统权限的可执行代码。

第三,yanked 机制被反向利用了。这个机制原本是为了让维护者"撤回"有问题的版本,防止新用户使用。攻击者反过来操作:把好的全 yanked,只留一个恶意的。Cargo 的警告反而成了攻击者的帮手。

如果你在用 Rust 项目,并且你的依赖树里有 arrayref(通过 tiny-skiasctk-adwaitawinit 等间接依赖概率很高),那昨天的 cargo build 有可能直接让你的开发机裸奔了。

谁干的

目前没有人认领。 Wiz 的分析指出,这次攻击使用的基础设施与朝鲜(DPRK)关联的黑客活动有大量重叠。C2 地址 23.254.165.112 出现在此前朝鲜发起的 Mastra 行动中,还有一个 IP 在分析朝鲜 npm 攻击的报告里见过。攻击者都用的 Hostwinds 的 IP 段。 不过目前没有任何组织被正式指控。

影响范围

被波及的项目包括:

  • blake3------高性能哈希库
  • egui、eframe、iced------Rust 生态主流 GUI 框架
  • 以太坊和 Solana 的部分组件

好消息是攻击窗口极短。arrayref@0.3.10 在 07:15 UTC 发布,08:41 被删除,只活了 86 分钟。append-only-vec@0.1.9 稍微长一点,107 分钟。Nextron Systems 的研究员发现后第一时间报告了 Rust 安全响应团队,响应速度算快了。

检查自己是否中招

如果你昨天有 Rust 项目在 build,建议赶紧查一下。 先翻 Cargo.lock,看有没有这三个版本:

csharp 复制代码
grep -E 'arrayref.*0.3.10|internment.*0.8.7|append-only-vec.*0.1.9|proc-macro1' Cargo.lock

再扫一下 cargo 缓存:

rust 复制代码
find ~/.cargo/registry/cache -type f \
  -name 'arrayref-0.3.10.crate' -o \
  -name 'internment-0.8.7.crate' -o \
  -name 'append-only-vec-0.1.9.crate' -o \
  -name 'proc-macro1-*.crate' \
  -print

如果确认 build 了恶意版本:

  1. 别慌,但也别拖。从这台机器能访问到的所有密码、token、SSH key,全部轮换
  2. /tmp/rust-setup 是否存在(Unix),查 %TEMP%\rust-setup.ps1%TEMP%\rust-setup-launch.vbs(Windows)
  3. 检查持久化:Windows 看注册表 Run key,macOS 看 ~/Library/LaunchAgents/,Linux 查 systemctl --user list-units
  4. 最好从干净备份重建开发环境

如果没中招,也建议锁定安全版本:arrayref 锁定到 0.3.9 或更早。

写在最后

这几个月供应链攻击密度明显在升。年初的 xz-utils 后门事件,8月初的 npm Keyv 供应链攻击,现在又是 Rust 的 arrayref。攻击者的手法越来越精细,越来越有耐心。 xz 那次是国家级力量花了好几年渗透,npm Keyv 那个是 typosquat 加上恶意 build 脚本,这次的 Rust 事件更狠------直接在维护者账号上动手,还用 yanked 机制来"逼"用户上钩。

有几个事情我觉得应该成为标配了:lock 文件进代码审查流程,CI 环境隔离做到跟生产环境一个标准,构建前跑一遍 cargo audit(npm 对应的是 npm audit)。 还有 build script 这个东西。npm 生态里大家已经习惯了 postinstall 可能有问题,但 Rust 的 build.rs 还没建立起同样的警惕。这次之后,怕是得重新评估一下了。

相关推荐
小小龙学IT3 小时前
ZeroMQ(libzmq)开源消息库深度解析:brokerless 时代的轻量消息内核
c++·开源
程序员老刘3 小时前
被400次配置逼疯后,我开源了个小工具
开源·ai编程
恒拓高科WorkPlus3 小时前
私有化视频会议:BeeWorks Meet让企业会议更安全、更协同
安全
天工开物开源基金会3 小时前
具身智能开源全栈生态协同分论坛成功举办
开源·开源大会·天工开物
嘟哩DuliDuli5 小时前
AI 短剧生成为什么要有角色库、场景库和镜头卡
android·人工智能·安全·ai·软件工程
高工智能汽车5 小时前
新石器发布行业首个L4无人车安全智能体“玄武“,升级规模化安全运营体系
安全
Arnold.Shen5 小时前
Dell Storage SC - 如何发送SupportAssist,并启用安全控制台
linux·安全
IvanCodes6 小时前
GitHub 本周热门开源项目:Agent Infra与端侧 AI|8.17–8.23
开源·github
猫咪宝妖6 小时前
【信息安全工程师】第2章 网络安全法律与标准
安全·web安全