jeudi 11 mars 2010

basics 5 - tutoriel crypt() - attaque de mots de passe hachés avec DES ou MD5


Dans cet article nous allons observer les méthodes de hachage de mot de passe DES et MD5. Ces méthodes étaient encore jusquà peu utilisées dans Ubuntu. Ubuntu utilise à présent SHA512 par défaut pour chiffrer ses mots de passe.




crypt()

Un coup d'oeil concernant la fonction crypt() sur le manuel de la libc [16].

ATTENTION, cette documentation est obsolète. Comme nous l'avons vu,Ubuntu Karmic 9.10 utilise SHA512 par défaut!
— Function: char * crypt (const char *key, const char *salt)
The crypt function takes a password, key, as a string, and a salt character array which is described below, and returns a printable ASCII string which starts with another salt. It is believed that, given the output of the function, the best way to find a key that will produce that output is to guess values of key until the original value of key is found.
The salt parameter does two things. Firstly, it selects which algorithm is used, the MD5-based one or the DES-based one. Secondly, it makes life harder for someone trying to guess passwords against a file containing many passwords; without a salt, an intruder can make a guess, run crypt on it once, and compare the result with all the passwords. With a salt, the intruder must run crypt once for each different salt.
For the MD5-based algorithm, the salt should consist of the string $1$, followed by up to 8 characters, terminated by either another $ or the end of the string. The result of crypt will be the salt, followed by a $ if the salt didn't end with one, followed by 22 characters from the alphabet ./0-9A-Za-z, up to 34 characters total. Every character in the key is significant.
For the DES-based algorithm, the salt should consist of two characters from the alphabet ./0-9A-Za-z, and the result of crypt will be those two characters followed by 11 more from the same alphabet, 13 in total. Only the first 8 characters in the key are significant.
The MD5-based algorithm has no limit on the useful length of the password used, and is slightly more secure. It is therefore preferred over the DES-based algorithm.
When the user enters their password for the first time, the salt should be set to a new string which is reasonably random. To verify a password against the result of a previous call to crypt, pass the result of the previous call as the salt.
Cette description appelle plusieurs remarques:
- Le salt de DES est constitué de seulement deux caractères,
- La clé DES a une taille maximale de 11 caractères, dont seuls les 8 premiers sont significatifs. Ainsi les clés 12345678 et 123456789, utilisées avec le même salt, fournissent le même hash.

DES vs MD5

Voyons tout cela:

Sur la machine intrus, copions le source suivant dans un fichier genere_password.c
#include < unistd.h>
#include < stdio.h>
#include < string.h>


int main(int argc, char *argv[]) {
char *clair;
char *salt;
if(argc<3) printf(“Usage : motDePasseClair salt \n”);
else {
clair=argv[1];
salt=argv[2];
printf("Le chiffré est : %s\n",(char*)crypt(clair, salt));
}
return(0);
}
compilons:
intrus$ gcc -lcrypt -o genere_password ./genere_password.c
voici le résultat avec DES:
intrus$ ./genere_password 1234567 ss
Le chiffré est: ssa3oBf/DtBng
intrus$ ./genere_password 12345678 ss
Le chiffré est: ssoQRtDQFsXkU
intrus$ ./genere_password 123456789 ss
Le chiffré est: ssoQRtDQFsXkU
Nous obtenons le même chiffré avec des clés de 8 et 9 caractères.

A présent utilisons MD5. Pour cela, il suffit de définir un salt sous la forme: $1$ 8caractères maximum $
intrus$ ./genere_password 12345678 '$1$123456789'
Le chiffré est: $1$12345678$f8QoJuo0DpBRfQSD0vglc1
intrus$ ./genere_password 123456789 '$1$123456789'
Le chiffré est: $1$12345678$yRP2PzM0ZPA3W0Q4o/Axk1
Nous remarquons bien que:
- pour utiliser MD5, il faut faire commencer le salt par $1$
- le salt est limité à 8 caractères (ce qui est toujours mieux que deux caractères pour DES),
- la taille de la clé n'est pas limitée à 8 caractères.

John the Ripper

A présent, voyons un outil pour tester la force des mots de passe:

prérequis: installer John-the-Ripper
intrus$ sudo apt-get install john
copions nos résultats précédents dans deux fichiers:
DES:
DES_1234567_ss:ssa3oBf/DtBng
DES_12345678_ss:ssoQRtDQFsXkU
DES_123456789_ss:ssoQRtDQFsXkU
MD5:
MD5_12345678_$1$123456789:$1$12345678$f8QoJuo0DpBRfQSD0vglc1
MD5_123456789_$1$123456789:$1$12345678$yRP2PzM0ZPA3W0Q4o/Axk1
puis lâchons john sur ses proies:
intrus$ john --show DES
DES_1234567_ss:1234567
DES_12345678_ss:12345678
DES_123456789_ss:12345678
3 password hashes cracked, 0 left
intrus$ john --show MD5
MD5_12345678:12345678
MD5_123456789:123456789
2 password hashes cracked, 0 left

conclusion

DES est un algorithme insuffisant pour chiffrer les mots de passe: la taille maximale du mot de passe est de 8 octets, le sel de 2.
Un mot de passe faible (simpliste ou trop court) est rapidement craqué avec un outil comme John The Ripper.

références

16) manuel libc – fonction crypt() - http://www.gnu.org/s/libc/manual/html_node/crypt.html

3 commentaires:

  1. Merci pour ce tutoriel.
    Cependant, je n'arrive pas à compiler le programme (sur Ubuntu 10.04 et 9.10), j'ai les erreurs suivantes :
    http://www.pastebin.org/382106
    J'ai pourtant installé les paquets build-essential et libc6-dev.
    Avez-vous une idée du problème ?
    Merci

    RépondreSupprimer
  2. Bonjour,
    Dans le code source, je suis obligé d'écrire
    #include < stdio.h> au lieu de
    #include (insertion d'un caractère SP après la balise < )

    En effet, Blogger bug si je ne fais pas cette modification du code source. Cela répond-il à ton pb?

    RépondreSupprimer
  3. Bonjour,
    Effectivement, la première partie du problème venait de là (je pensait que les espaces étaient muets ici aussi).
    Pour la suite des erreurs, elles venaient d'un problème de guillemets (ceux de Blogger ne fournissent pas le bon unicode).
    Merci de ton aide, tout fonctionne maintenant.

    RépondreSupprimer