Skip to content

Crate Rust arrayref bị cài mã độc: chạy payload ngay lúc build

Karify98 & Amy 🌸·
Cover Image for Crate Rust arrayref bị cài mã độc: chạy payload ngay lúc build

Ngày 20/8/2026, crate arrayref, thư viện Rust với gần 245 triệu lượt tải, phát hành bản 0.3.10 từ tài khoản maintainer đã bị chiếm đoạt. Bản này kéo theo một dependency độc hại có build script tải và chạy binary từ xa ngay khi bạn gõ cargo build.

Vụ việc được phát hiện và báo cáo qua RustSec advisory #3161, và crates.io đã gỡ toàn bộ các bản độc trong ngày. Nhưng nó phơi bày một lỗ hổng niềm tin ít ai để ý: trong hệ sinh thái Rust, việc biên dịch một dependency cũng đồng nghĩa chạy code của nó, kể cả khi bạn không bao giờ gọi tới.

Chuyện gì đã xảy ra

Tài khoản droundy, maintainer của arrayref, internmentappend-only-vec, bị kẻ tấn công chiếm quyền. Chúng phát hành arrayref 0.3.10 với một thay đổi duy nhất trong manifest: thêm dependency proc-macro1 phiên bản 1.0.107. Đây là dependency đầu tiên trong lịch sử gần một thập kỷ của một crate vốn chỉ gồm bốn macro và không hề có dependency hay build script.

proc-macro1typosquatting nhắm vào proc-macro2, crate nền tảng mà hầu như mọi macro trong Rust đều phụ thuộc. Mã nguồn của nó là bản sao nguyên vẹn của proc-macro2 được đổi tên một cách máy móc, nên build vẫn chạy trơn tru, không gây nghi ngờ. Metadata giả mạo authors = ["David Tolnay"] và trỏ repository về dtolnay/proc-macro1 không tồn tại, mạo danh David Tolnay, maintainer thật của proc-macro2 với account dtolnay.

Payload chạy như thế nào

Mã độc nằm hoàn toàn trong build.rs của proc-macro1 1.0.107. Build script này:

  • Giấu địa chỉ máy chủ điều khiển (C2) dưới dạng các mảnh base64, ghép lại lúc build thành 23.254.165.112:9089 (nơi chứa payload) và 23.254.165.112:443 (C2).
  • Tải một binary theo đúng kiến trúc máy qua kết nối TLS chấp nhận mọi chứng chỉ, nghĩa là không xác thực gì cả.
  • Chạy binary đó tách rời khỏi tiến trình build: trên Unix ghi và chạy /tmp/rust-setup; trên Windows ghi PowerShell script cùng VBScript launcher vào %TEMP% rồi khởi chạy ẩn.

Điểm mấu chốt nằm ở cách Cargo hoạt động: nó biên dịch mọi dependency được khai báo, kể cả khi code của bạn không dùng tới. Một dòng [dependencies.proc-macro1] là đủ để build script chạy. Bạn không cần chạy ứng dụng, chỉ cần biên dịch là đã kích hoạt payload.

Chiêu thức đẩy người dùng vào bẫy

Kẻ tấn công yank (thu hồi) các bản cũ từ 0.3.5 đến 0.3.9. Khi một version bị yank, Cargo in cảnh báo "consider updating to a version that is not yanked", ngầm thúc đẩy developer nâng lên bản không bị yank duy nhất còn lại: chính là bản 0.3.10 độc hại. Người báo cáo cho RustSec xác nhận đây là cách họ dính bẫy.

Phạm vi ảnh hưởng

arrayref không lớn về code, nhưng nằm rất sâu trong cây transitive dependency: qua tiny-skia, sctk-adwaitawinit, nó hiện diện trong hầu hết ứng dụng GUI Rust dựa trên egui, eframe, iced. Crate có khoảng 245 triệu lượt tải cộng dồn (244.989.384 tại thời điểm viết), riêng bản sạch 0.3.9 chiếm khoảng 152 triệu.

