Các gói npm của Dịch vụ Đám mây Red Hat bị xâm phạm trong cuộc tấn công đầu độc chuỗi cung ứng

iconMetaEra
Chia sẻ
Share IconShare IconShare IconShare IconShare IconShare IconCopy
AI summary iconTóm tắt

expand icon
Một vụ vi phạm bảo mật đã được báo cáo trong một số gói npm thuộc tổ chức Red Hat Cloud Services, theo tin tức trên chuỗi từ MetaEra. Hệ thống MistEye đã phát hiện 96 phiên bản độc hại trên 32 gói, trong đó có ba gói được phân tích chi tiết. Mã độc trong các gói như @redhat-cloud-services/frontend-components-config@6.11.3 được thực thi trong quá trình cài đặt thông qua hook preinstall. Phần mềm độc hại, một biến thể của Shai-Hulud, bao gồm việc đánh cắp thông tin xác thực và khai thác CI/CD. Kẻ tấn công đã sử dụng các phép dịch ROT/Caesar, AES-GCM và B5 để ẩn payload, vốn lây lan qua npm và các workflow trên GitHub.

Bối cảnh

Gần đây, hệ thống giám sát bảo mật MistEye đã phát hiện thông tin về việc nhiều gói npm thuộc tổ chức Red Hat Cloud Services có các phiên bản bất thường. Sự kiện này liên quan đến 32 gói npm và 96 phiên bản thuộc tổ chức này. Bài viết này chọn ra 3 mẫu cục bộ để phân tích ngoại tuyến sâu hơn: các mẫu này không phải là các gói giả mạo không gian tên hoặc typo-squatting, mà là các phiên bản thật sử dụng scope @redhat-cloud-services; từ mã nguồn mẫu, có thể xác nhận rằng tarball của chúng đã bị cài đặt một trình tải độc hại đa lớp được kích hoạt tự động trong giai đoạn cài đặt.

Sau khi phục hồi đầy đủ, có thể xác nhận: ba mẫu này có khả năng cốt lõi bao gồm đọc bộ nhớ GitHub Actions Runner, thu thập thông tin xác thực đa đám mây và cục bộ, truyền dữ liệu ra ngoài qua GitHub API và dead-drop, tiêm vào workflow GitHub, tự lan truyền qua npm, duy trì tính bền bỉ thông qua Claude Code / VS Code / systemd / LaunchAgent, chống lại Harden-Runner / StepSecurity, và phát hiện EDR / các sản phẩm bảo mật. Về phạm vi ảnh hưởng tiềm tàng, các đối tượng có thể bị ảnh hưởng bao gồm máy chủ nhà phát triển, CI/CD Runner, container xây dựng, kho lưu trữ GitHub, workflow GitHub Actions, chuỗi phân phối npm và thông tin xác thực môi trường đám mây; phạm vi ảnh hưởng thực tế cần được xác nhận thêm thông qua nhật ký cài đặt, kiểm toán kho lưu trữ và dữ liệu giám sát từ nền tảng.

Từ cấu trúc mã, đường lan truyền và tổ hợp khả năng, phần mềm độc hại này là một biến thể của phần mềm độc hại Shai-Hulud.

MistEye phản hồi

MistEye là hệ thống giám sát bảo mật động và tình báo đe dọa Web3 do SlowMist tự phát triển, tích hợp khả năng giám sát bảo mật và tổng hợp tình báo, cung cấp cảnh báo rủi ro thời gian thực và bảo vệ tài sản cho người dùng.

Sau khi phát hiện sự việc đầu độc chuỗi cung ứng gói npm của Red Hat Cloud Services và các mẫu độc hại liên quan, hệ thống MistEye đã kích hoạt cảnh báo cấp cao và tiến hành phân tích hệ thống đối với cấu trúc làm rối, giải mã tải trọng, phục hồi khả năng và IOC của chuỗi tấn công.

