[RE027] Nhóm APT Mustang Panda có thể vẫn đang tiếp tục hoạt động tấn công vào các tổ chức tại Việt Nam

Calendar 12/12/2023
Calendar 9:34 Chiều

1. Giới thiệu

Tại VinCSS, chúng tôi liên tục chủ động theo dõi tình hình an ninh mạng, săn tìm các mẫu mã độc và đánh giá mức độ nguy hiểm của chúng, đặc biệt là các mẫu mã độc nhắm tới Việt Nam. Gần đây, trong quá trình thực hiện hunting trên nền tảng của VirusTotal, thực hiện tìm kiếm các mẫu byte đặc trưng liên quan tới nhóm Mustang Panda (PlugX), chúng tôi đã phát hiện một loạt mẫu mã độc mà chúng tôi nghi ngờ là của nhóm này được tải lên từ Việt Nam.

Tất cả các mẫu này đều có chung tên là “log.dll” và có tỉ lệ phát hiện khá thấp.

Dựa vào thông tin trên, chúng tôi cho rằng có khả năng mã độc đã được cài cắm vào một vài đơn vị ở Việt Nam, do đó chúng tôi quyết định phân tích các mẫu mã độc này. Trong quá trình phân tích, dựa vào các dấu hiệu tìm được, chúng tôi tiếp tục hunting các dữ kiện còn thiếu để bổ sung bức tranh đầy đủ hơn cho quá trình phân tích.

Để tiện hình dung, chúng tôi vẽ lại luồng thực thi của mã độc như sau:

Bài phân tích này của chúng tôi bao gồm:

  • Phân tích kỹ thuật của file log.dll.
  • Phân tích kỹ thuật của shellcode được giải mã từ log.dat.
  • Phân tích PlugX Dll cũng như giải mã thông tin cấu hình của PlugX.

2. Phân tích log.dll

Trong danh sách các mẫu hunt được ở trên, chúng tôi lựa chọn mẫu có hash: 3171285c4a846368937968bf53bc48ae5c980fe32b0de10cf0226b9122576f4e

Sample này được submit lên VirusTotal từ Việt Nam vào thời gian 2022-04-25 14:04:36 UTC

Thông tin từ Rich Header cho thấy khả năng nó được compile bằng Visual Studio 2012/2013:

Kiểm tra các sections của file thì có thể thấy nó bị packed hoặc code bị obfuscated:

Sample có tên gốc là ljAt.dll, và nó export hai hàm là LogFree và LogInit:

Load sample vào IDA, tiến hành phân tích code của hai hàm trên:

  • Hàm LogFree:

Quan sát tại hàm này có thể thấy code của nó đã bị obfuscated hoàn toàn bằng Obfuscator-LLVM, sử dụng kĩ thuật Control Flow Flattening.

Sau khi phân tích thêm, nhận thấy hàm này không thực hiện nhiệm vụ gì cả.

  • Hàm LogInit:

Hàm này sẽ gọi tới hàm LogInit_0:

Cũng tương tự như trên, code tại hàm LogInit_0 cũng đã bị obfuscated hoàn toàn, phải mất rất lâu IDA mới decompile được code của hàm này:

Nhiệm vụ chính của hàm LogInit_0 là gọi tới hàm f_read_content_of_log_dat_file_to_buf để đọc nội dung của file log.dat và thực thi shellcode đã giải mã:

Code tại hàm f_read_content_of_log_dat_file_to_buf cũng bị obfuscated hoàn toàn:

Nhiệm vụ chính của hàm này như sau:

  • Gọi hàm GetModuleHandleW để lấy handle của kernel32.dll.
  • Gọi hàm GetProcAddress để lấy địa chỉ của các hàm APIs: VirtualAllocGetModuleFileNameACreateFileAReadFile.
  • Sử dụng các hàm APIs trên để lấy đường dẫn tới file log.dat và đọc nội dung của file này vào vùng nhớ đã được cấp phát.
  • Thực hiện giải mã nội dung của log.dat thành shellcode để sau đó shellcode này được thực thi bởi lời gọi từ hàm LogInit_0.

3. Phân tích shellcode

Căn cứ vào thông tin đã phân tích ở trên, chúng tôi biết được file log.dll sẽ đọc nội dung từ file log.dat và giải mã ra shellcode để thực thi tiếp. Dựa vào thông tin này, chúng tôi tiếp tục hunting file log.dat trên VirusTotal với phạm vi giới hạn nguồn submit là từ Việt Nam.