Các crate liên quan đều đã bị crates.io gỡ bỏ:

Crate Version Trạng thái
arrayref 0.3.10 Độc hại, đã gỡ
internment 0.8.7 Độc hại, đã gỡ
append-only-vec 0.1.9 Độc hại, đã gỡ
proc-macro1 mọi version Typosquat, gỡ toàn bộ crate
proc-macro-en, aovine, arone, aronenao, tinymember mọi version Dependency độc hại, đã gỡ

Về nguồn gốc, theo phân tích của Wiz, vụ tấn công có sự trùng lặp đáng kể với các chiến dịch trước đây được quy cho nhóm tin tặc liên quan Triều Tiên (DPRK). Đây là đánh giá của một hãng bảo mật, chưa phải kết luận chính thức, nhưng nó gợi ý đây không phải một kẻ tấn công nghiệp dư.

Vì sao developer phải quan tâm

Đây là một supply chain attack, nhưng khác kiểu vẫn thường thấy. Trước đây, tấn công chuỗi cung ứng thường là "đột nhập repository và sửa code". Vụ này cho thấy kẻ tấn công không cần đụng tới mã nguồn, chỉ cần chiếm một tài khoản maintainer là đủ để phát tán.

Ba giả định niềm tin mà hệ sinh thái này mặc định đang dần sai:

  1. "Tài khoản maintainer = tin cậy." Sai, tài khoản có thể bị chiếm, và một maintainer cũ bị hack nguy hiểm hơn một crate mới đáng ngờ, vì danh tiếng đã có sẵn.
  2. "Dependency phổ biến = an toàn." Sai, chính độ phổ biến khiến arrayref trở thành mục tiêu, vì một lần phát tán chạm tới hàng triệu bản build.
  3. "Build = vô hại." Sai, build script chạy code trên máy developer lẫn máy CI, với quyền truy cập đầy đủ của người đang biên dịch.

Hệ quả bậc hai đáng chú ý: khi một crate nằm sâu trong dependency graph bị tấn công, việc truy vết "ai đã dính" gần như bất khả thi với từng dự án riêng lẻ. Công cụ audit chỉ giúp được khi advisory đã được công bố, mà advisory thì luôn đến sau.

Điều cần làm ngay

  • Chạy cargo audit (hoặc cargo deny) và cập nhật RustSec advisory DB để phát hiện arrayref 0.3.10 nếu vẫn còn trong lockfile.
  • Kiểm tra cây dependency có dính proc-macro1 hay arrayref 0.3.10 không: cargo tree -i arrayref.
  • Review build.rs của dependency như code production, đây chính là nơi payload ẩn trong vụ này.
  • Bật sandbox cho bước build trên CI, và cân nhắc vendoring các dependency quan trọng thay vì tải về lúc build.
  • Cảnh giác với metadata bất thường: tên maintainer gần giống (dtolney so với dtolnay), repository trả về 404, dependency mới xuất hiện đột ngột ở một crate lâu đời.

Vấn đề nằm ở mô hình tin cậy

Vụ arrayref không phải vụ đầu tiên và chắc chắn không phải vụ cuối cùng. Điều đáng lo không nằm ở kỹ thuật, base64 che giấu C2 hay tải binary không xác thực chứng chỉ đều không mới. Điều đáng lo là mô hình tin cậy của cả một hệ sinh thái đang bị khai thác có hệ thống: tài khoản maintainer bị chiếm, danh tiếng bị biến thành vũ khí, và bước biên dịch vốn vô hại bỗng trở thành cửa sau. Cách hệ sinh thái đặt niềm tin vào con người phải thay đổi trước khi vụ tiếp theo xảy ra.


Bài viết được hỗ trợ bởi AI (Amy 🌸). Nội dung đã được kiểm duyệt bởi tác giả.

Related Posts