首页
社区
课程
招聘
[原创]MuddyWater(污水) APT组织针对塔吉克斯坦的攻击活动的分析
发表于: 2019-7-7 11:53 11345

[原创]MuddyWater(污水) APT组织针对塔吉克斯坦的攻击活动的分析

2019-7-7 11:53
11345

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载荷以进行侦查和后门的活动。

诱饵文档截图如下:

1

2

3

文档中的语言为塔吉克语,通过内容以及诱饵文档的名称可以大致推断出其目标针对的是塔吉克斯坦政府的采购部门

4

5

其文档的图标正是塔吉克斯塔政府的图标,故此MuddyWater这次攻击的目标基本上确定

6

Document_Open函数:frmLoader.show 加载并显示宏项目里内置的窗口

6

笔者猜想应该是在窗口里要么通过点击按钮进行载荷植入要么通过关闭窗口进行载荷植入
所以我们顺藤摸瓜定位到窗口处理的函数:

函数buttonQWERTY_Click()调用函数RgSh(id)并传入参数7
frmVisualizer.Show 加载frmVisualizer窗口并弹出
Unload Me 卸载本窗口

7

首先会调用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

8

这里面引入了两个新的函数,一个为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

9

这个fisa()函数后面会说到 但是归根结底其实就是返回scripting.filesystemobject这个字符串

传入参数的id数字与5进行取余,其实就是id的数字,因为case的方案里面,最高的数字为5

10

传入参数的id数字与5进行取余,其实就是id的数字,因为case的方案里面,因为最高的数字为5

11

那我们回到PuSH(id)函数中

通过读取frmlodr窗口中得label控件(14,15)以拼接好字符串scripting.filesystemobject

并且将这段字符串返回

12

至此宏代码中的主要函数功能已经分析完毕

其最主要的功能为:释放VBE Loader于%temp%\aulmgr.vbe下,将该文件通过修改注册表写入开机启动

样本截图如下(挺乱码的):

13

scrdec或者Decode VBE工具进行解密

摘取主要的VBS代码进行分析:

如图:VBE文件内置的b字符串(pwershell第一阶段的代码)

14

其主要内容为提取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中的数据

15

注意:笔者并没有去掉变量名和函数名混淆,所以其会有一些难懂,请结合图文进行理解

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命令

16

17

功能1:收集系统信息

获取当前用户名称 如下图 函数名:lTXxzy53

通过获取环境变量%username%来获取当前用户名称,如果失败返回error username字符串

18

获取用户所在域的名称 如下图 函数名:EdA4VNZrBAU37Pd7ND

通过%userdomain%环境变量获取用户所在域的名称,如果失败反而error userdomain字符串

19

遍历进程 如下图 函数名:zokOsMYYZQG1GyNMGDZ

利用ps命令(Process Status)枚举当前用户的进程信息,如果失败则返回error tasklist字符串

20

遍历桌面文件的文件名,文件大小以及最后编辑时间 如下图 函数名:UTFhxPjChlXs1OxREdR

通过ls命令遍历出桌面的文件,桌面的路径:%userprofile%\desktop,如果失败返回error ls字符串

21

获取外网IP地址 如下图 函数名:sp169N5

http://ip–api.com/json下载回显字符串以获得外网ip的目的,如果失败返回error remote IP字符串

21

效果如下:

22

返回结果:

23

收集系统名称 如下图 函数名:dYUUIGUfLNIoN

调用wmic.exe利用(win32_operatingsystem).name以获取系统名称,如果失败返回error os arch字符串

24

如下图,函数名:L82O_u0EwZy
按以下顺序分别调用函数:lTXxzy53(获取当前用户名称),EdA4VNZrBAU37Pd7ND(获取用户所在域的名称),zokOsMYYZQG1GyNMGDZ(遍历进程),UTFhxPjChlXs1OxREdR(遍历桌面文件的文件名,文件大小以及最后编辑时间),sp169N5(获取外网IP地址),dYUUIGUfLNIoN(获取系统名称)

然后将其函数L82O_u0EwZy调用后,使用out-file命令将结果输出到%temp%\\log.txt

