# [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) **blog.vincss.net/2020/12/re017-2-phan-tich-ky-thuat-dong-ma-doc-moi-co-nhieu-dau-hieu-lien-quan-toi-nhom-tin-tac-** Panda.html **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ể](https://github.com/dblock/msiext/tree/master/externals/WinDDK/7600.16385.1/inc/mfc42) [xem tại đường link này.](https://docs.microsoft.com/en-us/cpp/mfc/hierarchy-chart?view=msvc-160) 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 và 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 có **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 và** **CMalwareDlg. Do CMalwareDlg không có CRuntimeClass và 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)** -----