Bruteforcing d'un checksum md5

Soyez le premier à donner votre avis sur cette source.

Vue 15 356 fois - Téléchargée 1 142 fois

Cette source est considérée comme dangereuse, elle a néamoins été gardée dans un but pédagogique :
Cette source est considérée comme dangereuse, elle a néamoins été gardée dans un but pédagogique.

Description

Bon alor l'histoire commence ici : http://www.phpcs.com/code.aspx?ID=19322
J'ai pas testé le script, mais l'idée m'intéressait de savoir qu'elle est le puissance nécéssaire pour trouver un mot de passe valide sur mon site, et en combien de temps.
J'ai donc codé ça en C (LccWin32, m'enfin ça devrait tourner sur n'importe quel autre compilo sans trop de problèmes) en vitesse, le code est vraiment cochon (j'ai même repris 3 fonctions venant de BCX, et j'ai une tonne d'includes qui servent a rien, je sais, mais j'ai commenté comme j'ai pu pour le rendre compréhenssible), j'ai pas vraiment optimisé et ça me donne quand même dans les 10000 'mot de passes' testé par seconde, avec mon simple athlon 1.3 Ghz (sans compter toutes les taches de fond qui me pompe le CPU) !
J'ai donc essayer de 'décrypter' l'exemple de mavounet (aa36dc6e81e2ac7ad03e12fedcb6a2c0=mdp), et comme vous le voyez sur la capture il met que 6s !!! Bon d'acord après ça se complique si on passe au dessus de 3 caractères, et c'est considérablement ralenti, et ça devient quasi-impossible.
Conclusion: N'utilisez QUE des mots de passes complexes contenants un bon nombre de caractères, et le mieux seraient encore d'éviter de rendre public la liste des md5 !

Source / Exemple :


#include <windows.h>
#include <stdio.h>
#include "md5.h" //Le fichier magique qui permet d'encoder en md5

// *************************************************
//                System Variables
// *************************************************

COORD   cursor;
HANDLE  hConsole;
int     color_fg = 7;
int     color_bg = 0;

// *************************************************
//               Standard Prototypes
// *************************************************

void    cls(void);
void    color (int,int);
void    locate (int,int,int=1,int=12);

// *************************************************
//                  Main Program
// *************************************************

DWORD BrutesMade=0;
DWORD NumberFounds=0;
BOOL Tourne=TRUE;
md5_byte_t buffer[1024];
DWORD nForceChars=0;
md5_byte_t searched[16];

