OW-002-netscape-jpeg, révision 1 25 Juillet 2000 (Note du traducteur : traduction achevée le 07 mai 2001) Vulnérabilité dans le traitement du marqueur COM JPEG dans les butineurs Netscape---------------------------------------------------------------- Cet avis explique une vulnérabilité dans les butineurs Netscape présente au moins depuis la version 3.0 et jusqu'ŕ Netscape 4.73 et Mozilla M15. La vulnérabilité est fixée dans Netscape 4.74 et Mozilla M16. Impact ------ Il peut ętre possible, bien que difficile ŕ faire fiablement dans une attaque du monde réel, pour un site web malveillant d'exécuter du code assembleur arbitraire dans le contexte du butineur web. Dans le cas de Netscape Mail ou News, l'attaque peut ętre effectuée via un message mail ou un article news, également. Détails de la vulnérabilité --------------------------- Le format de flux JPEG interchange consiste en une collection ordonnée de marqueurs, de paramčtres, et de segments de données codées sur l'entropie. Beaucoup de marqueurs démarrent des segments de marqueurs, qui consistent en le marqueur suivi par une séquence de paramčtres en relation. Les segments de marqueurs sont d'une longueur variable, avec le premier paramčtre étant la longueur sur deux octets. Les longueurs codées incluent la taille du paramčtre lui-męme. Ainsi, les longueurs plus petites que 2 sont toujours invalides. Les butineurs Netscape utilisent la bibliothčque de décodage de l'Independent JPEG Group pour les fichiers au format JPEG File Interchange Format (JFIF). Toutefois, ils installent un gestionnaire sur mesure pour traiter le marqueur COM (commentaire) qui enregistre le commentaire en mémoire plutôt que de le sauter comme la bibliothčque le ferait. Malheureusement, le nouveau gestionnaire ne vérifie pas si la longueur du champ est valide, et soustrait 2 de la longueur encodée pour calculer la longueur du commentaire lui-męme. Il alloue alors de la mémoire pour le commentaire (avec un octets supplémentaire pour sa terminaison en NUL) et rentre dans une boucle pour lire le commentaire vers cette mémoire. En fixant la longueur du champ ŕ 1, il est possible de s'assurer que l'appel d'allocation mémoire (de 0 octet) va réussir. Comme la longueur calculée du commentaire est déclarée non signée, elle sera une grande valeur positive plutôt qu'une petite négative, donc la boucle ne se terminera pas avant la fin du flux JPEG. Elle lira le flux JPEG vers le tas, en réécrivant d'autres tampons de Netscape dynamiquement alloués, aussi bien que sur les structures internes de la mise en oeuvre de malloc(3). Exploiter cette vulnérabilité en exécutant du code arbitraire n'est pas trivial, mais possible sur quelques plate-formes. Le problčme réel ---------------- Est-ce que le problčme est le manque de vérification d'erreur dans le code ? Bien sűr. Une faute de programmeur. Est-ce un problčme causé par le choix d'un langage de programmation qui n'offre pas de vérification de débordement et de compilateurs qui traditionnellement n'offrent pas de vérification de limite ? Partiellement. Toutefois, regardons combien de formats de fichiers différents, de langages, et de protocoles un butineur web moderne doit supporter. Tous les analyseurs de fichiers ont ils été initialement mis en oeuvre avec l'intention d'ętre robustes contre des données non de confiance et peut-ętre malveillantes ? Si non, tous les cas ont ils été couverts avec des vérifications supplémentaires maintenant ? Avons nous une raison de croire qu'il n'y a pas de bogue dans la mise en oeuvre de chacun de ceux-ci, ou avons nous des raisons de suspecter le contraire ? Des solutions ? Il y a peu qu'un utilisateur final puisse faire, mais vous pouvez prendre cet avis comme encore un autre rappel d'exécuter le navigateur web que vous utilisez pour accéder ŕ des contenus de non confiance dans un environnement restreint, sans accčs ŕ vos données les plus critiques. Malheureusement, ceci n'est pas facile ŕ faire dans le monde Win32, encore. Réparations ----------- Mettez ŕ jour vers Netscape 4.74 ou Mozilla M16, ou plus récent. Comme alternative, les utilisateurs de Mozilla peuvent appliquer le patch suivant (contre Milestone 15) et recompiler les sources : --- mozilla/modules/libimg/jpgcom/jpeg.cpp.orig Tue Mar 28 02:08:15 2000 +++ mozilla/modules/libimg/jpgcom/jpeg.cpp Wed May 24 17:24:03 2000 @@ -469,6 +469,10 @@ /* Get 16-bit comment length word. */ INPUT_2BYTES(cinfo, length, return FALSE); + if (length < 2) { + cinfo->err->msg_code = JERR_BAD_LENGTH; + il_error_exit((j_common_ptr)cinfo); + } length -= 2; /* discount the length word itself */ PR_FREEIF(ic->comment); Contournement ------------- Inclus dans l'archive qui accompagne cet avis (voir ci-dessous) un patch binaire non officiel pour les versions plus anciennes des butineurs Netscape sur quelques plate-formes. Le code source et un binaire Win32 du programme patch sont fournis. Vous ne devriez seulement utiliser ce patch que si vous ne pouvez pas mettre ŕ jour vers une version réparée. Il n'y a aucune garantie. Ce patch empęche le butineur d'installer son propre gestionnaire de marqueur COM plutôt que de réparer le gestionnaire lui-męme. Ce dernier nécessiterait plus de code et résulterait dans un motif de recherche bien plus grand qui ne s'appliquerait pas ŕ autant de versions de Netscape. Merci de noter que celui-ci peut refuser de s'appliquer ŕ votre version de Netscape ou que celui-ci peut ne pas fonctionner pour vous. Assurez vous de vérifier que le patch a fonctionné comme destiné en essayant d'afficher le fichier de démonstration JFIF (crash.jpg). Votre butineur ne devrait plus planter, et vous devriez voir une image identique ŕ celle dans valid.jpg (męme si crash.jpg est en fait un fichier JFIF invalide, mais ce n'est plus un problčme de sécurité et c'est juste la façon dont la bibliothčque de l'Independent JPEG Group fonctionne). Exploiter la vulnérabilité -------------------------- La vulnérabilité nous permet de réécrire des endroits du tas au delŕ de l'espace alloué. Nous sommes limités par les caractčres imprimables, NUL et LF. Ainsi, la possibilité d'exploiter ceci pour faire plus qu'un plantage dépendra des configurations locales sur quelques plate-formes. D'abord nous avons besoin de décider sur quoi nous réécrivons. Les structures internes de la mise en oeuvre de la mémoire dynamique est la cible la plus prometteuse : elles sont toujours lŕ bas et elles contiennent typiquement des pointeurs. Pour l'exemple ci-dessous, nous assumerons le malloc de Doug Lea (qui est utilisé par la plupart des systčmes Linux, libc 5 et glibc) et un locale pour un jeu de caractčres 8 bits (tels que la plupart des locales qui viennent avec glibc, en incluant en_US, ou ru_RU.KOI8-R). Les champs suivants sont gardés pour tout les morceaux libres sur la liste : taille du morceau précédent (si libre), la taille de ce morceau, et des pointeurs vers les morceaux suivants et précédents. De plus, le bit 0 de la taille d'un morceau est utilisé pour indiquer si le morceau précédent est utilisé (LSB du morceau actuel est toujours zéro ŕ cause le la taille de la structure et de l'alignement). En jouant avec ces champs avec attention, il est possible de tromper des appels ŕ free(3) en réécrivant des endroits mémoire arbitraires avec nos données. free(3) vérifie si un morceau adjacent ŕ celui étant libéré est utilisé et, si non, consolide les deux morceaux en déliant les morceaux adjacents de la liste. Délier un morceau implique de configurer le pointeur "next" du morceau précédent et le pointeur "previous" du morceau suivant oů les deux de ces morceaux sont adressés via les pointeurs du morceau étant délié. Ainsi, afin d'obtenir le contrôle sur ces écritures de mémoire, nous avons besoin de réécrire les deux pointeurs dans un morceau (ou peut ętre d'allouer de la mémoire ŕ ce moment) et de façon préférée réinitialiser le drapeau PREV_INUSE du morceau suivant. Ceci prend 13 octets sur un 32-bit little endian, tel que Linux/x86 (8 octets pour les deux pointeurs, 4 octets de réservation pour le champ taille précédent, et 1 octet pour réinitialiser le drapeau). En pratique, nous voudrons répéter le motif désiré de 16 caractčres (duquel seulement 9 octets importent) au moins plusieurs fois pour augmenter nos chances en cas de morceaux alloués plus grands. Les pointeurs écrasés servent ŕ stocker ŕ la fois les adresses et les données, ce qui limite notre choix de données : elles doivent également représenter des adresses valides, et la mémoire ŕ cette adresse doit ętre en écriture. Maintenant nous avons besoin de décider quel pointeur nous voulons réécrire (il n'y a pas d'utilité ŕ réécrire ce qui n'est pas un pointeur avec une adresse). Un bon candidat serait toute adresse de retour sur la pile. Ceci fonctionnerait, mais ne serait pas trčs fiable puisque l'endroit d'une adresse de retour dépend de la quantité de données dans la pile. Une meilleure cible serait un pointeur de fonction. Nous ne voulons pas deviner des endroits exacts dans la pile et nous ne pouvons pas aller dans les sections ELF sur x86 (BS n'est pas un caractčre imprimable). Donc nous sommes effectivement limités aux pointeurs dans les bibliothčques partagées. Un pointeur intéressant que nous pouvons utiliser est __free_hook, ainsi le second appel ŕ free(3) nous donnera le contrôle. Les hooks de débogage sont toujours compilés quand le code de Doug Lea fait partie de la GNU libc. Notre prochaine décision est ŕ propos de l'endroit oů nous voulons que le contrôle soit transféré. Nous préférerions certainement d'avoir notre "shellcode" dans le fichier JFIF lui męme. Cependant, l'ensemble limité de caractčres pourrait nous empęcher de passer des adresses du tas. Nous devons installer dans la pile et y placer notre code via une autre partie du butineur avant de déborder. Nous pouvons utiliser un tas de NOP ou équivalents pour éviter d'avoir ŕ fournir un endroit exact de la pile. Un compilateur pour produire des fichiers JFIF mettant en oeuvre l'approche ci-dessus est inclus dans l'archive d'accompagnement. Merci de noter que ceci n'est par aucun moyen limité ŕ Linux/x86. C'est juste qu'une plate-forme devait ętre choisie pour l'exemple. Ainsi, il est connu que ceci est exploitable au moins sur les installations Win32 d'une façon trčs similaire (via ntdll!RtlFreeHeap). Références ---------- Les programmes supplémentaires et les fichier JFIF d'exemple mentionnés dans cet avis sont fournis dans l'archive d'accompagnement, qui peut ętre téléchargée via l'un de ces liens : http://www.openwall.com/advisories/OW-002-netscape-jpeg-r1.tar.gz http://www.openwall.com/advisories/OW-002-1.zip MD5 (OW-002-netscape-jpeg-r1.tar.gz) = 05b9879474e6b8988cd3141760e07826 MD5 (OW-002-1.zip) = ea3a7febd3d8410382bcbf7463cf32a3 Le format d'échange JPEG est documenté dans le Standard International ISO 10918-1 et la Recommandation CCITT (maintenant ITU-T) T.81. La spécification JFIF et la bibliothčque IJG sont disponibles sur : ftp://ftp.uu.net/graphics/jpeg/ Crédits et informations de contact ---------------------------------- Cette vulnérabilité a été trouvée et l'avis écrit par Solar Designer <solar@false.com>. Je voudrais remercier Kevin Murray de Netscape Communications et beaucoup d'autres de la communauté Mozilla et de Netscape pour leurs supports dans la gestion de cette vulnérabilité. Les version mises ŕ jour de cet avis et des autres avis Openwall seront disponibles sur : http://www.openwall.com/advisories/ Note du traducteur : cette traduction française (non officielle) a été réalisée par Denis Ducamp <Denis.Ducamp@groar.org> et est disponible sur : http://www.groar.org/~ducamp/english.html#sec-trad