【技术分享】带有加载保护机制的新型Neutrino僵尸程序

https://p2.ssl.qhimg.com/t01b49ef20d8254ebb5.jpg

翻译:興趣使然的小胃

预估稿费:200RMB(不服你也来投稿啊!)

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

本文将分析多功能Neutrino僵尸程序(也叫Kasidet)的一个最新版本,该程序通过以它命名的利用工具包(Neutrino Exploit Kit)进行分发。今年一月份时,我们已经大概描述了利用垃圾邮件传播的Neutrino僵尸程序,因此我们不会过多讨论这些细节,而会将重点放在它的程序加载部分。

程序使用多层虚拟机检测技术对其关键核心进行了隐藏,导致我们对其最终载荷的提取工作遇到了些许挑战。


一、分发机制

程序样本从美国的恶意广告活动中捕获,这些活动使用了Neutrino Exploit Kit进行恶意程序分发。恶意程序在受害主机上首先会进行指纹检测,探测虚拟化环境,捕获网络流量以及检查反病毒软件。如果程序发现所处环境异常(即不是典型的受害主机),则放弃感染过程。程序使用落地前页面中的大量混淆的JavaScript代码完成这一检查过程,而不是使用以往的Flash检测方法

pre-landing.png

程序初始检查通过后,下一步骤是启动一个特制的Flash文件,其中包含一系列的Internet Explorer和Flash Player漏洞利用工具(参考这里的相关介绍)。最后一步是使用wscript.exe下载和执行经过RC4编码的载荷,以绕过代理网络限制。

总体感染流程如下所示:

Neutrino_EK-flow.png

Maciej Kotowicz写了一个脚本,可以提取Flash文件中的功能组件。


二、分析的样本及哈希值

Neutrino Exploit Kit释放的原始样本:b2be7836cd3edf838ca9c409ab92b36d

加载器:349f5eb7c421ed49f9a260d17d4205d3

载荷(即Neutrino僵尸程序):6239963eeda5df72995ad83dd4dedb18


三、行为分析

样本采取了保护机制以防止在受控环境中投放。当样本探测到其运行在虚拟机或沙箱中时会进行自删除操作。

ping_and_delete.png

环境检测通过后,程序将副本拷贝到%APPDATA%/Y1ViUVZZXQxx/<random_name>.exe(本文中为abgrcnq.exe,uu.exe):

dropped.png

同时对释放的文件夹及文件进行隐藏。

样本通过计划任务完成本地持久化。

sched_task1.png

样本修改添加了几个注册表键值,如安装日期等基本设置信息:

properties.png

对几个键值进行修改,以在系统里保持隐藏性。注册表中的Hidden及SuperHidden功能可以使程序副本对用户保持隐藏。样本通过修改以下注册表项达到文件的隐藏性:

SoftwareMicrosoftWindowsCurrentVersionExplorerAdvancedHidden
SoftwareMicrosoftWindowsCurrentVersionExplorerAdvancedShowSuperHidden

样本利用命令将自身添加到防火墙白名单中:

cmd.exe " /a /c netsh advfirewall firewall add rule name="Y1ViUVZZXQxx" dir=in action=allow program=[full_executable_path]

与此类似,样本也将自身路径添加到Windows Defender的例外文件列表中:

exclusions.png

样本对终端服务设置表项进行修改,将MaxDisconnectionTime及MaxIdleTime值设为0,受影响表项为:

HKLMSOFTWAREPoliciesMicrosoftWindows NTTerminal ServicesMaxDisconnectionTimeHKLMSOFTWAREPoliciesMicrosoftWindows NTTerminal ServicesMaxIdleTime

如果安装过程一切顺利,样本将加载其核心部件,我们也可以观察到典型的Neutrino僵尸网络流量特征,比如下图中,经过base64编码的“enter”请求报文及“success”响应报文特征。响应包以注释形式嵌入到空白html页面中,避免引起用户警觉。

enter_success.png

程序发送自身信息作为下一个请求,而C2C服务器则会返回程序下一步要执行的命令。请求及响应报文也经过base64进行编码。解码后的一个示例为:

请求报文:

cmd&9bc67713-9390-4bcd-9811-36457b704c9c&TESTMACHINE&Windows%207%20(32-bit)&0&N%2FA&5.2&22.02.2017&NONE

响应报文:

1463020066516169#screenshot#1469100096882000#botkiller#1481642022438251#rate 15#

响应报文中,第一个命令是截屏命令,之后我们的确看到程序发送了一张JPG格式的屏幕截图:

enc_screenshot.png

