最近,一位绰号为MalwareTech的研究人员因涉嫌参与创建Kronos银行恶意软件而被捕,他因阻止WannaCry勒索软件而出名。我们仍然不清楚这些指控是否属实——但让我们看看克罗诺斯本身。

出身背景

自2014年6月左右以来,该恶意软件首次在黑市上发布广告,广告由昵称为VinnyK的个人用俄语撰写:

资料来源:https://twitter.com/x0rz/status/893191612662153216

广告全文已翻译成英文,已包含在IBM的安全情报文章

我们发现Kronos通过各种攻击工具传播,例如Sundown(更多信息在这里)。该恶意软件目前正在分发中–最近的一些样本已被销毁一个月前被抓获,从Rig EK空降

如今,Kronos经常被用来下载其他恶意软件由Proofpoint描述

分析样品

2014年的样本:

样本1(自2016年起)

样本2(2017年):

行为分析

运行后,Kronos将自己安装到一个新文件夹中(%APPDATA%/Microsoft/[特定于计算机的GUID]):

被删除的示例有一个隐藏属性。

毅力是在简单的帮助下实现的关键:

在执行开始时,恶意软件修改Firefox配置文件,覆盖user.js具有以下内容:

用户_pref(“network.cookie.cookieBehavior”,0);用户_pref(“privacy.clearOnShutdown.cookies”,false);用户\u pref(“security.warn\u viewing\u mixed”,false);用户\u pref(“security.warn\u viewing\u mixed.show\u once”,false);用户pref(“security.warn\u submit\u unsecurity”,false);用户_pref(“security.warn\u submit\u unsecurity.show\u once”,false);用户_pref(“app.update.auto”,false);用户_pref(“browser.safebrowsing.enabled”,false);用户_pref(“network.http.spdy.enabled”,false);用户_pref(“network.http.spdy.enabled.v3”,false);用户_pref(“network.http.spdy.enabled.v3-1”,false);用户_pref(“network.http.spdy.allow push”,false);用户_pref(“network.http.spdy.coalesce hostnames”,false);用户_pref(“network.http.spdy.enabled.deps”,false);用户_pref(“network.http.spdy.enabled.http2”,false);用户_pref(“network.http.spdy.enabled.http2draft”,false);用户_pref(“network.http.spdy.forced tls profile”,false);用户_pref(“security.csp.enable”,false);

新的设置应该让恶意软件对浏览器的行为有更多的控制,并降低安全设置。然后,恶意软件将自己注入到浏览器中svchost,然后继续从那里逃跑。我们可以发现它正在监听本地套接字。

值得注意的是,Kronos部署了一个简单的用户态rootkit,这会对监视工具隐藏受感染的进程。因此,运行主模块的进程可能不可见。但是,rootkit没有以非常可靠的方式实现,并且隐藏的效果并不总是有效。

每当部署了一些浏览器时。Kronos将其模块注入到那里,并与运行在svchost进程中的主模块连接。查看由特定进程(即使用)建立的TCP连接ProcessExplorer),我们可以看到一个浏览器与受感染的配对svchost

这个技巧经常被银行木马用来从浏览器中窃取数据。在浏览器中注入的模块钩住使用的API并窃取数据。然后,它将这些数据发送给主模块进行进一步处理,并向CnC报告。

网络通信

分析样本通过两个地址连接到CnCs:

http://springalove.at:80/noix/connect.php http://springahate.at:80/noix/connect.php

在分析时,每个CnC都死掉了(陷洞),但我们仍然可以发现这个恶意软件家族的一些典型模式。

首先,恶意软件发送一个74字节长的信标:

接下来是另一组数据:

在这两种情况下,我们都可以看到请求被带有随机字符的XOR混淆。这就是信标在被XOR解码后的样子:

我们可以看到,所有请求都从相同的头开始,包括特定于受感染机器的GUID。

关于解密Kronos通信的详细研究已经被描述在这里

内部

有趣的字符串

