• Aucun résultat trouvé

La famille des fonctions *scanf() et *sprintf()

Dans le document Exploitation avancée de buffer overflows - (Page 40-43)

argc argc user stack

7. La famille des fonctions *scanf() et *sprintf()

“A false sense of security, is worst than insecurity”,

Steve Gibson

7.1 Erreurs sur la taille maximale

La famille des fonctions scanf() est davantage connue pour les risques de format bugs dans leur utilisation. Cependant, comme les format bugs ne font pas partie de la classe des buffers overflows et bien que certaines méthodes d’exploitation des format bugs soit proche de celle des buffer overflow, et il ne sera pas question de cela dans ce chapitre.

Evidemment, pour la plupart des fonctions de la famille scanf(), si on ne teste pas la longueur de la string à copier il y a le même risque de buffer overflow que pour les fonctions strcpy() et strcat(). Par exemple, les utilisations suivantes de ces fonctions sont toutes dangereuses :

scanf("%s", dest);

sprintf(dest, "%s", source);

Pour remédier à ce problème, une taille limite peut être indiquée pour la format string dans le format tag. Pour les strings des fonctions *scanf(), cela se fait en plaçant un format tag de cette manière%<taille>s.

Malheureusement, une fois de plus, les programmeurs ont quelques problèmes quand il s’agit de comptabiliser ou non le byte NULL qui termine les strings. Dans le cas de ces fonctions, il ne faut pas comptabiliser le ce dernier byte !

Voici un exemple d’erreur où le programmeur croyait éviter un buffer overflow. Cet exemple est inspiré du récent bug découvert dans le daemon CVSd.

char buf[16];

int i ;

sscanf(data, "%16s", buf);

Ce morceau de code est vulnérable à un one byte overflow. Le programmeur aurait dû comptabiliser le NULL terminator de la string et utiliser un tag"%15s" pour éviter le buffer overflow.

Un autre risque de confusion est que, pour fixer la taille limite des strings des fonctions *sprintf(), il faut par contre utiliser le paramètre de précision dans le format tag, soit %.<taille>s. Pour les fonctions *sprintf(), le format tag %<taille>s

indique une taille minimale et est donc complètement sans valeur pour prévenir un buffer overflow.

Nous montrons ici pour sprintf() deux utilisations qui ne préviennent pas des buffer overflows :

char buf[BUF_SIZE];

sprintf(buf, "%.*s", sizeof(buf), "une-grande-string");

Le caractère * permet de passer la taille maximum en paramètre. Il s’agit donc de la même utilisation erronée que celle que nous avons montrée pour scanf(). En voici une autre :

char buf[BUF_SIZE];

sprintf(buf, "%*s", sizeof(buf)-1, "une-grande-string");

Ici nous n’avons omis le . dans le format tag. L’utilisation correcte serait donc de la forme :

char buf[BUF_SIZE];

sprintf(buf, "%.*s", sizeof(buf)-1, "une-grande-string");

7.2 Le cas de snprintf()

Une autre manière de contrôler la taille du buffer à copier pour la fonction sprintf() est d’utiliser son homologue sécurisé snprintf(). Cette fonction permet de passer en deuxième paramètre la taille maximale à copier. Toutefois, cette fonction souffre de quelques problèmes.

Le problème principal de snprintf() est qu'elle n'est pas une fonction C standart. Elle n'est pas définie dans le standart ISO 1990 (ANSI 1989) comme l'est sa cousine sprintf(). Ainsi, pas toutes les implémentations choisissent les mêmes conventions.

Certains vieux systèmes appellent ainsi directement sprintf() quand ils rencontrent une fonction snprintf()! Ce fut le cas par exemple de l'ancienne libc4 de Linux ou dans des vieilles versions du système d'exploitation HP-UX. Dans ces cas, on croit contôler l'apparition de buffers overflows alors que le programme reste vulnérable à l'exploitation de ces overflows. Dans certains systèmes, snprintf() n'est même pas définie. De plus, des versions de snprintf() n'ont pas le même usage suivant le système où elles sont définies: certaines implémentations, comme pour strncpy(), ne garantiraient pas une null-termination.

Enfin, la valeur de retour n’est pas la même pour toutes les implémentations.

Certaines vieilles versions retournent ainsi –1 si la string à copier a dû être tronquée après avoir dépassé la taille maximale spécifiée alors les autres, conformément au standart C99, retournent le nombre d’octet qui aurait du être copié dans la chaîne finale s’il y avait assez d’espace disponible.

7.3 Exemples d’erreurs de patch d’un overflow

Pourquoi parler de patch quand on s’intéresse à l’exploitation des buffer overflows ? Il se trouve en fait que certains programmeurs remarquent une situation d’overflow et tentent de la prévenir mais en le faisant de manière inadéquate laisse le programme toujours exploitable. Ceci est par exemple le cas lors des utilisations erronées des fonctions strncpy()/strncat() ou de celle des fonctions des familles scanf() et sprintf() dont nous avons parlé dans les chapitres précédents.

Nous montrons ici deux exemples de programmes qui tentent de prévenir un overflow mais échouent à cause d’erreurs de conception.

L’exemple qui suit, trouvé au hasard d’un audite de code, est élogieux en la matière :

char dest[BUF_SIZE] ; strcpy(dest, source);

if (strlen(dest) >= BUF_SIZE) { /* gestion de l’erreur*/

Le programmeur tente donc de faire récupérer la face au programme après un overflow. C’est une erreur grave. En effet, cela n’empêche en rien le programme d’être toujours exploitable. Même un appel direct à exit() pour gérér l’erreur est inapproprié, car dans certains cas cela n’empêcherait pas l’exploitabilité de l’overflow. La meilleure solution ici reste donc d’utilister une fonction comme strncpy().

Quelque fois certains programmeurs qui utilisent les fonctions strcpy() ou sprintf(), testent directement la longueur de la string source avant la copie pour gérer l’erreur en cas d’overfow.

char dest[BUF_SIZE] ;

if (strlen(dest) > BUF_SIZE) { /* gestion de l’erreur*/

}

strcpy(dest, source);

Là le programmeur oublie de comptabiliser le byte NULL lors de la comparaison, et son inégalité n’est donc pas complète. Il fallait utilisait un >= au lieu de l’inégalité stricte.

Dans le document Exploitation avancée de buffer overflows - (Page 40-43)

Documents relatifs