Mustang Panda 使用新型 Korplug 变种 Hodur
· 6 分钟阅读 · @admin

1.1 组织背景
Mustang Panda(野马熊猫)又名 PKPLUG,其名称源于该组织将 PlugX 恶意软件作为 DLL 侧加载包的一部分通过 ZIP 压缩文件进行投递的策略。由于 ZIP 文件格式在其文件头中包含 “PK” 标识字符串,因此该组织被命名为 PKPLUG。
1.2 新型变种 Hodur
ESET 研究人员最近发现了一起正在进行的攻击活动,该活动使用了 Mustang Panda 以前从未使用过的 Korplug 新变种。研究团队将该变种命名为 Hodur(霍德尔),原因在于该变种与 UINT42 团队发现的 Korplug 变种 THOR 有显著的相似性。在北欧神话中,Hodur 是 Thor 同父异母的兄弟,这一命名恰如其分地体现了两者之间的关联。
1.3 归因分析
基于代码相似性、技术手段和 TTP(战术、技术和程序)中的诸多共性,可以高度自信地将此次活动归因于 Mustang Panda。需要注意的是,PlugX 源码疑似由国内开发者编写并已在网上泄露多年,许多攻击者使用泄露的源码编译生成 RAT 后门。因此,部分国外安全厂商或研究人员仅根据代码相似性就将 PlugX 恶意程序背后的攻击者归因于中国 APT 组织的做法并不可靠。
1.4 攻击特点
Mustang Panda 的攻击活动通常使用自定义加载程序来投递恶意软件,包括 Cobalt Strike 和 PlugX,该组织以创建 Korplug 变种而闻名。本次活动的独特之处在于,在部署的每个阶段都使用了大量垃圾代码和不透明谓词(Opaque Predicates)来阻碍安全研究人员的分析工作。
2. 样本详情
| 文件名 | PotPlayer.exe |
|---|---|
| Md5 | f16903b2ff82689404f7d0820f461e5d |
| 文件名 | PotPlayer.dll |
|---|---|
| Md5 | 2102d225508c1f8f488a3f1574a34759 |
| 文件名 | REGULATION OF THE EUROPEAN PARLIAMENT AND OF THE COUNCIL.exe |
|---|---|
| Md5 | 8f17a2ec3c13bed031e99cb57af220cf |
| 文件名 | FontEDL.exe |
|---|---|
| Md5 | c03bc678d28b637327a757d7a35a2bcd |
| 文件名 | DocConvDll.dll |
|---|---|
| Md5 | 69ab42012ddce428c73940dcf343910e |
| 文件名 | COVID-19 travel restrictions EU reviews list of third countries.exe |
|---|---|
| Md5 | 01d8305b91524d83ccf2c26c1b3b7f1f |
3. 攻击流程图

4. 详细分析
4.1 攻击链概述
在目标机器上,攻击者部署了三个关键组件:具有 DLL 侧加载漏洞的合法可执行文件、包含恶意代码的 DLL 文件以及加密的 Korplug 后门文件。合法可执行文件加载恶意 DLL,恶意 DLL 负责解密并执行 Korplug RAT,形成完整的攻击链。
4.2 俄乌冲突作为钓鱼主题
4.2.1 REGULATION OF THE EUROPEAN PARLIAMENT AND OF THE COUNCIL.exe
文件概览
该文件名翻译为“欧洲议会和理事会条例“,表明本次攻击活动利用俄乌冲突事件作为社会工程学主题,针对特定人群进行钓鱼攻击。
字符串加密机制
恶意软件采用复杂的字符串加密技术,所有敏感字符串以加密形式保存在堆栈内存中,仅在使用时才进行动态解密。如下图所示,解密算法相当复杂,且在不同位置可能使用不同的密钥进行解密,这使得静态自动化字符串解密变得非常困难。

API 地址解析
该样本获取 API 地址的方式与以往的恶意程序有显著不同。传统恶意程序通常提供混淆的 DLL 名称字符串和 API 名称字符串,先获取 DLL 模块句柄,再根据该模块获取 API 地址。而该版本只提供混淆的 API 名称,通过遍历所有已加载的模块并尝试在每个模块中查找目标 API 地址。

垃圾代码混淆
从代码中可以看到大量穿插的垃圾代码。例如,变量 dword_426344 在其他位置未被赋值,因此其值默认为 0。该变量经过取反、或运算和与运算等操作后,最终结果仍为 0,对其余代码不会产生任何实际影响。这种技术旨在增加逆向分析的难度。
窗口回调机制
恶意程序注册了一个类名为 “Windows” 的窗口,并在窗口回调函数中执行恶意代码。当创建该类型的窗口时,会调用回调函数 malicous_windows_wndProc 来下载后续需要的文件。