/* ChangeLog
-les déclarations des variables pour calculer le md5 sont déclarés AVANT la boucle et plus pendant
-j'ai changé le char par un WORD (le int était pas une mauvaise idée, mais j'ai l'impression que c'est un peu plus lent chez moi)
-suprimé la conversion du md5 format brut vers le format héxa, et je compare le digest lui même (sans oublier de convertir avant le md5 que l'on recherche en format brut), mainteant sur mon pc ça tourne a 600000/s au lieu de 10000, 60x plus rapide !!!
-supression de la récusivité qui se fesait quand même bien sentir, merci à ccarniel
-adaptation a VC++ : plus grand rapidité que avec Lcc, mais mauvaise portabilité (il se trouv que le même exe, compilé sur une machine tourne moins bien sur une autre machine plus puissante !!!)
-et amélioration de la fonction de monitoring qui est maintenant plus précise (encore merci a ccarniel)

  • /
void brute_force(DWORD max, md5_byte_t searched[16]) { char md5buf[33]; DWORD maxm1=max-1; unsigned char ChiffreDebut = ' ', ChiffreFin = 254; int Curseur; bool Termine = false; md5_state_t state; md5_byte_t digest[16]; // Combinaison = new unsigned char[max+1]; memset(buffer, ChiffreDebut, (sizeof(char))*max); while (!Termine) { BrutesMade++; //On ajoute 1 au compteur de 'pass' testés //On fait un checksum md5 sur le buffer md5_init(&state); md5_append(&state, (const md5_byte_t*)buffer, max); md5_finish(&state, digest); if (!memcmp(digest, searched, 16)) { //memcmp est bcp plus rapide que strcmp, mais ne fait pas de comparaisons entre les minusucules et les majusucules, attention a ça quand vous mettez votre md5 a 'décrypter' ! locate(++NumberFounds, 29); //Si trouvé, on place le curseur a droite dans la console for (int di = 0; di < 16; ++di) sprintf(md5buf + di * 2, "%02x", digest[di]); //Ok c'est pas le plus puissant mais on s'en fout, on le fait qu'une seule fois printf(": md5('%s')='%s'\n", buffer, md5buf); //On affiche le md5 et le pass qui correspond (c'est vrai il y a des chances de pas trouver le vrai mot de passe, mais on s'en fout, si on entre ça l'ordi va le comprendre comme le vrai mot de passe !!!) Tourne=FALSE; //On arrête le thread de monitoring ExitProcess(0); //Et on quite } Curseur = 0; if (buffer[Curseur]>ChiffreFin) { do { buffer[++Curseur]++; if (Curseur == max) return ; // On a pas trouvé la combinaison } while (buffer[Curseur]>ChiffreFin); memset(buffer, ChiffreDebut, Curseur); } } } //Un ptit thread pour savoir où en est le prog parce que sinon on se fait un peu chier lol void ThreadMonitor(void) { DWORD LastBrutes=0, Secs=0; #if defined (_MSC_VER) && (_MSC_VER >= 1020) __int64 Freq,StartTime,CurTime; #else unsigned long StartTime,CurTime; #endif // defined (_MSC_VER) && (_MSC_VER >= 1020) #if defined (_MSC_VER) && (_MSC_VER >= 1020) QueryPerformanceFrequency((LARGE_INTEGER*)&Freq); QueryPerformanceCounter((LARGE_INTEGER*)&StartTime); #else StartTime = GetTickCount(); #endif // defined (_MSC_VER) && (_MSC_VER >= 1020) do { //Secs = GetTickCount() - Start; #if defined (_MSC_VER) && (_MSC_VER >= 1020) QueryPerformanceCounter((LARGE_INTEGER*)&CurTime); Secs = (CurTime - StartTime)*1000/Freq; #else CurTime = GetTickCount(); Secs = (CurTime - StartTime); #endif // defined (_MSC_VER) && (_MSC_VER >= 1020) if( Secs >= 1000 ) { cls(); //On efface l'écran et on met le curseur en haut a gauche. Ok j'avoue la fonction vient tout droit de BCX j'ai pas eu le courage d'aller mieux chercher et g pri le premier truc qui m'est tombé sous la main printf("%d décryptés.\n",BrutesMade); printf("%d/s (%ds écoulée(s)) \n",BrutesMade/(Secs/1000),(Secs/1000)); printf("Le mot de passe a au moins %d chars.\n\n== %s ==\n\n\n", nForceChars, buffer); //On affiche les stats LastBrutes=BrutesMade; //9a c'est pour le compteur de pass par secondes } Sleep(1000); //On attenton une seconde } while (Tourne==TRUE); //Une boucle jusqu'a se que un pass correct soit trouvé } int main(int argc, char *argv[]) { hConsole = GetStdHandle(STD_OUTPUT_HANDLE); // "aa36dc6e81e2ac7ad03e12fedcb6a2c0" = mdp // "1eec414adf814acbc887f59327db58fb" = ? // "02c425157ecd32f259548b33402ff6d3" = zzzz // "95ebc3c7b3b9f1d2c40fec14415d3cb8" = zzzzz char * md5s="02c425157ecd32f259548b33402ff6d3"; char cbit[3]; cbit[2]='\0'; for (int i=0; i<32; i+=2) { memcpy(cbit, md5s+i, 2); searched[i/2]=strtol(cbit, NULL, 16); } DWORD MaxSize=16; //Le nb maximum de caractères que le pass peut faire CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadMonitor, NULL, 0, NULL); //On démarre le monitoring en tant que thread seconde ==> comme ça, ça ralenti a peine le scanning, et c'est plus simple pour les fénéants^^ for (nForceChars=1; nForceChars<=MaxSize; nForceChars++) { ZeroMemory(buffer, MaxSize+1); //On efface le buffer pour plus de sécurité brute_force(nForceChars, searched); //Et on brute force ça } return 0; } // ************************************************* // Run Time Functions // ************************************************* void locate (int row,int col,int show,int shape) { CONSOLE_CURSOR_INFO cci = {0}; cursor.X = col-1; cursor.Y = row-1; SetConsoleCursorPosition(hConsole,cursor); cci.bVisible = show; cci.dwSize = shape; SetConsoleCursorInfo(hConsole,&cci); } void cls (void) { COORD coordScreen = {0,0}; DWORD cCharsWritten; CONSOLE_SCREEN_BUFFER_INFO csbi = {0}; DWORD dwConSize; register int attr; cursor.X = 0; cursor.Y = 0; GetConsoleScreenBufferInfo( hConsole, &csbi ); dwConSize = csbi.dwSize.X * csbi.dwSize.Y; FillConsoleOutputCharacter (hConsole, 32, dwConSize,coordScreen, &cCharsWritten); attr = color_fg + color_bg * 16; FillConsoleOutputAttribute (hConsole, attr, dwConSize,coordScreen, &cCharsWritten); locate(1,1,1); } void color (int fg, int bg) { SetConsoleTextAttribute (hConsole,fg+bg*16); color_fg = fg; color_bg = bg; }

Conclusion :


A oui et pour ceux qui connaissent pas, le md5 s'est une sorte de cryptage a sens unique, on peut pas décrypter, il fait 16 octects (ben oui 16 au lieu de 32, nous on en voit la version 'humaine' qui est décodée en héxadécimal)
Un octect=256 combinaisons. 16 octets=256^16 combinaisons, soit environ 3.4 puissance 38 combinaisons possibles, ou même d'après PowerCalc exactement 340282366920938463463374607431768211456... Donc autant dire que c'est quasi impossible de tomber dessus par hasard !
Le md5 est utilisé par exemple par la plus part des logiciels peer2peer pour reconnaitre un fichier vu qu'il est statistiquement impossible que deux fichiers aient le même md5.
Et il est aussi utilisé dans les site webs, quand vous entrez votre mot de passe il est tout de suite crypté en md5, et gardé sous cette forme dans la base de données, comme ça le webmaster où même un pirate ne peux avoir votre mot de passe, mais juste sa version cryptée en md5. (Sa évite les piratages quand sur tous les même sites vous mettez le même mot de passe, compte mail inclu...)

Des commentaires seraient les bien venus si vous avez de meilleures idées que moi pour trouver un mot de passe valide.

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
1
Date d'inscription
dimanche 18 avril 2010
Statut
Membre
Dernière intervention
12 mars 2011

moi, aussi je n'ai pas compris comment le faire fonctionner, expliquez nous svp
Messages postés
32
Date d'inscription
vendredi 10 septembre 2004
Statut
Membre
Dernière intervention
14 février 2016
1
Bonjour a tout le monde, pardonnez moi de rouvrir cela après près d'un an, mais je souhaiterais également savoir quels paramètres passer à ce programme pour le faire fonctionner, doit ont placer le Hash dans un fichier ?

Merci de toute réponse.
A bientot sur CS :-D
Messages postés
1
Date d'inscription
mardi 22 août 2006
Statut
Membre
Dernière intervention
30 septembre 2007

je suis un noob donc ma question va vous sembler idiote mais comment on fais pour ce servir de ce programme?
merci de pas trop me donner une reponse trop bete
Messages postés
1447
Date d'inscription
jeudi 2 novembre 2000
Statut
Membre
Dernière intervention
23 septembre 2007
1
pourquoi alors chez moi ca fini toujours par == ? (j'utilise la lib de Codes Sources)
Messages postés
2
Date d'inscription
mardi 7 août 2007
Statut
Membre
Dernière intervention
10 août 2007

swordfishP
Je ne sais pas, j'ai un petit doute d'avance sur les performances du C# mais à ce point...
Le code qui calcule le hash, est codé en C# ou ça fait appel à une librairie standard du C# ?

Je n'ai pas de quoi tester de codes ici vu que je n'ai que gcc, cependant le code de Clem semble correct, sachant que d'autres logiciels de crackage obtienne un résultat de 8 millions de hash testé par seconde (sur des processeurs plus modernes que l'époque bien sûr)
Il serait interessant de profiter des dual/quad cores aussi, on pourrait bénéficier d'un gain non négligeable sans trop de difficultés.



OneHacker
Tu confonds un peu tout là.
95ebc3c7b3b9f1d2c40fec14415d3cb8 est bien un hash md5. Ou plutôt sa représentation hexadécimale; un hash md5 est du binaire, sur 128 bits. Pour le rendre lisible dans la table ascii il y a plusieurs façons de le faire :
convertir ces 16 octets en héxadécimal, ce qui peut devenir quelque chose du genre 95ebc3c7b3b9f1d2c40fec14415d3cb8.
Mais on pourrait aussi utiliser la base64 ( http://en.wikipedia.org/wiki/Base64 ), ce qui donne quelque chose de plus court il faut l'admettre, mais aussi plus compliqué à utiliser.
La représentation en héxa est bien plus facile et du coup bien plus utilisée.
Afficher les 30 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.