- Đã xác nhận rằng trên kho lưu trữ NPM, hơn 100 gói độc hại dùng để đánh cắp thông tin xác thực đã được tải lên mà không bị phát hiện kể từ tháng 8, với tổng số lượt tải vượt 86.000 lần
- Công ty bảo mật Koi báo cáo rằng chiến dịch tấn công được đặt tên là PhantomRaven đã phát tán 126 gói độc hại bằng cách lạm dụng tính năng Remote Dynamic Dependencies (RDD) của NPM
- RDD là một cấu trúc cho phép gói tải mã phụ thuộc một cách động từ các miền không đáng tin cậy, nên không bị các công cụ phân tích tĩnh phát hiện
- Kẻ tấn công đã dùng tính năng này để tải mã độc qua kết nối HTTP, nhưng trong metadata của gói lại hiển thị là "0 Dependencies", khiến nhà phát triển và trình quét bảo mật không nhận ra
- Điểm yếu mang tính cấu trúc này cho thấy giới hạn trong quản lý bảo mật của hệ sinh thái NPM và rủi ro của cơ chế cài đặt tự động
Sự lan rộng của các gói độc hại trong kho NPM
- Kẻ tấn công đã lợi dụng điểm yếu cấu trúc của kho mã NPM để tải lên hơn 100 gói đánh cắp thông tin xác thực kể từ tháng 8
- Phần lớn các gói đã được phát tán mà không bị phát hiện, với tổng số lượt tải tích lũy hơn 86.000 lần
- Công ty bảo mật Koi đặt tên cho vụ tấn công này là chiến dịch PhantomRaven và phân tích rằng một tính năng cụ thể của NPM đã bị lạm dụng
- Theo Koi, trong số 126 gói độc hại, khoảng 80 gói vẫn còn tồn tại trên NPM tại thời điểm bài viết được thực hiện
Cấu trúc dễ bị tổn thương của Remote Dynamic Dependencies (RDD)
- RDD là tính năng cho phép gói tải mã phụ thuộc một cách động từ website bên ngoài
- Thông thường, phụ thuộc được tải từ hạ tầng đáng tin cậy của NPM, nhưng RDD còn cho phép tải qua các kết nối không được mã hóa như HTTP
- Kẻ tấn công PhantomRaven đã dùng tính năng này để cấu hình việc tải mã từ URL độc hại, ví dụ:
http://packages.storeartifact.com/npm/unused-imports
- Những phụ thuộc này không hiển thị với nhà phát triển và trình quét bảo mật, và trong thông tin gói chỉ hiện là "0 Dependencies"
- Do tính năng cài đặt tự động của NPM, loại mã phụ thuộc "vô hình" này sẽ được tự động thực thi
Giới hạn trong khả năng phát hiện của công cụ bảo mật
- Oren Yomtov của Koi cho biết: “PhantomRaven là một ví dụ tinh vi về việc khai thác điểm mù của các công cụ bảo mật hiện có”
- RDD không bị phát hiện bởi các công cụ phân tích tĩnh
- Vì vậy, kẻ tấn công có thể vượt qua khâu kiểm chứng bảo mật để phát tán mã độc
Các yếu tố làm tăng rủi ro
- Koi giải thích rằng các phụ thuộc được tải qua RDD sẽ được tải mới từ máy chủ của kẻ tấn công mỗi lần cài đặt
- Do không có cache hay quản lý phiên bản, ngay cả cùng một gói thì tại mỗi thời điểm cài đặt đều có khả năng bị chèn mã độc khác nhau
- Cấu trúc tải động như vậy khiến việc xác minh tính toàn vẹn của gói trở nên khó khăn
Cấu trúc và bối cảnh của NPM
- NPM là trình quản lý gói cho JavaScript, do npm, Inc., công ty con của GitHub, quản lý
- Đây là trình quản lý gói mặc định của Node.js, gồm client dòng lệnh và npm registry
- Registry lưu trữ các gói công khai và gói riêng tư trả phí, có thể tìm kiếm qua website
- Vụ việc lần này được chỉ ra là một ví dụ cho thấy cấu trúc quản lý phụ thuộc tự động của NPM có thể bị lợi dụng để tấn công
Các đề cập khác
- Ở cuối bài viết có nhắc đến ý kiến cho rằng cần chặn việc thực thi JavaScript không cần thiết
- Tuy nhiên, vụ tấn công lần này được chỉ ra là trường hợp ngay cả mã JavaScript thiết yếu cũng bị lợi dụng
2 bình luận
Tôi đã thử tạo một script scanner thời gian thực.
Trong path của repository đáng ngờ,
hãy nhập
npx sha1-hulud-scanner.Mã nguồn: https://github.com/developerjhp/sha1-hulud-scanner
Ý kiến trên Hacker News
Dạo này tôi đặt alias để chạy lệnh
npmbên trong container DockerLàm vậy sẽ không làm lộ biến môi trường của tôi, không truy cập được các tệp ngoài thư mục hiện tại, và cũng không chạm tới các tệp cấu hình như
.bashrcTham khảo: Run tools inside Docker
npmvẫn tải về mã tùy ý để chạy ngay lập tứcThay vào đó tôi khuyên dùng
pnpm. Mặc định nó không chạy lifecycle script, và có thể chỉ định whitelist cho những script được phép chạyNếu thực sự muốn được bảo vệ, bạn phải sandbox không chỉ lúc cài đặt mà cả toàn bộ quá trình chạy
Chỉ chặn post-install như hiện tại thì mới là giải pháp nửa vời. Tấn công chuỗi cung ứng đang ngày càng nguy hiểm hơn
Nếu
neovimhoặcvscodebị nhiễm thì chỉ với quyền người dùng cũng đã đủ làm được rất nhiều chuyện nguy hiểmAlias đơn giản thì áp dụng được với
node/npm, nhưng khó dùng cho các chương trình khác. Vì còn phải mount các tài nguyên cần thiết vào containerTôi đã thắc mắc chuyện này từ lâu. Tại sao mọi người lại thản nhiên chạy
npmtrên hệ thống của mình như vậyTừ góc nhìn quen với build có thể tái lập như
make, việcnpmmỗi lần lại tải về thứ khác và cho ra kết quả khác thực sự gây sốcNgay cả việc tạo CSS cũng bị trói vào dependency npm nghe đã thấy kỳ quặc. Vì vậy tôi từng thử đóng băng (freeze) toàn bộ môi trường npm trong Docker, nhưng cuối cùng có cảm giác đây là một cuộc chiến không thể thắng
maven,nuget,pip,npmđều vậyNếu vẫn phụ thuộc vào package manager của distro như trước đây thì sẽ không thể có được hệ sinh thái phát triển nhanh như hiện nay
Dù vậy, các package manager mới với bảo mật tốt hơn đang xuất hiện. Chỉ trích công cụ mà không hiểu lý do tồn tại của nó là không đúng
npmbằng Docker, tôi muốn hỏi là sau mỗi lần cập nhật dependency bạn có xác minh lại môi trường đó khôngThực ra
npmvàpnpmvốn đã cố định dependency bằng lock file theo mặc địnhnpm install thing” quá dễ và quá rẻRất nhiều mã nguồn mở bị lấp đầy bởi code viết để làm đẹp CV hơn là vì chất lượng, rồi cuối cùng lại được dùng để tạo ra những thứ như tracker quảng cáo của tập đoàn lớn hay ứng dụng ví điện tử
npm installkhông chỉ tải package về mà còn thực thi mãCác hook preinstall, install, postinstall trong
package.jsonthực sự được chạyCó lý do chính đáng nào để quá trình cài đặt lại phải hợp pháp hóa việc chạy lệnh tùy ý không?
Báo cáo liên quan: PhantomRaven npm malware
Một trường hợp khác: blog của Socket.dev
Ví dụ, package kernel Linux sẽ chạy post-install script để tạo lại initramfs, cập nhật GRUB sau khi cài đặt
Phần lớn package DEB/RPM đều có loại script này. Tức là đây là vấn đề ở cấp độ thiết kế
npmthì ai cũng có thể đăng package lênDistro Linux có hệ thống maintainer đáng tin cậy, thậm chí tự xây dựng root of trust dựa trên PGP
Trong khi đó
npm,pip,rubygems,cargovề bản chất chỉ là phiên bản trau chuốt hơn của “curl | bash”Loại build hậu cài đặt như vậy từng là cần thiết để giảm gánh nặng bảo trì
Package.swiftNhưng tôi nghe nói nó được sandbox rất chặt nên khó bị lạm dụng
Tham khảo: tài liệu SwiftPM, PackageDescription
pnpm v10mặc định vô hiệu hóa toàn bộ lifecycle script và yêu cầu người dùng tự cho phépThảo luận liên quan
Nhìn vào các vụ tấn công
npmgần đây, tôi bắt đầu tự hỏi liệu phát triển bằngnpmcòn an toàn nữa khôngMỗi lần khởi tạo một dự án React là hàng trăm package được cài vào, mà tôi cũng chẳng biết chúng làm gì
Ở backend thì tôi chỉ cài rõ ràng những package mình cần, còn frontend thì giống như chiếc hộp Pandora của lỗ hổng bảo mật
npmlớn nhất nên lên tin nhiều hơn thôijjcủa Rust thì có 470 package, cònwan2gpcủa Python thì kéo theo 211 package. Chỗ nào cũng vậy cảGiống vụ
xz, mỗi dependency đều phụ thuộc vào một cá nhân ngẫu nhiên nào đó, và bạn phải tin rằng họ sẽ không dính social engineeringPyPIcũng không an toàn. Đã có trường hợp mã độc bị chèn vào package hợp pháp thông qua việc GitHub Actions bị hackMỗi lần phát triển với các framework như Angular hay Vue tôi đều thấy bất an
Nhìn vào hàng nghìn dependency trong
node_modulescó cảm giác như điềm báo của thảm họaChỉ cần một nhà phát triển mã nguồn mở bị phishing là mọi thứ có thể nhiễm ngay
Hệ sinh thái JavaScript về căn bản là đang hỏng. Chỉ một cú gõ sai là có thể dính tấn công chuỗi cung ứng
NuGet hay Maven cũng có thể gặp chuyện tương tự, nhưng bên đó có thư viện chuẩn lớn hơn nên dependency ít hơn và mang lại cảm giác kiểm soát được hơn
Không hoàn hảo, nhưng vẫn tốt hơn một bậc
Trong 86.000 lượt tải xuống đó, phần lớn có khả năng không phải người dùng thực mà là scanner tự động hoặc bot
Mỗi khi đăng phiên bản mới thì chỉ sau một hai ngày đã có hàng trăm lượt tải, nhưng có thể chẳng phải con người
Tức là số người dùng thực sự bị nhiễm có thể gần như không có
Cũng có nhiều vụ tấn công nhắm vào tên package do chatbot AI bịa ra bằng ảo giác. Không chỉ là thống kê đơn thuần
Xem thêm mô tả chi tiết về cuộc tấn công trong bài viết của BleepingComputer
Tôi tự hỏi liệu có cách nào phát hiện hoặc lọc ra các package dùng URL HTTP làm dependency trong lúc
npm installhay khôngVì payload có thể được gửi khác nhau cho từng bên yêu cầu nên scanner thông thường sẽ khó mà phát hiện
Với tư cách là một lập trình viên hobby, tôi đang nghĩ xem nên làm gì để phòng bị trước các cuộc tấn công chuỗi cung ứng kiểu này
Cứ làm theo các tutorial nổi tiếng và cài dependency theo là dần dần trở nên vô cảm với chuyện bảo mật
Tôi cũng chạy khá nhiều dịch vụ trong homelab của mình, nên lo rằng bot có thể chui vào lúc nào không hay. Nên bắt đầu từ đâu?
Không đảm bảo hoàn hảo, nhưng vẫn tốt hơn rất nhiều so với việc toàn bộ máy chủ bị xâm nhập
Tự sao chép phần mã cần thiết để dùng trực tiếp cũng là một cách học tốt và an toàn hơn
Với cấu trúc như vậy, có thể đảm bảo độ tin cậy ở cấp distro mà không cần hàng triệu người dùng tự mình kiểm chứng
Ví dụ: Hono, Zod
Gần đây tôi đã chuyển sang Bun, vì nó tích hợp sẵn những thứ như driver DB hay client S3 nên giảm được số lần phải tải thêm
Cấu trúc lấy dependency trong lifecycle hook lúc nào cũng có thể trở thành điểm bẻ lái cho tấn công
Hiện tại có thể là bình thường, nhưng sau này nếu chủ sở hữu bị hack hoặc đổi ý thì nó có thể biến thành mã độc
Kiểu install hook như vậy rốt cuộc là một thiết kế không bền vững