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