Kết quả có được như sau:

Với kết quả trên, tại thời điểm phân tích, chúng tôi lựa chọn file log.dat (2de77804e2bd9b843a826f194389c2605cfc17fd2fafde1b8eb2f819fc6c0c84) được submit lên VirusTotal vào thời gian 2022-04-20 12:33:19 UTC (tức là trước 5 ngày so với file log.dll ở trên).

Tiến hành debug và dump ra shellcode đã được giải mã:

Sử dụng hai công cụ là FLOSS và scdbg để có cái nhìn tổng quan về shellcode này. Kết quả có được như sau:

Với các kết quả có được ở trên, có thể thấy shellcode này sẽ thực hiện cấp phát vùng nhớ và sau đó gọi hàm RtlDecompressBuffer để giải nén dữ liệu với tham số truyền cho hàm là COMPRESSION_FORMAT_LZNT1.

Tiếp tục sử dụng IDA để phân tích shellcode này, nhiệm vụ chính của nó là giải nén ra một Dll và gọi tới hàm được export của Dll này để thực thi. Hàm thực hiện nhiệm vụ này được tôi đặt tên là f_load_dll_from_memory:

Code tại hàm này đầu tiên sẽ lấy ra địa chỉ base của kernel32.dll dựa vào giá trị hash được tính toán trước là 0x6A4ABC5B. Giá trị hash này cũng đã từng được chúng tôi đề cập trong bài phân tích này.

Tiếp theo sẽ lấy địa chỉ hàm API GetProcAddress:

Sau đó bằng kĩ thuật stackstring, shellcode cấu thành tên các hàm APIs và lấy địa chỉ của các hàm sau:

Tiếp theo, shellcode thực hiện cấp phát vùng nhớ (compressed_buf) có kích thước 0x2E552, sau đó đọc dữ liệu từ offset 0x1592 (on disk) và thực hiện vòng lặp xor với key là 0x72 để điền dữ liệu vào compressed_buf. Trên thực tế, kích thước của compressed_buf là 0x2E542, tuy nhiên 16 bytes đầu của nó được dùng để lưu thông tin về signatureuncompressed_sizecompressed_size nên được cộng thêm 0x10.

Shellcode tiếp tục cấp phát vùng nhớ (uncompressed_buf) có kích thước là 0x4C000 và gọi hàm RtlDecompressBuffer để giải nén dữ liệu tại compressed_buf vào uncompressed_buf với định dạng nén là COMPRESSION_FORMAT_LZNT1.

Dựa vào kết quả phân tích ở trên, dễ dàng có được file Dll đã giải nén (tuy nhiên file này đã bị hủy thông tin header):

Sửa lại thông tin của header và kiểm tra bằng PE-bear, Dll này có tên gốc là RFPmzNfQQFPXX và chỉ export một hàm duy nhất là Main:

Quay trở lại với shellcode, sau khi giải nén ra được Dll trên memory, nó sẽ tiến hành nhiệm vụ của một loader thực hiện mapping Dll này vào một vùng nhớ mới. Sau đó, gọi tới hàm mà Dll này export (ở đây là hàm Main) để thực thi nhiệm vụ chính:

Lưu ý: Tại thời điểm phân tích shellcode này, chúng tôi vẫn chưa khẳng định nó là một biến thể của mã độc PlugX, mà chỉ đặt ra câu hỏi nghi ngờ. Chỉ tới khi phân tích Dll được giải nén ở trên, chúng tôi mới khẳng định chắc chắn đây là biến thể của PlugX và đặt lại tên các trường trong struct cho tường minh lại như trên.

4. Phân tích Dll đã giải nén

Chúng tôi sẽ không đi sâu vào phân tích chi tiết Dll này mà chỉ cung cấp những thông tin cần thiết để chứng minh đây là biến thế của PlugX cũng như quá trình giải mã thông tin cấu hình mà mã độc sẽ sử dụng.

4.1. Cách PlugX gọi hàm API

Ở biến thể này, thông tin về các hàm API được lưu tại các xmmword, sau đó được nạp vào thanh ghi xmm0 (128-bit), phần còn thiếu của tên hàm sẽ được nạp thông qua stack. Mã độc thực hiện lấy handle của Dll tương ứng tới các hàm API này, sau đó sử dụng GetProcAddress để lấy ra địa chỉ hàm API cần dùng:

4.2. Tạo thread chính để thực thi