与大多数恶意软件一样,Kronos由不同的打包器/密码器进行打包。在解压缩第一层后,我们会得到恶意负载。我们可以通过使用的典型字符串轻松识别Kronos:

此特定恶意软件的典型字符串更多:

这些字符串是用于动态加载特定导入函数的哈希值。恶意软件作者使用这种方法来混淆使用的API函数,并通过这种方式隐藏他们工具的真正使命。它们不是使用函数的显式名称来加载函数,而是枚举特定DLL中的所有导入,计算其名称的哈希值,如果哈希值与硬编码的哈希值匹配,则加载该函数。

尽管这种方法很常见,但在Kronos中看到的实现并不典型。大多数恶意软件以DWORD的形式存储哈希,而Kronos则以字符串的形式存储哈希。

在Kronos的早期示例中,我们可以找到调试符号的路径,显示构建代码的机器上的目录结构(01901882 c4c01625fd2eeecdd7e6745a):

C:\Users\Root\Desktop\kronos\VJF1\Binaries\Release\VJF.1.pdb

PDB路径也可以在DLL中找到(6 c64c708ebe14c9675813bf38bc071cf),属于2014年发行的Kronos:

C:\Users\Root\Downloads\Kronos2\VJF1\Bot\injlib\bin\injlib client Release\injlib-client.pdb

这个模块,injlib-client.dll,是注入到浏览器中的部分。在Kronos的新版本中,可以找到类似的DLL,但是PDB路径被删除了。

注入svchost

Kronos的主要模块将自身注入svchost(2014年版注入探索者相反)。为了实现此初始注入,恶意软件使用已知技术,包括以下步骤:

  1. 创建svchost过程为挂起
  2. 将它的部分映射到它自己的地址空间
  3. 修改部分,添加自己的代码并修补入口点,以便重定向那里的执行
  4. 恢复挂起的进程,让注入的代码执行

下面,您可以看到受感染svchost中的内存(在早期版本中,注入的目标是资源管理器)。该恶意软件被添加到一个新的虚拟区段中——在给定的示例中,映射为0x70000:

这就是svchost的补丁入口点的样子–正如我们所看到的,执行被重定向到位于添加部分(注入恶意软件)内的地址:

注入PE文件的执行现在开始在不同的函数-在RVA 0x11AB0:

恶意软件的原始入口点在RVA 0x12F22:

恶意软件从分析中保护自己,在VM或调试器被检测到的情况下,样本将在注入后不久崩溃。

从新入口点运行示例

恶意软件的主要操作从注入模块内部开始。这是新入口点的外观:

主功能负责加载所有导入,然后部署恶意操作。

若你们是一个试图从那个执行点运行Kronos的分析师,下面你们会发现一些提示。

函数的第一个块负责填充注入模块的导入表。如果我们希望从该点运行样本,而不是在注入时遵循它,那么有一些重要的事情需要注意。首先,加载程序应该填充注入的可执行文件中的一些变量,即变量module_base。其他函数将引用它,因此,如果它不包含有效值,则示例将崩溃。此外,填充导入的函数希望达塔先生(包含要填充的块)设置为可写。在注入样本的情况下,它将设置为可写,因为这样,完整的PE将映射到带有RWX(读写执行)的内存区域中访问权限。但是,在正常情况下,当样本从磁盘运行时,它不是。这就是为什么,为了通过此阶段,我们需要手动更改对节的访问权限。

另一个选项是从主函数的下一个块开始运行Kronos示例。这也会导致成功执行,因为如果示例是从磁盘运行而不是注入,则导入将由windows loader填充,手动执行只是多余的。

要绕过的最后一个问题是防御检查,如下所述。

防守技巧

恶意软件通过进行几次环境检查来部署防御。检查是相当标准的——搜索黑名单程序、模块等。从一个函数内部调用特定的检查序列,结果存储为在专用变量中设置的标志:

