[RE017-2] Phân tích kỹ thuật dòng mã độc mới được sử dụng để tấn công chuỗi cung ứng nhắm vào Ban Cơ yếu Chính phủ Việt Nam của nhóm tin tặc Panda Trung Quốc (Phần 2)


Static analysis code của eToken với IDA

Tiếp tục với phần trước, như đã đề cập chúng ta chỉ có RTTI của class type_info, lớp root của RTTI.

Hình 1. Thông tin RTTI của class type_info

Phần phân tích sẽ trình bày chi tiết cách xác định các class, tái tạo code của malware này, đồng thời chia sẻ kinh nghiệm áp dụng khi phân tích các malwares/files có dùng MFC.

Các plugin cần dùng:

  • ClassInformer của Simabus
  • HexRaysCodeXplorer của Matrosov
  • MFC_Helper (tự phát triển)

Mã nguồn C++ của MFC các bạn có thể tìm trong thư mục src\mfc của bộ cài đặt Visual Studio. Do MFC4.2 (MFC của VS6) đã rất cũ nên có thể tìm trên Github. Chúng tôi tham khảo tại đây. Về biểu đồ quan hệ của các class của MFC (Hierarchy Chart), các bạn có thể xem tại đường link này.


Ba file dlls quan trọng để diffing/compare với các malware dùng MFC, ví dụ trong mẫu eToken này, là mfc42.dll, mfc42d.dll, mfco42d.dll. Các bạn tìm và tải luôn cả debug symbol file (.pdb) đúng của các dlls các bạn có. Quan trọng nhất là mfc42d.dll (debug build), vì .pdb của nó sẽ chứa đầy đủ thông tin về các types, enumes, classes, vtables của các class của MFC. Chúng ta export local types từ mfc42d.dll thành file .h, rồi import vào idb database của chúng ta. Parse C++ của IDA còn lỗi, không parse được template syntax “<>” nên ta tìm và thay thế các cặp<” và “>” thành “_” trong các file .h.

Mở song song mfc42d.dll trong IDA mới cùng với IDA đang phân tích malware, thực hiện copy name, type của các classes, functions từ mfc42d.dll qua. Như đã nói, malware này là một MFC Dialog application, nên chúng ta sẽ chắc chắn có các class sau trong malware: CObject, CCmdTarget, CWinThread, CWnd, CDialog. Theo quy tắc đặt tên tự động của MFC Wizard, chúng ta đã có các class với tên sau: CVVSupApp (kế thừa từ CWinApp), CAboutDlg (dialog About, resID = 100), CVVSupDlg( dialog chính, resID = 102). 

Kết quả scan vtables, classes của hai plugin ClassInformer HexRaysCodeXplorer.

Hình 2. Kết quả scan vtables, classes

Dùng MFC_Helper scan CRuntimeClass, phát hiện ra đúng như dự đoán, CVVSupDlg CRuntimeClass và thêm một class khác: CVVSupDlgAutoProxy. Chứng tỏ tin tặc khi chạy MFC Wizard, đã bấm chọn support OLE Control.

Hình 3. Kết quả sau khi chạy MFC_Helper nhận diện được các class

Dựa vào hàm import CWinApp::GetRuntimeClass, xác định được CVVSupApp vtable, và dựa vào CDialog::GetRuntimeClass chúng ta xác định được hai vtable của hai dialog còn lại. Nhưng dialog là About, dialog nào là malware dialog. Xác định hết các internal structures của MFX như AFX_MSGMAP, AFX_DISPMAP, AFX_INTERFACEMAP

Sử dụng tính năng Xref to các lệnh call CDialog constructor: void __thiscall CDialog::CDialog(CDialog *this, unsigned int nIDTemplate, CWnd *pParentWnd), nIDTemplate chính là resID của dialog, chúng ta xác định được vtable của CAboutDlg CMalwareDlg. Do CMalwareDlg không có CRuntimeClass RTTI nên tạm đặt tên như vậy. Tin tặc khi build đã xóa đi dòng DECLARE_DYNAMIC_CREATE của hai class này và class CVVSupApp.

Hình 4. Xác định được vtable của của CAboutDlg và CMalwareDlg

Cây quan hệ các class của malware này được vẽ lại như sau:

Hinh 5. Cây quan hệ các class của malware

Copy tên các hàm, type, function type, parameter… từ các class mẹ tương ứng của các class trên, đúng thứ tự trong vtable, xác định được các hàm MFC Wizard sinh ra và các hàm tin tặc đã viết.

Hình 6. Kết quả sau khi copy tên các hàm, type, function type, parameter

Mọi ứng dụng MFC đều có một biến toàn cục là theApp, thuộc class chính CXXXApp kế thừa từ CWinApp. Trong trường hợp malware này là: CVVSupApp theApp; Biến toàn cục này được khởi tạo bởi C RTL trong hàm start, gọi trước main/WinMain, thuộc table __xc_a. Các hàm trong table này gọi sau các hàm khởi tạo của C RTL trong __xi_a. Các table này là param truyền cho hàm internal _initterm của C RTL.

