Buffer overflows: War FTP ========================= Recoucou tous ! Hehe. Vous commencez … en avoir marre des buffer overflows hein ! ;))) AprŠs l'article de __2, qui expliquait le principe de base du smashing stack, puis aprŠs mon article pr‚c‚dent qui expliquait les techniques pratiques pour programmer un exploit bas‚ sur un buffer overflow, y manquait encore un truc pour ˆtre tout … fait complet ! Y manquait un beau petit exploit... J'ai cherch‚ pas mal, aprŠs un programme relativement connu et r‚cent, qui aurait pu servir d'exemple. En me renseignant un ti peu, j'ai apprit que War FTPd version 1.65 finale contenait ce que nous cherchions ! ;))) Je vais donc vous montrer ici en d‚tail comment programmer un petit exploit pour les serveurs War FTP, en se servant de ce sacr‚ buffer overflow :) Tout d'abord avant de commencer, je vous conseille d'aller chercher War-FTP 1.65, sur http://www.jgaa.com . Ensuite, je vous conseille aussi d'avoir les outils suivants (pas que pour ce buffer overflow-ci, il vous servirons pour en exploiter d'autres aussi ;) Un petit ‚diteur hexad‚cimal: UltraEdit (http://www.idmcomp.com), Un debugger-d‚sassembleur: Win32dASM Un assembleur 386-Windows: MASM32 Et enfin, un outil formidable dont j'ai d‚j… parl‚ dans un article, … savoir NetCat, un programme de gestion de sockets TCP/IP provenant de Unix, trŠs puissant et trŠs facile d'emploi (http://www.l0pht.com/~weld/netcat). N'oubliez pas aussi de relire un petit peu les 2 articles pr‚c‚dents si c'est loin dans votre m‚moire hehe ;) OU EST LE BUFFER OVERFLOW ? =========================== Avant de commencer je vous conseille d'installer War-FTP chez vous, puis que vous me mailiez avec votre IP, comme ca je pourrai tester l'exploit... lol :) Non, pas besoin de me mailer l'IP, mais installer le quand mˆme, ca va ˆtre un peu plus facile pour que vous compreniez ski va spasser :) Alors l'exploit dans War FTP est assez bˆte, on se demande d'ailleurs comment il n'est pas encore corrig‚... C'est un buffer overflow dans les commandes USER et PASS, qui sont les 1Šres commandes que vous envoyer … un serveur FTP quand vous vous connectez dessus. On va essayer ca tout de suite. On lance d'abord WarFTP, on oublie pas de l'activer (hehehe ;), puis on cr‚e un petit fichier EXPLOIT1.BIN, qui contient ceci: USER exploit suivi de qq dizaines de lignes . Ensuite, nous allons utiliser NetCat, pour envoyer ces commandes au serveur FTP. Par exemple, si mon IP est 10.10.10.1, on lance: nc 10.10.10.1 21 < exploit1.bin (21 est le port FTP par d‚faut utilis‚ par WarFTP) Voici le r‚sultat: C:\>nc 10.10.10.1 21 < exploit1.bin 220- Jgaa's Fan Club FTP Service WAR-FTPD 1.65 Ready 220 Please enter your user name. 331 User name okay, Need password. Donc le serveur FTP recoit bien notre commande USER, et il attend un password, dont on a rien … foutre ici c justemment pour pas l'avoir qu'on bosse ;)) Maintenant rentrons de suite dans le vif du sujet. On va recr‚er un petit fichier EXPLOIT2.BIN en faisant un buffer overflow. Recr‚ons un 2Šme petit fichier, EXPLOIT2.BIN, contenant ceci: USER xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (pour ceux qui ont pas un bon ‚diteur, il y en a 1000+ ou - des "x" ;))) Normalement si on a mit assez de caractŠres, on devrait bien faire un buffer overflow. Lancons: nc 10.10.10.1 21 < exploit2.bin DŠs qu'on coupe NetCat (CTRL-C), Windows rame un petit peu, puis on a un beau message d'erreur "Ce programme va ˆtre arrˆt‚ car il a effectu‚ une op‚ration non conforme". Donc pas de doute, il y a bien un problŠme qq part :))))) ANALYSE DE WARFTP ================= Maintenant il va s'agir d'analyser un peu WarFTP, pour essayer de mieux comprendre d'ou vient ce buffer overflow, et aussi de chercher quelques informations pour l'exploiter. Nous allons pour cela lancer Win32DASM, et d‚sassembler WarFTP. (si vous ne savez pas vous servir de Win32DASM, lisez mon article sur le Cracking, qui vous en expliquera assez bien les bases de fonctionnement) Tout d'abord, nous allons essayer de localiser l'endroit ou la valeur de EIP est r‚cup‚r‚e de la pile via le RET critique. C'est … cet endroit que nous devrons en effet par la suite analyser l'ex‚cution et mettre une adresse EIP qui permettra l'ex‚cution de notre exploit. Une fois le d‚sassemblage termin‚ (menu "Disassembler", commande "Open file to disassemble..."), on va donc dans le menu "Refs", commande "String Data References". Nous allons chercher aprŠs la chaŒne "User name okay", qui est affich‚e lorsque le username … bien ‚t‚ recu par le serveur. En effet, c'est probablement aprŠs l'utilisation de cette chaŒne que se produit le RET recherch‚. Nous arrivons … l'adresse 0042363D. Nous notons cette adresse, puis nous lancons le debugger "Debug","Load Process", et placons un breakpoint … cet endroit, au moyen de la commande "Goto" "Goto Code Location" et de la touche F2. Ensuite, nous lancons le debugging par "Run", nous activons le serveur, minimisons sa fenˆtre, puis nous relancons notre nc 10.10.10.1 21 < exploit2.bin Nous ex‚cutons ensuite pas … pas, en pressant sur F8, jusqu'… ce que nous atteignons la fin de la proc‚dure (structure classique: probablement plusieurs POP suivi d'un RET), car c'est l… que doit se passer le problŠme. Nous arrivons ainsi … un RET … l'adresse 004232D0. Nous allons continuer le pas … pas dans le programme, jusqu'au RET qui va essayer d'ex‚cuter le saut vers l'adresse que nous avons overwrit‚ dans la pile. Pour plus de facilit‚, nous allons recommencer, en r‚‚crivant un EXPLOIT3.BIN, avec comme username des caractŠres 0FFh, comme ca nous saurons que le RET qui sera ˆtre ex‚cut‚ sera un saut vers l'adresse 0FFFFFFFFh, qui est un saut interdit par le systŠme (hors des adresses accessibles par le programme), et nous aurons donc plus facile pour rep‚rer l'emplacement du RET correspondant. Nous allons donc parcourir le code en suivant les RET successif, jusqu'au RET qui charge dans EIP la valeur 0FFFFFFFFh. Le RET … l'adresse 004232D0 renvoie … l'adresse 0421A2Bh, le RET suivant renvoie … 004219C1, puis le RET encore aprŠs nous renvoie … l'adresse 5F416294. Nous remarquons que cette adresse n'est plus dans l'espace de notre programme, mais que c'est une adresse contenue dans une DLL: MFC42.DLL Donc nous allons mettre un breakpoint … l'adresse du RET pr‚c‚dant ce saut, puisque nous ne pouvons pas mettre un breakpoint sur des instructions ne se trouvant pas dans le code. Nous mettons donc un breakpoint sur l'adresse 004219D7 RET 00000004 En continuant … partir de ce breakpoint, nous allons successivement aprŠs chaque RET arriver aux adresses suivantes: 5F416294 5F4161E4 5F416176 5F402679 5F40233C 5F4022C6 5F402251 5F402208 Ensuite, en continuant encore un peu, nous arrivons enfin … un saut vers l'adresse 0FFFFFFFFh, que nous attendions ! OFFSET DE LA VALEUR DE RETOUR ============================= Nous avons donc cr‚er un buffer overflow avec des caractŠres 0FFh, qui provoquent bien un saut vers l'adresse 0FFFFFFFFh. Nous allons donc maintenant essayer de d‚terminer exactement l'endroit dans notre chaŒne ou se trouve l'adresse de retour, de maniŠre … pouvoir aller y placer une adresse de retour vers notre exploit :))) Pour cela, nous allons proc‚der de la maniŠre suivante: nous allons cr‚er une chaŒne de username dans EXPLOIT4.BIN de la forme suivante: EEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, et lancer l'ex‚cution jusqu'… une des adresses suivantes: 0EEEEEEEEh: si nous avons cette adresse, cela veut dire que l'adresse de retour se trouve dans la partie ou nous avons des 0EEh, et donc, nous allons diminuer le nombre de caractŠres 0EEh, pour essayer de diminuer cette intervalle. 0FFFFFFFFh: si nous avons cette adresse, cela veut dire que l'adresse de retour se trouve dans l'autre partie (caractŠres 0FFh), et nous allons donc augmenter le nombre de caractŠres 0EEh, pour essayer de monter dans la pile. Nous allons proc‚der comme ca plusieurs fois, en modifier le nombre de 0EEh, jusqu'… ce que nous sautions … une adresse compos‚e de 0EEh et de 0FFh, ce qui voudra dire que l'on est vraiment tout prŠs de l'endroit recherch‚ ! Allons-y: mettons des 0EEh jusqu'… l'offset 4FFh (avec UltraEdit). Nous supprimons aussi les breakpoints, et lancons l'ex‚cution de WarFTP, ensuite nous lancons l'ex‚cution de nc 10.10.10.1 21 < exploit4.bin Nous fermons ensuite NetCat, avec CTRL-C, puis nous pressons sur "Pause" dans le debugger. Nous voyons ainsi la valeur de saut 0EEEEEEEEh. Nous allons ainsi continuer en rajoutant ou en supprimant des 0EEh, pour diminuer l'intervalle dans laquelle nous sommes certains que se trouve la valeur de retour: 0EEh jusqu'… l'offset: valeur de retour (EIP): => la zone devient: 4FFh 0EEEEEEEEh de 0h … 4FFh 2FFh (milieu de 0h,4FFh) 0EEEEEEEEh de 0h … 2FFh 1FFh (milieu de 0h,2FFh) 0FFFFFFFFh de 1FFh … 2FFh 28Fh 0EEEEEEEEh de 1FFh … 28Fh 22Fh 0FFFFFFFFh de 22Fh … 28Fh 25Fh 0EEEEEEEEh de 22Fh … 25Fh 23Fh 0FFFFFFFFh de 23Fh … 25Fh 24Fh 0EEEEEEEEh de 23Fh … 24Fh 247h 0EEEEEEEEh de 23Fh … 247h 243h 0FFFFEEEEh Nous arrivons donc … une adresse qui contient des 0EEh et des 0FFh. Que cela veut-il dire ? Cela veut dire que notre pile est comme ceci: EE EE EE EE EE EE EE EE EE FF FF FF FF FF FF FF FF || || || || adresse de retour Donc, si nous supprimons 2 0EEh, puis que nous mettons par exemple 4 0DDh, nous devrions avoir une pile comme ceci: EE EE EE EE EE EE EE DD DD DD DD FF FF FF FF FF FF || || || || Ou 0DDDDDDDDh repr‚senterait l'adresse de retour EIP. Nous mettons donc des 0EEh jusqu'… l'offset 241h compris, puis nous mettons DD DD DD DD, puis nous laissons des 0FFh derriŠre. Normalement nous devrions donc maintenant sauter … l'adresse 0DDDDDDDDh. Nous essayons, et... Yessssssssssssssssss it works ! :) Donc, l'adresse de retour que nous pouvons modifier se trouve … l'offset 242h dans le fichier EXPLOIT4.BIN . SHASHING DE EIP =============== Nous avons donc maintenant trouver l'endroit ou aller mettre la valeur pour revenir au d‚but de notre buffer. Cependant, nous arrivons ici … un cas particulier, mais courant dans les programmes Windows. De quoi s'agit-il ? L'adresse de notre buffer, est approximativement 00CCxxxx (en observant la valeur de ESP le plus vite possible aprŠs l'ex‚cution du saut vers 0DDDDDDDDh). Donc l'adresse de la pile contient un byte 00h, et le dernier byte que nous allons mettre va nous poser problŠme: il ne sera pas ajouter dans le buffer, et donc tout semble … refaire ! :(((((( Pour contourner ce problŠme, nous allons analyser la valeur des registres lors de l'ex‚cution du RET, et observer ceux d'entre eux, qui pointent vers des adresses trŠs proches de ESP (adresse de la pile). En effet, nous pourrions alors essayer de proc‚der comme ceci: par exemple, si la valeur du registre EDX est proche de l'adresse de ESP, nous pouvons essayer de trouver une instruction "CALL EDX" cod‚e dans une DLL charg‚e par le programme (… une adresse ne contenant pas de 00h), sauter vers l'adresse de ce CALL via le RET que nous ‚crasons, qui s'ex‚cutera et ressautera lui vers l'offset EDX, qui sera le plus prŠs possible de notre buffer. Nous relancons donc WarFTP, en r‚activant le breakpoint … l'adresse 004219D7 RET 00000004, et nous allons noter les registres ‚ventuels qui sont proches de notre buffer. DŠs le saut vers 0DDDDDDDDh, nous avons les valeurs de registres suivantes: EAX: 00CCFD6C EBX: 00CCFD6C ECX: 00CCF714 EDX: BFF76859 ESI: 81729ECC EDI: 00CCF73C EBP: 00CCF690 ESP: 00CCF670 Notre pile (ESP) est en 00CCF670, nous remarquons donc que les registres EAX,EBX,ECX,EDI,EBP pointent tous des adresses proches de notre pile. Dans Win32DASM, observons un peu plus attentivement notre pile: A la valeur ESP+00000700, nous observons ceci: ESP+000006F4 EEEEEEEE ESP+000006F8 EEEEEEEE ESP+000006FC EEEEEEEE ESP+00000700 DDDDDDDD <- notre adresse de retour ESP+00000704 FFFFFFFF ESP+00000708 FFFFFFFF ESP+0000070C FFFFFFFF Comme ESP vaut 00CCF670, c'est ‚quivalent …: 00CCFD6C EEEEEEEE 00CCFD70 DDDDDDDD <- notre adresse de retour 00CCFD74 FFFFFFFF Registres poss‚dant des valeurs "int‚ressantes": EAX: 00CCFD6C EBX: 00CCFD6C ECX: 00CCF714 EDI: 00CCF73C EBP: 00CCF690 Nous remarquons que tout ces registres pointent sur une valeur qui est avant notre ESP. Cependant, la valeur de ces registres d‚pent peut-ˆtre d'une ex‚cution … une autre. Nous allons donc essayer de modifier notre buffer overflow pour que mˆme si la valeur du registre soit l‚gŠrement modifi‚e, elle n'empˆche pas pour autant le saut. Nous allons donc placer comme instructions dans les bytes pr‚c‚dant notre valeur de retour toute une s‚rie de NOPs (90h) , … la place des 0EEh que nous avions tant“t. Et nous placerons le code … ex‚cuter aprŠs notre adresse de retour. Cela ne pose pas un grand problŠme. C'est peut-ˆtre mˆme plus pratique, car nous disposerons ainsi de plus de m‚moire pour notre code assembleur, et nous pourrons aussi empiler sans problŠmes des valeurs sur la pile, puisque celle-ci va continuer … descendre et ne remontra pas venir ‚craser notre code. Maintenant, nous allons essayer de trouver l'adresse d'un emplacement m‚moire ou on pourrait trouver une instruction de saut, qui pourrait sauter vers la valeur d'un de ces registres. Nous allons commencer avec EAX, donc nous allons essayer de trouver dans une des DLL charg‚es par WarFTP une instruction "CALL EAX", qui soit … une adresse ne contenant pas de 00h. Relancons Win32DASM. A partir de la ligne 663, nous avons la liste des fonctions que WarFTP importe, donc la liste des fonctions qu'il appelle dans des DLLs. Nous voyons par exemple qu'il appelle des fonctions de la DLL MFC42.DLL . Nous allons donc lancer avec Win32DASM le d‚sassemblage de MFC42.DLL. Une fois le d‚sassemblage termin‚, nous lancons dans le menu "Search" la commande "Find Text", et nous sp‚cifions comme texte "call eax". Win32DASM nous indique la ligne 13057, … l'adresse 5F402C28. Nous notons cette adresse sur un pti bout de papier ;))), puis nous retournons dans UltraEdit, fichier EXPLOIT5.BIN et nous allons placer … la place de 0DDDDDDh, les valeurs 28 2C 40 5F (d– … l'inversion des bytes en m‚moire). Nous modifions par la mˆme occasion les EEh en 90h, et nous remplacons juste le 90h qui pr‚cŠde notre adresse de retour la valeur CCh. Pourquoi ? La valeur CCh repr‚sente l'instruction assembleur "INT 03", qui est une exception, interdite dans un programme Windows normal. Donc, si nous lancons WarFTP puis notre exploit, normalement nous allon avoir un message d'erreur de Windows, qui prouvera que nous sommes bien en train d'ex‚cuter le code de notre buffer overflow. Nous lancons WarFTP (plus besoin de le lancer sous Win32DASM), puis nc 10.10.10.1 21 < exploit5.bin Qu'est-ce que nous avons ? Nous avons un message qui s'affiche dans NetCat, Invalid User Name !!!! Cela veut dire qu'un des caractŠres qui est utilis‚ dans notre adresse de retour est reconnu comme invalide par WarFTP. Nous allons aller chercher dans une autre librairie, qui sera situ‚e … une autre adresse en m‚moire, aprŠs une autre instruction "CALL EAX". Par exemple, dans MSVCRT.DLL, nous lancons la recherche, et nous trouvons: 780026B0 call eax Nous continuons, jusqu'… ce que nous trouvions une instruction "CALL EAX", dont l'adresse ne contienne pas de 00h et possŠde des caractŠres qui n'aient pas l'air "bizarre". Nous arrivons … l'adresse 780101DBh. Nous r‚essayons donc, en codant cette adresse … la place de l'ancienne adresse de retour ( DB 01 01 78 ). Nous r‚essayons, et nous un message d'erreur de Windows, qui nous indique: "WAR-FTPD a caus‚ une exception 03H dans le module … 0000:00CCFD70." Ca y est ! Donc, maintenant nous sommes certain que notre code est bien ex‚cut‚, puisque Windows a d‚tect‚ l'appel de l'interruption 3h. Si nous regardons plus en d‚tail, nous remarquons d'ailleurs que l'adresse 00CCFD70 est l'adresse du RET ! C'est logique, le processeur a ex‚cut‚ notre INT 03, puis il met … jour EIP, et enfin Windows provoque une erreur. D'ailleurs, en regardant un peu plus bas dans la boŒte de message de Windows, nous trouvons: "Octets … CS : EIP : db 01 01 78 ff ff ff ff ff ff ff ff ff ff ff ..." Donc c'est bien notre adresse que nous observons l… ! Maintenant, nous avons un petit problŠme. En effet nous avons plac‚ un INT 03, et donc le processeur s'est arrˆt‚ juste avant d'ex‚cuter les bytes suivants, qui sont justement ceux de notre adresse !!! Nous allons donc recommencer, en placant cette fois le CCh aprŠs l'adresse de retour. Nous verrons ainsi ce que les instructions que repr‚sente notre adresse sont "dangereuses" ou pas. Nous cr‚ons donc EXPLOIT6.BIN, avec le CCh aprŠs les bytes DB 01 01 78. Cependant, nous rajoutons quelque 90h (NOP), avant le CCh. En effet, les 4 bytes qui codent notre adresse de retour repr‚sente des instructio, mais il est fort possible que les instructions cod‚es fasse plus de 4 bytes, et donc que le processeur interprŠte certains bytes derriŠre comme les bytes de la fin de l'instruction. En mettant 5 NOPs (90h), par exemple, nous sommes ainsi certain que notre CCh ne fera pas partie d'une instruction pr‚c‚dente et qu'il codera bien un INT 3. Qu'observons nous ? WarFTP plante toujours de la mˆme maniŠre, mais maintenant les Octets … CS : EIP ne contiennent plus notre adresse de retour. C'est donc qu'elle a ‚t‚ interpr‚t‚e comme une ou plusieurs instructions, qui apparement sont sans danger pour nous... Quelles sont les instructions qui pourraient ˆtre dangereuses ? Ben il suffirait que notre adresse de retour code une instruction du style jmp xxxx par exemple, et l… cela serait la catastrophe. Cependant, il existe finalement assez peu d'instructions dangereuses: les JUMP, CALL, PUSH, POP et c'est … peu prŠs tout... Il est aussi important de noter que la valeur de EAX n'a pas ‚t‚ modif‚e par cette instruction. En effet, nous allons nous resservir par la suite du EAX, car il va nous aider … connaŒtre plus ou moins l'adresse du buffer dans notre exploit. Dans un cas ou nous aurions eu une instruction qui foutait la merde, nous aurions alors d– faire pr‚c‚der l'adresse de retour d'un JUMP qui sautait au dessus (jump de +4 bytes). Cela est tout … fait faisable, mais inutile dans ce cas-ci, mais c'est ptˆt bon de le mentionner ;) Voil…, donc maintenant, nous avons presque fait tout le boulot pour le buffer overflow proprement dit. Nous avons smasher EIP, donc il ex‚cute le code que l'ont veut qu'il ex‚cute ! N'est ce pas formidable ;) UN EXPLOIT SOUS WINDOWS ======================= Maintenant que nous pouvons ex‚cuter le code que nous voulons, nous allons essayer de programmer un petit exploit qui sera donc ex‚cut‚ sur la machine qui ex‚cutait le serveur WarFTP. Jusqu'… pr‚sent, la technique que nous avions employ‚e ‚tait fort portable d'un systŠme … un autre. Maintenant, ‚tant donn‚ que nous allons devoir faire appel … des fonctions du systŠme pour programmer l'exploit, nous allons nous concentrer un peu plus sur Windows. Pour programmer l'exploit, il n'y a pas 36 solutions, il faut ressortir notre bon vieil assembleur MASM32 ;) Keskon va programmer comme exploit ? Ici on a l'embarras du choix. D'habitude, on a envie de programmer quelque chose qui va nous permettre d'acc‚der au disque du serveur, d'y ex‚cuter un programme, d'y charger ‚ventuellement un fichier de mot de passe, etc... Nous allons nous essayer de cr‚er un exploit qui soit "portable", c'est … dire qu'il pourra ˆtre ex‚cut‚ sur une version quelconque (Windows 95/98), mais aussi que nous pourrons reprendre son code en grande partie pour ‚ventuellement l'utiliser dans un buffer overflow d'un autre programme. Pour cela, nous allons donc programmer notre exploit complŠtement sur la pile. Cela veut dire que nous allons devoir stocker les donn‚es dans le code mˆme, et que nos variables elles-aussi devront ˆtre … des adresses dans le code. Tout d'abord, la 1Šre chose est de ne pas oublier que notre exploit ne doit comporter aucun caractŠre sp‚cial. Pas de caractŠre 00h, pas de caractŠre 0Dh, 0Ah. Comme les APIs Windows n‚cessitent souvent le passage de constantes en paramŠtres, constantes qui peuvent contenir des 00h, nous utiliserons donc la commande assembleur NOT, qui permettra d'inverser la valeur juste au moment de l'ex‚cution, et donc d'‚viter les caractŠres 00h dans le code. 2Šmement, nous risquons aussi d'avoir des 00h dans le codage hexad‚cimal des sauts relatifs. En effet, la valeur hexad‚cimale qui est cod‚e est le nombre de bytes … ajouter … l'EIP courant pour arriver … la nouvelle adresse. Or quand on fait des sauts, on fait rarement des jump qui se d‚placent de 6500000 octets. Ce sont plus souvent des sauts de quelques 10aines d'octets au grand maximum. Donc nous risquons de voir apparaŒtre des 00h dans le codage de ces sauts. Pour l'‚viter, nous essayerons donc d'utiliser des Jx SHORT, qui codent le d‚placement du saut sur le moins d'octets possible. Remarquons que dans le cas d'un saut "retour en arriŠre", le d‚placement est n‚gatif, donc nous n'aurons pas de valeur 00h. Voyons un peu comment appeler des fonctions systŠmes (APIs) sous Windows dans notre exploit. Au d‚but d'un fichier.EXE, par exemple de WAR-FTPD.EXE, on trouve toutes les APIs qui sont import‚es par le programme. Ces APIs sont import‚es dans une table, en m‚moire (jump table), qui contient l'adresse r‚elle de l'API. Cette table est g‚n‚r‚e au moment du chargement du programme, et permet … l'API de se trouver … une adresse diff‚rente selon l'ex‚cution, selon la version du systŠme,etc... Cependant, les APIs que nous voulons ‚ventuellement utiliser dans notre exploit ne sont pas forc‚ment import‚es par le programme. Windows met pourtant … notre disposition 2 fonctions, dans KERNEL32.DLL, qui nous permettent de r‚aliser nous mˆme notre propre jump table. Il s'agit des fonctions LoadLibraryA et GetProcAddress: La fonction LoadLibrary recoit comme paramŠtre un pointeur sur la chaŒne contenant le nom de la DLL dans laquelle se trouve la fonction … importer, et nous renvoie un Handle. La fonction GetProcAddress recoit comme paramŠtres ce handle, et un pointeur sur la chaŒne contenant le nom de la fonction de la DLL. Dans un programme ex‚cutable, il est trŠs rare que ces 2 fonctions ne soient pas import‚es. Donc, nous pouvons connaŒtre l'adresse de ces 2 fonctions, et les appeler pour charger d'autres fonctions et APIs que nous voulons utiliser. OUTILS ====== Pour me faciliter la tƒche et faciliter la v“tre aussi, j'ai programm‚ un petit fichier d'include pour MASM, qui va nous permettre de facilemment ‚crire des exploits quelconques (EXPLOIT.INC). Ce fichier se compose de 3 macros, appelables dans un code assembleur classique. Pourquoi des macros et pas des proc‚dures ? Parce que des macros sont incluses directemment au bon endroit dans le code, et qu'elles ‚vitent donc d'utiliser des instructions non n‚cessaires (PUSH,POP,CALL,RET,...), qui prennent des bytes pour rien. On ‚crit ici un exploit qui doit ˆtre le plus petit possible, pas un programme pour apprendre … faire de la programmation structur‚e ;) Il y a 3 macros, mais 2 d'entre-elles sont compl‚mentaires et doivent ˆtre utilis‚es ensemble. Voici comment utiliser les 2 premiŠres: DEBUTEXPLOIT: ExploitPrologue db "donn‚es",... ExploitEpilogue AddrLoadLibrary,AddrGetProcAddress,BytesVariables Ou: AddrLoadLibrary repr‚sente l'offset de la zone m‚moire qui contient l'adresse de l'API LoadLibrary. AddrGetProcAddress repr‚sente l'offset de la zone m‚moire qui contient l'adresse de l'API GetProcAddress. BytesVariables repr‚sente un nombre de bytes … r‚server pour d'‚ventuelles variables (initialis‚es … 0). Le format des donn‚es est le suivant: Des chaŒnes de caractŠres, suivie chaque fois d'un caractŠre de contr“le: 255 indique la fin de la table de donn‚es 254 indique la fin d'un nom de librairie (qui va donc ˆtre charg‚e) 253 indique la fin d'un nom de fonction de la librairie courante 252 indique la fin d'une chaŒne Ces 2 macros vont donc balayer les donn‚es, et cr‚er une table. Cette table contiendra pour les fonctions, l'adresse de la fonction qui a ‚t‚ charg‚e, et pour les chaŒne, l'adresse de la chaŒne. Ces adresses seront accessibles via le registre ESI, en descendant. L'adresse de la derniŠre fonction ou chaŒne sera en [ESI-4], l'avant derniŠre en [ESI-8],... Ce codage est effectu‚ de maniŠre n‚gative pour ‚viter de nouveau d'avoir des 00h dans le codage hexad‚cimal. Ensuite, si le paramŠtre BytesVariables est diff‚rent de 0, la macro va cr‚er autant de bytes initialis‚s … 0, accessibles via [EDI-1],[EDI-2],... ATTENTION !!! Pour ‚conomiser de la place, la table d'adresses (ESI) et la table des variables (EDI) sont cr‚‚es par dessus la table des donn‚es. Pour les noms de fonctions cela n'est pas important, puisque ceux-ci deviennent inutiles une fois que l'on a l'adresse, par contre pour les chaŒnes, celles-ci ne doivent pas ˆtre ‚cras‚es, donc je vous conseille de les placer … la fin des donn‚es. Il faut aussi chaque fois utiliser la macro ExploitPrologue, puis la proc‚dure ExploitEpilogue aprŠs, car la fin de la proc‚dure ExploitPrologue contient un jump vers le d‚but de ExploitEpilogue, pour sauter au dessus des donn‚es. La macro suivante, ExploitAlloc, vous permet de cr‚er un espace pour les variables sur le heap du programme. L'avantage est que vous disposez l… de beaucoup plus de place pour cr‚er des variables ou stocker des donn‚es, l'inconv‚nient est qu'il faut quelques lignes de code en plus, et qu'il faut avoir l'adresse d'une API particuliŠre, l'API GlobalAlloc (plus ou moins ‚quivalente … un malloc en C). On appelle donc la proc‚dure ExploitAlloc comme ceci: ExploitAlloc AddrGlobalAlloc,BytesVariables ou: AddrGlobalAlloc repr‚sente l'offset de la zone m‚moire qui contient l'adresse de l'API GlobalAlloc (pr‚sente dans le programme, ou initialis‚e par les 2 macros pr‚c‚dentes). BytesVariables repr‚sente le nombre de bytes … r‚server pour les variables (initialis‚es … 0). AprŠs l'appel de cette macro, on accŠde aux variables cr‚‚es via [EBP-1], [EBP-2],... Voil…. Pour mieux comprendre ce qui se passe, je vous conseille de jeter un petit coup d'oeil … ces macros, dans le fichier EXPLOIT.INC. J'ai ‚crit ces macros en essayant d'optimiser le plus possible la taille du code, ce qui fait que leur structure est peut-ˆtre un peu complexe, mais rappelez vous qu'on a pas 1Mg de m‚moire pour coder notre exploit ;) L'EXPLOIT ========= Au d‚but, je voulai programmer un exploit qui active le partage de fichiers NetBIOs de l'ordinateur sur lequel WarFTP ‚tait ex‚cut‚. Pour r‚aliser cela, j'allai ‚crire quelques informations dans la base des registres. Le problŠme ‚tait que pour que ces informations soient valid‚es, il fallait absolumment un red‚marrage du systŠme sur la machine. Ce n'est pas trŠs compliqu‚ … faire, mais ce qui m'embˆtait beaucoup est que dans le cas d'un IP dynamique, on perd ainsi la trace de l'ordinateur dont on avait activ‚ le partage de fichiers. Finalement, j'ai programm‚ un autre exploit, qui ouvre un port TCP sur la machine ex‚cutant le serveur FTP, et qui attend une connection sur ce port. Il nous suffit ensuite d'envoyer un fichier ex‚cutable sur ce port (par exemple un trojan ;), pour que celui-ci soit ex‚cuter sur la machine distante. Pour programmer cet exploit, j'ai utilis‚ les fonctions Winsock 1.1, assez puissantes et pas trop compliqu‚es … programmer en assembleur. ATTENTION !!! Ne pas lancer EXPLOIT.EXE … la ligne de commande, sa conception est assez particuliŠre, vu qu'il n'y a pas de segment de donn‚es, pas de pile (puisqu'il va s'ex‚cuter sur la pile), et l'appel des fonctions APIs de Windows est lui aussi particulier, donc cela ne ferait que planter votre ordinateur... L'exploit utilise les fonctions classique de Winsock version 1.1 (plus faciles … utiliser que les fonctions de Winsock 2.2 etc...), et utilise les vieilles fonctions de gestion de fichiers _lwrite, etc..., qui sont plus faciles … utiliser aussi. Le nom du fichier ‚crit qui sera ex‚cut‚ est le plus court possible, et le port ouvert 4444, a ‚t‚ choisi pour ˆtre facile a retenir et pour ˆtre un port qui est habituellement ouvrable sans problŠme (mˆme derriŠre pas mal de firewalls). Il est bon de remarquer que le fichier est charg‚ sur l'ordinateur distant, ensuite il est ex‚cut‚, puis le process WarFTP est kill‚, pour ‚viter d'alerter la personne qui est sur la machine, ou pour ‚viter un message d'erreur de Windows (qui se produirait si le programme continerai … ex‚cuter des instructions cod‚es par les bytes sur la pile). Nous assemblons l'exploit (EXPLOIT.EXE), puis nous lancons Win32Dasm sur EXPLOIT.EXE, pour aller voir ou commence le code de l'exploit dans le fichier .EXE. On remarque que le point d'entr‚e du programme est … l'offset 200h dans le fichier EXPLOIT.EXE. Nous lancons donc UltraEdit, et nous allons … l'offset 200h du fichier EXPLOIT.EXE. En descendant un petit peu, nous observons un peu plus bas une suite de 00h, qui indique vraissemblablement la fin de l'exploit. Vous remarquez au passage que l'exploit est assez court, on peut ˆtre fier de nous ! ;))) On y observe aussi les chaŒnes qui sont utilis‚es dans l'exploit (noms de librairies, etc...). Il pourrait ˆtre int‚ressant de crypter ces chaŒnes, par un NOT, ou un XOR... Mais ici ce n'est pas trop important. Maintenant, nous copions collons tout ces bytes dans EXPLOIT7.BIN, derriŠre les NOPs qui se trouvent aprŠs notre adresse de retour, et nous supprimons tout les bytes FFh aprŠs, qui prennent de la place inutile. Voici maintenant de maniŠre pratique, comment utiliser l'exploit: Nous trouvons un serveur WarFTP 1.65. Nous lancons l'exploit avec NetCat, en tapant: NETCAT -vv ip_du_serveur 21