RSA DATA SECURITY, INC.: AN MD5 RECOVERY TOOL BASED ON BRUTE FORCE METHOD AND DI

cs_grandvizir Messages postés 1106 Date d'inscription samedi 8 novembre 2003 Statut Membre Dernière intervention 3 septembre 2006 - 9 avril 2005 à 12:36
ni69 Messages postés 1418 Date d'inscription samedi 12 juin 2004 Statut Membre Dernière intervention 5 juillet 2010 - 4 mai 2008 à 00:48
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/30641-rsa-data-security-inc-an-md5-recovery-tool-based-on-brute-force-method-and-dictionnaries

ni69 Messages postés 1418 Date d'inscription samedi 12 juin 2004 Statut Membre Dernière intervention 5 juillet 2010 12
4 mai 2008 à 00:48
Bonjour Grandvizir,

Je voulais te signaler un petit bug que j'ai découvert récemment dans le code de cette source qui rend absolument inopérante la méthode de Brute Force lorsque l'on choisit le filtrage défini par 'All ASCII characters'.

Par exemple, si l'on tente de retrouver la chaîne '!!' à partir de son empreinte (EF9FCDB53E4E10B12BFCD5E9E78135DC), le programme s'exécute... Mais n'a aucune chance de retrouver le résultat, qui est pourtant trivial (255^2 possibilités c'est rien quand on en teste plus de 600000 par seconde !)

En fait, dans la boucle de test, ce qui se passe concrètement est qu'une fois arrivée à 255, la valeur du premier élément de 'ArrTbl' repasse à 0. Hé oui c'est un array of byte !!! Or le masque ASCII est constitué de 256 caractères (en comptant #0) donc comme la boucle ne passe à l'étude du mot comportant un caractère de plus que si cette limite est atteinte, on tourne en rond en testant toujours les mêmes chaînes constituées d’un seul et unique caractère, et la boucle est ainsi infinie !

Il suffit de modifier la déclaration de ArrTbl en :
ArrTbl : array[1..MxBuff] of word
Avec un tableau de nombres codés sur 2 octets on est tout de suite un peu plus tranquille... et ça marche mieux !

A bientôt,
Nico
entity666 Messages postés 13 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 22 novembre 2007
22 nov. 2007 à 23:53
Bah comme tu es sur codes-sources il te faudra forcément le language pour compiler et en l'occurence tu es sur delphifr donc forcément te faut delphi ...( Je dirai même plus minimum delphi6 voire 7 c'est mieux lol )
xD
GodOfWaves Messages postés 2 Date d'inscription vendredi 3 août 2007 Statut Membre Dernière intervention 19 novembre 2007
19 nov. 2007 à 15:04
salut ta source a l'air d'être super mais peux tu peux dire s'y on a besoin d'un certain programme pour compiler ta source ? Merci
cs_grandvizir Messages postés 1106 Date d'inscription samedi 8 novembre 2003 Statut Membre Dernière intervention 3 septembre 2006 22
4 juin 2005 à 15:36
Ben non: les 9 lettres donnent 2^9 combinaisons si on considère uniquement les minuscules et majuscules. La capacité du dico est donc multipliée par 512 et non par 81 (les exposants n'étaient pas calculés dans le bon sens). Mais avec tous les caractères spéciaux dérivés, ça devient... pouf... un monument indestructible ! Jugez en avec les tableaux du dico que j'ai déjà établis.

Sinon j'ai fait une mise à jour digne de ce nom: l'historique résume tout. Mais j'aimerai revenir sur 2 points très très particuliers :
1) Dans les options du projet, si on coche la case "Construire avec les paquets", on gagne 15 000 pps.
2) Si on insère dans le projet un TTimer alors que l'option précédente n'est pas cochée, on perd 130 000 pps seulement pour la recherche des IP. Si la case est cochée, c'est comme si il n'y avait rien eu.

En reprenant et corrigeant l'expression de quelqu'un: «J'me demande quand même défois ...si [Windows] n'existait pas faudrait l'inventer pour pas s'ennuyer lol»

Maintenant, on peut donc dire qu'on décode à 565 000 passes par seconde.

Avant de conclure, jettez un coup d'oeil à la fonction "ReadableOutput" dans le code. En tentant des trucs, on finit par les adopter. L'astuce tient dans le secret des types énumérés.

