P³-Shellcode Loader est un chargeur qui implémente une technique d'injection de code utilisant la structure des paramètres de processus (Process Parameters) comme emplacement d'exécution et de mise en scène pour l'injection de shellcode dans des processus distants, sans déclencher les mécanismes de détection courants.
Auteurs : Max Hirschberger & Ogulcan Ugur
P³-Shellcode Loader est un chargeur qui implémente une technique d'injection de code exploitant la structure des paramètres de processus (Empoisonnement des paramètres de processus) comme emplacement d'exécution et de staging pour l'injection de shellcode dans des processus distants, sans déclencher les mécanismes de détection courants.
Un concept similaire a été décrit par le chercheur en sécurité modexp, qui a démontré que les arguments passés à l'API CreateProcess peuvent être utilisés à cette fin [1].
Les attaquants souhaitent rendre leurs activités moins suspectes. Avec l'injection de processus, les attaquants peuvent effectuer leurs activités depuis un processus différent, plus fiable ou attendu pour réaliser l'activité spécifique, réduisant ainsi les soupçons.
Voici les étapes typiques requises pour injecter du code dans un autre processus :
OpenProcess / NtOpenProcess ou CreateProcess / NtCreateProcess).VirtualAllocEx ou NtAllocateVirtualMemory).WriteProcessMemory / NtWriteVirtualMemory).VirtualProtectEx / NtProtectVirtualMemory).CreateRemoteThread ou NtCreateThreadEx).Les techniques d'injection supplémentaires incluent, sans s'y limiter, les suivantes :
NtSetContextThread)NtQueueApcThread)RtlCreateProcessReflection, qui implémente le forking de processus.
Lors de nos tests, nous avons observé que la plupart des EDR se concentrent sur une télémétrie spécifique pour détecter l'injection de processus. Les EDR surveillent principalement l'utilisation de WriteProcessMemory et VirtualAllocEx, ainsi que leurs appels système noyau sous-jacents NtWriteVirtualMemory, NtAllocateVirtualMemory et NtAllocateVirtualMemoryEx.Windows fournit la fonction API CreateProcessW pour créer de nouveaux processus, illustrée dans le Listing 1. Les trois premiers de ses paramètres lpCommandLine, lpEnvironment et lpStartupInfo sont pertinents pour la technique d'injection décrite, car ils sont utilisés pour transférer des données vers le nouveau processus.```c
BOOL CreateProcessW(
[in, optional] LPCWSTR lpApplicationName,
[in, out, optional] LPWSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCWSTR lpCurrentDirectory,
[in] LPSTARTUPINFOW lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
*Listing 1 : Définition de la fonction API Windows CreateProcessW*
Le paramètre `lpCommandLine` spécifie la ligne de commande du nouveau processus. Il est limité à un maximum de 32 767 caractères Unicode, y compris le terminateur nul Unicode. Pour la variante Unicode, il est nécessaire de fournir une chaîne que la fonction peut écrire. Si une chaîne constante est fournie, toute tentative d'écriture de la part de la fonction API entraîne une violation d'accès mémoire. Si la valeur est `NULL`, la ligne de commande du processus sera prise du paramètre `lpApplicationName`. Si `lpApplicationName` est `NULL`, elle doit être fournie dans le champ `lpCommandLine` et est limitée à `MAX_PATH` caractères.
Le paramètre `lpEnvironment` fournit une liste de variables d'environnement au processus. Si la valeur est `NULL`, l'environnement du processus créateur sera utilisé. La liste des variables d'environnement est constituée de chaînes terminées par un caractère nul successives au format `NOM=VALEUR` avec un autre terminateur nul à la fin.
Le paramètre `lpStartupInfo` est une structure présentée dans le Listing 2 avec des champs tels que la station de fenêtre, le bureau, les handles d'entrée et sortie standard ainsi que des champs qui configurent la fenêtre principale du nouveau processus. Selon la documentation Microsoft, le champ `lpReserved` est réservé à un usage interne sans documentation supplémentaire. Grâce à l'analyse avec le débogueur WinDbg, il a été possible de relier ce paramètre à la variable `ShellInfo` de type `UNICODE_STRING` dans le nouveau processus.```c
typedef struct _STARTUPINFOW {
DWORD cb;
LPWSTR lpReserved; // Copied to ShellInfo (UNICODE_STRING)
LPWSTR lpDesktop;
LPWSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
// (...) additional fields
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
// (...) additional fields
} STARTUPINFOW, *LPSTARTUPINFOW;
Liste 2 : Disposition de la structure de données STARTUPINFOW