Hình 7. Biến toàn cục theApp trong ứng dụng MFC

Lưu đồ khởi tạo và thực thi một ứng dụng của MFC như sau:

Hình 8. Lưu đồ khởi tạo và thực thi một ứng dụng của MFC

Hàm CVVSupApp::InitInstance cũng là code thông thường mà MFC wizard tạo ra

Hình 9. Hàm CVVSupApp::InitInstance

Constructor của CVVSupDlg: void CVVSupDlg::CVVSupDlg() cũng là code thông thường của MFC Wizard tạo ra. Nhưng trong CVVSupDlg::OnInitDialog, là hàm được gọi từ CVVSupDlg::DoModal(), ta thấy ngay, ở cuối đoạn code mà MFC Wizard sinh ra,  CMalwareDlg được khởi tạo và show, sau đó malware thoát cưỡng chế exit(0) ngay.

Hình 10.  CMalwareDlg được khởi tạo và show

Giá trị 129 chính là resID của dialog CMalwareDlg, và sizeof(CMalwareDlg) = 0x290, lớn hơn size của CDialog mẹ. Chứng tỏ CMalwareDlg được tin tặc thêm vào một số data member. Qua phân tích, chúng tôi đã tái tạo lại được các data member của CMalwareDlg:

Hình 11. Tạo lại các data member của CMalwareDlg

Constructor CMalwareDlg::CMalwareDlg làm các công việc khởi tạo sau. Để ý vào đoạn copy chuỗi “192.168” vào field m_szMask:

Hình 12. Đoạn code copy chuỗi “192.168” vào field m_szMask

Khi được show, CMalwareDlg::OnInitDialog sẽ được gọi, và hàm chính quan trọng để thực thi nhiệm vụ của malware được call ở đây:

Hình 13. Hàm chính Infect sẽ thực thi nhiệm vụ của malware

Hàm Infect (chúng tôi đặt tên) tương đối dài, nên được trình bày thông qua lưu đồ dưới:

Hình 14. Lưu đồ thực thi của hàm Infect

Chúng ta sẽ đi vào chi tiết từng hàm con quan trọng được hàm Infect của class CMalwareDlg gọi. Hàm UserIsAdmin, dùng API IsUserAdmin() của shell32.dll:

Hình 15. Hàm UserIsAdmin

Hàm GetSomeAPIAddrs là một hàm dư thừa, các con trỏ hàm được lấy mà hoàn toàn không dùng tới. Chúng tôi đoán đây có thể là một code cũ.

Hình 16. Hàm GetSomeAPIAddrs

Hàm Base64Decode cũng giống như các hàm Base64 decode khác, chỉ khác một điểm là bảng Base64 code table lại được tin tặc copy vào một char arrary m_szBase64Table và truy xuất từ đây. Sau khi được giải mã Base64, ServiceName ban đầu là “TmV0QmlvcyBNZXNzYWdlciBSZWdpc3Rlcg==” sẽ là "NetBios Messager Register". ServiceDescription ban đầu “TmV0QmlvcyBjb21tdW5pY2F0aW9uIGJldHdlZW4gc3lzdGVtIGNvbXBvbmVudHMu” sẽ là "NetBios communication between system components."

Hàm ExtractCabFile là hàm global, không thuộc class CMalwareDlg. Chú ý ở điểm là file được tạo ra với attribute là hidden.

Hình 17. Hàm ExtractCabFile

File .cab được nhúng hoàn toàn trong .data section, size = 94874 (0x1729A). Tức tin tặc đã khai báo tương đương sau: “static BYTE g_abCabFile[] = { 0xXXXX, 0xYYYY };” (không có const nên sẽ nằm ở .data section). Trích xuất vùng đó ra, ta có một file .cab chứa một file bên trong, tên là smanager_ssl.dll, ngày add vào cab là 26/04/2020 – 23:11 UTC, ngày build 26.04.2020 15:11:24 UTC.

Hình 18. File .cab được nhúng chứa file smanager_ssl.dll

File smanager_ssl.dll (tức netapi32.dll) sẽ được phân tích trong phần tiếp theo vì nó tương đối phức tạp.

Hình 19. Hàm RunExtrac32Exe

Hàm ExecuteAndWait cũng là hàm global, dùng API ShellExecuteExA để gọi và chờ tới khi thực thi xong.

Hình 20. Hàm ExecuteAndWait

Config của Proxy trên máy victim được tin tặc định nghĩa qua một struct như hình, PROXY_TYPE là một enum:

Hình 21. struct PROXY_CONFIG