如果检测到调试器/VM,则该变量有一个非零值。此外,这个检查的阳性结果被用来使恶意软件崩溃,中断分析。

崩溃是通过采用与部署样本的体系结构不匹配的执行路径实现的。该恶意软件是32位PE文件,但其执行路径稍有不同,具体取决于它是部署在32位还是64位系统上。首先,该恶意软件对系统进行指纹识别,并设置指示体系结构的标志:

DWORD是系统64位({DWORD flag=0;{xor eax,eax mov ax,cs shr eax,5 mov flag,eax};返回标志;}

这个技巧使用了对不同Windows版本的CS注册表的典型值的观察(更多信息)在这里).值得注意的是,它涵盖了大多数情况,但不是所有情况,由于这一点,在某些版本的Windows上,恶意软件可能无法正常运行。
如果检测到调试器/VM,则表明架构正在翻转:

这就是为什么下一次应该采用特定于体系结构的执行路径时,示例会崩溃。

例如,如果示例部署在Wow64下的64位机器上,则可以使用FS:[0xC0]所指向的地址执行系统调用。但是如果恶意软件运行在32位的机器上,FS:[0xC0]所指向的值将是NULL,因此,调用它会导致样本崩溃。

这种中断分析的方式是智能的——在检测到VM/调试器后,样本不会立即退出,这使得找出崩溃的原因变得更加困难。

使用原始系统调用

如前一段所述,Kronos使用原始系统调用。系统调用基本上是指允许从用户模式调用内核实现的某些函数的接口。应用程序通常通过系统DLL导出的API使用它们(详细说明,如。在EvilSocket的博客).

这些API调用可以很容易地被监控工具利用。这就是为什么,一些恶意软件为了更隐蔽,从适当的DLL读取系统调用号,并通过自己的代码调用它们,而不使用DLL作为代理。这个技巧已经被Floki机器人

让我们看看它是如何在Kronos中实现的。首先,它从系统dll中获取适当数量的系统调用。如前所述,函数由其名称的哈希值标识(您可以在Lexsi报告).

例如:

B6F6X4A8R5D3A7C6->NTQUERYSystemination

系统调用的数量存储在变量中,用常量表示。负责从DLL中提取原始系统调用的代码片段:

为了进一步使用它们,对于每个使用过的系统调用,Kronos使用适当数量的参数实现自己的包装器函数。你可以看到下面的例子:

EAX注册表包含系统调用的编号。在给定示例中,它表示以下函数:

00000105 - - - > NtQuerySystemInformation

Kronos使用原始系统调用调用与其他进程注入相关的函数,因为它们通常会触发警报。通过这种方式调用的函数如下所示:

NtAllocateVirtualMemory NtCreateFile NtCreateSection NtGetContextThread NtOpenProcess NtProtectVirtualMemory NtQueryInformationProcess NtQuerySystemInformation NtResumeThread NtSetContextThread NtSetValueKey

它与黑市广告相符,说明:木马使用一种未被发现的注入方法”().

Rootkit和挂钩引擎

恶意软件提供的一个功能是userland rootkit。Kronos钩住进程的API,使它们无法注意到它的存在。钩住是通过一个特制的外壳代码块完成的,该外壳代码块被植入每个可访问的运行进程中。

首先,克罗诺斯准备好要植入的shellcode块。它填满了所有必要的数据:将要使用的函数的地址,以及恶意软件安装的特定数据,这些数据是要隐藏的。

然后,它搜索正在运行的进程,并尽可能地进行注入。有趣的是,资源管理器chrome.exe省略了:

shellcode被部署在受感染进程的新线程中:

下面您可以看到受感染进程内存中的shellocode:

当它运行时,它在受感染进程的地址空间中钩子以下函数:

ZwCreateFile NtOpenFile ZwQueryDirectoryFile ntnumeratevaluekey rtlgetnative系统信息NtSetValueKey ZwDeleteValueKey ZwQueryValueKey NtOpenProcess

