This blog post analyzes a Word document that was used to deliver a ransomware executable. The Word document includes a macro that will execute when the document is opened if the end user clicks a button called “enable content”. If the macro runs, a ransomware executable is downloaded from a malicious website and executed on the computer. The ransomware encrypts documents on the victim computer and demands payment for the encryption key that is needed to decrypt the files.
The analysis was performed on a virtual machine running Windows 7 on an isolated, host only network. The virtual machine did not have access to the public internet during the analysis, so the ransomware could not be downloaded. Microsoft Office 2016 was installed on the virtual machine.
One again, please note that if macros are not enabled to run automatically, the end user must click on a button to run the macro. The figure below shows the button that must be clicked to run the macro after opening the malicious document. If the end-user does not click this button, he/she will not get infected with the ransomware.
Some Prep Work
For some reason, I wasn’t able to use the Microsoft Word’s built in debugger to step through the macros in the malicious document without clicking the Enable Content button, so I had to make some edits to the macros before starting the analysis. I’m not very familiar with VBA development, so there may be an easier way to analyze this sort of malicious document. However, I’ll describe the steps I used.
First, I clicked on the View tab, and then clicked on the Macros icon, then clicked on View Macros. MS Word will display a dialog box with the different macros that are available.
The autoopen macro is a special macro that is executed when the document is opened. I selected this macro, then clicked Edit. Word then displayed a window with the macro’s definition.
I renamed the macro to autoopen2 and clicked on the Save icon. Renaming the macro will prevent it from running even if the Enable Content button is clicked. After making this edit, we can close the window that displays the macros, so that the main Word document window is displayed.
After clicking on the Enable Content button, nothing should happen because there is no longer an autoopen function. We should be ready to start stepping through the macros.
General Info About Debugging VBA Macros
Once again, we’ll need to click on View Macros to display the Macros dialog box. After selecting autoopen2, click on Step Into instead of Edit. Execution of the macro should pause at the beginning of the autoopen2 function. This function will be highlighted in yellow with a yellow arrow next to it. Several other windows with macro code will also be present. The windows have names in their title bars that look like Module 1, Module 4, …
To start debugging the macros, I chose to display the debug toolbar. The toolbar can be displayed by selecting View -> Toolbars -> Debug. The toolbar contains icons for stepping into and over lines of code, and continuing code execution (if breakpoints are set). Breakpoints can be set by clicking in the grey column to the left of a macro line.
The debug toolbar also contains an icon for opening a watch window. The watch window can be used to inspect the state of a variable. The malicious macros in this document store deobfuscated information in global variables. The deobfuscated information is used in later macros to download and execute ransomware from the malicious website. If you click on the Watch Window icon, the watch window will be displayed on the bottom of the macros window. To add a variable to the watch window, right-click anywhere in the watch window, and select Add Watch… We’ll start by adding a watch entry for the global variable TextLenPart. In the Expression input field, type TextLenPart. In the Procedure drop down box, select (All Procedures), and in the Module drop down box, select (All Modules).
After clicking on OK, the variable will be displayed in the watch window.
The first function that is called in autoopen2 is ReplaceText. If you step over one line of code, execution of the macro will pause at the ReplaceText function. To determine what the ReplaceText function does, step into the function. Within this function the global variable TextLenPart is assigned a value. All of the global variables are declared in the window titled Module 1. A portion of the function is shown in the figure below.
The Split function is used to split a long hard-coded string (using the string “921029” to mark the places where the string should be split). Set a breakpoint on the line below the Split function call and click on continue. When execution pauses, there should be a plus sign next to the TextLenPart variable in the watch window. If you click on the plus sign, you will see the values that were assigned to the variable after the Split function completed. Notice that TextLenPart is an array of values, some of which are shown in the figure below. We will see later that this array of values is decoded into a URL in a subsequent function call.
There is additional code within the ReplaceText function. However, the additional code does not seem to serve any purpose, other than to cause confusion and make analysis more time consuming. Additional, unused code appears in all of the other functions that are executed as well.
To return to the autoopen2 function, set a breakpoint on the second function that is called, KJn…Word and then click on continue.
Step into the KJn…Word function. The function is shown in the figure below.
The purpose of the first 4 highlighted lines of the function is to assign a value to the global variable massiveMyData. The obfuscated value is stored in a ControlTipText property of a textbox of a form that is part of the VBA project (shown in the figure below). The pirognoe function is used to deobfuscate the text.
If you add this variable to the watch window and set a breakpoint on the line after massiveMyData is assigned a value, and then continue, you will be able to examine the value of the variable. The variable should now be an array of values as shown in the figure below.
The remaining highlighted lines of the function create several objects that are assigned to global variables:
- the global variable substruct1 references an adodb.stream object
- the global variable stadyBradus references a shell.Application object
- the global variable YKJJJnnnn3_pe__1 references a Microsoft.xmlhttp object
To return to the autoopen2 function, set a breakpoint on the third function that is called, KJn…Email and then click on continue.
The KJn…Email function is shown below.
The first two highlighted lines of the function are used to create an WshEnvironment object and assign it to the global variable YKJJJnnnn3_pe__3. The TextLenPart variable is also decoded into a URL, which is stored in the global variable DJeremy. The function RemoveSpecialChar is used to decode each element in the TextLenPart array into a single character. The decoded characters are combined to form the url shown below.
To return to the autoopen2 function, set a breakpoint on the fourth function that is called, KJn…Name and then click on continue.
The function KJn…Name is shown in the figure below. This function uses the objects created in the previous function calls to download a ransomeware executable from the URL stored in the global variable DJeremy. The lines of code can be translated as follows:
- xmlhttpObject.open(“GET”, DJeremy, False)
- YKJJJnnnn3_pe__4 = WshEnvironmentObject(“Temp”)
- YKJJJnnnn3_peNaStole = concatenation of the temp directory with “\filarmon.exe”
The first two lines use the xmlhttp object to send an HTTP GET request to the URL stored in the global variable Djeremy. The global variable YKJJJnnnn3_peNaStole is used to store the name of a file in the temporary directory stored in the TEMP environment variable.
Since we are debugging this macro in an isolated environment, we will receive error messages when attempting to send the requests to the website. So, instead of stepping through the rest of the code, we will perform static analysis instead.
So far, we’ve seen some lines of code that are used to send an HTTP GET request to a website. But, we haven’t seen the downloaded file written to disk, or being executed. The CheckDriveSpecError function is the final function that is called from within autoopen2. It calls three other functions that appear to be responsible for performing these actions. These functions are shown below.
Each of the functions is examined below.
The function KJn…Alpha is shown in the figure below. The global variable substruct1 is referenced in two locations. Recall substruct1 stores a reference to a Stream object. The highlighted lines in the figure show the stream’s type being set to 1, so the data stored by the stream object will be binary data, and the stream object being opened so data can be written to it.
The function KJn…Paragraph is shown in the figure below. The first highlighted line shows the response body received by the xmlhttp object YKJJJnnnn3_pe__1 being stored in the variable somebody. The response body contains the ransomware executable that was downloaded from the malicious website. The second highlighted line shows the contents of somebody being written to the stream object substruct1. Finally, the third highlighted line shows the contents of the stream object being written to a file. The name of the file was stored in the global variable YKJJJnnnn3_peNaStole. Recall that this variable contained the name of the temp directory stored in the environment variable TEMP with the filename “\filarmon.exe” appended to the end of the temp directory.
The function CheckKJn…BetterThen is shown in the figure below. The stadyBradus variable stores a reference to a ShellDispatch object. It uses the Open method to execute the file that was written to the temporary directory. After this line is executed, the ransomware executable is running and infecting the target computer.