导语:还记得WannaCry事件中发现kill-switch,从而阻止了全球10万多台计算机免遭勒索病毒感染的Marcus Hutchins小英雄吗?

1504280411278405.jpg

还记得WannaCry事件中发现kill-switch,从而阻止了全球10万多台计算机免遭勒索病毒感染的Marcus Hutchins小英雄吗?然而,根据日前媒体的报道,美国FBI逮捕了他,原因是他供职于网络安全厂商Kryptos Logic,是Kronos银行木马幕后黑手之一。

根据推特上的记录,他曾在在2014年7月13日发推文寻求银行木马的恶意样本。

04115125_3351.png

Kronos银行木马的背景介绍

自2014年6月以来,Kronos银行木马首次在黑市上出现,并且是以绰号为VinnyK的人以俄语打出的广告:

1.jpg

我发现Kronos是利用各种漏洞套件进行传播的,比如,Sundown漏洞攻击套件,它是目前市场上最新款的漏洞利用工具。截止到目前捕获的样本,利用Rig 套件的数量正在下降。

如今,Kronos经常被用于下载其他Kronos。网络安全公司Proofpoint已经对使用了Kronos作为下载器的攻击活动进行了长时间的跟踪。

分析样本

2014年的样本:

01901882c4c01625fd2eeecdd7e6745a -首次观察到的Kronos样本f085395253a40ce8ca077228c2322010 – 从Lexsi发布的文章中得到的样本

a81ba5f3c22e80c25763fe428c52c758 – Kronos(最终有效载荷)

6c64c708ebe14c9675813bf38bc071cf – injlib-client.dll(Kronos模块)

样本#1(2016年)

2452089b4a9d889f94843430a35fa34f – 封装

9818958e65a0a71e29a2f5e7ffa650ca – Kronos(最终有效载荷)

样本#2(2017年):

de9ab737905e09b69b28dc0999d08894 – 封装

4f5006835669d72c6ce121e66b3034d7  – 装载机(第二阶段)

b8986fe9e40f613804aee29b34896707 – Kronos(最终有效载荷)

cb7e33e5ede49301e7cd9218addd5c29 – DLL模块

行为分析

运行后,Kronos自己会安装在一个新的文件夹中(%APPDATA%/ Microsoft或,即计算机的GUID号):

2.png

这些样本所具有的持久性攻击属性,是通过简单的Run键来实现的:3.png

在攻击活动开始时,Kronos会修改Firefox配置文件,并覆盖具有以下内容的user.js:

4.png

重新修改候的设置应该能够使Kronos更好地控制浏览器的行为并降低安全设置,然后,Kronos自动注入到svchost中,并从那里继续运行。我可以在本地socket中找到它。

值得注意的是,Kronos部署了一个简单的用户名rootkit,它将被感染的进程从监视工具中隐藏起来。因此,运行主模块的进程是不可见的。然而,rootkit的实现不是很稳定,并且隐藏的效果并不明显。

每当针对浏览器进行攻击时,Kronos便会将模块注入其中,并与主模块连接,使其在svchost进程内运行。查看由特定进程(即使用Process浏览器)建立的TCP连接,我可以看到浏览器与受感染的svchost之间的关系:

5.png

Kronos经常使用这个技巧来窃取浏览器中的数据,在浏览器中注入的模块,会hook所使用的API并窃取数据。之后,将该数据发送到进一步处理的主模块,并向命令与控制服务器报告。

网络通信

分析的样本连接到两个不同地址的命令与控制服务器:

6.png

虽然,在分析时,每个命令与控制服务器的地址都无法打开了,但是我仍然可以发现Kronos家族的典型通信模式。

7.png

首先,该Kronos发送长度为74字节的信标:

8.png

然后,出现大量数据:

9.png

在这两种情况下,我可以看到请求被随机字符XOR混淆。

10.png

我可以看到所有的请求都是从相同的头文件开始的,包括特定感染设备的GUID。

关于解密Kronos通信的详细研究,请点击这里

有趣的字符串

像大多数Kronos一样,Kronos是由各种封packers/crypters分布式封装。打开第一层封装后,我得到恶意的有效载荷。我可以通过典型的字符串轻松识别Kronos:

11.png

其中特定的Kronos会有更多类似的字符串:

12.png

这些字符串是用于动态加载特定导入函数的哈希值,也就是说,Kronos开发者会使用这种方法来模糊使用的API函数,并通过这种方式隐藏其工具的恶意目的。它们一开始,会使用其表面显示的名称来加载函数,枚举特定DLL中的所有导入,计算其名称的哈希值,如果哈希与硬编码匹配,则它们便会加载该函数。

