Retrouvez cet article dans : Misc 17
Ce que le développeur a trouvé
Commençons par les erreurs trouvées par le collègue de Junior :-----Message d'origine----- De : Modeste Collegue Envoyé : vendredi 11 juin 2004 16:10 À : Junior Objet : Ton code est pourri Salut Junior, J'ai jeté un rapide coup d’œil à ton code. Y a tt de même des problèmes. Et notamment, tu es bien trop confiant. Tu devrais regarder - la RAM - la fonction buildMsgAuth de chapclient.c() et  doCheck() de chapserver.c - tester tes allocations mémoire
Examen de la RAM
Effectivement, tous les mots de passe (Integer Overflow
Junior a oublié d'examiner les cas où le client ou le serveur CHAP sont malicieux. Dans le code source de chapclient.c (fonction len_challenge = strlen(challenge);  todigest = (char*) malloc(len_passwd+len_challenge);  memcpy(todigest,passwd,len_passwd);  memcpy(todigest+len_passwd,challenge,len_challenge);En effet, le code source suppose que le challenge renvoyé par le serveur est une chaîne (par 'chaîne', on entend un buffer de caractères terminés par '\0') – en passant, ceci n'est d'ailleurs pas une très bonne idée. Mais que se passe-t-il si on est connecté à un serveur malicieux (ou buggé) qui n'envoie pas une chaîne ?
len_passwd = strlen(gDb[index].passwd);Cette fois-ci, on suppose que le mot de passe de l'utilisateur sera une chaîne, mais si la base de données des utilisateurs est vérolée, on se trouve confronté à un integer overflow.
Plus de mémoire disponible
Junior a également oublié de tester ses allocations mémoire. Que se passe-t-il s'il n'y a plus d'espace mémoire ? Par exemple, à la ligne 17 de la fonction doCheck dans chapserver.c, l'allocation du buffer n'est pas testée :    todigest = (char*) malloc(len_passwd+len_challenge);Donc, en cas de pénurie, un pointeur retourné sera NULL, et à la première utilisation de todigest l'application plantera. Il s'agit là avant tout d'une erreur de programmation, mais un attaquant peut s'en servir pour faire planter l'application : il remplit l'espace mémoire exprès, et provoque ainsi une erreur du client ou du serveur CHAP. De telles failles ont déjà été exploitées dans d'autres systèmes, voir par exemple [VFS99].
Ce que l'architecte a trouvé
Quant à l'architecte, il appela immédiatement Junior au bout du fil : " Junior ? Oui, j'ai vu ton code. Passe me voir, j'ai trouvé quelques petits points... ".Pas d'authentification du serveur
On constate en effet que le client s'authentifie auprès du serveur mais pas réciproquement. Ainsi, l'utilisateur n'a aucune garantie de bien dialoguer avec un serveur honnête. Dans certains cas, pour privilégier la simplicité, ceci peut être acceptable. Cependant, dans la majorité des cas, il faut faire attention aux conséquences : que se passe-t-il si le serveur envoie des paquets complètement erronés ? Aussi, que se passe-t-il si les messages du serveur ne parviennent pas au client ? Si les primitives de communication sendMsg et recvMsg n'implémentent pas de timeout, on risque fort d'attendre à l'infini un défi du serveur…Trop bavard
Le serveur d'authentification de Junior est trop bavard. En particulier, la fonction lookupName() dans chapserver.c affichera " utilisateur introuvable " si l'identifiant saisi est inconnu, mais rien du tout (si ce n'est "Authentification: REFUSE" dans doCheck) si le mot de passe est incorrect. Cette différence donne inutilement trop d'informations à l'attaquant. Il aurait fallu afficher seulementCe que le cryptologue a trouvé
Pour sa part, le cryptologue remonta aimablement les erreurs suivantes à Junior, avec une petite annotation tout de même " je donne des cours de cryptologie à l'Université, si ça vous intéresse... ".MD5 n'est pas un MAC
MD5 est une fonction de hashage, mais dans le code source de Junior elle est utilisée avec une clé, en tant que MAC (Message Authentication Code). Très exactement, la réponse au défi d'authentification est le calcul :MD5(mot de passe || texte), || signifiant la concaténationOr, d'une manière générale, il est risqué d'utiliser une fonction de hashage en guise de MAC avec tout simplement la clé en préfixe (voir [HAC, §9.64]). En effet, il est alors possible sous certaines conditions de calculer un hashé valide sans avoir la clé. Si on considère qu'une fonction de hashage H est constituée d'une fonction de compression f utilisée en boucle alors à l'étape i, le hashé de x est : hi=f(hi-1,x)) Donc si l'on connaît
R'= H(mot de passe || texte') = H(mot de passe || texte || ajout) = f(H(mot de passe || texte), ajout) =f(R,ajout).On calcule donc R' à l'aide de R et de " ajout ", sans avoir besoin du mot de passe. H est une fonction de hashage valide, mais un très mauvais
MD5 n'est pas " recommandé "
Junior utilise MD5, or cela fait des années qu'il n'est plus " recommandé " d'utiliser cette fonction. Plus exactement, des travaux de Dobbertin ont prouvé que la fonction de compression de MD5 était sujette à des collisions (on rappelle qu'on parle de " collision " lorsque deux textes initiaux t et t' donnent le même hashé – ce qui est bien entendu à éviter ! ). La démonstration a même été faite par l'exemple en moins de 10 heures sur un PC de 1996 [Rob96]. Il faut cependant nuancer cette trouvaille : on avait trouvé des collisions sur la fonction de compression mais pas sur MD5 dans son intégralité. Les cryptologues ne pouvaient donc pas dire que MD5 était " cassé ", mais juste pré-dire qu'il le serait dans un avenir proche. La prédiction s'est révélée justifiée, et tout récemment, lors de la conférence Crypto'2004, des chercheurs ont réussi à trouver des collisions sur MD5 même [WFLY04]. Dans la pratique, il resterait encore à exploiter cette faille (par exemple générer exprès des collisions pour tout texte), mais quoi qu'il en soit, la sécurité de MD5 est sérieusement compromise. Pourquoi s'embarrasser d'un tel algorithme, alors qu'il en existe d'autres bien plus sûrs tels que SHA-1, SHA-256, SHA-512 etc. ?Un mot de passe n'est pas une clé sûre
Le mot de passe entré par l'utilisateur est directement utilisé en tant que clé. Or, d'une manière globale, la solidité des algorithmes de cryptographie est basée sur la difficulté à trouver cette clé. Hélas, un mot de passe a bien moins d'entropie qu'une véritable clé " aléatoire ", et offre donc une sécurité amoindrie. Il est donc fortement " conseillé " d'utiliser des mécanismes tels que ceux décrits dans [PKCS#5] pour utiliser un mot de passe utilisateur en tant que clé cryptographique. Par ailleurs, un mot de passe de 8 caractères est généralement, hélas, d'une solidité douteuse. Le nombre de bits d'une clé se calcule par la formule log2(nm), où n est la taille du jeu de caractères utilisables et m la taille du mot de passe. Pour un mot de passe de 8 caractères utiles (on rappelle que dans le code de Junior le 9ème est forcément le caractère '\0'), si l'utilisateur se sert d'un jeu de 36 caractères alphanumériques et 10 caractères spéciaux (ce qui est déjà optimiste pour la majeure partie des utilisateurs), on obtient approximativement une clé de 44 bits. En guise de comparaison, DES utilise des clés de 56 bits et AES utilise au minimum 128 bits…Le défi n'est pas suffisamment aléatoire
Le protocole d'authentification par défi repose sur une génération aléatoire du défi. Si l'attaquant peut deviner le futur défi, cela perd de son intérêt. Or utiliser directement l'heure en tant qu'aléa n'est franchement pas très sérieux. Dans l'implémentation de Junior, le défi n'est modifié que toutes les minutes (voir la fonction buildMsgChallenge de chapserver.c). Il est fort possible d'effectuer un rejeu durant cette période là . Junior aurait au moins pu utiliser le générateur pseudo-aléatoire fourni dans OpenSSL (fonctions RAND_xxx). Attention à ne pas oublier de l'initialiser avec des données aléatoires (RAND_add). Remerciements Je remercie tout particulièrement Philippe Biondi, Christophe Grenier et Frédéric Raynal pour leurs suggestions et remarques. Références- [CC++] Anonyme, C and C++ are obsolete, papier n°2, Mars 2003, http://www.cs.rutgers.edu/~rmartin/teaching/spring03/cs553/papers01/
- [HAC] A. Menezes, P. van Oorschot, S. Vanstone, Handbook of Applied Cryptography, CRC Press, ISBN 0-8493-8523-7, Octobre 1996.
- [HMAC] H. Krawczyk, M. Bellare, R. Canetti, HMAC: Keyed-Hashing for Message Authentication, RFC 2104, Février 1997, http://www.faqs.org/rfcs/rfc2104.html
- [MISC6] G. Bart, " Récupérez votre code PIN ou une clé RSA avec un chronomètre ", MISC n°6, mars/avril 2003.
- [MISC14] P. Biondi, S., " Reverse engineering sous Unix ", MISC n°14, juillet/août 2004.
- [PKCS#5] PKCS #5, " Password Based Cryptography Standard  ", v2.0, http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/
- [Phra02] Blexim, Basic Integer Overflows", Phrack Issue 60, No. 10/16, 28 décembre 2002, http://www.phrack.org/phrack/60/p60-0x0a.txt
- [Reas03] Reasoning, How Open Source and Commercial Software Compare, British Computing Society, SIGiST - 1er août 2003
- [Rob96] M. J. B. Robshaw, "Â On Recent Results for MD2, MD4 and MD5Â ", RSA Laboratories' Bulletin, no. 4, 12 Novembre 1996.
- [SSL] OpenSSL, http://www.openssl.org
- VFS99] C. M. Hannum, FreeBSD vfs_cache Memory Consumption DoS, 21 septembre 1999, http://www.osvdb.org/displayvuln.php?osvdb_id=1079
- WinHex] WinHex, http://www.x-ways.net/winhex/index-m.htmlÂ
- [WFLY04] Xiaoyun Wang, Dengguo Feng, Xuejia Lai, Hongbo Yu, Collisions for hash functions MD4, MD5, HAVAL-128 and RIPEMD, Crypto'2004.Â
Retrouvez cet article dans : Misc 17





Donnez votre avis
Vous devez avoir ouvert une session pour écrire un commentaire.