1 điểm bởi GN⁺ 4 giờ trước | Chưa có bình luận nào. | Chia sẻ qua WhatsApp
  • Sau khi đề nghị tuyển dụng vị trí kỹ sư phần mềm trên LinkedIn, kẻ tấn công đã gửi một kho GitHub riêng tư được ngụy trang thành bài tập React/Web3 hợp lệ; khi chạy, mã độc JavaScript ẩn trong tailwind.config.js sẽ hoạt động trên máy tính của lập trình viên
  • Tệp cấu hình 30.987 byte đã giấu 27KB mã bị làm rối sau hàng nghìn ký tự khoảng trắng; nó nhận payload giai đoạn 2 được mã hóa bằng AES-256-CBC từ máy chủ từ xa, lưu vào %TEMP%\pack rồi chạy bằng node pack
  • Kết quả quan sát khoảng 10 phút trong một VM cách ly Windows 11 ARM cho thấy payload kích hoạt bốn thành phần: backdoor điều khiển từ xa, trình đánh cắp trình duyệt/ví, bộ quét tệp đệ quy và trình giám sát clipboard
  • Thông qua Socket.IO, nó điều khiển terminal, SSH, màn hình, bàn phím và chuột; thu thập cơ sở dữ liệu Chromium, kho lưu trữ tiện ích ví, khóa SSH, mã nguồn, tệp cấu hình, v.v.; đồng thời ghi nhận 2.588 yêu cầu ở cổng tải tệp lên
  • Các kho bài tập do người lạ gửi nên được xem là mã không đáng tin cậy và cần kiểm tra trong VM hoặc container dùng một lần, không có hồ sơ trình duyệt thật, khóa SSH, thông tin xác thực đám mây hay ví; nếu đã bị nhiễm, cần ngắt mạng, bảo toàn bằng chứng rồi thay cả các thông tin bí mật

Kho lưu trữ ngụy trang thành bài tập tuyển dụng Web3 hợp lệ

  • Người dùng LinkedIn Wayan Adrian đề nghị vị trí kỹ sư phần mềm tại shrapnel.com và gửi kho GitHub riêng tư tech-active-workplace-frontend-main của tài khoản yevhen-o làm bài tập
  • Nền tảng chiến dịch NFT tên BLAIEXS nhìn bề ngoài là một dự án React/Web3 bình thường
    • Frontend React cung cấp thương hiệu, bảng điều khiển quản trị, quản lý chiến dịch, luồng tạo NFT, v.v.
    • Express API xử lý xác thực, dữ liệu dashboard, kiểm tra KYB, tạo/claim NFT, tải tệp lên và một số endpoint stub
    • Script seed tạo các tài khoản demo superadmin, thương hiệu và người tiêu dùng, chiến dịch Demo NFT Drop, cùng NFT Demo Collectible có số lượng cung ứng 100
  • Phạm vi bài tập thực tế chỉ là một tính năng hiển thị mạng MetaMask đơn giản
    • Triển khai getChainId() bất đồng bộ trong src/utils/ethereum.js để gọi eth_chainId và trả về giá trị thập lục phân đã parse hoặc null
    • Triển khai getNetworkLabel(chainId) trong cùng tệp để tìm tên mạng dễ đọc từ đối tượng NETWORKS hiện có
    • Sửa src/components/Wallet/ConnectWalletButton.js để gọi hai hàm này sau khi kết nối ví
  • Sau khi hoàn tất triển khai và chạy máy chủ phát triển, nó không khởi động trong một thời gian dài; người dùng phát hiện bất thường và rút cáp Internet

Mã thực thi ẩn trong tailwind.config.js

  • Trong ls -la, tailwind.config.js có kích thước 30.987 byte, nhưng trong trình soạn thảo chỉ thấy 97 dòng; wc -c cũng xác nhận cùng kích thước
  • Gần dòng 95, một khối JavaScript lớn khó đọc được giấu sau hàng nghìn ký tự khoảng trắng
  • Mã sử dụng các kỹ thuật làm rối JavaScript phổ biến
    1. Lưu các chuỗi quan trọng trong một mảng lớn
    2. Xoay mảng cho đến khi checksum khớp
    3. Che giấu việc truy cập chuỗi phía sau hàm decoder
    4. Thay tên rõ nghĩa bằng chỉ mục số và lời gọi wrapper
  • Một trong hai decoder khôi phục chuỗi ở dạng Base64, decoder còn lại áp dụng khóa theo từng chuỗi và mật mã dòng tương tự RC4; mảng chuỗi được xoay trước khi chỉ mục decoder khớp
  • Có thể gỡ rối mà không cần chạy mã độc theo trình tự sau
    1. Trích xuất mảng chuỗi
    2. Tái hiện việc xoay mảng để đạt checksum dự kiến
    3. Triển khai lại hàm decoder
    4. Thay các lời gọi như b(0x214), c(0x2f1, "key") bằng chuỗi thực
    5. Đơn giản hóa các đối tượng wrapper và hàm trợ giúp để làm lộ ý đồ thực thi