混淆为了进一步躲避杀软侦查,又声明了一个新的变量叫:m2g9a1mNOtasOaLofMKD,其的内容是:%temp%\log.txt

也就是录入收集到系统信息的文件.

25

功能2:将收集到的信息发送请求给C2

再通过GC(Get-Connect)命令读取%temp%\\log.txt的内容

然后将其通过GetByte命令获取其字符数组,然后将其进行base64的编码后,再将编码后的字符串获取utf–8的字符数组,然后通过POST的方式UploadData(上传数据),将刚刚编码后字符发送到这个指定的地址:

http://185.185.25.175/up1.php?UU={GUID}.

26

效果如下:

27

发送报文内容(Base64):

28

解密字符串:

当前用户用户名以及进程列表信息:

29

桌面上文件(文件名,最后修改时间,文件长度):

30

外网IP地址,系统名称:

31

功能3:循环请求PowerShell Backdoor后门,然后将其下载到本地执行

通过while(1)一直死循环,向c2地址发出请求:

http://185.185.25.175/sDownloads/{GUID}.jpeg

如果其存在则调用DownloadFile下载{GUID}.JPEG文件并另存为%public%\\ieee.dat

32

如图所示:一直对PowerShell Backdoor进行请求

33

攻击者会对其所感兴趣的受感染机器进行筛选,以植入PowerShell Backdoor

然后调用iex命令去执行gc命令所读取%public%\\ieee.dat中的内容

34

利用[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命令

如图所示:

35

功能1:信息收集

获取本机的GUID以及标记感染,函数名:CwC1Fafld_XtJSe6wx

首先检查HKCU:\SOFTWARE\Microsoft\key是否存在,如果存在则利用

Get-ItemProperty获取SecretKey键名的键值

若不存在则调用New-Item创建新项Key,并且利用$Guid = [guid]::NewGuid().Guid;生成GUID,然后调用Set-ItemProperty创造HKCU:\SOFTWARE\Microsoft\keySecretKey键,并写入键值{GUID}以标记感染.

36

获取当前用户名称 ,函数名:wltJBgnP

通过环境变量%username 失败则返回Username Error

37

获取系统名称,函数名:VDf4TkTOMy3p_Br8UL5nH

调用wmic.exe利用(win32_operatingsystem).name以获取系统名称,如果失败返回os Name Error字符串
并且将返回结果的所有:替换为;

38

获取系统位数,函数名:Aj9VVbP5C

调用wmic.exe利用Win32_OperatingSystem).OSArchitecture以获取系统位数,如果失败返回Architecture Error字符串

39

获取外网IP地址,函数名:S4xKxH_WG0KMOE

调用D_1smifUAajwThfuQgh函数从https://api.ipify.org/地址上下载回显数据
如果失败则返回IP Error字符串

40

获取当前用户所在用户组,函数名:QTix4hifIA2oQE8g

调用Security.Principal.Identity::GetCurrent()获取当前用户标识
IsInRole判断用户处于什么用户组

将获取到的本账户用户组和最后管理员的用户组做对比

如果一样 则返回Admin字符串

如果不一样 则返回User字符串

如果没有识别则返回error role字符串

41

代码如下:

利用yKGVMK8K函数,将所收集到的信息进行拼接

如图:按以下顺序去执行函数CwC1Fafld_XtJSe6wx(获取本机的GUID以及标记感染),wltJBgnP(获取当前用户名称),VDf4TkTOMy3p_Br8UL5nH(获取系统名称),Aj9VVbP5C(获取系统位数),S4xKxH_WG0KMOE(获取外网IP地址),QTix4hifIA2oQE8g(获取当前用户所在用户组)

将返回结果按照以下的格式进行拼接:
{GUID}:{UserName}:{OS Name} {OS Arch}:{Remote IP Address}:{UserRole}

42

功能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流中,全部读取。然后返回读取的数据

43

功能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下载回显

44

功能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函数去解析返回数据中的攻击者后门的命令

45

功能5:后门指令解析

该PowerShell BackDoor一共有三个主要的后门功能,分别是屏幕截图,Cmd命令执行,任意PowerShell 代码执行