尽管这种做法很常见,但大多数Kronos是以DWORD形式存储这些哈希值的,只有Kronos将会将它们存储为字符串。

在Kronos的早期样本中,我可以找到调试符号的路径,从而为你揭示构建代码的目录结构。从野外观察到的一个Kronos样本(01901882c4c01625fd2eeecdd7e6745a)中提取以下路径:

13.png

PDB文件路径也可以从属于2014年Kronos发行版的DLL(6c64c708ebe14c9675813bf38bc071cf)中找到:

14.png

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

注入svchost

Kronos的主要模块注入到svchost中(从2014版本开始注入到浏览器中)。为了实现这种初始注入,Kronos使用了包括以下4个步骤:

1.把svchost进程创建为暂停;

2.将部分暂停映射到地址空间中;

3.修改映射的部分,添加Kronos的代码并修复入口点,以便重定向执行;

4.恢复暂停的进程,让注入的代码执行。

如下图所示,你可以看到被感染的svchost内的内存(在早期版本中,注入是针对浏览器)。Kronos被添加到一个新的虚拟部分,在我所给的示例中,映射为0x70000:

15.png

以上就是svchost的修复入口点,你可以看到,执行被重定向到添加部分(注入的Kronos)内的地址:

16.png

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

17.png

Kronos的原始入口点为RVA 0x12F22:

18.png

不过,Kronos为了防止自己被分析,会在检测到VM或调试器的情况下,自行把进程停止。

从新的入口点运行

Kronos的主要操作是在注入模块内部启动,以下就是新入口点:

19.png

主要的函数负责加载所有导入,然后部署恶意进程。

20.png

函数的第一部分代码块负责填写注入模块的导入表,如果你想要选择从新入口点运行样本,而不是在注入后运行,则需要注意的是,装载器应该在注入的可执行文件中填充一些变量,即变量module_base。其他函数也将利用该变量,所以如果文件中没有有效的填充变量,则样本运行将会崩溃。此外,填充导入的函数将.rdata(包含要填充的块)部分设置为可写。在注入的情况下,将被设置为可写入,因为完整的PE被映射到具有RWX访问权限的存储器区域中。但是,在正常情况下,样本是从磁盘运行的。这就是为什么我需要告诉你要手动修改该部分访问权限的原因。

除了上述运行办法之外,另一个方法是从主函数的下一个代码块开始运行Kronos样本。因为如果样本在没有注入的情况下,是从磁盘运行的,则导入过程将由Windows加载程序填充,手动执行变成多余的了。

现在,要做的就是如何绕过各种安全防护的检测。

绕过各种安全防护的检测

Kronos会通过进行多次环境检查来检测运行环境,这些检查包括:搜索黑名单的进程,模块等。这一系列的检查都会从一个函数内部调用,检测结果会设置为专用标志进行保存。

21.png

如果检测到调试器或VM,则该变量就具有非零值。此外,Kronos的开发者会利用环境检测的结果进行崩溃分析和更新升级。

在对样本崩溃日志进行分析之后,我发现Kronos是一个32位的PE文件,但它具有不同的执行路径,这取决于它是否部署在32位或64位系统上。首先,Kronos的指纹系统会设置指向系统架构的标志:

22.png

不过要注意的是,在某些版本的Windows上,Kronos可能无法正常运行。

如果检测到调试器或VM,则表示架构的标志就会发生变化:

23.png

这就是为什么样本在下一个环境中崩溃时,应该采取体系结构特定的执行路径。

例如,如果样本部署在64位设备上,则在WOW64下,可以使用FS指定的地址([0xC0])执行系统调用。但如果Kronos在32位计算机上运行,则FS指示的值为[0xC0]将为NULL,因此调用它将导致样本崩溃。

24.png

由此可见,Kronos的这种中断分析的方法是非常聪明的,在检测到VM或调试器之后,样本不会立即退出运行,这样就使得安全分析员更难找出崩溃的原因。

使用原始系统调用

如上所述,Kronos使用原始系统调用。Syscall基本上意味着允许从用户模式调用的内核实现的一些函数,应用程序通常通过系统DLL导出的API来使用它们。

这些API调用可以轻松地通过监视工具被检测到,这就是为什么在不使用该DLL作为代理的情况下,一些Kronos为了偷偷读取DLL中的系统调用数字,目前,该技巧已经被Floki bot银行木马使用了。

现在,让我来看看它是如何在Kronos中实现的。首先,它从系统DLL中获取适当数量的系统调用。如前所述,函数会通过其名称的哈希值来标识。

