[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

 


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 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: VirtualAlloc, GetModuleFileNameA, CreateFileA, ReadFile.
  • 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à FLOSSscdbg để 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_buf0x2E542, tuy nhiên 16 bytes đầu của nó được dùng để lưu thông tin về signature, uncompressed_size, compressed_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 SeDebugPrivilegeSeTcbPrivilege 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ệnh

Lệnh con

Mô tả

Disk

0x3000

Lấy thông tin các ổ đĩa

0x3001

Tìm file

0x3002

Tìm file đệ quy

0x3004

Đọc nội dung file

0x3007

Ghi nội dung vào file

0x300A

Tạo thư mục

0x300C

Tạo tiến trình trình trên màn hình ẩn

0x300D

Thực hiện sao chép, di chuyển, đổi tên hoặc xóa file

0x300E

Thay thế tham số biến môi trường bằng giá trị chỉ định

Nethood

0xA000

Liệt kê các tài nguyên mạng

Netstat

0xD000

Thu thập thông tin kết nối TCP

0xD001

Thu thập thông tin kết nối UDP

0xD002

Thiết đặt trạng thái của kết nối TCP

Option

0x2000

Khóa màn hình của máy

0x2001

Tắt máy ngay lập tức

0x2002

Khởi động lại máy

0x2003

Tắt máy an toàn

0x2005

Hiển thị thông báo

PortMap

0xB000

Thực hiện port mapping

Process

0x5000

Liệt kê danh sách các tiến trình

0x5001

Liệt kê danh sách các modules

0x5002

Tắt tiến trình được chỉ định

RegEdit

0x9000

Thu thập thông tin registry

0x9001

Tạo registry

0x9002

Xóa registry

0x9003

Sao chép registry

0x9004

Liệt kê thông tin các giá trị của một key cụ thể

0x9005

Thiết lâp giá trị cho một key cụ thể

0x9006

Xóa giá trị của một key cụ thể

0x9007

Lấy giá trị của một key

Service

0x6000

Thu thập cấu hình của service

0x6001

Thay đổi các thông số cấu hình service

0x6002

Khởi chạy service

0x6003

Gửi mã điều khiển tới service

0x6004

Xóa service

Shell

0x7002

Tạo pipe và thực thi command line

SQL

0xC000

Lấy thông tin nguồn dữ liệu

0xC001

Thu thập thông tin trình điều khiển

0xC002

Thực thi câu lệnh SQL

Telnet

0x7100

Thiết lập telnet server

Screen

0x4000

Mô phỏng hoạt động trên giao thức RDP

0x4100

Chụp ảnh màn hình

KeyLog

0xE000

Thự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 (1, 2, 3, 4) 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:

IP

Port

86.78.23.152

53

86.78.23.152

22

86.78.23.152

8080

86.78.23.152

23

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)




No comments:

Post a Comment