屏幕截图
函数名:Get-ScreenShot

首先调用VirtualScreen获取虚拟屏幕

New-Object Drawing.BitMap用以初始化一个新的绘制bitmap的对象

CopyFromScreen屏幕图像拷贝到新创建的绘制图像的对象

将图像保存为png图片格式并且将图片数据存入内存流

将png图片的内存流数据转数组后进行base64编码后返回加密后的值

46

cmd命令执行
调用cmd /c {cmdline}以执行C2回传的Cmd命令,并利用out-string获取命令执行返回结果

47

任意PowerShell代码执行
调用iex函数以执行C2回传的PowerShell代码,并利用out-string获取执行结果

48

函数名: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

49

样本流程图:

50

通过相同的诱饵文档内容笔者关联到了一个同样针对塔吉克斯坦政府采购部门的样本

但是其C2以及自启动技术发生了变化

根据C2:185.185.25.175笔者关联到了一个docx文件样本

其运用了远程模板注入技术,并且注入的模板中利用了cve-2017-0199漏洞,但是由于C2已结挂了,所以无法继续分析

诱饵文档截图:

57

58

远程模板注入技术:

59

与之前的样本诱饵内容完全一样

诱饵文档内容如下:

51

并没有之前复杂的混淆,内容很简单,主要还是通过窗体去提取VBE Loader,唯一的区别是该样本实现自启动的技术是通过在自启动文件夹中释放antibiotic.vbe

如图所示:

52

与上个样本一样的技术,这里不再赘述

53

基本相同的信息收集手段

54

将收集好的信息以POST方式发送到http://185.244.149.218/game.php?NewsIID={GUID}

55

循环向http://185.244.149.218/JpeGDownload/{GUID}.png发送GET请求
下载后另存为%public%\\Dri.dat

56

文档截图如下:

66

并没有之前复杂的混淆,内容很简单,主要还是通过窗体去提取VBE Loader,唯一的区别是该样本实现自启动的技术是通过在自启动文件夹中释放antibiotic.vbe

如图所示:

67

与上个样本一样的技术,这里不再赘述

68

基本相同的信息收集手段

69

将收集好的信息以POST方式发送到http://185.244.149.218/game.php?NewsIID={GUID}

70

循环向http://185.244.149.218/JpeGDownload/{GUID}.png发送GET请求
下载后另存为%public%\\Dri.dat,并且执行

71

诱饵样本截图:

60

和上文一样通过读取窗口控件的标题中提取VBE loader,将其拼凑后,将拼凑好的字符串写入pKio.vbE,pKio.vbE文件位于系统自启动文件夹中,达到自启动的目的

61

与上个样本一样的技术,这里不再赘述,释放Recon Powershell到%TEMP%\HTM.log文件
并且调用iex执行gc读取的代码内容

62

去除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去获取系统名称,系统版本,系统位数,系统样式

63

将信息侦查的结果存入%public%\\jYtHGrrfWE.log 将其内容进行base64编码,之后利用gc命令读取jYtHGrrfWE.log中编码的内容
以POST的方式向C2地址发送请求http://185.82.202.240/ttryeJte76.php?Tok=jKlMNtr65Vbf&newsUID={RandonName}POST的方式将编码后的数据发送到该C2地址

64

循环向该C2地址请求http://185.82.202.240/DwnDir/下载其文件存入
%temp%\\tRLHteSw.log 文件中,并且利用iex执行gc读取的%temp%\\tRLHteSw.log的内容

65

诱饵样本截图:

72

通过从控件中提取VBE loader代码将其写入自启动文件夹下的S0NN3.VbE文件中,
以达到开机启动的目的

73

相同的手段,释放Recon PowerShell于%temp%\\plr.dat通过iex执行gc所读取%temp%\\plr.dat文件的内容

74

去除PowerShell代码的混淆后

和之前说到的Recon PowerShell的功能大致相同

获取当前用户的所在域名称以及当前用户名,进程列表,桌面文件信息

75

将收集到的信息以POST的方式发送到http://185.141.27.14/trjjmfnnv.php?T=Tew39mvn21hhsy&Tw={RandomName}