Hoạt động của dropper giai đoạn 1

  • Mã sau khi gỡ rối nạp child_process, os, fs, path, crypto và cài axios cùng socket.io-client vào thư mục tạm
  • Các trình xử lý uncaughtExceptionunhandledRejection ở cấp tiến trình được cấu hình để bỏ qua lỗi
  • Luồng thực thi payload từ xa như sau
    • UID là 59e605dd78fb2aafccd1b622f06a00ca
    • Lấy dữ liệu từ http://45.146.252.17/api/service/59e605dd78fb2aafccd1b622f06a00ca
    • Đưa UID và chuỗi salt vào crypto.scryptSync để dẫn xuất khóa 32 byte
    • Tách phản hồi theo định dạng base64_iv:base64_ciphertext và giải mã bằng aes-256-cbc
    • Ghi plaintext vào tệp pack trong thư mục tạm
    • Chạy bằng child_process.execSync("node pack", { windowsHide: true, cwd: os.tmpdir() })
  • Đây là malware dropper tải xuống và chạy phần mềm độc hại khác thay vì tự thực hiện chức năng
  • Mã tải xuống không có xác minh chữ ký, danh sách cho phép hash, cố định nguồn, giới hạn đường dẫn hay guard chống thực thi, nên endpoint từ xa có thể chạy mã với quyền của tài khoản hệ điều hành đã nạp cấu hình Tailwind

Phân tích động thực hiện trong VM cách ly

  • Để không làm lộ hệ thống host, một VM Windows 11 ARM dùng một lần được cấu hình bằng UTM
    • Bộ nhớ 4096 MiB
    • Ổ đĩa 64 GiB
    • Kết nối mạng shared/NAT
    • Tắt thư mục chia sẻ
  • Các công cụ được cài đặt để thu thập hành vi mã độc từ nhiều góc độ
    • Wireshark: thu thập gói tin và lưu lượng C2/rò rỉ dữ liệu
    • Sysinternals Sysmon: telemetry sự kiện Windows bền vững
    • Procmon: thu thập hoạt động tiến trình, registry và hệ thống tệp khi đang chạy
  • Để xác định mục tiêu thu thập của mã độc, dữ liệu mồi nhử được đặt sẵn
    • Cặp khóa SSH
    • Kho GitHub riêng tư
    • Ví tiền mã hóa
    • Dữ liệu trình duyệt
    • Các tệp khác mà trình đánh cắp thông tin có thể nhắm đến
  • Chạy yarn start trong VM, quan sát khoảng 10 phút, rồi thu được run1-full.pcapng, run1-sysmon.evtx, stage2-pack.bin

Luồng lây nhiễm được xác nhận trên mạng

  • Các yêu cầu HTTP tới 45.146.252.17 được phân chia vai trò theo cổng
    • Cổng 80: lấy payload giai đoạn 1, đăng ký host, gửi log
    • Cổng 7641: backdoor điều khiển và ra lệnh qua Socket.IO
    • Cổng 7646: 2.588 lượt tải tệp lên
    • Cổng 7649: 3 lượt tải dữ liệu trình duyệt lớn hơn nhưng số lượng ít hơn
  • Yêu cầu đầu tiên là GET /api/service/59e605dd78fb2aafccd1b622f06a00ca, và phản hồi có dạng base64_iv:base64_ciphertext với Content-Length: 150897
  • tailwind.config.js giải mã phản hồi bằng AES-256-CBC, ghi plaintext vào %TEMP%\pack, rồi chạy bằng node pack
  • Đặc điểm của payload giai đoạn 2 thu được như sau
    • SHA-256: 68a64d8c015c06fd70bcb8c5878c1e430da827dd00b62f8e6ef69e76bb94de5b
    • Kích thước: 113136 byte
    • Định dạng: JavaScript ASCII một dòng
  • pack sau khi giải mã cũng bị làm rối lại, nhưng dùng kỹ thuật giống giai đoạn đầu nên có thể gỡ rối bằng cùng quy trình