程序创建了一个窗口类名为 “Windows”、窗口标题为 “title” 的窗口。当窗口被创建时,窗口回调函数被执行。

在回调函数中,参数2 表示消息类型。当使用 SetWindowPos 函数时,会向恶意窗口回调函数发送 WM_SIZE(消息值为 5)。恶意窗口收到该消息后,会判断接收的消息是否为 WM_SIZE,如果是则调用函数 download_malious_file 下载恶意文件;否则调用窗口默认回调函数。

互斥量机制
创建互斥量 “Windows API” 以避免程序被重复执行。

环境变量获取
获取环境变量 %TEMP% 的完整路径,用于保存下载的恶意文件。

诱饵文档下载
调用函数 WinHttpCrackUrl 下载诱饵文档。

下载完诱饵 PDF 文档后立即打开该文件,以迷惑受害者。

诱饵文档内容涉及欧盟与乌克兰边境局势的讨论,如下图所示:

延迟执行机制
调用 CMD 命令启动 “FontEDL.exe”。其中 ping 命令使用参数 -n 70 表示发送 70 次 ICMP 包,在此处的作用是延迟执行程序 FontEDL,因为此时 FontEDL 尚未从远程 C&C 服务器下载完成,需要等待下载完毕后再执行。

恶意载荷下载
从远程服务器下载三个关键文件:恶意 DLL 文件 DocConvDll.dll、合法文件 FontEDL.exe 以及加密的 Korplug 文件 Fontlog.dat。

4.2.2 FontEDL.exe
合法程序利用
该程序是用于生成字体文件的合法程序,具有有效的数字签名。由于存在 DLL 侧加载漏洞,被 Mustang Panda 利用来加载恶意程序 DocConvDll.dll。

侧加载漏洞分析
在加载文件 “DocConvDll.dll” 时,程序未对其进行任何完整性校验,攻击者可以轻易将该 DLL 替换为同名的恶意程序,从而导致恶意代码被执行。

4.2.3 DocConvDll.dll
加载器分析
该程序为加载器(Loader),主要功能是解密 FontLog.dat 文件然后执行其中的恶意载荷。程序导出了多个函数,除了包含恶意代码的导出函数外,大部分函数仅直接返回一个固定值或执行无实际作用的垃圾代码。许多导出函数由随机字母组成并指向同一地址。主要恶意代码位于导出函数 createSystemFontsUsingEDL 中。

解密执行流程
FontLog.dat 文件名被硬编码在加载程序中。加载器将文件内容读取到内存中进行解密,使用 VirtualProtect 将该段内存属性设置为可执行,然后从该段内存偏移 0x00 处开始作为代码执行。

API 混淆技术对比
Windows API 函数调用与下载器使用了不同的混淆技术。下载器使用比较 API 名称字符串的方式来查找对应的 API 地址;而加载器则遍历所有已加载模块的导出函数,对每个导出函数计算哈希值,然后与预先计算好的 API 哈希值进行比较来查找对应的 API 地址。
由于远程连接已失效,无法下载 FontLog.dat 文件并解密出 Korplug 后门进行进一步分析。
4.3 新冠疫情作为钓鱼主题
4.3.1 COVID-19 travel restrictions EU reviews list of third countries.exe
功能概述
该文件主要功能是下载与该文件同名的诱饵文档、合法可执行程序 PotPlayer.exe、恶意程序 PotPlayer.dll 以及加密的 Korplug 文件。该文件及其下载的恶意程序与前面利用俄乌冲突事件钓鱼的样本有所不同,虽然也使用了大量垃圾代码和不透明谓词,但所使用的字符串均为明文,而非存储在栈上的混淆字符串。
环境变量获取
获取环境变量 %TEMP% 的完整路径,用于保存下载的恶意文件。

诱饵文档投递
下载同名诱饵文档并打开,以掩人耳目。

网络连通性检测与延迟执行
使用 ping 命令检测网络连接并延迟执行合法可执行程序。

恶意载荷下载
从远程服务器下载恶意 DLL 文件 PotPlayer.dll 和加密文件 PotPlayerDB.dat。

4.3.2 PotPlayer.exe
DLL 侧加载漏洞
该程序同样未对加载的 DLL 文件进行验证,导致了 DLL 侧加载漏洞。

4.3.3 PotPlayer.dll
加载器功能
该程序是加载器,主要功能为解密 PotPlayerDb.dat 文件然后执行。具有多个导出函数,其中函数 SetPotPlayRegKeyW 执行恶意代码,其他函数则执行无意义的垃圾代码。

API 地址获取机制
首先从寄存器 FS 指向的内存偏移 0x18 处读取 TEB(Thread Environment Block)结构地址,用于遍历所有已加载的模块信息。