Hàm ReadProxyConfig sẽ đọc từ registry của nạn nhân trước, nếu không có sẽ đọc từ file pref.js của Firefox. Hiện chúng tôi vẫn chưa rõ tại sao tin tặc lại cố đọc từ Firefox, có thể chúng đã thực hiện các hoạt động tìm hiểu trước để biết về các trình duyệt web được dùng phổ biến ở mục tiêu.

Hình 22. Hàm ReadProxyConfig

Hàm ReadProxyConfigFromRegistry hơi dài nên ở đây chỉ nêu các đoạn quan trọng:

Hình 23. Nhiệm vụ chính của hàm ReadProxyConfigFromRegistry

Hàm ReadProxyConfigFromFireFox rất dài nên chúng tôi sẽ không đề cập chi tiết ở đây. Hàm UpdateFile dùng hàm tương đương memsearh để tìm một chuỗi trong nội dung file, và C&C Info sẽ được ghi vào tại vị trí tìm ra. Trong trường hợp malware này thì chuỗi mask là “192.168”.

Hình 24. Hàm UpdateFile dùng hàm tương đương memsearh để tìm một chuỗi

Chúng tôi đã tái tạo lại struct của C&C Info như sau:

Hình 25. struct của C&C Info 

Và C&C info đã được tin tặc hard-coded ngay trong code:

 Hình 26. Thông tin C&C được hard-coded trong code của mã độc

Nội dung của file smanager_ssl.dll* (netapi32.dll**) nguyên gốc và sau khi được update từ g_CCInfo structure qua:

Hình 27. Nội dung của file smanager_ssl.dll (netapi32.dll) trước và sau khi được update

Hàm để load file đã extract lên và tạo Scheduler Task:

Hình 28. Hàm LoadDllAndCreateSchedulerTask để load file đã extract lên và tạo Scheduler Task
Sau đó, nếu malware được khởi chạy với quyền admin, nó sẽ đăng ký như một ServiceDll, với name đã đề cập ở trên, Service registry key được chọn ngẫu nhiên từ một table gồm mười phần tử, và được nối thêm “Ex” vào. Các chuỗi đó gồm: Winmads”, “Winrs”, “Vsssvr”, “PlugSvr”, “WaRpc”, “GuiSvr”, “WlanSvr”, “DisSvr”, “MediaSvr”, “NvdiaSvr.

Sau khi nối thêm Ex bằng hàm sprintf, thì registry key trên máy victim được tạo dưới nhánh HKLM\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost sẽ là một trong các chuỗi sau: WinmadsEx”, “WinrsEx”, “VsssvrEx”, “PlugSvrEx”, “WaRpcEx”, “GuiSvrEx”, “WlanSvrEx”, “DisSvrEx”, “MediaSvrEx”, “NvdiaSvrEx.

Do hàm cũng tương đối dài nên ở đây chỉ trình bày các điểm chính:

Hình 29. Tạo registry key trên máy victim

Hình 30. Tạo service trên máy victim

Hàm RegistryCall là hàm tin tặc tự viết, nó là hàm toàn cục, cũng chỉ làm các nhiệm vụ thao tác với Registry. Theo góc nhìn của chúng tôi, phong cách lập trình của tin tặc cực kỳ lộn xộn và không thống nhất (cũng có thể đây là cách họ cố tình tạo nhiễu), đã gây nhiều khó khăn cho chúng tôi trong quá trình phân tích. Sau khi đăng ký như một service Dll xong, hàm Infect hoàn tất và return. Malware sẽ thoát do lệnh gọi exit(0)OnInitDialog đã nói ở trên

Chúng tôi sẽ cung cấp file .xml chứa thông tin phân tích trên IDA để những ai quan tâm tới mã độc này có thể sử dụng để import vào lại IDA và Ghidra bằng plugin xml_importer.py của Ghidra. 

Các IOCs của mã độc đã được phân tích rõ trong bài viết. Các bạn có thể tự viết file .bat hay script bằng PowerShell, VBS… để tìm và gỡ bỏ malware này trên các máy của các nạn nhân.


Note:

*smanager_ssl.dll gốc:

  • MD5: C11E25278417F985CC968C1E361A0FB0
  • SHA256: F659B269FBE4128588F7A2FA4D6022CC74E508D28EEE05C5AFF26CC23B7BD1A5
**netapi32.dll (tức smanager_ssl.dll đã cập nhật CCInfo):

  • MD5: 43CE409C21CAD2EF41C9E1725CA12CEA
  • SHA256: 6C1DB6C3D32C921858A4272E8CC7D78280B46BAD20A1DE23833CBE2956EEBF75


(Còn tiếp...)
 

Trương Quốc Ngân (aka HTC)

Chuyên gia Phân tích mã độc - VinCSS (a member of Vingroup)



 

2 comments:

  1. Không hiểu gì hết nhưng mà thích lắm

    ReplyDelete
  2. Phần đọc proxy firefox có thể do firefox có cơ chế không dùng chung proxy với máy anh ạ.

    ReplyDelete