25.png

例如:

QQ截图20170901234955.png

系统调用的数字会存储在变量中,用常数填充,负责从DLL中提取原始系统调用的代码片段如下:

26.png

为了进一步使用它们,对于每一个使用过的系统调用程序,Kronos都会使用适当数量的参数来将其变为封装函数( wrapper function )。你可以看到以下示例:

syscall_interface.png

EAX注册表包含系统调用的编号,在所举的例子中,它代表以下函数:

28.png

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

29.png

Rootkit和hook engine 

Kronos提供的恶意功能之一便是用户级rootkit。Kronos hook进程的API,以便进行隐藏。hook是通过一个特制的shellcode块来实现的,这些shellcode块会被植入每个可访问的运行过程中。

首先,Kronos会准备好要植入的shellcode块。它将填写所有必要的数据,比如,要使用的函数的地址等。

然后,它会搜索正在运行的进程,并尽可能地进行注入。有趣的是,explorer.exe和chrome.exe会被自动忽略:

30.png

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

31.png

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

32.png

运行时,它会将以下函数hook在受感染进程的地址空间中:

33.png

在hook时,可能会遇到并发问题。如果一个半覆盖( half-overwritten)的函数则将被另一个线程使用,这样应用程序也将崩溃。为了避免这种情况,最好通过单个汇编指令来安装hook。

Kronos使用的hook函数有两个参数,分别是要hook的函数地址以及用作代理的函数地址。以下就是植入的部分shellcode,其中hook函数被调用:

34.png

首先,hook函数可以在攻击的函数的代码中搜索合适的位置,其中可以安装hook:

35.png

要得到以上代码,请点击以下链接:

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

然后,安装hook:

36.png

我可以看到,安装hook的方法几乎与以下的方法相同:

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

下面你会看到一个Kronos的例子,该函数在被攻击的进程内存中会绑定一个函数ZwResumeThread。

37.png

hook安装后,每当受感染的进程调用hook的函数时,执行将重定向到恶意模块中的代理代码:

38.png

Kronos使用的hook engine会更加复杂,首先,它是一个shellcode而不是一个PE文件,实现它的难度很高。开发者必须自己填写所有的函数地址。而且,Kronos的开发者在预测可能的攻击环境时也很有经验。例如,他们会非常小心检查代码是否有hook(即由其他木马或监控工具):

39.png

攻击浏览器

Kronos会将一个额外的模块(injlib-client.dll)注入浏览器。下面你可以看到一个注入到Firefox地址空间的DLL的例子:

40.png

Kronos在注入的shellcode的帮助下启动注入的模块:

41.png

可以看到,Kronos添加的API被重定向。注入到受攻击的浏览器的一些函数被hook,以便通过浏览器的所有数据被Kronos监控,然后将使用hook浏览器API抓取的数据发送到主模块。

读到这里,我想你已经了解了Kronos的安装过程,并解释了Kronos为了保持更隐身而使用的技术细节。现在我将继续介绍Kronos可以执行的恶意行为。

分析样本

ede01f7431543c1fef546f8e1d693a85 – 下载器(恶意宏.doc)

2a550956263a22991c34f076f3160b49 – 主机(封装)

配置和攻击目标

为了启用和配置银行木马的功能,攻击者可以从其命令与控制服务器附加配置文件下载。被下载后,Kronos会以加密形式存储在安装文件夹中。不过要注意的是,当通过网络发送配置时,它将使用AES CBC模式进行加密,不过当它存储在磁盘上时,将使用ECB模式的AES。

下面你可以看到在%APPDATA%/Microsoft中创建的Kronos的安装文件夹示例,文件夹名称进一步用作BotId。存储的文件,可执行文件和配置都具有与扩展名不同的名称:

1.png

点击以下链接,你就可以查看捕获的配置文件:

https://gist.github.com/malwarezone/d6de3d53395849123596f5d9e68fe3a3#file-config-txt

配置文件会出现在目标网站中注入的外部脚本以及注入位置,以下你可以看到一个示例目标的部分配置(以富国银行为例):

2.png

在以上例子中,注入的脚本是figrabber.js,它被托管在攻击者的后台服务器上:

3.png

目前的配置主要针对几家世界大型银行,除此以外,还窃取了Google,Twitter和Facebook等流行服务的凭据。

事实上,如果我打开Kronos所攻击的目标网站,就可以看到注入已被执行。在配置中定义的代码片段会被植入合法网站的源代码中。

Facebook的例子:

4.png

花旗银行的例子:

5.png

