Remco Sprooten

EMOTET 动态配置提取

基于模拟的 EMOTET 配置动态提取工具。

阅读时长 16 分钟安全研究
EMOTET Dynamic Configuration Extraction

关键要点

  • EMOTET 开发人员已更改了他们在 64 位版本恶意软件中编码配置的方式。
  • 使用代码模拟,我们可以绕过多种代码混淆技术。
  • 未来,代码模拟器在配置提取器中的使用将变得越来越普遍。

要下载 EMOTET 配置提取器,请查看我们关于该工具的帖子。

前言

EMOTET 家族在 2014 年作为 模块化银行木马 进入恶意软件领域,专注于通过检查流量来收集和泄露银行账户信息。EMOTET 已被用作早期植入物,用于加载其他恶意软件家族,例如 QAKBOTTRICKBOTRYUK。尽管国际执法机构已拆除了多个 EMOTET 攻击活动,但它仍然是网络犯罪中最猖獗的活动之一。

在过去的几个月里,Elastic 安全团队观察到 EMOTET 开发人员 转向 了 64 位版本的恶意软件。虽然这种变化似乎没有影响到我们观察到的样本的核心功能,但我们确实注意到配置和字符串的混淆方式发生了变化。在早期版本的 EMOTET 中,配置以加密形式存储在二进制文件的 **.data** 部分。在新版本中,配置是在运行时计算的。因此,我们需要从二进制文件中提取配置的信息隐藏在实际代码中。

在接下来的部分中,我们将讨论以下与 64 位 EMOTET 样本相关的内容:

  • EMOTET 加密机制
  • 查看 EMOTET C2 列表
  • 有趣的 EMOTET 字符串
  • EMOTET 配置提取器实用程序

加密密钥

EMOTET 使用嵌入式 椭圆曲线加密 (ECC) 公钥来加密其网络通信。虽然在以前的版本中,密钥会存储在 XOR 加密的 Blob 中,但现在内容是在运行时计算的。

相比之下,以前的 EMOTET 版本会将密钥数据的加密版本存储在二进制文件的 **.text** 部分。

为了使安全研究人员更难找到给定的代码,恶意软件使用 混合布尔算术 (MBA) 作为其混淆技术之一。它将常量和简单表达式转换为包含布尔运算和算术运算混合的表达式。

在此示例中,实例化了一个常量数组,但查看汇编代码,我们会发现每个常量都是在运行时计算的。这种方法使得开发针对此函数的签名具有挑战性。

我们注意到 椭圆曲线 Diffie-Hellman (ECDH) 和 椭圆曲线数字签名算法 (ECDSA) 密钥都使用相同的函数来解码内容。

ECDH 密钥(您可以通过其魔术 ECK1 字节识别)用于加密目的,而 ECDSA 密钥 (ECC1) 用于验证 C2 服务器的响应。

通过利用 YARA 签名找到此解码函数在 EMOTET 二进制文件中的位置,我们可以观察以下过程:

  1. 在二进制文件中找到解码算法。
  2. 找到解码函数的任何交叉引用 ( Xrefs )。
  3. 模拟调用解码函数的函数。
  4. 从内存中读取结果数据。

正如我们提到的,我们首先使用 YARA 在二进制文件中找到该函数。签名在 本文末尾 提供。值得指出的是,这些 YARA 签名用于识别二进制文件中的位置,但以其当前形式,无法用于识别 EMOTET 样本。

为了从多个样本中自动检索数据,我们创建了一个配置提取器。在下面的代码片段中,我们将以高级方式演示如何从恶意软件样本中收集配置信息。

在上面的代码片段中:

  1. 首先加载 YARA 签名。
  2. 尝试查找匹配项,如果在文件中找到签名。
  3. 根据文件中的偏移量计算函数偏移量。