Payload giai đoạn 2 gồm bốn chương trình

  • pack không phải là một script đơn lẻ mà là một cây tiến trình nhỏ chạy bốn chương trình sau
    1. Ghi và chạy backdoor điều khiển–ra lệnh scdata trong thư mục tạm
    2. Ghi và chạy trình đánh cắp trình duyệt–ví ldata trong thư mục tạm
    3. Chạy trực tiếp trình quét tệp đệ quy trong bộ nhớ bằng node -e
    4. Chạy trực tiếp trình giám sát clipboard trong bộ nhớ bằng node -e
  • Cấu hình chính gồm UID 59e605dd78fb2aafccd1b622f06a00ca, khóa người dùng 308, host 45.146.252.17, cổng Socket.IO 7641, cổng khóa 7648, cổng tải lên trình duyệt 7649, cổng tải lên tệp 7646

scdata: backdoor điều khiển từ xa tương tác

  • scdata được ghi thành tệp trong %TEMP%, sau đó chạy bằng npm i axios socket.io-client ... && node scdata, và tồn tại như một tiến trình con chạy lâu dài
  • Sau khi chạy, nó tự cấu hình để trông như một tiến trình bình thường
  • Nó cũng cài đặt thêm các package cần cho chức năng điều khiển từ xa
    • socket.io-client, ssh2, node-pty: chức năng giống terminal và SSH
    • sharp, screenshot-desktop, clipboardy, @nut-tree-fork/nut-js: chụp màn hình, clipboard, di chuyển·nhấp·cuộn chuột, nhập bàn phím
  • Các sự kiện Socket.IO trực tiếp cho thấy phạm vi điều khiển từ xa
    • Terminal: start-terminal, terminal-input, terminal-resize, stop-terminal, command
    • Xác nhận host và chụp: whour, capture
    • Điều khiển đầu vào: mouseMove, mouseClick, mouseScroll, keyTap, keyCombo
    • Clipboard: copyText, pasteText
    • SSH và kết thúc: start_ssh, ssh_input, kill
  • Trong PCAP, đã xác nhận polling trên cổng 7641, bắt tay WebSocket và sự kiện máy chủ đầu tiên whour; trong Sysmon lần lượt ghi nhận node.exe scdata, PowerShell truy vấn thông tin hệ thống và việc cài đặt hai nhóm package npm
  • Vượt ra ngoài đánh cắp thông tin đơn thuần, nó còn cung cấp cho kẻ tấn công cả shell và chức năng điều khiển desktop

ldata: trình đánh cắp dữ liệu trình duyệt và ví

  • ldata được ghi vào %TEMP% và chạy bằng npm i axios && node ldata, tiêu đề tiến trình là npm-cache
  • Nó thu thập hồ sơ trình duyệt và kho lưu trữ extension ví rồi gửi đến http://45.146.252.17:7649/upload, đồng thời kiểm tra trạng thái LevelDB tại /cldbs
  • Trình duyệt mục tiêu được cấu hình rộng theo từng hệ điều hành
    • Windows: Chrome, Edge, Brave, LT Browser
    • macOS: Chrome, Brave, Opera, LT Browser, Edge và keychain đăng nhập cục bộ
    • Linux: các thư mục hồ sơ Chromium tương ứng
  • Từ thư mục Default hoặc Profile*, nó tải lên các cơ sở dữ liệu Chromium sau
    • Login Data
    • Login Data For Account
    • Web Data
  • Sau đó nó duyệt Local Extension Settings/<extension-id>; trong các ID extension ví được hard-code cũng có nkbihfbeogaeaoehlefnkodbefgpgknn của MetaMask
  • Với 8 đường dẫn extension ví đầu tiên, nó sao chép thư mục LevelDB vào thư mục tạm rồi tải lên từng tệp, và quyết định hoàn tất hay thử lại dựa trên phản hồi cldbs từ máy chủ
  • Ba lượt tải lên được xác nhận trên cổng 7649 là các cơ sở dữ liệu sau
    • Login_Data.sqlite: 51.200 byte
    • Login_Data_For_Account.sqlite: 51.200 byte
    • Web_Data.sqlite: 262.144 byte
  • Dữ liệu thử nghiệm không có mật khẩu đã lưu hay dòng thẻ, nhưng có 6 giá trị tự động điền và metadata trình duyệt
  • Các trình duyệt họ Chrome mã hóa cục bộ một số trường, nên chỉ với cơ sở dữ liệu không phải lúc nào cũng khôi phục được bí mật dạng rõ
    • Tuy nhiên, khi kết hợp với bí mật hệ điều hành, cookie, kho extension và trình duyệt đang mở khóa, nó trở thành một phần của pipeline đánh cắp thông tin xác thực
  • Sau khi tải lên dữ liệu trình duyệt và LevelDB cần thiết, hoặc khi máy chủ đánh dấu hoàn tất, nó kết thúc và không chờ lệnh riêng từ người vận hành