从发送报文中我们可知程序版本为5.2版(与这篇文章分析的类似:https://blog.malwarebytes.com/cybercrime/2017/01/post-holiday-spam-campaign-delivers-neutrino-bot/)


四、深入分析

程序使用的第一层是加密器层,用于覆盖内存中加载器映像的初始PE结构,可参考这里的相关解密视频

第二层是个加载器层,防止核心程序在受控环境中(如虚拟机或调试器环境)运行。这可能是它新使用的一个功能(我们从未在之前的Neturino僵尸网中观察到)。我们发现这一层非常有效,测试期间大多数沙箱和虚拟机环境无法提供该样本的任何有用信息。

最后一层是Neutrino僵尸家族的典型功能载荷层。

从加载器代码中可知,它并非依附于独立加密器的一层,而是完整Neutrino僵尸包中的一个集成部分。载荷层和加载器层都采用C++进行开发,使用类似的函数,包含重叠的字符串,本文后半部分将就此进行详细分析。这两层的编译时间戳非常接近,分别为2017-02-16 17:15:43和2017-02-16 17:15:52。

可以在这里找到禁用环境检查功能的加载器修复版。


五、加载器分析

5.1 混淆技术

代码包含了基层混淆技术,几个可见的字符串如下所示:

open_strings.png

字符串中包含目录名、一些函数名、准备禁用的与Windows安全功能相关的注册表键值、计划任务中要添加的字符串。

大多数字符串在运行时进行解密,以下是一个加密字符串的加载过程:

enc_str1.png

程序首先使用专用函数将混淆字符串写入动态加载的内存中,然后使用简单的异或方法进行解密:

def decode(data):
    maxlen = len(data)
    decoded = bytearray()
    for i in range(0, maxlen):
        dec = data[i] ^ 1
        decoded.append(dec) 
    return decoded

解密后的字符串为:

decrypting_proc.png

大多数API调用同样也经过了动态解析处理,如:

load_func.png

跟踪API调用可以理解程序的功能,因此样本的作者不使用某些API,而是自己实现了这些函数功能。比如,作者通过读取底层线程环境块(Thread Envioroment Block,TEB)结构实现了GetLastError()的功能:

get_last_err.png

5.2 功能分析

加载器创建了一个互斥量(mutex)以避免重复执行,mutex名为1ViUVZZXQxx,硬编码在样本文件中。

加载器的主要任务是环境检查,以确保软件运行不受监视。与大多数恶意软件不同,环境检查工作不是只执行一次,而是有一个专门线程负责这项工作:

env_check.png

它在死循环中不断重复这一工作:

checking_loop.png

如果程序在任一时刻检测到某些位于黑名单中的进程,则会终止自身执行。

典型的检查过程如下:

1. 枚举当前运行的进程列表(使用动态加载CreateToolhelp32Snapshot、Process32First、Process32Next函数完成)。计算每个进程名的校验和,与内置的进程黑名单进行比较。

search_process-1.png

校验和黑名单如下:

0x6169078A
0x47000343
0xC608982D
0x46EE4F10
0xF6EC4B30
0xB1CBC652 ; vboxservice.exe
0x6D3E6FDD ; vboxtray.exe
0x583EB7E8
0xC03EAA65

黑名单进程的枚举实现代码如下图所示。从中可知每个函数都在对应校验和下动态加载执行:

enc_searching_blacklisted.png

2. 在当前进程中搜索黑名单中的模块(使用动态加载CreateToolhelp32Snapshot、Module32First、Module32Next函数完成)。类似地,程序计算每个进程名的校验和并与内置黑名单进行比较。

校验和计算算法为(详细的实现在此):

calc_checksum.png

校验和黑名单为:

0x1C669D6A
0xC2F56A18
0xC106E17B
0x5608BCC4
0x6512F9D0
0xC604D52A
0x4D0651A5
0xAC12B9FB ; sbiedll.dll
0x5B747561
0x53309C85
0xE53ED522

3. 使用IsDebuggerPresent、CheckRemoteDebuggerPresent判断程序是否正被调试。

4. 使用GetTickCount、Sleep、GetTickCount进行单步执行时间检测。

5. 使用QueryDosDevices(如VBoxGuest)检测黑名单设备,判断是否处于虚拟环境中。

6. 使用EnumWindows、GetClassName(如procexpl)检查并隐藏黑名单程序窗口。

search_window-498x600.png

校验和黑名单为:

0xFE9EA0D5
0x6689BB92
0x3C5FF312 ; procexpl
0x9B5A88D9 ; procmon_window_class
0x4B4576B5
0xAED304FC
0x225FD98F
0x6D3FA1CA
0xCF388E01
0xD486D951
0x39177889

另一个线程中,样本执行与bot安装的相关操作,如在计划任务中添加任务、往防火墙中添加例外等。

最后,样本释放并使用PE运行方法启动最终载荷。首先,它创建自身的另一个实例:

run_pe.png

其次,在同一位置映射一个新的PE文件:

loading_new_pe.png

5.3 载荷分析

有效载荷就是一个Neutrino僵尸程序,其功能与我们先前文章中分析的非常类似,我们可以在加载器中找到某些类似的元素,比如下图中的字符串:

matching_strings.png


六、结论

Neutrino僵尸程序已经风行好几年,它功能丰富,但内部结构则让人印象平平。本文分析的Neutrino僵尸程序同样如此,恶意软件作者没有对程序的结构做任何显著的改进,但他们为程序添加了一个保护层,可以对运行环境做极其严格的指纹检测,避免程序被轻易探测到。


(完)