Brute Force prelamovanie MD5 hashov v multi vláknach

 

 

V tomto tutoriále si ukážeme spôsob prelámovania MD5 hashov vo viacerých vláknach.


Na internete je háfo návodov na MD5 brute force cracking, podľa ktorých je možné prelámovať heslá, ale čo v prípade, ak chceme vypočetný výkon rozdeliť do viacerých vlákien, a tým pádom zrýchliť samotné prelámovanie?
V budúcnu môžeme uvažovať o algoritmu, ktorý bude úlohy rozdeľovať medzi vypočetný výkon počítačov zavedených napríklad v botnetu.

Pre príklad nášho Brute Force útoku som použil nejaký kód, voľne šíriteľný z internetu, ktorý som poupravoval.
Následný kód by mohol vypadať takto:
BruteForce.h

  

#include <vector> #include <time.h> #include <string>
namespace Diall_bruteforce { class CrackMe { private: MD5 md5; ::std::string cracked; ::std::vector Characters; int I,K,N;
private: void CharInit(void) { for(char charset_='a'; charset_<= 'z'; charset_++) { this->Characters.push_back(charset_); } }
public: CrackMe(void) { this->cracked = ""; this->CharInit(); }
public: void CrackIt(::std::string password, char* thread, int j_,int n_) { ::std::cout << ::std::endl << "PASSWORD TO CRACK: "
<< password <<" " << thread << ::std::endl;
this->I = 1;
while(true) { this->I++; this->N = 1;
for(int j=j_;j<this->I;j++) { this>->N*=n_; }
for(int j = j_;j<this->N;j++) { this->K = 1;
for(int k=0;k<this->I;k++) { this->cracked += this->Characters[j/this->K%n_]; this->K *= n_; }
if(password.compare(md5.digestString(&this->cracked[0u])) == 0) { ::std::cout << ::std::endl << " Cracked password : " << this->cracked << " from "<< thread << " Finished Time " << thread <<" : " << clock() / (double) CLOCKS_PER_SEC<<::std::endl<<::std::endl;
return; } } } } }; }





Jednotlivé "dilčí" operácie prevádzame zvolením vstupných hodnôt: j_ a n_ metódy CrackMe.

Pri vytvorení inštancie sa nám zinicializuje dátové úložisko, v našom prípade Characters typu vector, do ktorého sa nám úloží množina kontrolovaná pri behu crackingu, v tomto prípade množina znakov "a" -> "z".
Veľikosť je 26, pri behu jedného vlákna potom 26.

Zadávanie hodnôt pri crackingu zodpovedá následovnému rozdeleniu:

   Thread A 0-26   -> čas: 13.711

   Thread A 0-12   -> čas: 0.733
   Thread B 13-26


   Thread A 0-9     -> čas: 0.309
   Thread B 10-19
   Thread C 20- 26


   Thread A 0-6    -> čas: 0.079
   Thread B 7-15
   Thread C 16-22
   Thread D 23-26


   Thread A 0-4   -> čas: 0.027
   Thread B 5-11
   Thread C 12-16
   Thread D 17-22
   Thread E 23-26



   Thread A 0-2   -> čas: 1.592
   Thread B 3-9
   Thread C 10-14
   Thread D 15-19
   Thread E 20-23
   Thread F 24-26


Časovú zložitosť môžeme reprezentovať grafom:




Obsah súboru main.cpp:

#include <windows.h> 
#include <iostream> 
#include "md5.h"    //https://bobobobo.wordpress.com/2010/10/17/md5-c-implementation/ 
#include "thread.h" //https://www.netbot.sk/sk/14-blog-headers/87-thread-h 
#include "BruteForce.h" 
using namespace std; void CrackA(void); void CrackB(void); void CrackC(void); void CrackD(void); void CrackE(void); void CrackF(void); void CrackG(void);
#define passwordtocrack "babac"
unsigned int __stdcall _Thread0(void * input) { CrackA();
return 0; }
unsigned int __stdcall _Thread1(void * input) { CrackB();
return 0; }
unsigned int __stdcall _Thread2(void * input) { CrackC();
return 0; }
unsigned int __stdcall _Thread3(void * input) { CrackD();
return 0;
}
unsigned int __stdcall _Thread4(void * input) { CrackE();
return 0; }
unsigned int __stdcall _Thread5(void * input) { CrackF();
return 0; }
unsigned int __stdcall _Thread6(void * input) { CrackG();
return 0; }