Mã độc thực hiện điều chỉnh các token SeDebugPrivilege và SeTcbPrivilege cho chính tiến trình của nó nhằm có được quyền truy cập đầy đủ tới các tiến trình hệ thống. Sau đó, nó tạo một thread chính được đặt tên là “bootProc”:

4.3. Giao tiếp với C2

Mã độc có thể giao tiếp với C2 thông qua các giao thức TCP, HTTP hoặc UDP:

4.4. Các lệnh mã độc thực thi

Mã độc sẽ nhận lệnh từ kẻ tấn công để thực thi các chức năng tương ứng liên quan tới Disk, Network, Process, Registry, v..v…

Dưới đây là bảng tổng kết danh sách toàn bộ cách lệnh mà kẻ tấn công thực hiện thông qua mẫu mã độc này:

Nhóm lệnhLệnh conMô tả
Disk0x3000Lấy thông tin các ổ đĩa
0x3001Tìm file
0x3002Tìm file đệ quy
0x3004Đọc nội dung file
0x3007Ghi nội dung vào file
0x300ATạo thư mục
0x300CTạo tiến trình trình trên màn hình ẩn
0x300DThực hiện sao chép, di chuyển, đổi tên hoặc xóa file
0x300EThay thế tham số biến môi trường bằng giá trị chỉ định
Nethood0xA000Liệt kê các tài nguyên mạng
Netstat0xD000Thu thập thông tin kết nối TCP
0xD001Thu thập thông tin kết nối UDP
0xD002Thiết đặt trạng thái của kết nối TCP
Option0x2000Khóa màn hình của máy
0x2001Tắt máy ngay lập tức
0x2002Khởi động lại máy
0x2003Tắt máy an toàn
0x2005Hiển thị thông báo
PortMap0xB000Thực hiện port mapping
Process0x5000Liệt kê danh sách các tiến trình
0x5001Liệt kê danh sách các modules
0x5002Tắt tiến trình được chỉ định
RegEdit0x9000Thu thập thông tin registry
0x9001Tạo registry
0x9002Xóa registry
0x9003Sao chép registry
0x9004Liệt kê thông tin các giá trị của một key cụ thể
0x9005Thiết lâp giá trị cho một key cụ thể
0x9006Xóa giá trị của một key cụ thể
0x9007Lấy giá trị của một key
Service0x6000Thu thập cấu hình của service
0x6001Thay đổi các thông số cấu hình service
0x6002Khởi chạy service
0x6003Gửi mã điều khiển tới service
0x6004Xóa service
Shell0x7002Tạo pipe và thực thi command line
SQL0xC000Lấy thông tin nguồn dữ liệu
0xC001Thu thập thông tin trình điều khiển
0xC002Thực thi câu lệnh SQL
Telnet0x7100Thiết lập telnet server
Screen0x4000Mô phỏng hoạt động trên giao thức RDP
0x4100Chụp ảnh màn hình
KeyLog0xE000Thực hiện chức năng của key logger,  lưu vào file “%allusersprofile%\MSDN\6.0\USER.DAT

4.5. Giải mã thông tin cấu hình của PlugX

Như đã phân tích ở trên, mã độc sẽ kết nối tới địa chỉ C2 thông qua các giao thức HTTP, TCP hoặc UDP tùy vào cấu hình được chỉ định. Vậy cấu hình này được lưu ở đâu? Với những mẫu cũ mà chúng tôi đã từng phân tích (1234) thì cấu hình của PlugX thường được lưu tại section .data với độ lớn là 0x724 (1828) bytes.

Quay trở lại với mẫu đang phân tích, chúng tôi thấy rằng trước bước thực hiện kiểm tra các tham số truyền vào khi mã độc thực thi, nó sẽ gọi tới hàm thực hiện nhiệm vụ giải mã cấu hình:

Đi sâu vào hàm này, kết hợp với việc debug thêm từ shellcode, đặt lại tên các trường trong struct đã tạo, chúng tôi có được thông tin:

  • Cấu hình của PlugX được nhúng trong shellcode và bắt đầu từ offset 0x69.
  • Độ lớn của cấu hình là 0x0150C (5388) bytes.
  • Key giải mã là 0xB4.

Với toàn bộ thông tin đầy đủ ở trên, hoàn toàn có thể giải mã được thông tin cấu hình một cách dễ dàng:

IPPort
86.78.23.15253
86.78.23.15222
86.78.23.1528080
86.78.23.15223