76

循环向该C2地址请求http://185.141.27.14/Newsii/{RedomName}下载其文件存入
%public%\\nvtge44.log 文件中,并且利用iex执行gc读取的%public%\\nvtge44.log的内容

77

MuddyWater组织的样本并不是非常复杂,但是在分析过程中也可以抓到部分该组织攻击过程的影子

笔者可以在网上搜索到有关被利用者的信息
这里笔者用一张图的形式说明.

可见攻击者充分利用了被利用者所泄露的信息,使得诱饵文档看起来更加逼真,加大攻击的成功几率.

78

该样本Muddywater采用了获取加利福尼亚大学在搜索引擎上使用的合法文档,并且对其进行重新的编辑,如下图所示:将加利福尼亚大学大学的标志替换为塔吉克斯坦电信供应商的微标,将标题也做了替换,其他的部分完全相同

79

攻击者在构造载荷的时候通常对宏以及powershell代码进行了加密
对宏的加密主要体现在Chr()以及StrReverse()函数
并且将部分关键变量藏匿于窗口控件之中

而针对PowerShell的混淆,第一步就是一层base64,从第二层开始都有一个解密函数
用于解密C2地址,以及释放文件的位置。并且每个脚本的解密算法都不是相同的,这里只单单给出一个例子:


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-7-12 12:09 被CrazymanArmy编辑 ,原因:
收藏
免费 9
支持
分享
最新回复 (16)
雪    币: 2605
活跃值: (5058)
能力值: ( LV9,RANK:225 )
在线值:
发帖
回帖
粉丝
2
加油。
2019-7-7 23:02
0
雪    币: 9662
活跃值: (4588)
能力值: ( LV15,RANK:800 )
在线值:
发帖
回帖
粉丝
3
day day up~
2019-7-8 09:45
0
雪    币: 194
活跃值: (44)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
大佬NB,day day up~
2019-7-9 19:11
0
雪    币: 2141
活跃值: (7221)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
5
2019-7-10 15:50
0
雪    币: 6054
活跃值: (12594)
能力值: ( LV12,RANK:312 )
在线值:
发帖
回帖
粉丝
6
T-APT-14代码写的很精彩,同样分析的也很精彩
最后于 2019-7-11 11:02 被一半人生编辑 ,原因:
2019-7-11 10:46
0
雪    币: 3129
活跃值: (3668)
能力值: ( LV8,RANK:158 )
在线值:
发帖
回帖
粉丝
7
膜拜大佬!
2019-7-12 09:09
0
雪    币: 6911
活跃值: (9064)
能力值: ( LV17,RANK:797 )
在线值:
发帖
回帖
粉丝
8
支持支持,大佬加油
2019-7-12 22:46
0
雪    币: 9792
活跃值: (1670)
能力值: ( LV12,RANK:261 )
在线值:
发帖
回帖
粉丝
9
无名侠 支持支持,大佬加油
谢谢,膜拜dalao
我会努力的
2019-7-17 09:23
0
雪    币: 9792
活跃值: (1670)
能力值: ( LV12,RANK:261 )
在线值:
发帖
回帖
粉丝
10
银雁冰 day day up~
谢谢dalao
我会努力的
2019-7-17 09:24
0
雪    币: 9792
活跃值: (1670)
能力值: ( LV12,RANK:261 )
在线值:
发帖
回帖
粉丝
11
三十二变 加油。
共勉
加油
2019-7-17 09:24
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
dalao加油,小萌新要向你学习
2019-10-21 21:04
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
加油(ง •̀_•́)ง
2019-12-2 21:11
0
雪    币: 109
活跃值: (314)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
很赞
2019-12-2 21:12
0
雪    币: 4684
活跃值: (4634)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
大老牛B
2019-12-29 20:32
0
雪    币: 73
活跃值: (3090)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
16
很详细哎,需要明年才会发新帖了么?
2019-12-30 11:34
0
雪    币: 1475
活跃值: (14652)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
17
前几天刚接到污水的任务,早些看到你这个帖子就好了
2021-3-12 14:07
0
游客
登录 | 注册 方可回帖
返回
//