Trình quét tệp đệ quy và trình giám sát clipboard

  • Trình quét tệp đệ quy không tạo tệp riêng mà chạy bằng node -e, bắt đầu quét từ thư mục home của người dùng
    • Trên Windows, nó liệt kê ký tự ổ đĩa bằng Get-CimInstance Win32_LogicalDisk và cũng kiểm tra thư mục gốc của từng ổ
    • Các mẫu tệp thu thập gồm *.env*, *.md, *.pem, *.ini, *.secret, *.json, *.js, *.ts, *.csv, *.txt, *.doc, *.docx, *.pdf, *.xlsx, .zsh_history, .bash_history
    • ~/.ssh, ~/.aws, ~/.azure, ~/.config, ~/.foundry tự động được coi là các thư mục đáng quan tâm
    • Nó cũng tìm các tên như metamask, bitcoin, btc, solana, secret phrase, private key
    • Kết quả được gửi đến http://45.146.252.17:7646/upload
  • Trong môi trường mồi nhử, các tệp như id_ed25519, id_ed25519.pub, History.txt, seed.js, password.js, tokens.js, ConnectWalletButton.js, ExportWallet.js, RegisterWallet.js, tailwind.config.js, aptos-cli.json đã thực sự được tải lên
  • Nếu ldata chuyên trách trình duyệt và kho ví, thì trình quét tệp thu thập trên diện rộng khóa SSH, cấu hình, mã nguồn, bí mật cục bộ, lịch sử shell và tệp dự án
  • Trình giám sát clipboard cũng chạy bằng node -e, tiêu đề tiến trình là npm-compiler.log
    • Sau khi đợi vài giây, nó lặp lại việc đọc clipboard
    • Trên macOS dùng pbpaste, trên Windows dùng powershell -NoProfile -NonInteractive Get-Clipboard
    • Giá trị đã thay đổi được gửi đến http://45.146.252.17/api/service/makelog
  • Ngay cả khi không phân tích định dạng, nó vẫn có thể bắt nguyên văn mật khẩu, cụm từ khôi phục, khóa riêng tư, token API, mã dùng một lần, URL GitHub, địa chỉ ví và bí mật triển khai mà người dùng sao chép

Nguyên tắc cần tuân thủ trước khi chạy bài tập tuyển dụng

  • Kho bài tập do người lạ gửi phải được xem là mã thực thi không đáng tin cậy cho đến khi độ an toàn được xác minh
  • Trước yarn install, npm install, yarn build, yarn start, cần rà soát các mục sau
    • package.json
    • Script vòng đời
    • Tệp cấu hình
    • Các hook phụ thuộc rõ ràng
  • Mã độc trong trường hợp này ẩn trong tailwind.config.js, nơi mọi người dễ bỏ qua; tệp cấu hình, dependency và công cụ build đều có thể được thực thi như mã
  • Dự án phỏng vấn nên được chạy trong VM hoặc container dùng một lần không mount bí mật thật
    • Hồ sơ trình duyệt cá nhân
    • Trình quản lý mật khẩu
    • Khóa SSH
    • Ví tiền mã hóa
    • Token GitHub
    • Thông tin xác thực cloud
    • Phiên ngân hàng
    • Tài khoản email chính
  • Với bài tập cần tài khoản hoặc ví, hãy dùng danh tính thử nghiệm mới, không có tiền và không tái sử dụng ở dịch vụ khác
  • Nếu là bài tập Web3, chỉ dùng testnet, và không kết nối ví thật với dự án không rõ nguồn gốc dù trông có vẻ vô hại