遍历链表 InMemoryOrderModuleList 来获取已加载的模块信息。

根据模块的加载基址获取所有导出函数并对其计算哈希值,然后与要查找的 API 哈希值进行比较,如果相等则返回 API 地址。

解密与执行
读取加密文件 PotPlayerDb.dat 到本地分配的缓冲区中然后解密。解密方式如下图所示,最终解密后得到 PE 文件。使用 VirtualProtect 将该段缓冲区的内存属性设置为可执行,然后将 PE 文件偏移 0x00 处的数据作为代码来执行。

4.3.4 Korplug 后门分析
后门概述
加密的 DAT 文件解密后为 Korplug 后门(又称 PlugX),多个 APT 组织经常使用该 RAT 作为后门工具。该后门与 THOR 变种有多个相似之处,例如 C&C 服务器配置使用相同格式、使用注册表项 Software\CLASSES\ms-pu 和静态窗口类等,这也是将其命名为 Hodur 的原因。
直接从该文件导出函数的入口点启动时,它不会执行主要有效载荷,且加载过程非常复杂。
手动映射机制
如下图所示,在 PE 头部偏移 0 处存在一段 Shellcode,寄存器 EBX 值加上偏移 0x2079 为导出函数 ZfwObuncPtCZ 的地址。

这段代码主要解析内存中的 PE 数据,并将其作为库手动映射到分配的缓冲区。这包括映射各个节(Section)、解析导入表等操作。
非标准 DllMain 参数
调用 DllMain 时,参数 fdwReason 使用非标准值 4(正常值为 0~3)。要执行有效载荷时需要使用这个特殊值。这样可以防止 Korplug 被类似 rundll32.exe 的加载工具直接执行。
字符串混淆
通过解密存储在堆栈上的混淆字符串来获得被调用的 API 函数,例如:

