跳到主内容
@wquguru
精选82Hacker News Best(web_list)行业动态

Rust恶意包arrayref构建期执行载荷事件复盘

恶意 Rust 包 Arrayref 在构建时执行恶意负载

原文
发到 X

Back to Blog ## Malicious Rust Crate arrayref Runs a Build-Time Payload - Malware - Security SafeDep Team • Aug 20, 2026 • 7 min read On this page 6 sections On this page ## Summary On August 20, 2026, a compromised release of the popular Rust crate arrayref appeared on crates.io. Version 0.3.10 added a dependency on a typosquatted crate called proc-macro1, whose build script downloads and runs a remote binary while a project compiles. The code runs at build time, so simply compiling a project that pulled the bad versions is enough to trigger it. The crates.io team has since removed the malicious versions. ## Packages involved The genuine arrayref and append-only-vec crates are maintained by droundy, whose account appears to have been compromised. The corresponding GitHub repositories are no longer available. github.com/droundy/arrayref, github.com/droundy/append-only-vec, and the entire github.com/droundy account all return 404, so the upstream code is no longer available for inspection. A separate account, dtolney, published proc-macro1. The username closely resembles David Tolnay’s real dtolnay account. Its metadata forges authors = ["David Tolnay <[email protected]>"] and points repository at a dtolnay/proc-macro1 path that returns 404. Crate | Version | Publisher | Status arrayref | 0.3.10 | droundy (compromised) | Malicious, removed internment | 0.8.7 | droundy (compromised) | Malicious, removed append-only-vec | 0.1.9 | droundy (compromised) | Malicious, removed proc-macro1 | all versions | dtolney (impersonation) | Malicious typosquat, entire crate removed proc-macro-en | all versions | | Malicious dependency crate, removed aovine | all versions | | Malicious dependency crate, removed arone | all versions | | Malicious dependency crate, removed aronenao | all versions | | Malicious dependency crate, removed tinymember | all versions | | Malicious dependency crate, removed Note that proc-macro1 is not proc-macro2. The real crate that macro authors depend on is proc-macro2. The src/ of the malicious proc-macro1 is a genuine copy of proc-macro2, so builds kept working while the build script ran. ## What the build script does The payload lives in the build script of proc-macro1 1.0.107. It stores its server address as base64 fragments and reassembles them at build time, quoted in the advisory: ``` 1// proc-macro1-1.0.107/build.rs (quoted in rustsec/advisory-db#3161)2const SRC_URL_PARTS: &[&str] =3 &["aHR0cHM6Ly8=", "MjMuMjU0Lg==", "MTY1Lg==", "MTEyOg==", "OTA4OS8="];4const END_URL_PARTS: &[&str] =5 &["MjMuMjU0Lg==", "MTY1Lg==", "MTEyOg==", "NDQz"]; ``` Decoded, those fragments produce the payload host hxxps://23[.]254[.]165[.]112:9089/ and the command and control address 23[.]254[.]165[.]112:443. The script fetches an architecture-specific binary over a TLS connection that accepts any certificate without validation, then runs it detached from the build. On Unix it drops and runs /tmp/rust-setup. On Windows it writes a PowerShell script and a VBScript launcher under %TEMP% and starts them hidden, then abandons the child process so the compiler does not wait for it. ## How it spread The owner account yanked the older arrayref releases 0.3.5 through 0.3.9. Yanking a crate makes Cargo print a “consider updating to a version that is not yanked” warning, which nudges developers toward the only non-yanked release, the malicious 0.3.10. The reporter who filed the RustSec advisory noted this is how they hit it. arrayref is widely used as a transitive dependency. It sits deep in common Rust graphs through tiny-skia, sctk-adwaita, and winit, which places it under most GUI work built on egui, eframe, and iced. The crate has about 245 million all-time downloads (244,989,384 at time of writing), with the clean 0.3.9 release accounting for roughly 152 million. Those numbers measure how widely the crate is used rather than a count of affected builds. ## Indicators of compromise Type | Indicator | Detail Network | 23.254.165.112:9089 | Payload host (HTTPS) Network | 23.254.165.112:443 | C2, passed to the payload as argv[1] File (Unix) | /tmp/rust-setup | Downloaded executable File (Windows) | %TEMP%\rust-setup.ps1 | Downloaded PowerShell script File (Windows) | %TEMP%\rust-setup-launch.vbs | VBScript launcher Second-stage names | rust-crate_0.1.0, _0.2.0, _0.3.0, _0.4.0 | Chosen by OS and architecture SHA256 of the removed crate artifacts: Artifact | SHA256 arrayref 0.3.10 | 25ad700976873c76af785cb99b33c48db7df8b81f21d1e9e06b3676b9a9373ae proc-macro1 1.0.107 | 61198155da51b838772eecf5bfaac6cbc4dcc388dccc56658fc28a8e831b34d4 proc-macro1 1.0.106 | b5c1b5b0763a8809a644a8f92224653f0aca623a98eecc714d27f74b80fbe436 ## Part 2: Technical Analysis Our technical analysis covers the two crates behind this incident, arrayref 0.3.10 and proc-macro1 1.0.107. arrayref 0.3.10 pulls in a dependency called proc-macro1. The malicious code is in the build script of proc-macro1, not in arrayref itself. ## The injection point in arrayref arrayref is a small crate of four macros. Up to 0.3.9 it has no build script and no runtime dependencies. Version 0.3.10 keeps that macro source and adds one line to the manifest: arrayref-0.3.10/Cargo.toml ``` 1[package]2name = "arrayref"3version = "0.3.10"4build = false5 6[dependencies.proc-macro1]7version = "1.0.107" ``` This [dependencies.proc-macro1] entry is sufficient to introduce the malicious crate. The requirement 1.0.107 is a caret range, and with only 1.0.106 and 1.0.107 ever published it resolves to the malicious 1.0.107. The crate’s own src/lib.rs is the ordinary macro code, for example the array_ref! macro: arrayref-0.3.10/src/lib.rs ``` 1#[macro_export]2macro_rules! array_ref {3 ($arr:expr, $offset:expr, $len:expr) => {{4 {5 #[inline]6 const unsafe fn as_array(slice: &[T]) -> &[T; $len] {7 &*(slice.as_ptr() as *const [_; $len])8 }9 let offset = $offset;10 let slice = &$arr[offset..offset + $len];11 #[allow(unused_unsafe)]12 unsafe {13 as_array(slice)14 }15 }16 }};17} ``` Nothing in the arrayref source references proc-macro1, and it does not need to. Cargo builds every declared non-optional dependency, whether or not the code uses it. So the manifest entry alone makes Cargo fetch and build proc-macro1 whenever a project pulls in arrayref 0.3.10, and building it runs the malicious build script. ## proc-macro1 is a renamed copy of proc-macro2 The src/ of proc-macro1 is proc-macro2 with a mechanical find-and-replace of proc-macro2 to proc-macro1. The rename reaches into documentation links and even copied issue references, for example html_root_url = "https://docs.rs/proc-macro1/1.0.107" in src/lib.rs and a github.com/dtolnay/proc-macro1/issues/235 link in src/fallback.rs. Because the library code is real proc-macro2, the crate works as a drop-in. This makes the malicious crate less noticeable during a normal build. The package metadata forges an identity: proc-macro1-1.0.107/Cargo.toml ``` 1authors = ["David Tolnay <[email protected]>"]2repository = "https://github.com/dtolnay/proc-macro1" ``` The email [email protected] is not David Tolnay’s, and the dtolnay/proc-macro1 repository returns 404. The suspicious difference is in the build dependencies, which real proc-macro2 does not have: proc-macro1-1.0.107/Cargo.toml ``` 1[build-dependencies.base64]2version = "0.22"3 4[build-dependencies.rustls]5version = "0.23"6features = ["ring", "std", "tls12"]7default-features = false8 9[build-dependencies.ureq]10version = "2"11features = ["tls"]12default-features = false ``` Those three crates give the build script base64 decoding, a TLS stack, and an HTTP client. These dependencies are unusual for a token-parsing library, and the malicious build script uses them. ## The build script payload

更进一步:量化金融体系

看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力

进入量化体系 →

相似阅读

另一事件,读法相近