注入的脚本负责打开额外的弹出窗口,该弹出窗口正在尝试欺骗用户并窃取用户的隐私数据:

6.png

富国银行的例子:

7.png

8.png

更多的案例以及感染前后网站的比较,会在以下视频中展示:

该表单是自定义的,以适应每个页面的主题。但是,其内容对于每个目标都是一样的。总的来说,这次攻击并不十分复杂,甚至有分析家认为它就是基于社会工程的攻击,比如,它试图说服用户输入银行的登录信息:

10.png

下载

除了感染浏览器和窃取数据外,Kronos还具有下载功能。在我的测试实验中,检测样本还下载了一个新的可执行文件,并将其保存在%TEMP%中。有效载荷存储在与主安装目录相同名称的附加目录中:

11.png

已下载的有效载荷:6f7f79dd2a2bf58ba08d03c64ead5ced – nCBngA.exe

有效载荷会从Kronos命令与控制服务器下载:

12.png

而且是以未加密的形式:

13.png

命令与控制服务器

在以上分析的样品中,Kronos使用Fast-Flux技术作为其命令与控制服务器。域名每次都被解析成不同的IP,例如,域hjbkjbhkjhbkjhl.info就被解析出来的IP地址就是从下面中随机选择的:

14.png

在观察命令与控制服务器的通信时,我注意到对connect.php的网站的查询,并附有可选参数a:

15.png

命令与控制服务器控制面板

像大多数恶意软件的控制面板一样,Kronos面板也是使用PHP编写的,并使用的是MySQL数据库。

16.png

事实证明,恶意控制功能的程序代码总共有三个命令:

a = 0 – 发送抓取的页面内容

a = 1 – 获取配置文件

a = 2 – 发送记录的窗口

下面我可以看到面板代码的相关片段(在connect.php中实现),负责解析和存储相应命令上传的数据。

命令#0(a = 0):

17.png

命令#2(a = 2):

18.png

发送到恶意程序的配置由以下代码组成:

命令#1(a = 1):

19.png

我还可以非常清楚地看到配置如何加密,在CBC模式下使用AES,其关键是BotId的md5的前16个字节。

20.png

然而,AES并不是Kronos所使用的唯一加密算法。其他命令在ECB模式下使用Blowfish算法:

命令#0(a = 0):

21.png

命令#2(a = 2):

22.png

在所有情况下,都有一个名为UniqueId的变量,用它来用作为密钥。UniqueId不过是BotId,它是在每个POST请求中以XOR编码形式发送的。

23.png

你可以在以下链接中找到相应的Python脚本来解码相应的请求和响应:

https://github.com/hasherezade/malware_analysis/tree/master/kronos

Kronos还可以添加一些插件,扩展核心功能:

24.png

由此我得出了一个结论,插件能够扩展具有一些间谍功能的Kronos,例如VNC(用于查看桌面)和键盘记录。

解密通信

现在,我就可以解密Kronos bot和命令与控制服务器之间的通信了,不过前提是,我有一个具有捕获流量的PCAP文件。

BotId

我需要从获取Kronos的BotId开始,因为只有用它来导出密钥。我会在恶意程序发送给其命令与控制服务器(74字节长)的请求中找到它:

25.png

转储请求后,我可以使用以下脚本对其进行解码:

26.png

输出时,我将得到解码的信标,包括:

1.配置文件的哈希值(如果目前没有配置文件,这部分将填写“X”字符)

2.BotId

例如:

27.png

因此,在此种情况下,BotId是{117BB161-6479-4624-858B-4D2CE81593A2}。

配置

现在,我已拥有了BotId,就可以用它来解密配置。a = 1请求的响应如下:

28.png

来自命令与控制服务器的响应被加密后的请求示例:

29.png

在转储响应之后,我可以使用另一个脚本进行解码,把BotId作为参数:

30.png

这样,我将得到配置文件。解码配置示例的链接如下:

https://gist.github.com/malwarezone/a7fc13d4142da0c6a67b5e575156c720#file-config-txt

发送报告

有时我可以在请求中找到命令与控制服务器以 a = 0或a = 2的响应报告:

31.png

加密请求的示例:

32.png

如果我转储数据并使用专用脚本,找出Kronos窃取的数据并不是很困难:

33.png

解码报告示例的链接如下:

https://gist.github.com/malwarezone/a03fa49de475dfbdb7c499ff2bbb3314#file-a0_req-txt

总结

综上所述,在代码性能方面,Kronos并没有什么神奇之处。但恶意程序所体现的攻击功能却是非常受黑客的欢迎。 

源链接

Hacking more

...