Et puis, l'application peut se comporter comme une DLL. Qui sait, ça peut servir...

Et compiler le code avec C++Builder n'accélère pas le processus. Peut-être faut-il utiliser l'interface Pascal avec un générateur de MD5 en C++ ? Mais j'y crois pas trop... même c'est techniquement possible.

;)
cs_grandvizir Messages postés 1106 Date d'inscription samedi 8 novembre 2003 Statut Membre Dernière intervention 3 septembre 2006 22
15 avril 2005 à 18:21
Dernière chose vis-à-vis du mode TIMECRITICAL. Surtout, ne perdez pas le focus de l'application au profit d'une autre !!!! Il y a peu (pas forcément pas) de chance pour que Windows la réactive. C'est un comportement tout à fait normal sous Windows et justifié dans l'aide incontournable WIN32.HLP. Boostez à la critique que si vous n'avez rien à faire d'autre.

J'améliorerai bien plus tard la méthode du dictionnaire afin de démultiplier leur capacité. En ignorant la casse, un mot de 3 lettres donne 9 combinaisons, 4 lettres fournissent 16 mots...

Les dictionnaires offrent 4'350'531 mots en minuscules pour près de 40'910'694 octets de données. Cela fait une moyenne de 9 caractères par mot. Offrant chacun 81 combinaisons en moyenne, on obtient finalement 81 fois plus de mots dans la totalité du dictionnaire, soit 352 millions de mots. Et encore, on n'a pas géré les accents.

On génère ainsi virtuellement 3,08 GigaOctets de données, correspondant à une analyse de 20 minutes à raison de 300 000 passes par seconde.

Encore une fois, j'espère ne pas avoir fait des fautes de calcul.
cs_grandvizir Messages postés 1106 Date d'inscription samedi 8 novembre 2003 Statut Membre Dernière intervention 3 septembre 2006 22
15 avril 2005 à 18:08
C'est vrai que mon code est bien fait, mais il faut au passage préciser qu'il n'a rien de bien exceptionnel et c'est très facile à faire. Voici quand même un résumé succint des principes:

- Conversion:
Simple application de la formule du MD5

- IP:
Utilisation de 4 boucles imbriquées
Reconstitution de la chaîne
Test de concordance
Affichage d'information

- Dictionnaire:
Simple boucle
Défilement de tous les mots du dico jusqu'au bon

- Brute Force:
Utilisation d'un tableau de 32 cases (mathématique raisonnable)
Initialisation des variables
Spécification de l'intervalle des longueurs
Si présence d'une chaîne initiale
> Vérification de la validité de la chaîne
> Initialisation du tableau buffer
> Modification des variables déjà initialisées
Amorçage d'une boucle très longue considérée comme infinie
> Test du mot
> Passage au mot suivant
> Affichage de la progression
Finalisation: affichage et reset


