针对一个红队病毒样本逆向分析

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
简介: 近日翻到一个比较新颖的样本,在最终后门载荷释放前运用了不少免杀手段,包括堆栈欺骗,实现反射性调用API,以及DLL侧加载、DLL挖空、HOOK规避等手法,对其执行流程和部分手法做详细分析记录。

近日翻到一个比较新颖的样本,在最终后门载荷释放前运用了不少免杀手段,包括堆栈欺骗,实现反射性调用API,以及DLL侧加载、DLL挖空、HOOK规避等手法,对其执行流程和部分手法做详细分析记录。

样本概述

  • 初始载荷


初始载荷如下,其中loader.exe是作者编译的一个shellcode加载器。


  • 执行流程


有合法签名可执行文件(taskhost.exe)侧载恶意 DLL (sbiedll.dll)。这个恶意DLL作为中间载荷,解密密文载荷DAT文件(sbiedll.dat)获取二阶段有效负载。解密的有效负载MoonWalk充当后门,滥用Google Drive进行命令和控制(C2) 通信。流程图如下:


  • 精心构造的配置信息


样本主要使用“AES-CFB”算法解密载荷,多次使用MD5 hash算法做载荷校验或将hash值作为AES算法的KEY、IV值。主要配置信息如下:


  • 较为丰富的杀软规避
  • DLL 侧加载执行恶意载荷
  • 指定特定的执行参数,期望参数“--type driver”。
  • FNV1a hash动态解析 API。
  • 堆栈欺骗调用win API,规避win API调用过程检测(构造伪造堆栈、修改堆栈指针、调用 API、恢复原始堆栈)
  • 使用了大量的windows底层函数(如内核函数NtCreateFile等)。
  • 使用当前植入主机的GUID md5值作为AES IV值,生成唯一、绑定载荷。
  • hook规避、断点检查。
  • MD5 hash算法和AES-CFB算法进行解密,MD5hash算法进行完整性检查

样本分析

侧加载

  1. “白加黑”侧加载执行初始恶意载荷。由Sandboxie签名的合法可执行文件 (taskhost.exe) 侧载恶意 DLL (sbiedll.dll)。



“sbiedll.dll”中初始化了三个导出函数,但实际上都指向相同的地址,函数名称“SbieDll_Hook”。



  1. 编写一个加载器执行恶意导出函数“SbieDll_Hook”,同步虚拟内存地址,动态、静态结合调试主要功能。


配置信息解密

  1. 利用MD5校验加密配置信息,确保配置的完整性。计算密文段的MD5 hash来于硬编码在样本中的正确hash值做比对。



两段密文hash值:


FE93E8E1C5C3032A26D783A78A820587
1E8EE70F02D60E389D8F721E8CE6DF1F


  1. AES-CFB算法进行解密,获取解密配置信息入下,其中包括明文字符“sbiedll.dat”、“--type”以及其他配置信息或密钥供后续使用。

杀软规避

  1. 执行进程是否使用正确的参数启动,验证期望参数包含“--type driver”,如果此验证检查失败,则终止进程。计参数的MD5哈希值,多次计算结果与硬编码的哈希值进行比较。


硬编码hash值:


E2D45D57C7E2941B65C6CCD64AF4223E


  1. 利用加盐的FNV-1a哈希算法来逃避针对WINAPI的静态检测。在哈希计算过程中添加盐值不同样本的哈希值不同,提高了逃避静态检测的能力。



上图中伪代码通过指针运算和类型转换访问内存,还原C代码,所需API地址通过结构体成员访问。


sImportTable->ntdll_LdrLoadDll = ResolveImport(L"ntdll", 0xFE0B07B0, 0xCA7BB6AC);


函数体内部关键步骤入下:

  • 初始化哈希值。
  • 对输入字符串(DLL名或函数名)进行哈希计算。
  • 对盐值进行哈希计算。



首先,它对输入字符串(代表 DLL 或函数名称)进行哈希处理。然后,它单独对盐值进行哈希处理。此两步哈希处理过程相当于对输入字符串和盐的连接进行哈希处理。