Ngoài danh sách các địa chỉ C2 như trên, còn có thêm thông tin liên quan đến thư mục được tạo trên máy nạn nhân để chứa các file của mã độc cũng như tên của service có thể được tạo:

Để dễ dàng hơn, tôi đã viết một python script để tự động trích xuất thông tin cấu hình cho biến thể này. Kết quả sau khi chạy script như sau:

5. Kết luận

Các nhà nghiên cứu của CrowdStrike lần đầu tiên công bố thông tin về Mustang Panda vào tháng 6 năm 2018, sau khoảng một năm quan sát các hoạt động của nhóm này. Tuy nhiên, theo nghiên cứu và tổng hợp từ nhiều công ty an ninh mạng khác nhau thì nhóm APT này đã tồn tại trong hơn một thập kỷ với các biến thể khác nhau được tìm thấy trên khắp thế giới. Mustang Panda, được cho là nhóm tin tặc có trụ sở hoạt động tại Trung Quốc, được đánh giá là một trong những nhóm APT có động cơ cao, áp dụng kĩ thuật tinh vi để lây nhiễm và cài cắm mã độc, mục tiêu có được quyền truy cập vào máy của nạn nhân để từ đó thực hiện các hoạt động gián điệp và đánh cắp thông tin.

Trong bài viết này, chúng tôi đã phân tích các kĩ thuật mà dòng PlugX RAT áp dụng để thực thi và tránh bị phát hiện. Qua đó, có thể thấy nhóm APT này vẫn đang hoạt động và liên tục tìm cách cải tiến kĩ thuật. VinCSS sẽ tiếp tục tìm kiếm các mẫu và biến thể khác có thể được liên kết với biển thể mà chúng tôi phân tích trong bài viết này.

6. Tài liệu tham khảo

7. Tổng hợp IOCs

log.dll – db0c90da56ad338fa48c720d001f8ed240d545b032b2c2135b87eb9a56b07721
log.dll – 84893f36dac3bba6bf09ea04da5d7b9608b892f76a7c25143deebe50ecbbdc5d
log.dll – 3171285c4a846368937968bf53bc48ae5c980fe32b0de10cf0226b9122576f4e
log.dll – da28eb4f4a66c2561ce1b9e827cb7c0e4b10afe0ee3efd82e3cc2110178c9b7a
log.dat – 2de77804e2bd9b843a826f194389c2605cfc17fd2fafde1b8eb2f819fc6c0c84 Decrypted config:
[+] Folder name: %ProgramFiles%\BitDefender Update
[+] Service name: BitDefender Crash Handler
[+] Proto info: HTTP://
[+] C2 servers:
86.78.23.152:53.
86.78.23.152:22.
86.78.23.152:8080.
86.78.23.152:23
[+] Campaign ID: 1234
log.dat – 0e9e270244371a51fbb0991ee246ef34775787132822d85da0c99f10b17539c0
Decrypted config:
[+] Folder name: %ProgramFiles%\BitDefender Update
[+] Service name: BitDefender Crash Handler
[+] Proto info: HTTP://
[+] C2 servers:
86.79.75.55:80.
86.79.75.55:53.
86.79.75.46:80.
86.79.75.46:53
[+] Campaign ID: 1234
log.dat – 3268dc1cd5c629209df16b120e22f601a7642a85628b82c4715fe2b9fbc19eb0
Decrypted config:
[+] Folder name: %ProgramFiles%\Common Files\ARO 2012
[+] Service name: BitDefender Crash Handler
[+] Proto info: HTTP://
[+] C2 servers:
86.78.23.152:23.
86.78.23.152:22.
86.78.23.152:8080.
86.78.23.152:53
[+] Campaign ID: 1234
log.dat – 02a9b3beaa34a75a4e2788e0f7038aaf2b9c633a6bdbfe771882b4b7330fa0c5 (THOR PlugX)
Decrypted config:
[+] Folder name: %ProgramFiles%\BitDefender Handler
[+] Service name: BitDefender Update Handler
[+] Proto info: HTTP://
[+] C2 servers:
www.locvnpt.com:443.
www.locvnpt.com:8080
www.locvnpt.com:80.
www.locvnpt.com:53
[+] Campaign ID: 1234

Dang Dinh Phuong – Threat Hunter

Tran Trung Kien (aka m4n0w4r) – Malware Analysis Expert

R&D Center – VinCSS (a member of Vingroup)

Chia sẻ bài viết