(https://enterprise.misteye.io/threat-intelligence/SM-2026-378450)

Overview of the Attack Chain

Phần phân tích kỹ thuật trong bài viết này dựa trên phân tích tĩnh ngoại tuyến, giải nén, giải mã và xác minh làm rõ 3 mẫu npm tgz.

Các mẫu được kiểm tra trong đợt xác minh này bao gồm:

@redhat-cloud-services/frontend-components-config

Phiên bản: 6.11.3

tgz SHA-256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060

@redhat-cloud-services/types

Phiên bản: 3.6.1

tgz SHA-256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558

@redhat-cloud-services/rule-components

Phiên bản: 4.7.2

tgz SHA-256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f

Ba mẫu tấn công đều có cùng điểm xâm nhập: trong file package.json đều có scripts.preinstall = "node index.js". Điều này có nghĩa là bất kỳ khi nào máy chủ phát triển hoặc môi trường CI/CD cài đặt các phiên bản này, file index.js ở thư mục gốc sẽ được tự động thực thi trong giai đoạn cài đặt, mà không cần người dùng nhập khẩu hoặc chạy mã nghiệp vụ một cách rõ ràng.

Ba mẫu chia sẻ cùng một tải trọng độc hại cốt lõi, nhưng các tham số bao bọc bên ngoài khác nhau. Nói cách khác, ba mẫu sử dụng các giá trị dịch ROT/Caesar và key/iv/tag AES-GCM khác nhau; điều này khiến các đặc trưng tĩnh dựa trên hash bao bọc bên ngoài, key cố định hoặc dịch cố định khó có thể tái sử dụng trực tiếp giữa các mẫu. Tuy nhiên, trình khởi động môi trường chạy Bun sau khi giải mã và tải trọng độc hại cốt lõi có hash hoàn toàn giống nhau: một là mô-đun hỗ trợ khởi động dùng để chuẩn bị môi trường chạy Bun, còn một là tải trọng cốt lõi thực sự chứa các chức năng độc hại. Bài viết này gọi hai thành phần này lần lượt là "Trình khởi động môi trường chạy Bun (tên biến mã nguồn _b)" và "Tải trọng độc hại cốt lõi (tên biến mã nguồn _p)".

Chuỗi tấn công sau khi phục hồi như sau:

Technical Analysis

1. Đầu vào: Bị chiếm quyền kiểm soát script vòng đời npm

Cả ba mẫu đều kích hoạt chuỗi tấn công thông qua hook vòng đời preinstall trong package.json:

"scripts": {

"preinstall": "node index.js"

}

preinstall sẽ được tự động thực thi trong giai đoạn cài đặt npm. Đối với các thành phần frontend thông thường, định nghĩa kiểu hoặc gói thành phần quy tắc, thường không cần chạy một tệp JavaScript lớn ở thư mục gốc trong giai đoạn cài đặt; đây là tín hiệu bất thường trực tiếp nhất.

Bằng chứng cấp mẫu như sau:

@redhat-cloud-services/frontend-components-config@6.11.3

  • chính: lib/index.js
  • Trường files: ["/lib", "/bin"]
  • Tập tin gốc index.js SHA-256: 545a1838c66e1771f58d84a17b3e1841e5eeab91a73f4ccc59c9492450a6d9c0

@redhat-cloud-services/types@3.6.1

  • main: index.d.ts
  • Trường files: chưa được thiết lập
  • Tập tin index.js ở thư mục gốc có SHA-256: b86c5ae9e95bd841a595440faa3eb6317441e746f241ae8fd641ab59ed1d1966

@redhat-cloud-services/rule-components@4.7.2

  • main: index.js
  • Trường files: chưa được thiết lập
  • Tập tin index.js ở thư mục gốc, SHA-256: 1a30a9abe20bab121aaa75ed040565af14e6cdfb745609ee0e7b94a2d814fb9c

Trong đó, trường files của frontend-components-config@6.11.3 chỉ khai báo "/lib" và "/bin", nhưng trong thư mục gốc của tarball có thêm file index.js được gọi bởi preinstall. Ngoại lệ này chỉ đúng với mẫu này; types@3.6.1 và rule-components@4.7.2 không thiết lập trường files, do đó không khái quát hóa ngoại lệ này cho tất cả các mẫu.

2. Lớp đầu tiên: Mảng số + thay thế chữ cái ROT/Caesar

Ba tệp index.js ở thư mục gốc của ba mẫu đều là các tệp JavaScript một dòng cực lớn, có cấu trúc tương tự nhau, với phần chính là bộ bao bọc try { eval(...) } catch (...)

Bộ bao bọc đầu tiên chuyển đổi mảng số lớn thành chuỗi thông qua String.fromCharCode, sau đó thực hiện phép dịch ROT/Caesar trên các chữ cái tiếng Anh trong chuỗi, và cuối cùng truyền kết quả đã giải mã cho eval thực thi. Xử lý ngoại lệ chỉ hiển thị tiền tố wrapper: để giảm thiểu việc phơi bày lỗi rõ ràng khi cài đặt thất bại.

Giá trị dịch chuyển bên ngoài và Stage 2 hash của ba mẫu như sau:

frontend-components-config@6.11.3

kích thước index.js: 4.294.798 byte

ROT/Caesar shift: 10

Giai đoạn 2 SHA-256: b19c2fd48535c8c40aeb3e627ce92775f33ef9292611767bb1236c238e6f90cc

types@3.6.1

kích thước index.js: 4.135.588 byte

ROT/Caesar shift: 4

Giai đoạn 2 SHA-256: 9c0425aa6e6d7792ac38d24f3e7245f42fcaa553ddfeb6bd97677017f10c3b75

rule-components@4.7.2

index.js kích thước: 4.294.336 byte

ROT/Caesar shift: 11

Giai đoạn 2 SHA-256: d590bd375d95e4ac072b7ebc1fc4489bcaf5f20a939e92486267aa398bcf1e5d

3. Lớp thứ hai: Giải mã AES-128-GCM cho bộ hướng dẫn Bun và tải trọng chính

Mã Stage 2 sau khi giải mã ROT/Caesar được giải mã bằng AES-128-GCM (Advanced Encryption Standard - Galois/Counter Mode) thông qua Node.js crypto.createDecipheriv và thiết lập nhãn xác thực thông qua setAuthTag. Mục tiêu giải mã là hai thành phần tiếp theo—bộ khởi động môi trường chạy Bun và tải trọng độc hại chính.

Trong đó, trình khởi động môi trường Bun chịu trách nhiệm phát hiện, định vị hoặc chuẩn bị môi trường chạy Bun để các mã sau đó có thể được thực thi thông qua Bun; tải trọng độc hại chính là thành phần chính của chuỗi tấn công, bao gồm các khả năng độc hại chính như thu thập thông tin xác thực, lan truyền qua GitHub/npm, duy trì tính bền vững, chống lại các biện pháp phòng vệ và giải mã tài nguyên nhúng.

Ba mẫu khác nhau đã sử dụng các khóa AES-128-GCM, vector khởi đầu và nhãn xác thực khác nhau để mã hóa hai thành phần này, nhưng sau khi giải mã, SHA-256 của ba trình khởi động môi trường Bun đều là ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6, và SHA-256 của ba tải trọng độc hại chính đều là 0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35. Điều này cho thấy kẻ tấn công đã thay đổi các tham số bao bọc bên ngoài trong các gói npm khác nhau, nhưng tái sử dụng cùng một bộ thành phần độc hại chính.

Sau khi giải mã, Stage 2 sẽ ghi tải trọng độc hại chính vào /tmp, sau đó thực thi thông qua Bun và xóa tệp tạm thời. Logic thực tế được khôi phục từ ba mẫu như sau:

Do đó, mẫu tệp tạm thời có thể xác minh trong ba mẫu là:

/tmp/p.js

Bun runtime bootloader có kích thước 898 byte, ba mẫu hash hoàn toàn giống nhau:

ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6

Bun runtime bootstrapper chứa các logic như child_process.execSync, fs.existsSync, fs.mkdtempSync, fs.chmodSync, os.platform(), os.arch(), getBunPath() để định vị hoặc chuẩn bị môi trường chạy Bun. Nói cách khác, Stage 2 không đơn giản giả định hệ thống đã cài đặt Bun toàn cục; trong các đường dẫn không phải là môi trường chạy Bun, nó sẽ tải trước bootstrapper môi trường chạy Bun, sau đó gọi Bun thông qua getBunPath() để thực thi tải trọng độc hại chính.

4. Lớp thứ ba: bảng chuỗi obfuscator.io

Tải trọng độc hại được giải mã không phải là JavaScript dạng văn bản rõ ràng có thể đọc trực tiếp, mà tiếp tục được làm rối bởi phong cách obfuscator.io với bảng chuỗi. Lớp này tập trung nhiều chuỗi vào một mảng và khôi phục chúng thông qua chỉ số thời gian chạy và logic xoay vòng, khiến các chuyên gia phân tích không thể truy cập trực tiếp đến các API, đường dẫn và tên cấu hình quan trọng tiếp theo cho đến khi hoàn thành việc khôi phục bảng chuỗi.

5. Lớp thứ tư: B5 mã hóa chuỗi tùy chỉnh

Sau khi khôi phục bảng chuỗi từ obfuscator.io, vẫn còn một lớp mã hóa chuỗi tùy chỉnh B5 trong tải trọng độc hại chính. Các tham số đã được xác nhận như sau:

  • KDF: PBKDF2 (Password-Based Key Derivation Function 2)
  • Hàm băm: SHA-256
  • Số lần lặp lại: 200000
  • độ dài khóa: 32 byte
  • Số vòng giải mã: 3
  • mật khẩu:ba2c6ddb3672bdd6a611e6850b4f700b52aed3dab2f1b3d5f8c839d4a157a709
  • salt: 5b26508dc0f1075a7c0b4d8aa464487e

Kết quả sau khi giải mã như sau:

Trong đó, sau khi giải mã B5, có thể thấy nhiều chuỗi văn bản rõ ràng quan trọng. Cần lưu ý rằng một số chuỗi ban đầu nằm trong bảng chuỗi của obfuscator.io, chỉ sau khi hoàn thành cả hai bước “thay thế bảng chuỗi + giải mã B5” thì mới có thể grep trực tiếp:

6. Lớp nhúng bổ sung: AES-256-GCM + gzip

Tải trọng độc hại chính còn chứa các tài nguyên nhúng được mã hóa bằng AES-256-GCM và nén bằng gzip. Quy trình khôi phục sử dụng:

Các tài nguyên nhúng quan trọng đã được giải mã được chia thành ba loại theo chức năng:

Đọc bộ nhớ liên nền tảng:

Các tài nguyên này được sử dụng để đọc bộ nhớ của các tiến trình đang chạy. Khóa và token trong tệp tin thông thường có thể được phát hiện thông qua việc tìm kiếm tệp, nhưng CI/CD Runner hoặc các công cụ phát triển sẽ tạm lưu một số giá trị nhạy cảm vào bộ nhớ trong lúc chạy. Kẻ tấn công nhúng các script đọc bộ nhớ trên ba nền tảng Linux, Windows và macOS nhằm mục đích thu thập những secret tạm thời này từ bộ nhớ tiến trình trên các hệ điều hành khác nhau.

Cấu hình lưu trữ:

Các tài nguyên này được sử dụng để “đặt điểm kích hoạt backdoor”. Nói cách khác, ngay cả khi quá trình cài đặt npm ban đầu đã kết thúc, kẻ tấn công vẫn muốn mã độc được thực thi lại khi nhà phát triển mở dự án sau này, khởi động trình soạn thảo, tham gia phiên Claude Code, hoặc sau khi hệ thống đăng nhập lại. Do đó, các tài nguyên này nhắm vào cơ chế cấu hình cấp dự án và cơ chế khởi động tự động cấp người dùng: cấu hình cấp dự án ẩn hơn, trong khi dịch vụ cấp hệ thống phù hợp hơn để chạy lâu dài.

C2 và truyền bá:

Các tài nguyên nhúng này được sử dụng để điều khiển chuỗi và vận chuyển secrets của kho lưu trữ. Sau khi giải mã, YZ là trình giám sát tìm kiếm commit GitHub, sẽ tìm kiếm định dạng commit message firedalazer . theo chu kỳ, xác minh chữ ký rồi tải và thực thi nội dung Python từ xa; zZ sau khi giải mã là một mẫu workflow GitHub Actions có tên Run Copilot, sẽ ghi ${{ toJSON(secrets) }} vào file format-results.txt và tải lên dưới dạng artifact.前者 cung cấp chuỗi lấy/thực thi nhiệm vụ tiếp theo,后者 cung cấp mẫu vận chuyển secrets của repository thông qua artifact của GitHub Actions; việc tiêm workflow thực tế, chờ chạy và tải xuống artifact được thực hiện bởi logic API GitHub đi kèm trong tải trọng chính.

Phân tích năng lực tải trọng độc hại chính

Sau khi hoàn thành nhiều lớp giải nhiễu, mẫu cuối cùng giải phóng và thực thi tải trọng độc hại chính. Tất cả các phân tích sau đây đều tập trung vào module tải trọng độc hại chính, được tách thành năm giai đoạn: thu thập dữ liệu, truyền ra ngoài, lây lan, duy trì tính bền vững và chống đối.

1. Đọc bộ nhớ GitHub Actions Runner:

Mẫu bao gồm các script đọc bộ nhớ cho ba nền tảng Linux, Windows và macOS, có khả năng dump đa nền tảng. Trong đó, triển khai trên Linux thực hiện trích xuất bộ nhớ bằng cách đọc /proc//maps và /proc//mem của tiến trình mục tiêu:

Logic chủ động kích hoạt tải trọng độc hại nhắm vào Linux runner của GitHub Actions: khi GITHUB_ACTIONS === "true" và RUNNER_OS === "Linux", mã sẽ tìm kiếm tiến trình Runner.Worker và trích xuất bộ nhớ, sau đó trích xuất các bí mật bị che giấu theo định dạng "":{"value":"","isSecret":true}. Các đường dẫn thu thập chủ động được xác nhận trong ba mẫu đều tập trung vào Linux runner, nhưng các script cho cả ba nền tảng đều đã được nhúng sẵn.

2. Thu thập thông tin xác thực từ nhiều đám mây và cục bộ của nhà phát triển:

Tải trọng độc hại chính bao gồm mô-đun thu thập thông tin xác thực có hệ thống, bao gồm các nhà cung cấp đám mây, môi trường CI, cấu hình cục bộ của nhà phát triển, GitHub CLI, trình quản lý mật khẩu và tệp ví.

Mục tiêu thu thập thông tin xác thực từ nhà cung cấp đám mây:

Mô-đun AWS cũng bao gồm logic liên quan đến ECS/IMDS (Instance Metadata Service)/STS WebIdentity.

Việc thu thập thông tin xác thực cục bộ của nhà phát triển bao gồm các mục tiêu sau:

Logique quản lý mật khẩu được triển khai trong mã nguồn dưới dạng mảng runCommand(command, args), thay vì nối chuỗi shell.

Mô-đun thu thập thông tin xác thực này bao phủ nhiều mục tiêu rộng rãi từ nền tảng đám mây đến thiết bị cục bộ của nhà phát triển; dữ liệu nhạy cảm thu thập được được truyền ra ngoài thông qua các cơ chế sau.

3. GitHub API và dead-drop:

Tải trọng độc hại chính sử dụng GitHub API làm kênh truyền dữ liệu chính. Yêu cầu giả mạo User-Agent là python-requests/2.31.0, sau khi xác thực token với x-oauth-scopes (cần chứa repo, public_repo hoặc workflow) sẽ thực hiện thao tác truyền dữ liệu: tạo repository (description cố định là Miasma: The Spreading Blight), sau đó ghi dữ liệu bị đánh cắp đã được mã hóa base64 qua PUT /repos///contents/results/.

Ngoài ra, tải trọng đã triển khai cơ chế dead-drop dựa trên tìm kiếm commit trên GitHub, bằng cách tìm kiếm marker "thebeautifulmarchoftime" (hoặc "thebeautifulsnadsoftime") để nhận lệnh C2:

let result = await X9("thebeautifulmarchoftime ", xZ);

Tài nguyên nhúng YZ.bin là một công cụ theo dõi commit GitHub độc lập, quét định kỳ mỗi 3600 giây để tìm commit message theo định dạng firedalazer ., sau khi xác minh chữ ký thành công, tải về và thực thi nội dung Python từ xa. Điều này tạo thành một đường dẫn điều khiển phụ độc lập với kênh truyền thông chính.

Mã nguồn còn chứa một cấu hình sender HTTP POST nhắm đến các điểm cuối api.anthropic.com và v1/api. Trường noop trong cấu hình này được đặt thành true, nghĩa là nếu không bị thay đổi bởi bên ngoài, sender này sẽ không thực hiện yêu cầu mạng thực tế. Do đó, phân tích tĩnh chỉ có thể xác nhận sự tồn tại của cấu trúc mã, nhưng không chứng minh được hành vi truyền dữ liệu ra ngoài Anthropic API đang hoạt động.

4. Kho lưu trữ GitHub và nhiễm Workflow:

Tải trọng độc hại chính có thể thao tác các đối tượng git của kho lưu trữ thông qua API REST / GraphQL của GitHub:

Workflow độc hại được xây dựng với tên release, yêu cầu quyền id-token: write, sử dụng đường dẫn OIDC (OpenID Connect) để đổi lấy token phát hành npm. Biến môi trường và giao diện của đường dẫn OIDC là ACTIONS_ID_TOKEN_REQUEST_TOKEN, ACTIONS_ID_TOKEN_REQUEST_URL, với audience được thiết lập là npm:registry.npmjs.org. Ở cấp độ mã nguồn, có thể xác nhận payload có khả năng tiêm workflow vào kho lưu trữ GitHub và tận dụng OIDC / trusted publishing của npm để lấy quyền phát hành.

Ngoài cách tiêm workflow thông qua git refs như đã nêu trên, tải trọng còn nhúng một cơ chế vận chuyển bí mật tinh vi hơn: workflow GitHub Actions giả danh Run Copilot sẽ ghi ${{ toJSON(secrets) }} vào file format-results.txt và tải lên artifact. So với việc ghi trực tiếp secrets vào nội dung kho lưu trữ, cách này thiên về việc vận chuyển dữ liệu thông qua sản phẩm chạy của workflow, và các cuộc kiểm tra diff mã nguồn thông thường có thể không trực tiếp phát hiện được nội dung secrets đã được xuất ra.

5. Chạy quy trình Copilot thông qua artifact để di chuyển secrets:

Tài nguyên nhúng zZ.bin là một workflow GitHub Actions giả danh Copilot, ghi ${{ toJSON(secrets) }} vào format-results.txt và tải lên dưới dạng artifact.

Các hành vi API GitHub đi kèm bao gồm: tạo/cập nhật branch tạm thời → ghi blob workflow → chờ chạy workflow → tải xuống file zip artifact → đọc format-results.txt → xóa workflow run và branch tạm thời. Các từ khóa tìm kiếm liên quan bao gồm Run Copilot, VARIABLE_STORE, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml.

6. npm tự lan truyền:

Tải trọng độc hại chính có hai đường dẫn phát hành / lan truyền npm độc lập.

Đường dẫn token npm: Tải dữ liệu thông qua GET /-/npm/v1/tokens để liệt kê các token npm của người dùng hiện tại, lọc các token có bypass_2fa === true và có quyền ghi gói, sử dụng các token này để tự động hóa việc phát hành. bypass_2fa là trường metadata của token, không phải tham số trong body của lệnh publish.

Đường dẫn GitHub Actions OIDC: Đọc biến môi trường ACTIONS_ID_TOKEN_REQUEST_TOKEN và ACTIONS_ID_TOKEN_REQUEST_URL, yêu cầu OIDC token với audience là npm:registry.npmjs.org, trao đổi quyền đăng tải thông qua giao diện trao đổi OIDC token của npm.

Quy trình thao tác làm ô nhiễm tarball là giải nén → ghi tệp index.js độc hại → chỉnh sửa package.json:

Ở đây phân biệt hai loại điểm vào: ba mẫu tải lên cục bộ sử dụng preinstall: "node index.js" —— lúc này, môi trường cài đặt không cần cài đặt sẵn Bun, việc sử dụng Node.js làm điểm vào ban đầu ẩn hơn; khi tự lây lan gây ô nhiễm các gói khác thì ghi preinstall: "bun run index.js" và thêm phụ thuộc bun —— vì logic tải trọng độc hại chính sau đó phụ thuộc vào các API do runtime Bun cung cấp (như Bun.gunzipSync và Bun.file), trong các tình huống tự lây lan cần đảm bảo môi trường mục tiêu đã có Bun.

7. Cơ chế lưu trữ bền vững:

Tải trọng độc hại chính bao gồm bốn phương thức duy trì, bao phủ cả thư mục dự án và khởi động hệ thống.

Claude Code SessionStart hook: Nhúng tài nguyên S8.bin để ghi SessionStart hook vào .claude/settings.json, tự động thực thi node .claude/setup.mjs mỗi khi bắt đầu phiên Claude Code. Tải trọng độc hại cũng được ghi vào .claude/setup.mjs và .claude/index.js (đường dẫn được tạo bằng cách nối ".claude/" với M0, M0 = "index.js").

Nhiệm vụ folderOpen của VS Code: Nhúng tài nguyên EZ.bin để ghi nhiệm vụ folderOpen vào tệp .vscode/tasks.json, tự động thực hiện cùng một script khi mở thư mục dự án bị nhiễm. Đồng thời ghi vào .vscode/setup.mjs.

kitty-monitor (systemd / LaunchAgent): Nhúng tài nguyên RZ.bin để cài đặt dịch vụ duy trì, các tệp được phân bố tại /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service (Linux) và ~/Library/LaunchAgents/com.user.kitty-monitor.plist (macOS). Tải trọng độc hại tạo thư mục /tmp/kitty-, ghi YZ.bin (bộ giám sát commit GitHub) vào cat.py sau đó cài đặt thông qua RZ.bin.

gh-token-monitor (systemd / LaunchAgent): Nhúng tài nguyên jZ.bin để cài đặt dịch vụ giám sát token GitHub, các tệp được phân bố trong các thư mục /.local/bin/gh-token-monitor.sh và /.config/gh-token-monitor/ cùng các đường dẫn systemd / LaunchAgent tương ứng. Monitor này kiểm tra xem token GitHub có trả về mã trạng thái 40x hay không và liệu metadata của gói npm @cap-js/openapi@1.4.1 có bất thường hay không, khi kích hoạt sẽ thực hiện handler:

Điều này có nghĩa là khi monitor phát hiện GitHub API trả về mã trạng thái 40x, ví dụ như token bị thu hồi, hết hạn hoặc trạng thái quyền hạn bất thường, mã độc sẽ thực thi handler được truyền vào. Handler được khôi phục từ ba mẫu trong bài viết này là rm -rf ~/; rm -rf ~/Documents. Khi xử lý, không được thu hồi token trực tiếp trên máy chủ có thể vẫn đang chạy payload—thay vào đó, trước tiên phải cô lập máy chủ, xóa các mục duy trì và tiến trình đang chạy, sau đó đổi mới thông tin xác thực từ môi trường sạch.

8. Harden-Runner / StepSecurity đối đầu:

Tải trọng độc hại chính chứa logic phát hiện và phá hoại StepSecurity Harden-Runner, vượt qua các biện pháp bảo vệ CI/CD thông qua các bước sau:

  1. Kiểm tra xem socket Docker /var/run/docker.sock có khả dụng không;
  2. Liệt kê các container Docker, tìm kiếm các từ khóa harden-runner / stepsecurity trong tên hoặc hình ảnh;
  3. Kết thúc container phù hợp thông qua POST /containers//kill;
  4. Tạo container Alpine có quyền ưu tiên, ghi đè sudoers thành runner ALL=(ALL) NOPASSWD:ALL;
  5. Ghi các tên miền liên quan đến StepSecurity vào /etc/hosts với bản ghi phân giải không hợp lệ;
  6. Ghi đè /etc/resolv.conf với 8.8.8.8 và 1.1.1.1.

Logic kháng cự này cho thấy mẫu được điều chỉnh đặc biệt để nhắm vào môi trường CI/CD được StepSecurity bảo vệ.

9. EDR / Phát hiện sản phẩm bảo mật, đánh giá môi trường và tránh né:

Tải trọng độc hại chính phát hiện tên tiến trình và đường dẫn cài đặt của nhiều sản phẩm EDR (Endpoint Detection and Response) / bảo mật:

Tải trọng cũng bao gồm logic bỏ qua khu vực: phát hiện các biến môi trường LC_ALL, LC_MESSAGES, LANGUAGE, LANG, sau khi chuyển thành chữ thường, nếu bắt đầu bằng ru thì bỏ qua thực thi. Hỗ trợ nhận diện môi trường CI bao gồm GitHub Actions, GitLab CI, Travis CI, CircleCI, Jenkins, AWS CodeBuild, Buildkite, AppVeyor, Bitbucket, Drone, TeamCity, Cirrus CI, v.v. Các dấu trạng thái được sử dụng trong thời gian chạy bao gồm tmp.0987654321.lock, __IS_DAEMON (đánh dấu tiến trình con daemon tách rời), SKIP_DOMAIN (bỏ qua đường dẫn sender domain), /tmp/kitty-*, cat.py và /var/tmp/.gh_update_state.

Impact Analysis

Từ khả năng mã nguồn, tác động của ba mẫu này không giới hạn ở việc thực thi một lần trong giai đoạn cài đặt npm. Rủi ro thực tế của chúng có thể được chia thành bốn cấp độ:

Ở cấp độ máy chủ phát triển. Mẫu sẽ thu thập biến môi trường, .npmrc, .pypirc, khóa SSH, cấu hình Docker, .env, token CLI GitHub, dữ liệu trình quản lý mật khẩu và tệp ví, đồng thời duy trì khả năng kích hoạt tiếp theo thông qua Claude Code, VS Code, dịch vụ người dùng systemd hoặc macOS LaunchAgent.

Ở cấp độ CI/CD Runner. Mẫu sẽ nhận diện runner Linux của GitHub Actions, đọc bộ nhớ tiến trình Runner.Worker và trích xuất các bí mật đã che; đồng thời có logic đối phó với StepSecurity Harden-Runner, cố gắng phá hoại hoặc vượt qua các thành phần bảo vệ CI/CD.

Ở cấp độ tổ chức và kho lưu trữ GitHub. Mẫu có thể sử dụng GitHub API để tạo kho lưu trữ, ghi vào contents/results/, thao tác với git refs/blobs/trees/commits, tiêm workflow độc hại và vận chuyển secrets thông qua Run Copilot workflow + artifact.

Ở cấp độ lan truyền sinh thái npm. Có thể lọc các token npm có quyền viết package và bypass_2fa === true, hoặc tận dụng đường dẫn GitHub Actions OIDC / npm trusted publishing để đổi lấy quyền phát hành; sau đó tải về tarball mục tiêu, chèn loader độc hại, sửa đổi preinstall, thêm phụ thuộc Bun, nâng phiên bản patch và phát hành, từ đó tạo thành chuỗi tự lan truyền trên npm.

Summary

Bằng chứng mã nguồn từ ba mẫu cho thấy gói độc hại này không phải là kịch bản đánh cắp thông tin chỉ trong giai đoạn cài đặt, mà là sự kết hợp của một loader đa giai đoạn và một implant đầy đủ: lớp ngoài được ngẫu nhiên hóa theo gói, trình khởi động môi trường chạy Bun và tải trọng độc hại cốt lõi được giữ nhất quán; implant chính bao phủ nhiều khía cạnh như thu thập thông tin xác thực, trích xuất bí mật CI, lan truyền qua GitHub/npm, duy trì tính bền vững và chống lại các biện pháp phòng vệ.

Thiết kế lối vào ẩn giấu cao. Kẻ tấn công không chèn logic độc hại vào mã ứng dụng, mà gắn trình nạp bị làm rối vào các script vòng đời npm. Trình nạp này chủ yếu chịu trách nhiệm giải mã và thực thi tải trọng nhúng, khiến việc phát hiện khả năng thực sự trở nên khó khăn chỉ thông qua việc kiểm tra mã nguồn ứng dụng.

Chuỗi giải làm rõ nhiều lớp lồng nhau. Tải trọng độc hại được đóng gói qua năm lớp: mảng số nguyên + thay thế chữ cái ROT, mã hóa AES-128-GCM, làm rối bởi obfuscator.io, mã hóa chuỗi tự chế B5, và lớp nhúng AES-256-GCM + gzip. Khóa hoặc tham số cho mỗi lớp có thể thay đổi độc lập giữa các gói, khiến việc phát hiện hàng loạt dựa trên đặc điểm tĩnh trở nên khó khăn hơn.

Khả năng tấn công cấp tổ chức đầy đủ. Implant này có khả năng đọc bộ nhớ GitHub Actions Runner, thu thập thông tin xác thực trên nhiều nền tảng đám mây và tại chỗ, truyền dữ liệu ra ngoài qua GitHub API và dead-drop, lây nhiễm kho lưu trữ và workflow của GitHub, tự lan truyền qua npm, duy trì tính bền vững và chống lại các biện pháp phòng vệ. Từ cấu trúc mã nguồn, nó đã có các đường dẫn mã để kích hoạt lan rộng từ điểm cài đặt đơn lẻ đến các chuỗi kho lưu trữ, CI/CD và phát hành npm; phạm vi lan truyền thực tế vẫn cần được xác nhận thông qua nhật ký cài đặt, kiểm toán kho lưu trữ và dữ liệu giám sát từ nền tảng.

Từ bằng chứng mã nguồn có thể xác nhận: cả ba mẫu đều được kích hoạt tự động thông qua preinstall và giải mã thực thi cùng một implant chính. Tuy nhiên, không thể chứng minh chỉ dựa vào ba mẫu tgz này về cách thức đạt được quyền truy cập ban đầu trong sự kiện thực tế.

Khuyến nghị xử lý

  1. Kiểm tra và gỡ bỏ các phiên bản độc hại trong phụ thuộc dự án, lockfile, bộ nhớ đệm registry riêng và bộ nhớ đệm xây dựng.
  2. Kiểm tra xem trong nhật ký cài đặt có xuất hiện các mục preinstall, node index.js, bun run, /tmp/p*.js, tmp.0987654321.lock hay không.
  3. Đừng trực tiếp thu hồi token trên máy bị nhiễm vẫn có thể thực thi payload. Đề xuất cách ly máy bị nhiễm, làm sạch các tiến trình đang chạy và các mục duy trì, sau đó đổi token liên quan đến GitHub, npm, chứng chỉ đám mây, Kubernetes, Vault, SSH, registry Docker và trình quản lý mật khẩu từ môi trường sạch.
  4. Kiểm tra các nhánh, commit, workflow, artifact và kho lưu trữ mới nhất trên GitHub, tập trung vào các từ khóa như Run Copilot, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml, OIDC_PACKAGES.
  5. Kiểm tra xem thư mục dự án có được thêm mới hoặc chỉnh sửa không: .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json, .vscode/setup.mjs.
  6. Kiểm tra tính bền vững cấp người dùng: /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service, ~/Library/LaunchAgents/com.user.kitty-monitor.plist, các tệp liên quan đến gh-token-monitor.
  7. Kiểm tra lịch sử npm publish để xác minh xem có sự phát hành patch không được ủy quyền nào không; đồng thời kiểm toán metadata token npm, tập trung vào các token có thể bypass 2FA (Xác thực 2 yếu tố) và có quyền ghi package.
  8. Thực hiện kiểm toán tính toàn vẹn của các sản phẩm downstream được xây dựng trong môi trường bị ô nhiễm.

IOC

Tập tin độc hại

tên tệp: redhat-cloud-services-frontend-components-config-6.11.3.tgz MD5: 633ad8849a59e2bfb7a0fe589e816a07 SHA1: 675294612f455fe6a9acb195f0cbe3687d8e2e34 SHA256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060

tên tệp: redhat-cloud-services-types-3.6.1.tgz MD5: 9e6c5af01438b52c9a411686c1f1b8ff SHA1: 88d098c8d96e9ae17550e9798c3b62c420464b8c SHA256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558

tên tệp: redhat-cloud-services-rule-components-4.7.2.tgz MD5: f1ffdbf5e639899f26a6ebab2eec408d SHA1: f3c5c21274045ae02fef11e931de6dcf8462a067 SHA256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f

SHA256

ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6

0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35

Malicious dependency

npm:@redhat-cloud-services/topological-inventory-client@3.0.10

npm:@redhat-cloud-services/topological-inventory-client@3.0.11

npm:@redhat-cloud-services/topological-inventory-client@3.0.13

npm:@redhat-cloud-services/compliance-client@4.0.3

npm:@redhat-cloud-services/compliance-client@4.0.4

npm:@redhat-cloud-services/compliance-client@4.0.6

npm:@redhat-cloud-services/rbac-client@9.0.3

npm:@redhat-cloud-services/rbac-client@9.0.4

npm:@redhat-cloud-services/rbac-client@9.0.6

npm:@redhat-cloud-services/insights-client@4.0.4

npm:@redhat-cloud-services/insights-client@4.0.5

npm:@redhat-cloud-services/insights-client@4.0.7

npm:@redhat-cloud-services/frontend-components@7.7.2

npm:@redhat-cloud-services/frontend-components@7.7.3

npm:@redhat-cloud-services/frontend-components@7.7.5

npm:@redhat-cloud-services/frontend-components-utilities@7.4.1

npm:@redhat-cloud-services/frontend-components-utilities@7.4.2

npm:@redhat-cloud-services/frontend-components-utilities@7.4.4

npm:@redhat-cloud-services/remediations-client@4.0.4

npm:@redhat-cloud-services/remediations-client@4.0.5

npm:@redhat-cloud-services/remediations-client@4.0.7

npm:@redhat-cloud-services/frontend-components-notifications@6.9.2

npm:@redhat-cloud-services/frontend-components-notifications@6.9.3

npm:@redhat-cloud-services/frontend-components-notifications@6.9.5

npm:@redhat-cloud-services/patch-client@4.0.4

npm:@redhat-cloud-services/patch-client@4.0.5

npm:@redhat-cloud-services/patch-client@4.0.7

npm:@redhat-cloud-services/host-inventory-client@5.0.3

npm:@redhat-cloud-services/host-inventory-client@5.0.4

npm:@redhat-cloud-services/host-inventory-client@5.0.6

npm:@redhat-cloud-services/rule-components@4.7.2

npm:@redhat-cloud-services/rule-components@4.7.3

npm:@redhat-cloud-services/rule-components@4.7.5

npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.2

npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.4

npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.6

npm:@redhat-cloud-services/notifications-client@6.1.4

npm:@redhat-cloud-services/notifications-client@6.1.5

npm:@redhat-cloud-services/notifications-client@6.1.7

npm:@redhat-cloud-services/sources-client@3.0.10

npm:@redhat-cloud-services/sources-client@3.0.11

npm:@redhat-cloud-services/sources-client@3.0.13

npm:@redhat-cloud-services/integrations-client@6.0.4

npm:@redhat-cloud-services/integrations-client@6.0.5

npm:@redhat-cloud-services/integrations-client@6.0.7

npm:@redhat-cloud-services/frontend-components-config@6.11.3

npm:@redhat-cloud-services/frontend-components-config@6.11.4

npm:@redhat-cloud-services/frontend-components-config@6.11.6

npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.2

npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.3

npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.5

npm:@redhat-cloud-services/hcc-pf-mcp@0.6.1

npm:@redhat-cloud-services/hcc-pf-mcp@0.6.2

npm:@redhat-cloud-services/hcc-pf-mcp@0.6.4

npm:@redhat-cloud-services/frontend-components-remediations@4.9.2

npm:@redhat-cloud-services/frontend-components-remediations@4.9.3

npm:@redhat-cloud-services/frontend-components-remediations@4.9.5

npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.1

npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.2

npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.4

npm:@redhat-cloud-services/javascript-clients-shared@2.0.8

npm:@redhat-cloud-services/javascript-clients-shared@2.0.9

npm:@redhat-cloud-services/javascript-clients-shared@2.0.11

npm:@redhat-cloud-services/quickstarts-client@4.0.11

npm:@redhat-cloud-services/quickstarts-client@4.0.12

npm:@redhat-cloud-services/quickstarts-client@4.0.14

npm:@redhat-cloud-services/config-manager-client@5.0.4

npm:@redhat-cloud-services/config-manager-client@5.0.5

npm:@redhat-cloud-services/config-manager-client@5.0.7

npm:@redhat-cloud-services/hcc-feo-mcp@0.3.1

npm:@redhat-cloud-services/hcc-feo-mcp@0.3.2

npm:@redhat-cloud-services/hcc-feo-mcp@0.3.4

npm:@redhat-cloud-services/entitlements-client@4.0.11

npm:@redhat-cloud-services/entitlements-client@4.0.12

npm:@redhat-cloud-services/entitlements-client@4.0.14

npm:@redhat-cloud-services/tsc-transform-imports@1.2.2

npm:@redhat-cloud-services/tsc-transform-imports@1.2.4

npm:@redhat-cloud-services/tsc-transform-imports@1.2.6

npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.1

npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.2

npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.4

npm:@redhat-cloud-services/frontend-components-testing@1.2.1

npm:@redhat-cloud-services/frontend-components-testing@1.2.2

npm:@redhat-cloud-services/frontend-components-testing@1.2.4

npm:@redhat-cloud-services/types@3.6.1

npm:@redhat-cloud-services/types@3.6.2

npm:@redhat-cloud-services/types@3.6.4

npm:@redhat-cloud-services/chrome@2.3.1

npm:@redhat-cloud-services/chrome@2.3.2

npm:@redhat-cloud-services/chrome@2.3.4

npm:@redhat-cloud-services/frontend-components-translations@4.4.1

npm:@redhat-cloud-services/frontend-components-translations@4.4.2

npm:@redhat-cloud-services/frontend-components-translations@4.4.4

npm:@redhat-cloud-services/vulnerabilities-client@2.1.8

npm:@redhat-cloud-services/vulnerabilities-client@2.1.9

npm:@redhat-cloud-services/vulnerabilities-client@2.1.11

Tuyên bố miễn trừ trách nhiệm: Thông tin trên trang này có thể được lấy từ bên thứ ba và không nhất thiết phản ánh quan điểm hoặc ý kiến của KuCoin. Nội dung này chỉ được cung cấp cho mục đích thông tin chung, không có bất kỳ đại diện hay bảo đảm nào dưới bất kỳ hình thức nào và cũng không được hiểu là lời khuyên tài chính hay đầu tư. KuCoin sẽ không chịu trách nhiệm về bất kỳ sai sót hoặc thiếu sót nào hoặc về bất kỳ kết quả nào phát sinh từ việc sử dụng thông tin này. Việc đầu tư vào tài sản kỹ thuật số có thể tiềm ẩn nhiều rủi ro. Vui lòng đánh giá cẩn thận rủi ro của sản phẩm và khả năng chấp nhận rủi ro của bạn dựa trên hoàn cảnh tài chính của chính bạn. Để biết thêm thông tin, vui lòng tham khảo Điều khoản sử dụngTiết lộ rủi ro của chúng tôi.