银行窃密木马综合分析报告

科技   2024-07-09 17:02   江苏  

文章来源|MS08067 安全团队

本文作者:小玉玉

一. 背景

燥热的夏天,最近一段时间三四个金融客户都中了一个同一种木马病毒,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, 0070002u);
  v4 = GetCommandLineW();
  v5 = v4;
  if ( v4 )
  {
    deal_string((int)v4);                       // 根据处理在命令行显示出的自己的路径
    if ( byte_441879 )                          // 判断字符串是否处理成功
    {
      v6 = OpenFileMappingW(0xF001Fu, 0L"winrarsfxmappingfile.tmp");// 打开命名文件映射对象
      hObject = v6;
      if ( v6 )
      {
        v7 = MapViewOfFile(v6, 0xF001Fu, 00070002u);
        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, 0x800u);      // 检测自己的路径
  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;
}

三. 总结

通过静态分析发现,其样本为经典自解压钓鱼样本。主要过程有以下几个阶段:

  1. 将winrarsfxmappingfile.tmp文件转到自己内存空间

  2. 通过设置环境变量的方式触发自解压

  3. 通过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, 00x7002u);
  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))(9830710, &unk_43135C);
      v10 = v9;
      if ( v9 )
      {
        v11 = (_BYTE *)((int (__stdcall *)(intsigned int, _DWORD, _DWORD, signed int))((char *)&byte_430001 + 299))(
                         v9,
                         983071,
                         0,
                         0,
                         28674);
        v12 = v11;
        if ( v11 )
        {
          memmove(&byte_442100, v11, 0x7002u);
          *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, 0x32u, 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 AccessExecutionPersistencePrivilege EscalationDefense EvasionCredential AccessDiscoveryLateral MovementCollectionExfiltrationCommand and Control
PhishingUser ExecutionHide 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序列如下:

  1. GetCpInfo
  2. SetEnvironmentVariableW
  3. MapViewOfFile

其他信息:

NANOCORE Malware Information (trendmicro.com)



—  实验室旗下直播培训课程  —



和20000+位同学加入MS08067一起学习



Ms08067安全实验室
“Ms08067安全实验室”致力于网络安全的普及和培训!
 最新文章