Các chỉ dấu kiểm tra tình trạng lây nhiễm

  • Trên macOS và Linux, hãy ưu tiên kiểm tra các mục sau
    • Các tiến trình đang chạy liên quan đến node, pack, scdata, ldata, npm-compiler, vhost.ctl
    • Kết nối tới 45.146.252.17 hoặc các cổng 7641, 7646, 7649
    • pack, scdata, ldata, vhost.ctl trong thư mục tạm, Downloads, Desktop, Documents, Library
    • Tệp đánh dấu */.npm/vhost.ctl
    • Các chuỗi IP, UID, /api/service/makelog, node scdata, node ldata, node pack trong dự án đã tải xuống
  • Trên Windows, hãy kiểm tra các mục sau
    • Trong các tiến trình node, npm, cmd, powershell, những mục có dòng lệnh chứa pack, scdata, ldata, node -e, địa chỉ IP, Get-Clipboard
    • Kết nối TCP đang mở tới 45.146.252.17 hoặc các cổng từ xa 7641, 7646, 7649
    • pack, scdata, ldata, vhost.ctl, .npm\vhost.ctl dưới %TEMP%
    • Các chuỗi C2 đã biết trong thư mục đã clone kho lưu trữ phỏng vấn
  • Nếu phát hiện dù chỉ một trong các dấu hiệu: tiến trình Node còn đang chạy, kết nối tới IP đó, hoặc các hiện vật pack·scdata·ldata, thì phải coi hệ thống đã bị lộ
  • Các chỉ dấu này là bước kiểm tra ban đầu dành riêng cho mẫu đã phân tích, không phải quy trình pháp chứng hoàn chỉnh

Dọn dẹp hệ thống bị lây nhiễm và thay thế bí mật

  • Trước hết, hãy ngắt máy tính khỏi mạng và không tiếp tục dò tìm, gỡ lỗi hoặc sao chép bí mật mới trong môi trường bị nhiễm
  • Nếu cần bằng chứng, hãy lưu giữ các dữ liệu sau trước khi xóa
    • Danh sách tiến trình
    • Kết nối mạng
    • Tệp đáng ngờ
    • Lịch sử trình duyệt
    • Kho lưu trữ độc hại
  • Sau đó, kết thúc các tiến trình liên quan đến node pack, node scdata, node ldata, node -e, npm-compiler, vhost.ctl và xóa pack, scdata, ldata, .npm/vhost.ctl trong thư mục tạm
  • Nếu đó là VM dùng một lần và không cần giữ lại công việc Node hợp lệ, có thể dùng pkill node trên macOS·Linux hoặc buộc kết thúc toàn bộ tiến trình node trên Windows
  • Xóa kho lưu trữ độc hại và node_modules, nhưng nếu cần phân tích thêm thì lưu một bản ZIP ngoại tuyến
  • Chỉ xóa tệp là chưa đủ; cần thay thế hoặc hủy bỏ các thông tin bí mật sau
    • Khóa SSH
    • Token GitHub·npm
    • Khóa đám mây và API key
    • Bí mật triển khai
    • Mật khẩu đã lưu trong trình duyệt
    • Phiên đăng nhập đang hoạt động
  • Nếu seed ví hoặc khóa riêng có khả năng đã chạm tới hệ thống bị nhiễm, hãy tạo ví mới trên thiết bị sạch và chuyển tiền sang đó

Tấn công khai thác ranh giới tin cậy của công cụ phát triển

  • Các sản phẩm antivirus truyền thống không phát hiện kho lưu trữ này, và AI coding agent phổ biến được dùng để giải bài tập cũng không nhận diện được mã độc ẩn trong dự án
  • Vì Tailwind đánh giá tệp cấu hình JavaScript như một module Node, nên IIFE ở dòng 95 sẽ chạy ngay khi công cụ phát triển, script build, tích hợp editor, Tailwind CLI, bundler hoặc tác vụ CI nạp cấu hình
  • Cấu hình Tailwind hợp lệ chỉ kéo dài đến dòng 94, sau đó có thêm khoảng 27KB mã bị làm rối
  • Payload được tải xuống chạy với cùng quyền hệ điều hành như người dùng đã nạp cấu hình
    • Có thể truy cập tệp cục bộ, hồ sơ trình duyệt, thông tin xác thực đã lưu, dữ liệu extension ví, khóa SSH, biến môi trường, token gói, thông tin xác thực đám mây, mã nguồn, clipboard
    • Nếu chạy trong CI, bí mật triển khai, artifact build, thông tin xác thực registry và token truy cập production cũng có thể bị lộ
  • Cách khắc phục cần thiết là loại bỏ hoàn toàn blob JavaScript bị làm rối khỏi tailwind.config.js

Chưa có bình luận nào.

Chưa có bình luận nào.