int _cdecl main (void) { ::std::cout << endl;
::Threading::ThreadID thread0 = 0; ::Threading::ThreadID thread1 = 1; ::Threading::ThreadID thread2 = 2; ::Threading::ThreadID thread3 = 3; ::Threading::ThreadID thread4 = 4; ::Threading::ThreadID thread5 = 5; ::Threading::ThreadID thread6 = 6; ::Threading::ThreadHandle tHandle0 = ::Threading::MultyThreads->ThreadStart(_Thread0, NULL,
&thread0); ::Threading::ThreadHandle tHandle1 = ::Threading::MultyThreads->ThreadStart(_Thread1,
NULL,
&thread1); ::Threading::ThreadHandle tHandle2 = ::Threading::MultyThreads->ThreadStart(_Thread2,
NULL,
&thread2); ::Threading::ThreadHandle tHandle3 = ::Threading::MultyThreads->ThreadStart(_Thread3,
NULL,
&thread3); ::Threading::ThreadHandle tHandle4 = ::Threading::MultyThreads->ThreadStart(_Thread4,
NULL,
&thread4); ::Threading::ThreadHandle tHandle5 = ::Threading::MultyThreads->ThreadStart(_Thread5,
NULL,
&thread5); ::Threading::ThreadHandle tHandle6 = ::Threading::MultyThreads->ThreadStart(_Thread6,
NULL,
&thread6); ::Threading::MultyThreads->WaitingForThread(tHandle0); ::Threading::MultyThreads->WaitingForThread(tHandle1); ::Threading::MultyThreads->WaitingForThread(tHandle2); ::Threading::MultyThreads->WaitingForThread(tHandle3); ::Threading::MultyThreads->WaitingForThread(tHandle4); ::Threading::MultyThreads->WaitingForThread(tHandle5); ::Threading::MultyThreads->WaitingForThread(tHandle6); ::Threading::MultyThreads->CloseThread(tHandle0); ::Threading::MultyThreads->CloseThread(tHandle1); ::Threading::MultyThreads->CloseThread(tHandle2); ::Threading::MultyThreads->CloseThread(tHandle3); ::Threading::MultyThreads->CloseThread(tHandle4); ::Threading::MultyThreads->CloseThread(tHandle5); ::Threading::MultyThreads->CloseThread(tHandle6);
return 0; }
void CrackA(void) { MD5 md5 ;
string pass = md5.digestString( passwordtocrack );
Diall_bruteforce::CrackMe * crackme = new Diall_bruteforce::CrackMe(); crackme->CrackIt(pass, "Thread A", 0, 2); }
void CrackB(void) { MD5 md5 ;
string pass = md5.digestString( passwordtocrack );
Diall_bruteforce::CrackMe * crackme = new Diall_bruteforce::CrackMe(); crackme->CrackIt(pass, "Thread B", 3, 6); }
void CrackC(void) { MD5 md5 ;
string pass = md5.digestString( passwordtocrack );
Diall_bruteforce::CrackMe * crackme = new Diall_bruteforce::CrackMe(); crackme->CrackIt(pass, "Thread C", 7, 12); }
void CrackD(void) { MD5 md5 ;
string pass = md5.digestString( passwordtocrack );
Diall_bruteforce::CrackMe * crackme = new Diall_bruteforce::CrackMe(); crackme->CrackIt(pass, "Thread D",13, 16); }
void CrackE(void) { MD5 md5 ;
string pass = md5.digestString( passwordtocrack );
Diall_bruteforce::CrackMe * crackme= new Diall_bruteforce::CrackMe(); crackme->CrackIt(pass, "Thread E",17, 21); }
void CrackF(void) { MD5 md5 ;
string pass = md5.digestString( passwordtocrack );
Diall_bruteforce::CrackMe * crackme = new Diall_bruteforce::CrackMe(); crackme->CrackIt(pass, "Thread F",22, 23); }
void CrackG(void) { MD5 md5 ;
string pass = md5.digestString( passwordtocrack );
Diall_bruteforce::CrackMe * crackme1 = new Diall_bruteforce::CrackMe(); crackme1->CrackIt(pass, "Thread G",24, 26); }