4.3.4.1 安装机制
安装目录用于创建注册表自启动项的名称。值为合法可执行程序名称附加三个随机字母,假设安装目录为 PotPlayerACX。在 %ALLUSERPROFILE% 目录下创建属性为隐藏和系统的安装目录。
运行时会检查运行路径是否为 %ALLUSERPROFILE%\PotPlayerACX,如果是则执行 RAT 功能;否则将 PotPlayer.dll、PotPlayerDB.dat 和 PotPlayer.exe 三个文件复制到 PotPlayerACX 目录执行安装过程。设置注册表启动项 Software\Microsoft\Windows\CurrentVersion\Run 的值为 PotPlayer.exe 的路径,然后退出程序,等待下次开机时自动启动。
4.3.4.2 RAT 功能
通信协议
Korplug 与远程 C&C 通信使用自定义格式,基于 TCP 协议完成。通信时使用的通用头部格式如下,该部分以明文形式传输:
struct header {
uint32_t nonce; // 用于进行 RC4 加密的随机数
uint32_t command_number; // C&C 指令编号
uint32_t command_exit_status; // 返回命令执行后的结果
}
4.3.4.3 命令组 0x1001
用于管理后门执行并对新主机进行初始侦察的命令。
| ID | 名称 | 描述 |
|---|---|---|
| 0x1000 | Ping | 心跳检测 |
| 0x1001 | 获取系统信息 | 收集受害者机器的详细系统信息 |
| 0x1002 | 监听线程 | 创建一个线程来处理 0x1002 组的命令 |
| 0x1004 | 重置连接 | 重新建立与 C&C 的连接 |
| 0x1005 | 卸载自身 | 删除自启动项和安装目录 |
当 ID 为 0x1001 时获取的系统信息格式如下:
struct system_info {
uint32_t magic_bytes; // 魔术字节,值为 0x20190301
uint32_t client_ip; // 客户端 IP 地址
uint32_t server_ip; // 服务器 IP 地址
uint32_t ram_size; // 内存大小
uint32_t cpu_clock_rate; // CPU 时钟频率
uint32_t display_width; // 显示器宽度
uint32_t display_height; // 显示器高度
uint32_t default_locale; // 默认语言
uint32_t tick_count; // 系统运行时间
uint32_t os_major_version; // 操作系统主版本号
uint32_t os_minor_version; // 操作系统次版本号
uint32_t os_build_number; // 操作系统构建号
uint32_t os_platform_id; // 操作系统平台 ID
uint16_t service_pack_major_version; // 服务包主版本号
uint16_t service_pack_minor_version; // 服务包次版本号
uint16_t product_type; // 产品类型
uint16_t isWow64; // 是否为 WOW64 进程
uint16_t time_with_year; // 时间戳(年)
uint16_t time_with_month; // 时间戳(月)
uint16_t timestamp_off; // 时间戳偏移
uint16_t service_pack_version_string_off; // 服务包版本字符串偏移
uint16_t unknown; // 未知字段
uint16_t user_name_off; // 用户名偏移
uint16_t computer_name_off; // 计算机名偏移
uint16_t mutex_name_off; // 互斥量名称偏移
uint16_t unknown1; // 未知字段 1
uint16_t list_ip_off; // IP 列表偏移
uint16_t end_zero; // 结束标志,总是为 0x0000
}
4.3.4.4 命令组 0x1002
| ID | 名称 | 描述 |
|---|---|---|
| 0x1002 | Ping | 心跳检测 |
| 0x3000 | 驱动器列表 | 枚举系统驱动器 |
| 0x3001 | 目录列表 | 枚举指定目录内容 |
| 0x3002 | 列表完成 | 由客户端在执行完 0x3001 命令后发送 |
| 0x3004 | 读取文件 | 读取指定文件 |
| 0x10003005 | 读取文件块 | 分块读取大文件 |
| 0x10003006 | 读取完成 | 执行完 0x10003005 后发送 |
| 0x3007 | 写文件 | 写入文件 |
| 0x10003008 | 写文件块 | 分块写入大文件 |
| 0x10003009 | 写文件完成 | 完成文件写入 |
| 0x300A | 创建目录 | 创建指定目录 |
| 0x300B | 读取文件 | 读取文件内容 |
| 0x300C | 在隐藏桌面执行 | 在隐藏桌面执行命令 |
| 0x300D | 文件操作 | 执行文件操作(复制、移动、删除等) |
| 0x300E | 获取环境变量 | 获取指定环境变量的值 |
| 0x300F | 创建程序数据目录 | 创建目录 %SYSTEM%\ProgramData |
| 0x3102 | 递归搜索文件 | 递归搜索指定后缀的文件 |
| 0x7002 | 创建远程 Shell | 创建交互式远程 Shell |
| 0x7003 | 获取执行结果 | 获取上次命令执行的结果 |
5. 威胁情报指标(IOC)
5.1 文件哈希(MD5)
f16903b2ff82689404f7d0820f461e5d
2102d225508c1f8f488a3f1574a34759
8f17a2ec3c13bed031e99cb57af220cf
c03bc678d28b637327a757d7a35a2bcd
69ab42012ddce428c73940dcf343910e
01d8305b91524d83ccf2c26c1b3b7f1f
5.2 网络指标
https://69.90.184.125/europa/2022.pdf
https://69.90.184.125/europa/FontLog.dat
https://69.90.184.125/europa/FontEDL.exe
https://69.90.184.125/europa/DocConvDll.dll
https://45.154.14.235/2022/COVID-19 travel restrictions EU reviews list of third countries.doc
https://45.154.14.235/2022/PotPlayer.exe
https://45.154.14.235/2022/PotPlayer.dll
https://45.154.14.235/2022/PotPlayerDB.dat
6. ATT&CK 矩阵映射
| 战术(Tactic) | 技术 ID | 技术名称(Name) | 描述(Description) |
|---|---|---|---|
| Execution | T1129 | Shared Modules | 使用 LoadLibrary 在运行时加载其他 DLL。加载器和 RAT 均为 DLL 文件。 |
| T1204 | User Execution | 依赖于用户执行初始下载程序。 | |
| T1574.002 | Hijack Execution Flow: DLL Side-Loading | 下载程序获取并启动存在漏洞的应用程序,因此该应用程序会加载并执行包含第二阶段的恶意 DLL | |
| Persistence | T1547.001 | Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder | 通过注册表运行键注册启动项以实现持久化 |
| T1053.005 | Scheduled Task/Job: Scheduled Task | 创建计划任务实现自动启动 | |
| Defense Evasion | T1140 | Deobfuscate/Decode Files or Information | Korplug 文件经过加密,仅在运行时解密,其配置数据使用 XOR 加密。 |
| T1564.001 | Hide Artifacts: Hidden Files and Directories | 在安装过程中创建的目录被设置为隐藏和系统属性。 | |
| T1564.003 | Hide Artifacts: Hidden Window | 可以在隐藏桌面上运行命令。在部署过程中使用多个隐藏窗口。 | |
| T1112 | Modify Registry | 能够创建、修改或删除注册表项 | |
| T1027 | Obfuscated Files or Information | 下载加密的文件;使用大量垃圾代码和不透明谓词进行代码混淆 | |
| Command and Control | T1071 | Application Layer Protocol: Web Protocols | 使用 HTTPS 协议进行通信 |
| T1573 | Encrypted Channel: Symmetric Cryptography | 通信流量使用 RC4 算法加密 | |
| T1105 | Ingress Tool Transfer | 能够从远程服务器下载其他文件和工具 | |
| T1132 | Data Encoding: Standard Encoding | 使用 LZNT1 压缩算法压缩传输的数据 |