为了找到此函数的 Xrefs,我们使用了优秀的 SMDA 反编译器。找到 Xrefs 后,我们可以使用 CPU 模拟器 Unicorn 开始模拟过程。

  1. 初始化 Unicorn 模拟器。
  2. 将可执行代码从 PE 文件加载到内存中。
  3. 反汇编函数以查找返回和执行结束位置。
  4. 二进制文件将尝试使用 Windows HeapAlloc API 为解码数据分配空间。由于我们不想模拟任何 Windows API(因为这会增加不必要的复杂性),因此我们挂钩到代码,以便我们可以自己分配空间。
  5. 模拟运行后,64 位“长整型大小”寄存器 ( RAX ) 将包含指向内存中密钥数据的指针。
  6. 为了以更易读的方式呈现密钥,我们将其转换为标准 PEM 格式。

通过模拟我们感兴趣的二进制文件部分,我们不再需要静态地消除混淆以检索隐藏的内容。这种方法增加了配置提取器创建的复杂性。但是,由于恶意软件作者正在添加越来越多的混淆,因此需要一种通用的方法来消除这些技术。

C2 服务器列表

跟踪恶意软件家族的重要部分是通过识别和发现它们用于运营网络的 C2 服务器来获得新的见解。

在 EMOTET 的 64 位版本中,我们看到 C2 服务器的 IP 和端口信息也是在运行时动态计算的。每个 C2 服务器都由一个函数表示,该函数计算并返回 IP 地址和端口号的值。

这些函数没有可用于搜索的直接交叉引用。但是,一个过程引用了所有 C2 函数并创建了指向 **p_c2_list** 数组的指针。

之后,我们可以单独模拟每个 C2 服务器函数以检索 IP 和端口组合,如下所示。

字符串

相同的方法也应用于内存中字符串的使用。每个字符串都有其自己的函数。在以下示例中,该函数将返回指向字符串 **%s\regsvr32.exe "%s"** 的指针。

所有 EMOTET 字符串都共享一个通用的函数来在运行时解码或解析字符串。在我们分析的示例中,字符串解析器函数被引用了 29 次。

这使我们能够遵循前面提到的相同方法来解码所有 EMOTET 字符串。我们使用 YARA 精确定位字符串解码函数,找到交叉引用并模拟结果函数。

配置提取器

自动化提取 EMOTET 的有效载荷是威胁狩猎的一个关键方面,因为它可以提供攻击活动和威胁参与者部署的恶意软件的可见性,使从业人员能够及时发现新的未知样本。

% emotet-config-extractor --help
usage: Emotet Configuration Extractor [-h] (-f FILE | -d DIRECTORY) [-k] [-c] [-s] [-a]

options:
  -h, --help            show this help message and exit
  -f FILE, --file FILE  Emotet sample path
  -d DIRECTORY, --directory DIRECTORY
                        Emotet samples folder
  -k                    Extract Encryption keys
  -c                    Extract C2 information
  -s                    Extract strings
  -a                    Extract strings (ascii)

我们的提取器可以使用 **-d** 选项指定样本目录,或使用 **-f** 选项指定单个样本,然后可以输出一些值得注意的配置部分,具体来说:

  • -k:提取加密密钥
  • -c:提取 C2 信息
  • -s:提取宽字符字符串
  • -a:提取 ASCII 字符串

EMOTET 使用不同的例程来解码宽字符和 ASCII 字符串。这就是为什么提取器提供标志分别提取它们的原因。

C2 信息显示了在样本中找到的 IP 地址列表。值得注意的是,EMOTET 会下载子模块来执行特定任务。这些子模块可能包含它们自己的 C2 服务器列表。提取器还可以处理这些子模块。

我们观察到的子模块不包含加密密钥。处理子模块时,您可以省略 **-k** 标志。

[...]
[+] Key type: ECK1
[+] Key length: 32
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2DWT12OLUMXfzeFp+bE2AJubVDsW
NqJdRC6yODDYRzYuuNL0i2rI2Ex6RUQaBvqPOL7a+wCWnIQszh42gCRQlg==
-----END PUBLIC KEY-----
[...]
[+] Key type: ECS1
[+] Key length: 32
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9C8agzYaJ1GMJPLKqOyFrlJZUXVI
lAZwAnOq6JrEKHtWCQ+8CHuAIXqmKH6WRbnDw1wmdM/YvqKFH36nqC2VNA==
-----END PUBLIC KEY-----
[...]
[+] Found 64 c2 subs
174.138.33.49:7080
188.165.79.151:443
196.44.98.190:8080
[...]
[+] Starting emulation
[+] String BLOB address: 0x4000000
KeyDataBlob
[...]
[+] String BLOB address: 0x4000000
bcrypt.dll
[...]
[+] String BLOB address: 0x4000000
RNG