while ( 1 )
  {
    Fun_FNV1a_Hash = 0x811C9DC5;                // FNV-1a 初始哈希值
    InputString = (unsigned __int8 *)(a1 + *v12);
    v18 = -1i64;
    do
      ++v18;
    while ( InputString[v18] );                 // 输入字符长度计算
    for ( i = &InputString[(unsigned int)v18]; InputString < i; Fun_FNV1a_Hash = 0x1000193 * (Fun_FNV1a_Hash ^ v20) )// 计算输入字符串FNV-1a哈希
      v20 = *InputString++;
    v21 = (unsigned __int8 *)&unk_7FFFBEAD7D78; // Salt value: CB 24 B4 BA
    do
    {
      v22 = *v21++;
      Fun_FNV1a_Hash = 0x1000193 * (Fun_FNV1a_Hash ^ v22);// 对盐值进行哈希计算
    }
    while ( v21 < byte_7FFFBEAD7D7C );


盐值,CB 24 B4 BA



最终将API函数地址放置与连续的内存地址中,即结构体成员变量中。下图以API函数“LookupAccountSidw”为例。



此外ResolveImport中还有内置了一些API函数调用相关功能,此样本中暂时没用到。

  1. DodgeBox在完成API初始化后,它就会扫描并解除从System32目录加载的 DLL。此过程包括遍历 .pdata每个 DLL 的部分,检索每个函数的起始和结束地址,并计算每个函数字节的 FNV1a 哈希值。计算存储在磁盘上的相同函数字节的相应哈希值。如果两个哈希值不同,则可以检测到潜在的篡改,将用磁盘中的原始版本替换内存中的函数。



此过程包括遍历 .pdata每个 DLL ,步骤方法入下:


p_InMemoryOrderModuleList = &NtCurrentTeb()->ProcessEnvironmentBlock->Ldr->InMemoryOrderModuleList;


当前线程的线程环境块(TEB)->进程环境块(PEB)->已加载模块的信息链表InMemoryOrderModuleList。


获取链表信息后再循环遍历加载模块列表的每个节点。


p_InMemoryOrderModuleList = &NtCurrentTeb()->ProcessEnvironmentBlock->Ldr->InMemoryOrderModuleList;
  for ( i = p_InMemoryOrderModuleList->Flink; i != p_InMemoryOrderModuleList; i = i->Flink )
  {
    Flink = (__int64)i[2].Flink;
    v3 = (const wchar_t *)i[4].Flink;
    if ( ((__int64)i[5].Blink & 0x60000000) != 0x20000000
      && (*(_WORD *)(*(int *)(Flink + 60) + Flink + 22) & 0x2000) != 0 )

DAT文件有效载荷解密及加载

  1. 在当前进程堆中开辟内存,读取“sbiedll.dat”文件流。



在完成路径等相关字符初始化后,利用NtReadFile读取文件流至当前进程的堆空间中。

  1. DAT文件有效载荷解密


读取计算机唯一标识符GUID,计算MD5。检索注册表“SOFTWARE\Microsoft\Cryptography MachineGuid”值获取系统GUID,计算其MD5值,作为后续解密AES算法的IV值。



检查文件的前四个字节。如果这些字节非零,则表示 DAT载荷投递在了特定目标上,如果DAT文件不是特定于机器的,DodgeBox将继续使用 AES-CFB 加密解密文件,利用存储在配置文件中的密钥参数。从“sbiedll.dat”载荷的第五个字节开始解密,解密获取一个隐藏PE头的PE文件。



使用前机器GUID的MD5哈希作为AES IV重新加密载荷。


在完成有效载荷解密后,样本将载荷与当前植入机器绑定,使用原有的AES密钥key,但是将 GUID 的 MD5 哈希作为 AES IV。这种方法保证了解密的 DAT 文件无法在任何其他机器上解密,从而增强了有效载荷的安全性。



  1. 关于堆栈调用欺骗可以再做一些更详细的说明。这里借鉴原始报告的描述。


首先设置堆栈,精心构造堆栈的内容,包括插入返回地址和所需的参数,确保API调用能按预期进行。


真实API调用,在准备好堆栈和寄存器后,执行jmp指令,将控制流重定向到目标 API。这种方式使得 API 调用看起来像是从正常位置发起的。



这种方法结合了堆栈伪造和 API 调用技术,通过控制堆栈和寄存器的状态来确保 API 调用能够成功并达到隐蔽的效果。这种复杂的技术可以有效地绕过静态分析和动态监控,增加了恶意代码的隐蔽性。


样本的加盐 FNV1a 哈希的 Python 实现如下所示:


func fnv1aSalted(data, salt []byte, seedValue uint32) uint32 {
    combinedData := append(data, salt...)
    hash := seedValue
    prime := uint32(0x01000193)
    for _, byteValue := range combinedData {
        hash ^= uint32(byteValue)
        hash *= prime
        hash &= 0xFFFFFFFF 
    }
    return hash
}
func main() {
    ntdll := []byte("n\x00t\x00d\x00l\x00l\x00") 
    salt := []byte{0xba, 0xb4, 0x24, 0xcb}
    hash1 := fnv1aSalted(ntdll, salt, 0x811c9dc5)
    fmt.Printf("Hash for ntdll: 0x%08x\n", hash1)
    ldrLoadDll := []byte("LdrLoadDll")
    hash2 := fnv1aSalted(ldrLoadDll, salt, 0x811c9dc5)
    fmt.Printf("Hash for LdrLoadDll: 0x%08x\n", hash2)
}


整体样本尤其是一些免杀首发相对复杂,因为中途快照出现了些问题,注释等信息缺失,所以记录思路显得有点混乱,不过还是基本描述清除了相关手法。

相关实践学习
基于Hologres轻松玩转一站式实时仓库
本场景介绍如何利用阿里云MaxCompute、实时计算Flink和交互式分析服务Hologres开发离线、实时数据融合分析的数据大屏应用。
Linux入门到精通
本套课程是从入门开始的Linux学习课程,适合初学者阅读。由浅入深案例丰富,通俗易懂。主要涉及基础的系统操作以及工作中常用的各种服务软件的应用、部署和优化。即使是零基础的学员,只要能够坚持把所有章节都学完,也一定会受益匪浅。
相关文章
【论文速递】NDSS2021 - 操纵 Byzantine: 联邦学习的模型中毒攻击与防御优化
【论文速递】NDSS2021 - 操纵 Byzantine: 联邦学习的模型中毒攻击与防御优化
|
22天前
|
云安全 安全 Linux
钓鱼特辑(二)在红队眼皮底下拆解木马
一场牵动人心的攻防演练正在如火如荼地开展,红方每天变着花样对目标进行钓鱼攻击,亿格云枢EDR也捕获到诸多木马样本:如XX市场业务部招聘jd&福利“、个人简历docx.rar、VX截图_20240731.exe 、图片文件-XXX公司相关问题咨询20240730.zip....
|
1月前
|
安全 数据安全/隐私保护 Windows
某黑产最新免杀攻击样本详细分析
去年使用“银狐”黑客工具的多个黑产团伙非常活跃,今年这些黑产团伙仍然非常活跃,而且仍然在不断的更新自己的攻击样本,采用各种免杀方式,逃避安全厂商的检测,免杀对抗手法一直在升级。
|
安全 Ubuntu Python
工控CTF_纵横网络靶场_恶意软件样本分析
工控CTF_纵横网络靶场_恶意软件样本分析
工控CTF_纵横网络靶场_恶意软件样本分析
|
Web App开发 开发框架 安全
网络安全实验四 熊猫烧香病毒剖析
网络安全实验四 熊猫烧香病毒剖析
221 0
|
机器学习/深度学习 安全 算法
针对恶意软件分类器的可解释性后门投毒
基于机器学习 (ML) 的恶意软件分类的训练通常依赖于众包威胁源,从而暴露自然攻击注入点。在本文中研究了基于特征的 ML 恶意软件分类器对后门投毒攻击的敏感性,特别关注攻击者无法控制样本标记过程的“干净标签”攻击。建议使用可解释机器学习的技术来指导相关特征和值的选择,从而以与模型无关的方式创建有效的后门触发器。使用多个用于恶意软件分类的参考数据集,包括 Windows PE 文件、PDF 和 Android 应用程序,展示了针对各种机器学习模型的有效攻击,并评估了对攻击者施加的各种约束的影响。为了证明后门攻击在实践中的可行性,为 Windows PE 文件创建了一个水印程序,以保留二进制文件。
123 0
|
安全 API Windows
恶意病毒逆向分析实验1
恶意病毒逆向分析