关于Kronos的这部分有趣的事情是它与描述的挂钩引擎相似MalwareTech于2015年1月在他的博客上发表了一篇文章.后来他他在推特上抱怨说,网络罪犯窃取并采用了他的代码.看看克罗诺斯的挂钩引擎,我们可以看到很大的重叠,这让我们怀疑克罗诺斯的这一部分可能确实是基于他的想法。然而,事实证明这种技术在更早的时候就被描述过了(即。在这里//多亏了@xorsthings的链接),两位作者都是从其他来源而不是凭空捏造的。

让我们来看看这项技术本身。在挂接期间,可能会遇到并发问题。如果一个半覆盖的函数将开始被另一个线程使用,则应用程序将崩溃。为了避免这种情况,最好通过一条汇编指令安装一个挂接。MalwareTech的引擎用于此目的的是一条指令锁定cmpxch8b。类似的实施可在Kronos中找到。

Kronos使用的钩子函数接受两个参数—要钩子的函数的地址和用作代理的函数的地址。这是被植入shellcode的片段,钩子函数正在被调用:

首先,钩子函数在被攻击函数的代码中搜索合适的位置,钩子可以安装在哪里:

上面的代码相当于下面的代码:

https://github.com/MalwareTech/BasicHook/blob/master/BasicHook/hook.cpp#L103

然后,安装钩子:

如我们所见,使用的安装吊钩的方法几乎与以下相同:

https://github.com/MalwareTech/BasicHook/blob/master/BasicHook/hook.cpp#L77

下面您可以看到Kronos钩住函数的示例ZwResumeThread在记忆中被攻击的过程。指令锁定cmpxch8b确实用于覆盖函数的开头:

安装钩子后,每当被感染的进程调用被钩子的函数时,执行就会被重定向到恶意模块内部的代理代码:

Kronos使用的钩接引擎总体上更复杂。首先,即使它是shellcode而不是PE文件,实现它的难度也会更高。作者必须自己填写所有的函数地址。但同时,《克罗诺斯》的作者在预测可能的现实生活场景方面表现出了更多的经验。例如,他特别注意检查代码是否已经被其他木马或监控工具钩住:

攻击浏览器

恶意软件在浏览器中注入一个额外的模块(injlib-client.dll).下面我们可以看到一个将DLL注入到Firefox地址空间的例子:

恶意软件在注入外壳代码的帮助下启动注入模块:

我们可以看到恶意软件添加的一些API重定向。被攻击的浏览器导入的一些函数被钩住,因此所有通过它们的数据都被Kronos模块点击。

使用钩子浏览器API抓取的数据随后被发送到主模块,该模块负责协调恶意软件的工作并向CnC服务器报告。

结论

对Kronos使用的技巧的全面观察表明,作者在实现恶意软件解决方案方面具有一定的先验知识。代码经过了很好的模糊处理,还使用了各种技巧,需要了解操作系统的一些低级工作。作者不仅使用了有趣的技巧,而且还通过登录将它们连接在一起精确的程度使我们得出这样的假设,即Kronos是一个成熟的开发人员的作品,而不是一个正在试验的年轻人。

必威平台APP用户可以免受Kronos恶意软件的攻击。

附录

概述克朗诺斯银行恶意软件rootkit“莱克西

解密配置

另见:

克罗诺斯恶意软件的内部-第二部分

此视频无法显示,因为您的功能性Cookies目前禁用。

要启用它们,请访问我们的隐私政策然后搜索Cookies部分。选择“单击此处”打开隐私偏好中心并选择“功能性Cookies”在菜单。您可以将选项卡切换回“活动”或通过将选项卡移动到禁用“不活动。”点击“保存设置”。


这是一篇由Hasherezade撰写的客座文章,他是一个对InfoSec有浓厚兴趣的独立研究员和程序员。她喜欢详细了解恶意软件,并与社区共享威胁信息。在推特上查看她@hasherezade以及她的个人博客:https://hshrzd.wordpress.com