介绍
几天前,Cybaze-Yoroi ZLAB团队遇到了一个十分“异类”的Office文档,它当中包含的一些特性引起了研究人员的兴趣。文档中携带的payload能绕过Microsoft现今一些高级别的安全机制,如AppLocker(应用程序控制策略),或是较新版本的防恶意软件扫描接口AMSI——这是一个与供应商无关的安全接口,可以对运行的脚本、宏代码甚至内存块进行反病毒控制,旨在解决混淆和无文件威胁。
因此,Cybaze-Yoroi ZLAB决定对检测样本进行更进一步的分析。
技术分析
表1.样本信息
初始文档界面如下图所示,表面上是提示用户启用宏以显示文档的实际内容,实际上感染链已在后台悄悄启动。
图1.初始文档界面
几秒钟后,将显示一个弹出窗口,提示文档解密失败,然后自动关闭Word文档。
此时,不知情的受害者可能认为文档有问题,什么都没有发生,但实际上恶意软件已经在秘密潜入的过程中了。仔细看,会注意到文档左侧小框中的可疑字符块:
图2.弹出窗口
图3.放大后的字符串
名为“Kplkaaaaaaaz”的框中包含一个base64编码的payload,由宏执行提取并分配给“dopzekaoooooooo”变量,它将用于填充下一阶段的bat文件。这种将部分payload放置在Word Label或单元格对象中的技术,能隐藏代码并将更多代码直接嵌入攻击向量中,从而降低被检测的风险。
此外,恶意软件采用了一种逃避技术来确定它是否在沙箱环境中执行。它会检查机器的域名是否与计算机的名称相同,如果此条件成立,则先前的“Kplkaaaaaaaz”变量将设置为以下文字:“此文档中已包含VBA。”,并让感染链停止。此项技术可以绕过所有主要的沙箱服务,如Any.run和Hybrid Analysis。
图4.混淆的宏代码
在反混淆阶段之后,恶意软件的行为将显现。“%temp%\ errors.bat”脚本中包含了需要执行的下一个操作,并由存储在%appdata%文件夹中的“cmd.exe”副本执行,该副本名为“msutil.exe”。
图5.反混淆的宏函数
上面的代码是弹出窗口的指令(图2),这是一个简单的Visual Basic MsgBox。与大多数恶意软件不同之处在于,该恶意软件使用了另一种技术在文档打开时自动启动宏代码:它不使用Workbook_Open或Auto_Open函数,而是利用Word InkEdit对象来调用InkEdit1_GotFocus函数,该函数会在InkEdit1(图1)显示时立即生效。
“errors.bat”文件中包含一个Base64编码的powershell脚本,它能关闭初始Word文档的进程并将原文件从文件系统中删除。而该脚本对系统上可用的内存量的检测则展示了另一种规避技术——如果检测到可用内存小于1 GB,则恶意软件会终止执行并删除所有感染痕迹。
图6.启动宏的函数
图7.“errors.bat”文件中的Powershell代码
对可用内存的检查是通过CIM(公共信息模型)服务器实例完成的。奇怪的是,此cmdlet的返回值被分配给名为“diskSizeGB”的变量,即使该函数返回的是可用RAM的数量而不是磁盘的数量(这可能是作者犯的错误)。
在评估了前面的条件之后,BAT文件会继续设置一个新的注册表项,以受害者的用户名命名,并在其中存储一个随机值。
随机值是创建新的TXT文件所必需的,该文件将填充base64的payload。 然后使用“certutil”Windows实用程序解码文件内容,最后使用以下指令执行:
start /b regsvr32 /u /n /s /i:%appdata%\9711.txt scrobj.dll
图8.恶意软件设置的RegKey
这种技术被称为“Squiblydoo”,它能绕过Windows AppLocker。AppLocker是微软Windows 7操作系统引入的应用程序白名单技术,可以限制用户可以通过组策略执行哪些程序,就好比企业管理员可以在企业域的每台机器上禁用脚本执行。因此,使用该技术可以启动任何脚本。
绕过技术的基本部分是“scrobj.dll”,属于Windows Utility DLL。它能够使用脚本语言(如VBScript和JScript)创建COM组件。而图8中的“9711.txt”则是能生成新的COM对象的脚本文件,它能使用“regsvr32”实用程序进行注册。
图9. Squiblydoo技术中使用的脚本文件
显然,这段代码也经过混淆,但使用JScript解释器可以提取一些有趣的证据。
图10.通过Squiblydoo执行的ActiveXObject
刚刚创建的ActiveXObject使用先前存储的随机值将恶意软件持久性设置为HKCU \\ Environment \\ UserInitMprLogonScript,以便在登录时启动恶意操作。
图11.恶意软件持久性
之后,恶意软件将启动一个新的混淆Powershell脚本,如下所示:
图12.最终payload含有Empire stager
恶意软件在此阶段展示了一种避免沙箱分析长时间等待(超过5分钟)的逃避技术。它会检查操作系统版本,并从“hxxp://riscomponents[.]pw/test[.]txt”处检索相应代码,而检索出的Powershell指令用于绕过反软件扫描接口(AMSI)。
AMSI是一种通用的接口标准,它能让应用程序或服务与计算机上任意反恶意软件产品集成。它主要是为了帮助两类人:一是希望能从应用程序向反恶意软件发出请求的开发人员,二是希望其产品能直接向应用程序提供功能的反病毒软件开发商。此外,AMSI在默认情况下会集成到一些Win10组件中,比如用户帐户控制(UAC)、PowerShell、Windows Script Host、JavaScript、VBScript和Office VBA。在代码彻底去混淆后,它能在代码执行之前对其评估。
不过,当前网上也有几种AMSI绕过的方法,其中一些只需要几行代码就可以了,就如同我们在分析中发现的那样:
图13.恶意软件使用的AMSI绕过代码
对此段代码检索后发现其属于“amsi.dll”系统库的AmsiScanBuffer函数的内存地址,在缓冲区{0xB8,0x57,0x00,0x07,0x80,0xC3}重写其部分字节,就能永久禁用AMSI扫描功能。攻击者可能借鉴了网上一个现成的脚本,该脚本用C#编写。如下图所示,恶意软件使用的代码段与此脚本中某些代码段几乎相同:
图14. Github上提供的绕过AMSI的代码段
在剩余代码中,我们发现其目标是从位于hxxps://185.198.57[.]142/admin/login.php的C2服务器中检索需要执行的新命令。通过分析下载指令所涉及到的脚本后发现,它似乎是Empire powershell stager,正如SANS在其论文的一些案例所示。然而,在我们分析期间,服务器却宕机了,无法进行进一步调查。
考虑到恶意软件的复杂性,我们将其感染流程做了简要的划分,如下图所示。
图15.恶意软件感染方案
结论
攻击者使用了多种规避技术并将之组合,成功设计出了一个能绕过现代Windows系统中诸如AppLocker和AMSI等高级安全机制的方案,让攻击匿于无形之中。面对层出不穷的攻击手段,此次行动也再一次为当前Windows系统的安全机制敲响了警钟。
IOCs
Dropurl:
· hxxp://riscomponents[.]pw/
· hxxp://riscomponents[.]pw/test[.]txt
· 185.198.57.142:443
· https://185.198.57.142/admin/login.php
Persistence:
· regsvr32 /u /n /s /i:C:\Users\admin\AppData\Roaming\%filename%.txt scrobj.dll
· HKCU\Software\Microsoft\Notepad\%username%
Hash:
· 127e9f68f0f97d6dafe55ad651f5b3c0f6a7b504b9b4b4d9aecc1f2141347447
· 3170e1504a914376442766b02633252e364aa75fc9b891598c6fac9389c1723c
· 5a87604a53f13a2afe5b760dac115af9ca028c15e853c74f9ad2e8f2c64d3bb8
Yara Rules
rule doc_macro_14_03_2019{
meta:
description = "Yara Rule for doc_macro sample"
author = "Cybaze Zlab_Yoroi"
last_updated = "2019_03_14"
tlp = "white"
category = "informational"
strings:
$a = {3C F1 6E 56 75 4A 2C 87 98}
$b = {10 5A AC FA 32 0E 0E 03 81 6A 23 10}
$c = "MDFLYUhadFpFaFFh"
$d = "InkEdit"
$e = "373035373536363"
condition:
all of them
}
rule App_Locker_Bypass_14_03_2019{
meta:
description = "Yara Rule for App_Locker_Bypass sample"
author = "Cybaze Zlab_Yoroi"
last_updated = "2019_03_14"
tlp = "white"
category = "informational"
strings:
$a = "'ht'+'tp:/'+'/riscomp'+'"
$b = "'185.'+'198.'+'57.142:443'"
$c = "BXOR"
$d = "session='+'55pN'+'RTeT'"
condition:
all of them
}