Dans le programme, le truc le plus délicat concerne le tableau-mémoire. Dans le Brute Force, vous choisissez un masque prédéfini (SPMASK) et sa longueur est donnée par (BUFLEN). Le buffer mémoire est de longueur fixe (MXBUFF=32). Cette longueur est ignorée dans le reste du processus [elle peut seulement servir à la vérification des étendues]. La variable principale de boucle est indirectement (LEN) et arrête la boucle dès lors que LEN dépasse LNMAX (valeur supérieure de l'intervalle des longueurs). Dès lors, tous les mots ont été testés.

Il ne faut pas confondre le numéro de case avec son contenu. Pour passer au mot suivant, on incrémente de 1 la case N°1. Le maximum d'incrémentation est donné par LNMAX (=longueur du masque). Si ça dépasse, on passe à 1 la case N°1, et on incrémente en cascade les cases suivantes en les repassant aussi à 1 si nécessaire. Dans ces incrémentations, on en profite pour regénérer !!PARTIELLEMENT!! la chaîne qui sera traitée en MD5 au tour suivant. Si la dernière case (de position LEN, avec LEN<=LNMAX<=MXBUFF) vaut LNMAX, alors toutes les cases passent à 1, et la case LEN+1 est activée à 1, celles qui suivent restant bien sûr à 0.

Chaque case N°i du tableau-mémoire détermine le caractère LEN-i+1 dans la chaîne traitée en MD5, et le contenu des cases désigne le nnième caractère du masque. La chaîne à analyser est donc logiquement une combinaison des caractères du masque. Prenons un exemple.
MASQUE: abcd
CHAÎNE: bdaac
BUFFER: [3,1,1,4,2,0,...,0]
Si on convertit dans l'ordre naturel du tableau le buffer, on a la chaîne "caadb", qui est l'inverse de la chaîne réelle. Pourquoi ce choix inversé ? C'est plus naturel de gérer un tableau comme cela.

Bien que le buffer ait une correspondance par l'envers, la chaîne est créée en direct dans le bon ordre [principe du LEN-i+1]. Cela est nécessaire afin que l'affichage soit cohérent du point de vue de l'utilisateur. Dans le cas contraire, il verait que "avion" passe à "bvion" en se disant «Waouh, il va super vite ce prog» et pourtant, le logiciel n'a analysé que une seule chaîne.

Donc voilà... En moins d'une demi-journée, c'est proprement bouclé. Ce code a juste hiberné quelques mois dans mon coffre à codes sources ;)
entity666 Messages postés 13 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 22 novembre 2007
11 avril 2005 à 02:09
franchement même chose : respect !
je crois que c'est une des meilleures sources que j'ai eu l'occasion de voir ici depuis plusieurs années ...
chapeau guy !
CCJ Messages postés 565 Date d'inscription mercredi 19 mai 2004 Statut Membre Dernière intervention 30 avril 2008 1
10 avril 2005 à 14:10
Moi je dis respect
1) c asser complexe
2)ta fallu combien de temps pour ecrire tt ca ??!!
^^
10/10
cs_grandvizir Messages postés 1106 Date d'inscription samedi 8 novembre 2003 Statut Membre Dernière intervention 3 septembre 2006 22
9 avril 2005 à 15:37
Merci Nico... C'est tout pile le fragment de code qui me manquait. Spy++ a réagit à ton code conformément à mes attentes. Mais je n'ai pas vu de différences flagrantes niveau performances (ça ne m'étonne pas).

Attention: si vous vous mettez en mode TIMECRITICAL, ça va pomper un max sur le CPU. Ceci dit, l'application sera plus régulière.

=> Code source terminé.
ni69 Messages postés 1418 Date d'inscription samedi 12 juin 2004 Statut Membre Dernière intervention 5 juillet 2010 12
9 avril 2005 à 14:48
Salut !
C'est vraiment du bon boulot tout ça ! Bravo !
Je n'ai pas eu le temps de regarder tout le code, mais voici au moins comment gérer les priorités d'exécution... ;)

procedure TfrMD5.mnPrioLowestClick(Sender: TObject);
const Priority : array[0..3] of integer = (IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS);
begin
//CHANGE THE PRIORITY
SetPriorityClass(GetCurrentProcess, Priority[(Sender as TMenuItem).Tag]);
(Sender as TMenuItem).Checked:=true; // Cette ligne peut être évitée grâce à la propriété AutoCheck := true des items dans l'inspecteur d'objets...
Logging('Thread''s priority changed to level '+IntToStr((Sender as TMenuItem).Tag));
end;

Voilà !
@+ Nico ;)
cs_grandvizir Messages postés 1106 Date d'inscription samedi 8 novembre 2003 Statut Membre Dernière intervention 3 septembre 2006 22
9 avril 2005 à 12:36
Je suis tombé sur cela:
http://www.microsoft.com/france/msdn/technologies/outils/vbasic/info/info.asp?mar=/france/msdn/technologies/technos/securite/info/20040105-cryptosimplified.html

«Chacun des algorithmes de hachage présentés exécute le même type d'opération. Les différences de l'un à l'autre viennent simplement de la taille de la clé employée pour produire le hachage. Plus la clé utilisée est grande, plus le cryptage est robuste. Par exemple, l'algorithme SH1 utilise une clé de cryptage de 160 bits, alors que MD5 utilise une clé de 128 bits ; par conséquent, SHA1 est plus sûr que MD5 et le hachage est plus difficile à violer.»

Je ne comprend pas alors pourquoi on continue d'utiliser le MD5... en PHP surtout.

Je voulais aussi préciser que la personne qui trouvera 2 chaînes différentes ayant même MD5 sera une personne TRES chanceuse (riche? je sais pas ;). Alors, faut se manifester. Croyons donc au hasard !!
Rejoignez-nous