本文作者:小玉玉
一. 背景
燥热的夏天,最近一段时间三四个金融客户都中了一个同一种木马病毒,MS08067安全团队对此事进行了相关跟进,获取到了相应的样本,并对其一个最新的变种样本进行了详细分析,初步判定是nanocore 木马。
NanoCore 是一种臭名昭著的远程访问木马 (RAT),于 2013 年首次发现。它以能够在受害者不知情的情况下远程访问和控制受害者的计算机而闻名。由于其源代码被泄露并在地下论坛中广泛传播,它仍然与网络犯罪世界相关,是一款比较著名且复杂的银行木马。
商业窃密木马已形成了一条完整的窃密产业链,主要包含制作、混淆、销售、传播、获利等环节。产业链分工协作明确:窃密木马编写者负责程序设计、开发和测试;混淆服务提供商负责混淆程序以规避检测;销售者进行推广销售以获取更多利益;传播者负责投放窃密木马感染用户设备。窃密攻击者可通过在窃密产业链中购买各个攻击阶段的服务来实现“一条龙”式的完整攻击,最终将窃取到的数据出售给信息购买者从而获利。
二. 详细分析
样本伪装成压缩文档,如下所示:
基本信息
信息:
文件名: tasksche.exe
大小: 2061938(1.97 MiB)
操作系统: Windows(2000)
架构: I386
模式: 32 位
类型: GUI
字节序: LE
区节段:
主函数
int
__stdcall
WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int
nShowCmd)
{
LPWSTR v4;
// eax
const
WCHAR *v5;
// edi
HANDLE v6;
// eax
_BYTE *v7;
// eax
_BYTE *v8;
// edi
HMODULE v9;
// edi
int
result;
// eax
WCHAR Value;
// [esp+Ch] [ebp-D4h]
char
v12;
// [esp+70h] [ebp-70h]
int
v13;
// [esp+90h] [ebp-50h]
char
v14;
// [esp+9Ch] [ebp-44h]
int
v15;
// [esp+BCh] [ebp-24h]
struct
_
SYSTEMTIME
SystemTime
;
// [esp+C8h] [ebp-18h]
char
v17;
// [esp+D8h] [ebp-8h]
HANDLE hObject;
// [esp+DCh] [ebp-4h]
______kernel32______(
1
);
// 在不修改环境变量的情况下将kernel32设置为默认的dll搜索路径
OleInitialize(
0
);
is_ansi(&unk_44F5B0);
// 判断是否是ansi
memset
(&byte_43A820,
0
,
070002u
);
v4 = GetCommandLineW();
v5 = v4;
if
( v4 )
{
deal_string((
int
)v4);
// 根据处理在命令行显示出的自己的路径
if
( byte_441879 )
// 判断字符串是否处理成功
{
v6 = OpenFileMappingW(
0xF001F
u,
0
,
L"winrarsfxmappingfile.tmp"
);
// 打开命名文件映射对象
hObject = v6;
if
( v6 )
{
v7 = MapViewOfFile(v6,
0xF001F
u,
0
,
0
,
070002u
);
v8 = v7;
if
( v7 )
{
memcpy
(&byte_43A820, v7,
070002u
);
// 映射对象转到内存中
*v8 =
1
;
set_env(&word_43A822);
// 设置当前进程的指定环境变量的内容 内容为自解压
}
UnmapViewOfFile(v8);
}
CloseHandle(hObject);
}
else
{
set_env(v5);
}
}
GetModuleFileNameW(
0
, &::Value,
0x800
u);
// 检测自己的路径
SetEnvironmentVariableW(
L"sfxname"
, &::Value);
// 将自己添加到自解压的过程中
GetLocalTime(&SystemTime);
swprintf(
&Value,
(
const
wchar_t
*)
0x32
,
L"%4d-%02d-%02d-%02d-%02d-%02d-%03d"
,
SystemTime.wYear,
SystemTime.wMonth,
SystemTime.wDay,
SystemTime.wHour,
SystemTime.wMinute,
SystemTime.wSecond,
SystemTime.wMilliseconds);
SetEnvironmentVariableW(
L"sfxstime"
, &Value);
// 设置自解压的时间为立即自解压
v9 = GetModuleHandleW(
0
);
dword_4335A4 = v9;
::hInstance = v9;
lParam = (LPARAM)LoadIconW(v9, (LPCWSTR)
0x64
);
// 自动选择图表显示
dword_439818 = (LPARAM)LoadBitmapW(::hInstance, (LPCWSTR)
0x65
);
// 从自己的模块中加载位图资源
sub_41A060((HMODULE *)&v17);
// 加载富编辑控件
sub_40C3A8(&unk_4335BC, &::Value);
// 以下所有代码都是显示相关
sub_419137(&v12);
sub_419137(&v14);
v13 = sub_419DD0(
100
);
v15 = sub_419DD0(
100
);
dword_438814 = &v12;
lpParam = &v14;
DialogBoxParamW(v9,
L"STARTDLG"
,
0
, sub_40F58D,
0
);
lpParam =
0
;
dword_438814 =
0
;
sub_41915C(&v14);
sub_41915C(&v12);
sub_41A0BA(&v17);
if
( byte_441870 )
sub_40D896();
sub_40D0FE(&unk_44CE20);
if
( (
unsigned
int
)dword_441858 >
0
)
free
(dword_44184C);
DeleteObject((HGDIOBJ)lParam);
if
( dword_439818 )
DeleteObject((HGDIOBJ)dword_439818);
if
( !dword_4335AC && byte_44183C )
sub_4062BA(
255
);
byte_44183C =
1
;
if
( hHandle )
{
sub_40D857(hHandle);
CloseHandle(hHandle);
}
if
( dwMilliseconds )
Sleep(dwMilliseconds);
// 睡眠时间
OleUninitialize();
result = dword_441860;
if
( (
unsigned
int
)dword_441860 <=
0
)
result = dword_4335AC;
return
result;
}
功能函数
在不修改环境变量的情况下将kernel32设置为默认的dll搜索路径
// 在不修改环境变量的情况下将kernel32设置为默认的dll搜索路径
HMODULE __stdcall ______kernel32______(
char
a1)
{
HMODULE result;
// eax
result = GetModuleHandleW(
L"kernel32"
);
if
( result )
{
result = (HMODULE)GetProcAddress(result,
"SetDllDirectoryW"
);
if
( result )
result = (HMODULE)((
int
(__stdcall *)(
unsigned
int
))result)(a1 !=
0
? (
unsigned
int
)&String :
0
);
}
return
result;
}
判断是否是ansi
// 判断是否是ansi
bool
__thiscall
is_ansi
(_BYTE *
this
)
{
unsigned
int
v1;
// esi
_BYTE *v2;
// edi
bool
result;
// al
struct
_
cpinfo
CPInfo
;
// [esp+8h] [ebp-14h]
v1 =
0
;
v2 =
this
;
GetCPInfo(
0
, &CPInfo);
v2[
256
] = CPInfo.MaxCharSize >
1
;
do
{
result = IsDBCSLeadByte(v1) !=
0
;
v2[v1++] = result;
}
while
( v1 <
0x100
);
return
result;
}
根据命令行中的显示内容处理字符串
// 根据命令行中的显示内容处理字符串
unsigned
__int16 *__stdcall
deal_string
(
int
a1)
{
unsigned
__int16 *result;
// eax
unsigned
__int16 *i;
// edi
LPWSTR v3;
// eax
int
v4;
// eax
int
v5;
// eax
LPWSTR v6;
// eax
int
v7;
// eax
int
v8;
// eax
__int16 v9;
// [esp+8h] [ebp-804h]
unsigned
__int16 v10;
// [esp+Ah] [ebp-802h]
wchar_t
v11;
// [esp+Ch] [ebp-800h]
__int16 v12;
// [esp+Eh] [ebp-7FEh]
int
v13;
// [esp+808h] [ebp-4h]
v13 =
0
;
result = sub_410C58((
unsigned
__int16 *)a1, (
int
)&v9,
1024
);
for
( i = result; result; i = result )
{
if
( ++v13 ==
1
|| v9 !=
47
&& v9 !=
45
)
goto
LABEL_22;
v3 = CharUpperW((LPWSTR)v10) -
34
;
if
( v3 )
{
v4 = (
int
)v3 -
1
;
if
( !v4 )
{
if
( CharUpperW((LPWSTR)v11) == (LPWSTR)
76
&& !v12 )
byte_441879 =
1
;
goto
LABEL_22;
}
v5 = v4 -
11
;
if
( v5 )
{
if
( v5 ==
3
)
{
v6 = CharUpperW((LPWSTR)v11);
if
( v6 && (v7 = (
int
)v6 -
49
) !=
0
)
{
v8 = v7 -
1
;
if
( v8 )
{
if
( v8 ==
30
)
sub_410B9C((
wchar_t
*)&word_44287A, (
wchar_t
*)&v12,
2048
);
goto
LABEL_22;
}
dword_441874 =
2
;
}
else
{
dword_441874 =
1
;
}
byte_44184A =
1
;
}
}
else
{
sub_40D033(&unk_44387A, &v11);
}
}
else
{
sub_410B9C((
wchar_t
*)&word_44187A, &v11,
2048
);
}
LABEL_22:
result = sub_410C58(i, (
int
)&v9,
1024
);
}
return
result;
}
设置环境变量内容 具体内容为自解压相关
unsigned
__int16 *__stdcall
set_env
(LPCWSTR lpValue)
{
unsigned
__int16 *result;
// eax
const
WCHAR *v2;
// edi
char
v3;
// [esp+8h] [ebp-800h]
SetEnvironmentVariableW(
L"sfxcmd"
, lpValue);
result = sub_410C58((
unsigned
__int16 *)lpValue, (
int
)&v3,
1024
);
v2 = result;
if
( result )
{
while
( (
unsigned
__int8)sub_410B7F(*v2) )
++v2;
result = (
unsigned
__int16 *)SetEnvironmentVariableW(
L"sfxpar"
, v2);
}
return
result;
}
加载富编辑控件
HMODULE *__thiscall
sub_41A060
(HMODULE *
this
)
{
HMODULE *v1;
// esi
INITCOMMONCONTROLSEX picce;
// [esp+8h] [ebp-8h]
v1 =
this
;
this
[
1
] =
0
;
*
this
=
0
;
*
this
= LoadLibraryW(
L"riched32.dll"
);
v1[
1
] = LoadLibraryW(
L"riched20.dll"
);
OleInitialize(
0
);
picce.dwSize =
8
;
picce.dwICC =
2047
;
InitCommonControlsEx(&picce);
SHGetMalloc(&ppMalloc);
return
v1;
}
三. 总结
通过静态分析发现,其样本为经典自解压钓鱼样本。主要过程有以下几个阶段:
-
将winrarsfxmappingfile.tmp文件转到自己内存空间
-
通过设置环境变量的方式触发自解压
-
通过LoadIconW和LoadBitmapW函数实现修改样本后缀名后自适应图标功能的实现
如图:
后续的富编辑控件都是伪装显示一个提示弹窗,实际上真实的功能在自解压的过程中完成。
伪造的弹窗:
实际的功能:
从实际的功能中可以发现,自解压之后的内容命名为eee.exe文件
动态分析(tasksche.exe)
在之前静态分析中的字符串处理函数并未实现upperchar的实现,直接跳转了
内存中的内容疑似受到损坏,所以自解压的文件显示不完善
从其他渠道方式拿到这个eee.exe文件,继续分析。
静态分析(eee.exe)
基本信息
信息:
文件名: eee.exe
大小: 1981503(1.89 MiB)
操作系统: Windows(XP)
架构: I386
模式: 32 位
类型: GUI
字节序: LE
比较特别的是 这个样本没有导入函数
主函数
int
__stdcall
WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int
nShowCmd)
{
int
v4;
// ebp
int
v5;
// edi
int
v6;
// esi
int
v7;
// eax
int
v8;
// esi
int
v9;
// eax
int
v10;
// edi
_BYTE *v11;
// eax
_BYTE *v12;
// esi
int
v13;
// esi
void
(__stdcall *v14)(
int
);
// esi
int
result;
// eax
char
v16;
// [esp+50h] [ebp-BCh]
__int16 v17;
// [esp+54h] [ebp-B8h]
char
v18;
// [esp+64h] [ebp-A8h]
char
v19;
// [esp+88h] [ebp-84h]
char
DstBuf;
// [esp+ACh] [ebp-60h]
sub_40EF68(
1
);
dword_43AB50(
0
, v5, v6, v4);
sub_4102DE(&unk_441E88);
memset
(&byte_442100,
0
,
0x7002
u);
v7 = ((
int
(*)(
void
))((
char
*)&byte_430001 +
315
))();
v8 = v7;
if
( v7 )
{
sub_41A0D8(v7);
if
( byte_449119 )
{
v9 = ((
int
(__stdcall *)(
signed
int
, _DWORD,
void
*))((
char
*)&byte_430001 +
311
))(
983071
,
0
, &unk_43135C);
v10 = v9;
if
( v9 )
{
v11 = (_BYTE *)((
int
(__stdcall *)(
int
,
signed
int
, _DWORD, _DWORD,
signed
int
))((
char
*)&byte_430001 +
299
))(
v9,
983071
,
0
,
0
,
28674
);
v12 = v11;
if
( v11 )
{
memmove(&byte_442100, v11,
0x7002
u);
*v12 =
1
;
sub_41B5D9(&word_442102);
}
((
void
(__stdcall *)(_BYTE *))((
char
*)&byte_430001 +
303
))(v12);
}
((
void
(__stdcall *)(
int
))((
char
*)&byte_430001 +
19
))(v10);
}
else
{
sub_41B5D9(v8);
}
}
((
void
(__stdcall *)(_DWORD))((
char
*)&byte_430001 +
119
))(
0
);
((
void
(__stdcall *)(
void
*,
wchar_t
*))((
char
*)&byte_430001 +
319
))(&unk_431390, &word_4547F0);
((
void
(__stdcall *)(__int16 *))((
char
*)&byte_430001 +
295
))(&v17);
sub_403CD1(&DstBuf,
0x32
u, aLb, v17);
((
void
(__stdcall *)(
void
*,
char
*))((
char
*)&byte_430001 +
319
))(&unk_4313E4, &DstBuf);
v13 = ((
int
(__stdcall *)(_DWORD))((
char
*)&byte_430001 +
123
))(
0
);
dword_43CB98 = v13;
dword_43CB94 = v13;
dword_4547E4 = dword_43AA9C(v13,
100
);
dword_4557F0 = dword_43AA98(dword_43CB94,
101
);
sub_41895F(&v16);
sub_40C6F2(&word_4547F0);
sub_417622(&v19);
sub_417622(&v18);
dword_449108 = (
int
)&v19;
dword_44910C = (
int
)&v18;
dword_43AA78(v13, &unk_4313F8,
0
, sub_41939B,
0
);
dword_44910C =
0
;
dword_449108 =
0
;
sub_4176A2(&v18);
sub_4176A2(&v19);
sub_4189A5(&v16);
if
( dword_455804 )
((
void
(__stdcall *)(
int
))((
char
*)&byte_430001 +
151
))(dword_455804);
if
( byte_449110 )
sub_418B32();
sub_40DAAF(&unk_4546E0);
if
( (
unsigned
int
)dword_449104 >
0
)
j___free_base(dword_4420FC);
v14 = (
void
(__stdcall *)(
int
))dword_43AA1C;
dword_43AA1C(dword_4547E4);
if
( dword_4557F0 )
v14(dword_4557F0);
if
( !dword_43CBD8 && byte_4420F3 )
sub_406C14(
255
);
byte_4420F3 =
1
;
if
( dword_456808 )
{
sub_41B638(dword_456808);
((
void
(__stdcall *)(
int
))((
char
*)&byte_430001 +
19
))(dword_456808);
}
dword_43AB44();
result = dword_455800;
if
( !dword_455800 )
result = dword_43CBD8;
return
result;
}
从代码结构上看几乎与之前的样本代码完全一致,在动态分析的过程中发现大概率原因是由于导入表损坏无法访问指定内存位置二无法打开。
yara规则
规则文件
rule ea2ad4d3bb98673b88e18eea1bf06c371c206b64246a9193b2a64ba4fe4f4900 {
meta:
description = "sha256:ea2ad4d3bb98673b88e18eea1bf06c371c206b64246a9193b2a64ba4fe4f4900"
strings:
$a = {FF 15 E8 A0 42 00 [63] 50 68 C4 AB 42 00} // 将自解压时间设置为立即解压
$text = {77 00 69 00 6E 00 72 00 61 00 72 00 73 00 66 00 78 00 6D 00 61 00 70 00 70 00 69 00 6E 00 67 00 66 00 69 00 6C 00 65 00 2E 00 74 00 6D 00 70 00}
//0042AB04 77 00 69 00 6E 00 72 00 w.i.n.r.
//0042AB0C 61 00 72 00 73 00 66 00 a.r.s.f.
//0042AB14 78 00 6D 00 61 00 70 00 x.m.a.p.
//0042AB1C 70 00 69 00 6E 00 67 00 p.i.n.g.
//0042AB24 66 00 69 00 6C 00 65 00 f.i.l.e.
//0042AB2C 2E 00 74 00 6D 00 70 00 ..t.m.p.
//字符串特征
condition:
any of them
}
测试脚本
import
yara
# 定义一个规则
rules = yara.compile(filepath=
'tasksche.rule'
)
# 使用规则匹配文件
data = open(
'tasksche.exe'
,
'rb'
).read()
matches = rules.match(data=data)
# 输出结果
print(matches)
测试结果
python .yaratest.py
[ea2ad4d3bb98673b88e18eea1bf06c371c206b64246a9193b2a64ba4fe4f4900]
四.防范建议
根据笔者近期的观察,银行木马家族最近一段时间都非常活跃,包括:Emotet、TrickBot、Ursnif、Osiris、Zeus等家族,不同的银行木马使用的恶意代码技术都不同,银行木类木马主要针对一些大型的金融或银行企业进行定点攻击,可以预测在未来一段时间里,可能会有新一轮专门针对金融行业的恶意攻击,请金融行业的各大企业做好相应的防范准备工作。
同时MS08067安全团队提醒广大用户:
1.不要点击来源不明的邮件附件,不从不明网站下载软件
2.及时给主机打补丁,修复相应的高危漏洞
3.对重要的数据文件定期进行非本地备份
4.尽量关闭不必要的文件共享权限以及关闭不必要的端口,如:445,135,139,3389等
5.RDP远程服务器等连接尽量使用强密码,不要使用弱密码
6.安装专业的终端安全防护软件,为主机提供端点防护和病毒检测清理功能
五.相关ioc
sha256:
tasksche.exe:ea2ad4d3bb98673b88e18eea1bf06c371c206b64246a9193b2a64ba4fe4f4900
eee.exe:4afa76fccc7f8a489b3b9791b6413d7165a8fbbc2cb7400c20eb8a5a780bfba9
编译时间:
tasksche.exe:2015-09-21 03:44:01
eee.exe:2017-08-11 21:54:06
威胁平台收录时间:
魔盾:2018-01-17 10:37:32
微步:2022/05/05
trage:未收录
virustotal:2021年
anyrun:2024-03-22
ATT$CK:
Initial Access | Execution | Persistence | Privilege Escalation | Defense Evasion | Credential Access | Discovery | Lateral Movement | Collection | Exfiltration | Command and Control |
---|---|---|---|---|---|---|---|---|---|---|
Phishing | User Execution | Hide Artifacts | Multi-Stage Channels | |||||||
Native API |
六.类似样本情报
CloudDuke, Software S0054 | MITRE ATT&CK®
NanoCore Malware - Malware Analysis - Malware Analysis, News and Indicators
Trojan.Rasftuby.Gen.11_84d9bd5283 – Adaware
在这些样本中相似度最高的为nanocore 可以基本判定该样本为nanocore
其家族windowsapi序列如下:
-
GetCpInfo -
SetEnvironmentVariableW -
MapViewOfFile
其他信息:
NANOCORE Malware Information (trendmicro.com)
原文始发于微信公众号(Ms08067安全实验室):银行窃密木马综合分析报告
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论