为了使社区能够进一步抵御现有和新的 EMOTET 变种,我们正在根据 Apache 2 许可证开源有效载荷提取器。访问 有效载荷提取器文档和二进制下载

EMOTET 的未来

EMOTET 开发人员正在实施新的技术来隐藏其配置,以防止安全研究人员对其进行分析。这些技术将减缓初始分析速度,但是,EMOTET 最终必须执行才能实现其目的,这意味着我们可以收集信息,并利用这些信息来揭示更多关于攻击活动和基础设施的信息。使用代码模拟器,我们仍然可以从二进制文件中查找和提取信息,而无需处理任何混淆技术。EMOTET 是一个很好的例子,它展示了多种混淆技术如何使静态分析变得更加困难。但当然,我们预计会有更多的恶意软件作者效仿。这就是为什么我们预计未来会看到更多基于模拟的配置提取器。

检测

YARA

Elastic Security 创建了 YARA 规则来识别此活动。此处显示的 YARA 规则并非旨在单独用于检测 EMOTET 二进制文件,而是为了支持配置提取器而创建的。检测 EMOTET 的 YARA 规则可以在 protections-artifacts 存储库 中找到。

EMOTET 密钥解密函数

rule resolve_keys
{
meta:
     author = "Elastic Security"
     description = "EMOTET - find the key decoding algorithm in the PE"
     creation_date = "2022-08-02"
     last_modified = "2022-08-11"
     os = "Windows"
     family = "EMOTET"
     threat_name = "Windows.Trojan.EMOTET"
     reference_sample = "debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1"
   strings:
       $chunk_1 = {
        45 33 C9
        4C 8B D0
        48 85 C0
        74 ??
        48 8D ?? ??
        4C 8B ??
        48 8B ??
        48 2B ??
        48 83 ?? ??
        48 C1 ?? ??
        48 3B ??
        49 0F 47 ??
        48 85 ??
        74 ??
        48 2B D8
        42 8B 04 03
     }
   condition:
       any of them
}

EMOTET C2 聚合

rule c2_list
{
     author = "Elastic Security"
     description = "EMOTET - find the C2 collection in the PE"
     creation_date = "2022-08-02"
     last_modified = "2022-08-11"
     os = "Windows"
     family = "EMOTET"
     threat_name = "Windows.Trojan.EMOTET"
     reference_sample = "debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1"
  strings:
     $chunk_1 = {
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
     }
  condition:
     any of them
}

EMOTET 字符串解码器

rule string_decode
{
   meta:
     author = "Elastic Security"
     description = "EMOTET - find the string decoding algorithm in the PE"
     creation_date = "2022-08-02"
     last_modified = "2022-08-11"
     os = "Windows"
     family = "EMOTET"
     threat_name = "Windows.Trojan.EMOTET"
     reference_sample = "debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1"
  strings:
     $chunk_1 = {
        8B 0B
        49 FF C3
        48 8D 5B ??
        33 CD
        0F B6 C1
        66 41 89 00
        0F B7 C1
        C1 E9 10
        66 C1 E8 08
        4D 8D 40 ??
        66 41 89 40 ??
        0F B6 C1
        66 C1 E9 08
        66 41 89 40 ??
        66 41 89 48 ??
        4D 3B D9
        72 ??
     }
     $chunk_2 = {
        8B 0B
        49 FF C3
        48 8D 5B ??
        33 CD
        0F B6 C1
        66 41 89 00
        0F B7 C1
        C1 E9 ??
        66 C1 E8 ??
        4D 8D 40 ??
        66 41 89 40 ??
        0F B6 C1
        66 C1 E9 ??
        66 41 89 40 ??
        66 41 89 48 ??
        4D 3B D9
        72 ??
     }
  condition:
     any of them
}