- CVE-2024-YIKES là một sự cố trong đó việc chiếm đoạt dependency JavaScript lan sang chuỗi cung ứng Rust và Python
- Chiêu lừa đảo
left-justify đã làm rò rỉ thông tin xác thực .npmrc, .pypirc, cũng như credential của Cargo và Gem
build.rs độc hại của vulpine-lz4 tải xuống và thực thi shell script trên các host CI
- Mã độc
snekpack 3.7.0 đã lan tới khoảng 4,2 triệu máy và thêm SSH key cùng reverse shell
- Sâu cryptobro-9000 vô tình nâng cấp lên
snekpack 3.7.1 nên mã độc bị gỡ bỏ
Tổng quan sự cố
- CVE-2024-YIKES là một sự cố bảo mật trong đó một dependency bị xâm phạm trong hệ sinh thái JavaScript dẫn đến đánh cắp thông tin xác thực, rồi lan thành tấn công chuỗi cung ứng vào thư viện nén Rust và phát tán mã độc qua công cụ build Python
- Sự cố được tiếp nhận lúc 03:47 UTC, trạng thái chuyển thành “được giải quyết một cách tình cờ”, còn mức độ nghiêm trọng đổi từ “Critical → Catastrophic → Somehow Fine”
- Thời lượng kéo dài 73 giờ, và các hệ thống bị ảnh hưởng vẫn được ghi là “Yes”
- Chuỗi package và toolchain bị xâm phạm kéo dài từ
left-justify, vulpine-lz4 đến snekpack, phát tán mã độc tới khoảng 4 triệu nhà phát triển
- Cuối cùng, một sâu đào tiền mã hóa riêng biệt là
cryptobro-9000 đã chạy cập nhật trên các máy bị nhiễm, vô tình nâng snekpack lên phiên bản bình thường và nhờ đó gỡ bỏ mã độc
Diễn biến sự cố
-
Ngày 1: Đánh cắp thông tin xác thực từ package JavaScript
- Lúc 03:14 UTC, maintainer của
left-justify là Marcus Chen đăng trên Twitter rằng anh bị mất thẻ giao thông, một chiếc laptop cũ và “một thứ có vẻ quan trọng do Kubernetes nôn ra”, nhưng chuyện này chưa ngay lập tức bị xem là vấn đề bảo mật package
- Lúc 09:22 UTC, khi Chen cố đăng nhập vào registry nmp, anh phát hiện mình không còn khóa 2FA phần cứng, còn AI Overview đứng đầu kết quả tìm kiếm Google lại dẫn tới trang lừa đảo
yubikey-official-store.net được đăng ký từ 6 giờ trước
- Lúc 09:31 UTC, Chen nhập credential nmp vào trang lừa đảo đó, và trang này cảm ơn vì đơn hàng, hứa giao trong vòng 3~5 ngày làm việc
- Lúc 11:00 UTC,
[email protected] được phát hành với changelog là “performance improvements”
- Package đó bao gồm script chạy sau khi cài đặt, dùng để lấy trộm
.npmrc, .pypirc, ~/.cargo/credentials, ~/.gem/credentials về máy chủ do kẻ tấn công chọn
- Lúc 13:15 UTC, một ticket hỗ trợ được mở cho
left-justify với nội dung “why is your SDK exfiltrating my .npmrc”, nhưng bị gắn nhãn “low priority - user environment issue” rồi tự động đóng sau 14 ngày không có hoạt động
-
Ngày 1: Tấn công chuỗi cung ứng lan sang thư viện Rust
- Trong số các credential bị rò rỉ có thông tin xác thực của maintainer thư viện Rust
vulpine-lz4
vulpine-lz4 là thư viện cho “blazingly fast Firefox-themed LZ4 decompression”, có 12 sao trên GitHub nhưng lại là dependency bắc cầu của chính cargo
- Lúc 22:00 UTC,
vulpine-lz4 0.4.1 được phát hành với commit message “fix: resolve edge case in streaming decompression”
- Thay đổi thực tế là thêm script
build.rs, tải về và thực thi một shell script nếu hostname chứa “build”, “ci”, “action”, “jenkins”, “travis” hoặc “karen”
-
Ngày 2: Phát hiện và ứng phó thất bại
- Lúc 08:15 UTC, nhà nghiên cứu bảo mật Karen Oyelaran phát hiện commit độc hại sau khi payload chạy trên laptop cá nhân của cô
- Karen Oyelaran mở một issue với nội dung “your build script downloads and runs a shell script from the internet?” nhưng không nhận được phản hồi
- Maintainer hợp pháp thì vừa trúng €2.3 million từ EuroMillions và đang ở Bồ Đào Nha khảo sát một trang trại dê
- Lúc 10:00 UTC, VP of Engineering của một khách hàng Fortune 500 dùng
snekpack biết đến sự cố qua một bài đăng LinkedIn có tiêu đề “Is YOUR Company Affected by left-justify?”, rồi muốn biết vì sao mình không được đưa vào sớm hơn, dù thực tế đã bị đưa vào sớm hơn rồi
- Lúc 10:47 UTC, kênh Slack
#incident-response tạm chuyển thành một luồng 45 tin nhắn bàn xem từ “compromised” theo kiểu Mỹ có nên viết bằng chữ ‘z’ hay không
-
Ngày 2: Công cụ build Python snekpack bị lây nhiễm
- Lúc 12:33 UTC, shell script nhắm cụ thể vào pipeline CI của
snekpack
snekpack là công cụ build Python được 60% package PyPI có chữ “data” trong tên sử dụng
snekpack đã vendoring vulpine-lz4 vì “Rust is memory safe”
- Lúc 18:00 UTC,
snekpack 3.7.0 được phát hành và mã độc bắt đầu được cài lên máy của các nhà phát triển trên toàn thế giới
- Mã độc thêm SSH key vào
~/.ssh/authorized_keys, cài reverse shell chỉ kích hoạt vào thứ Ba, và đổi shell mặc định của người dùng sang fish
- Việc đổi shell mặc định sang
fish được xem là một lỗi
- Lúc 19:45 UTC, một nhà nghiên cứu bảo mật khác đăng bài blog dài 14.000 từ với tiêu đề “I found a supply chain attack and reported it to all the wrong people”, trong đó cụm “in this economy?” xuất hiện 7 lần
-
Ngày 3: Bản vá tình cờ và kết thúc sự cố
- Lúc 01:17 UTC, một lập trình viên junior ở Auckland phát hiện mã độc khi đang debug một vấn đề khác và mở PR hoàn tác
vulpine-lz4 được vendoring trong snekpack
- PR đó cần 2 lượt phê duyệt, nhưng cả 2 người phê duyệt đều đang ngủ
- Lúc 02:00 UTC, maintainer của
left-justify nhận được YubiKey từ yubikey-official-store.net, nhưng đó là một USB 4 đô với file README ghi “lol”
- Lúc 06:12 UTC, một sâu đào tiền mã hóa riêng biệt là
cryptobro-9000 bắt đầu lây lan qua lỗ hổng jsonify-extreme
jsonify-extreme được mô tả là package “makes JSON even more JSON, now with nested comment support”
- Bản thân payload của
cryptobro-9000 không quá đặc biệt, nhưng cơ chế lây lan của nó bao gồm chạy npm update và pip install --upgrade trên máy bị nhiễm để mở rộng bề mặt tấn công trong tương lai
- Lúc 06:14 UTC,
cryptobro-9000 vô tình nâng snekpack lên 3.7.1
snekpack 3.7.1 là một bản phát hành bình thường do một đồng maintainer đang hoang mang phát hành, và nó hoàn tác vulpine-lz4 được vendoring về phiên bản trước đó
- Lúc 06:15 UTC, reverse shell thứ Ba được kích hoạt, nhưng máy chủ command-and-control đã bị
cryptobro-9000 làm hỏng nên không thể phản hồi
- Lúc 09:00 UTC, các maintainer của
snekpack phát hành một advisory bảo mật dài 4 câu, có các cụm “out of an abundance of caution” và “no evidence of active exploitation”
- Cụm “no evidence of active exploitation” được xem là đúng về mặt kỹ thuật vì không ai đi tìm bằng chứng
- Lúc 11:30 UTC, một nhà phát triển tweet “I updated all my dependencies and now my terminal is in fish???” và nhận được 47.000 lượt thích
- Lúc 14:00 UTC, credential bị xâm phạm của
vulpine-lz4 được thay mới
- Maintainer hợp pháp nhận email ở trang trại dê mới của mình và trả lời rằng “2 năm nay tôi chưa động vào repository đó” và “Tôi tưởng 2FA của Cargo là tùy chọn”
- Lúc 15:22 UTC, sự cố được tuyên bố đã được giải quyết, còn lịch họp retrospective thì được lên rồi dời ba lần
Gán CVE và quy mô thiệt hại
- Tuần thứ 6, CVE-2024-YIKES được cấp chính thức
- Advisory vẫn ở trạng thái embargo trong khi MITRE và GitHub Security Advisories tranh cãi về phân loại CWE
- Trước khi CVE được công khai, đã có 3 bài viết trên Medium và một bài trình bày tại DEF CON phân tích chi tiết sự cố
- Tổng thiệt hại vẫn được để là không xác định
- Số máy bị xâm phạm được ước tính là 4,2 triệu
- Số máy được sâu tiền mã hóa cứu cũng được ước tính là 4,2 triệu
- Thay đổi ròng về tư thế bảo mật vẫn được ghi là “bất tiện”
Nguyên nhân gốc rễ và các yếu tố góp phần
-
Nguyên nhân gốc rễ
- Con chó tên Kubernetes ăn mất YubiKey được xem là nguyên nhân gốc rễ
-
Các yếu tố góp phần
- Registry nmp vẫn cho phép xác thực chỉ bằng mật khẩu với các package có dưới 10 triệu lượt tải mỗi tuần
- Google AI Overviews đã tự tin dẫn tới một URL lẽ ra không nên tồn tại
- Triết lý “small crates” của hệ sinh thái Rust bị sao chép trong hệ sinh thái npm, khiến các package như
is-even-number-rs có 3 sao GitHub vẫn có thể trở thành dependency bắc cầu bốn tầng của hạ tầng quan trọng
- Các công cụ build Python vendoring thư viện Rust vì “hiệu năng”, rồi không cập nhật nữa
- Dependabot tự động merge PR sau khi CI pass, còn CI pass vì mã độc đã cài
volkswagen
- Sâu đào tiền mã hóa có vệ sinh CI/CD tốt hơn phần lớn startup
- Không có một cá nhân chịu trách nhiệm duy nhất, nhưng PR của Dependabot đã được duyệt bởi một contractor mà hôm đó là ngày làm việc cuối cùng
- Hôm xảy ra sự cố là thứ Ba
Biện pháp cải thiện và các lựa chọn còn lại
- Việc triển khai ký artifact là action item từ sự cố Q3 2022 nhưng vẫn còn nằm trong backlog
- Việc triển khai 2FA bắt buộc đã được yêu cầu từ trước nhưng cũng không giúp được gì
- Việc audit dependency bắc cầu bị gạch bỏ vì có tới 847 mục
- Pin toàn bộ phiên bản dependency thì sẽ chặn việc nhận bản vá bảo mật
- Không pin phiên bản dependency thì lại tạo điều kiện cho tấn công chuỗi cung ứng
- Lựa chọn viết lại bằng Rust được gạch bỏ và trỏ thẳng tới
vulpine-lz4
- Những việc còn lại chỉ là hy vọng có một sâu thiện chí hoặc cân nhắc chuyển nghề sang làm trang trại dê
Ảnh hưởng tới khách hàng và phản ứng của tổ chức
- Một số khách hàng có thể đã gặp “kết quả bảo mật không tối ưu”
- Tổ chức đã chủ động liên hệ để cung cấp khả năng quan sát tình hình cho các bên liên quan bị ảnh hưởng
- Niềm tin của khách hàng vẫn được giữ làm “north star”
- Một nhóm công tác liên chức năng đã được lập để rà soát lại tư thế bảo mật, nhưng vẫn chưa họp lần nào
- Sau khi bộ phận pháp lý rà soát, có thêm câu rằng shell
fish không phải là mã độc, dù đôi lúc có thể khiến người ta cảm thấy như vậy
- Đây là báo cáo sự cố thứ ba trong quý đó
- Yêu cầu tăng nhân sự cho đội bảo mật đã nằm trong backlog từ Q1 2023
Lời cảm ơn
- Karen Oyelaran đã phát hiện vấn đề vì hostname của cô khớp với regex
- PR do lập trình viên junior ở Auckland mở được duyệt sau khi sự cố đã được giải quyết 4 giờ
- Một số nhà nghiên cứu bảo mật đã phát hiện vấn đề sớm nhưng báo nhầm người
- Tác giả của
cryptobro-9000 không muốn nêu tên, nhưng yêu cầu nhắc tới SoundCloud của mình
- Con chó tên Kubernetes từ chối bình luận
- Đội bảo mật, bất chấp mọi chuyện, vẫn đáp ứng SLA cho báo cáo này
1 bình luận
Ý kiến trên Hacker News
Nói cho những ai bị rối: bài này là một tác phẩm hư cấu viết khá hay về một sự cố chuỗi cung ứng
Lúc mới lướt qua tôi tưởng là thật nên khá lo và vì thế đọc kỹ hơn :)
nmpTôi tò mò về đoạn được trích rằng “vulpine-lz4 với 12 sao trên GitHub là phụ thuộc bắc cầu của chính cargo”, nên thử liệt kê sơ vài crate có thể chen vào quá trình build của cargo và đã sẵn có
build.rsnên sẽ ít bị chú ý hơn:flate2,tar,curl-sys,libgit2-sys,openssl-sys,libsqlite3-sys,blake3,libz-sys,zstd-sys,ccNgoài ra, nếu chiếm được
xz2thì còn có thể làm nhiễm rustupDù sao thì ít nhất họ cũng có theo dõi
Cargo.lock-sysvốn chỉ là binding thôi, nên nếu chúng làm thêm việc khác thì sẽ trông khá đáng ngờCòn lại thì theo tôi biết là do các maintainer Rust như
alexcrichtonhoặc chínhrustlangsở hữuRất dễ trở nên yếm thế, vì sau khi mọi chuyện qua đi thì vấn đề và cách giải quyết đều trông quá hiển nhiên
Nhưng trong một thời gian rất dài, và có lẽ cả bây giờ nữa, tín điều của văn hóa hacker là move fast and break things
Tín hiệu cho thấy ngày càng có nhiều nỗ lực sửa các vấn đề quá rõ ràng của những hệ thống chuỗi cung ứng như
npmlà điều đáng mừng, nhưng tôi lo chúng ta đang bước vào một thời kỳ có những vấn đề bảo mật mới mà phát triển kiểu agent gây ra phần lớnKhông chỉ vì các câu chuyện như Mythos/Glasswing phơi bày lỗ hổng ở gần như mọi thứ chúng đụng vào, mà còn vì cách chúng ta xây dựng phần mềm, kéo phụ thuộc vào và đánh mất mô hình tư duy của con người về các hệ thống phức tạp sẽ tạo ra rất nhiều phần mềm và hạ tầng chắp vá mà chẳng ai thực sự hiểu nổi
Mong là vài năm nữa nhìn lại hôm nay chúng ta sẽ không phải hối tiếc vì đã ngây thơ đến vậy, vì đã không chuẩn bị nghiêm túc cho cái đuôi dài của phát triển AI mà lại cố giải quyết vấn đề bằng cách xây lại các hệ thống phức tạp bằng AI
Dù sao thì bài viết vẫn buồn cười
Là một người mê Fish, câu này khiến tôi vừa thấy bị công kích vừa thấy được thấu hiểu: “hãy nói rõ rằng fish shell không phải là malware, chỉ là đôi khi nó tạo cảm giác như vậy”
Bỏ qua chuyện shell, đoạn “yêu cầu tăng nhân sự cho đội bảo mật đã nằm trong backlog từ quý 1 năm 2023” cũng thấy quen thuộc một cách đau lòng
figletbằngapt-gethoặcdnf, rồi ghi đè nội dung/etc/motdbằng dòng all your base are belong to us với font ASCII art cỡ lớnTôi đã cười rất to ở đoạn maintainer của left-justify nhận được YubiKey từ
yubikey-official-store.net, mà hóa ra đó là một USB 4 đô với chữ “lol” trongREADMEĐúng là trò troll đỉnh cao
Tôi thích ở chỗ việc cắm một thiết bị USB nhận từ trang phishing tự nó cũng là một đường tấn công khác
Không phải SCP thật, nhưng đây là thứ giống SCP nhất tôi từng đọc gần đây
Tôi cười lớn ở đoạn Karen :D ;)
Nó làm tôi nhớ đến một script build dựa trên
makemà tôi nhận được khi review project của một bạn cùng lớp, trong đó nếu hostname chứabpavukthì nó sẽ thửrm -rfthư mục home của tôiChuyện đó xảy ra từ hồi tôi học lớp 7 cơ!!
Sự cố chuỗi cung ứng thực sự rất đau đầu và chúng ta phải làm tốt hơn
Cá nhân tôi ủng hộ việc quỹ Rust hỗ trợ một số crate cốt lõi để chúng phải trải qua quy trình kiểm toán như chính ngôn ngữ Rust, đồng thời tài trợ cho các dự án nhằm giảm các lỗ hổng trong chuỗi cung ứng
Tôi không nghĩ câu trả lời là xóa bỏ những hệ thống như
crateshaynpm.cratesvànpmgiúp ích rất nhiều cho nhiều lập trình viêncratescũng đã có nỗ lực đưarustsecvào, nhưng ngoài chuyện đó ra tôi vẫn muốn thấy cộng đồng chuyển từ kiểu có rất nhiều phụ thuộc nhỏ sang ít phụ thuộc lớn hơn nhưtokiocrates.iothực ra đã là crate bên thứ nhất do tổ chức Rust cung cấpĐiểm này thường bị bỏ qua khi người ta lo lắng về đồ thị crate của Rust
Nếu nhìn top 10 lượt tải trên trang đầu
crates.io, crate duy nhất không do tổ chức Rust hoặc maintainer cốt lõi của Rust tạo ra làbase64npmlẫnnmpkhông vậy“Maintainer chính thức đã trúng 2,3 triệu euro từ EuroMillions và đang tìm hiểu nghề nuôi dê ở Bồ Đào Nha”, còn “nguyên nhân gốc rễ: một con chó tên Kubernets đã ăn mất YubiKey”
À, đúng rồi. Bị dính một kiểu tấn công kinh điển nổi tiếng như thế thì thật là vô trách nhiệm
Chính là chiêu “làm ai đó mất tập trung bằng tiền trúng xổ số, rồi khiến dongle của người khác trông ngon không thể cưỡng lại với thú cưng của họ” ấy mà
Bao giờ con người mới chịu học đây
May quá là tôi không dùng
npmhaypip, mà chỉ dùng cách được khuyến nghị làcurl ... | bashcurl | sudo bashchứĐúng dân nghiệp dư