360 lines
9.5 KiB
C++
360 lines
9.5 KiB
C++
|
#include "lib/md5.h"
|
||
|
#include "lib/sha256.h"
|
||
|
#include <iostream>
|
||
|
#include <thread>
|
||
|
#include <string>
|
||
|
#include <fstream>
|
||
|
#include <vector>
|
||
|
#include <algorithm>
|
||
|
#include <chrono>
|
||
|
#include <cstring>
|
||
|
#include <atomic>
|
||
|
#include <unistd.h>
|
||
|
#include <random>
|
||
|
#include <sys/stat.h>
|
||
|
#include "sys/sysinfo.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
using namespace std;
|
||
|
using namespace chrono;
|
||
|
|
||
|
#define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
|
||
|
#define PBWIDTH 60
|
||
|
|
||
|
enum Error {
|
||
|
ERR_UNKNOWN_OPTION,
|
||
|
ERR_CANT_OPEN_FILE,
|
||
|
ERR_ARGS,
|
||
|
ERR_THREADS
|
||
|
};
|
||
|
|
||
|
void error(Error n, string file)
|
||
|
{
|
||
|
switch (n) {
|
||
|
|
||
|
case ERR_UNKNOWN_OPTION:
|
||
|
cout << "Error, unknown option" << endl;
|
||
|
break;
|
||
|
|
||
|
case ERR_CANT_OPEN_FILE:
|
||
|
cout << "Error, can't open file: "<< file << endl;
|
||
|
break;
|
||
|
|
||
|
case ERR_ARGS:
|
||
|
cout<< "Usage:\ncrack -f [file] -d [dict] -t [threads] --trace [worst performance] --check [sys info]" << endl;
|
||
|
break;
|
||
|
|
||
|
case ERR_THREADS:
|
||
|
cout<< "Error, wrong number of threads" << endl;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
enum Info{
|
||
|
CHECK_SYS
|
||
|
};
|
||
|
|
||
|
void info(Info i){
|
||
|
struct sysinfo memInfo;
|
||
|
sysinfo (&memInfo);
|
||
|
long long totalPhysMemBytes = memInfo.totalram;
|
||
|
long long totalPhysMemGBytes = (totalPhysMemBytes/(1024*1024*1024));
|
||
|
const auto processor_count = std::thread::hardware_concurrency();
|
||
|
|
||
|
switch (i) {
|
||
|
|
||
|
case CHECK_SYS:
|
||
|
cout << "Number of threads: " << processor_count << endl;
|
||
|
cout << "Total RAM: " << totalPhysMemGBytes << "GB ("<<totalPhysMemBytes<<" bytes)"<<endl;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void loadingFunction(double percentage){
|
||
|
int val = (int) (percentage * 100);
|
||
|
int lpad = (int) (percentage * PBWIDTH);
|
||
|
int rpad = PBWIDTH - lpad;
|
||
|
printf("\r%3d%% [%.*s%*s]", val, lpad, PBSTR, rpad, "");
|
||
|
fflush(stdout);
|
||
|
}
|
||
|
|
||
|
long long countLines(string &nombre){
|
||
|
ifstream inFile(nombre);
|
||
|
long long c = count(istreambuf_iterator<char>(inFile),
|
||
|
istreambuf_iterator<char>(), '\n')+1;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
void readFile(string *&words,string &nombre, long long &size){
|
||
|
ifstream fichero; string fila;
|
||
|
words = new string[size];
|
||
|
|
||
|
long long i = 0;
|
||
|
fichero.open(nombre.c_str(), ios::in);
|
||
|
if(fichero.is_open()){
|
||
|
while(!fichero.eof()){
|
||
|
getline(fichero, fila);
|
||
|
words[i] = fila;
|
||
|
i++;
|
||
|
}
|
||
|
fichero.close();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void readFileDict(char *&dict,string &nombre, long long &sizeWordsDICT){
|
||
|
cout<<"Loading dictionary in memory..."<<endl;
|
||
|
std::ifstream fichero(nombre, ios::in);
|
||
|
fichero.read(dict, sizeWordsDICT);
|
||
|
}
|
||
|
|
||
|
void crackPasswords(string *wordsMD5, char *&dict, string *&result, long long *&rangs, long long &sizeMD5, long long &sizeWordsDICT, int core, int &recovered, bool &trace)
|
||
|
{
|
||
|
MD5 hashMD5;
|
||
|
|
||
|
for(long long j=rangs[0];j<rangs[1];j++){
|
||
|
if(core==0 && trace){
|
||
|
loadingFunction(static_cast<double>(j)/static_cast<double>(rangs[1]));
|
||
|
}
|
||
|
string word = "";
|
||
|
while(dict[j] != '\n' && j<=sizeWordsDICT){
|
||
|
word = word + dict[j];
|
||
|
j++;
|
||
|
}
|
||
|
word.erase(std::remove(word.begin(), word.end(), '\r' ), word.end());
|
||
|
string wordHashMD5 = hashMD5(word);
|
||
|
for(int word2crack=0;word2crack<sizeMD5;word2crack++){
|
||
|
if(result[word2crack]!=""){
|
||
|
continue;
|
||
|
}
|
||
|
if(wordsMD5[word2crack]==wordHashMD5){
|
||
|
recovered++;
|
||
|
result[word2crack] = word;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void fillSplit(long long **&rangs, long long &sizeWordsDICT, int &numThreads){
|
||
|
long long split = sizeWordsDICT/numThreads;
|
||
|
long long resto = sizeWordsDICT%numThreads;
|
||
|
long long endSPlit = split+resto;
|
||
|
long long currentB=0;
|
||
|
long long currentF=split-1;
|
||
|
|
||
|
|
||
|
for(int rang=0; rang<numThreads; rang++){
|
||
|
rangs[rang] = new long long[2];
|
||
|
rangs[rang][0]=currentB;
|
||
|
rangs[rang][1]=currentF;
|
||
|
if(rang + 2 == numThreads){
|
||
|
currentB = currentF+1;
|
||
|
currentF += endSPlit;
|
||
|
}
|
||
|
else{
|
||
|
currentB = currentF+1;
|
||
|
currentF += split;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool checkIfExist(string &nombre){
|
||
|
ifstream fichero;
|
||
|
fichero.open(nombre.c_str(), ios::in);
|
||
|
if(fichero.is_open()){
|
||
|
return true;
|
||
|
}
|
||
|
else{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
string gen_random(const int len) {
|
||
|
static const char alphanum[] =
|
||
|
"0123456789"
|
||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||
|
"abcdefghijklmnopqrstuvwxyz";
|
||
|
std::string tmp_s;
|
||
|
tmp_s.reserve(len);
|
||
|
|
||
|
random_device rd;
|
||
|
mt19937 mt(rd());
|
||
|
uniform_real_distribution<double> dist(0, sizeof(alphanum)-1);
|
||
|
|
||
|
for (int i = 0; i < len; ++i) {
|
||
|
tmp_s += alphanum[(int)(dist(mt))];
|
||
|
}
|
||
|
|
||
|
return tmp_s;
|
||
|
}
|
||
|
|
||
|
void outputFileCrack(string *result, long long &sizeMD5){
|
||
|
ofstream fichero("plain.txt");
|
||
|
if(fichero.is_open()){
|
||
|
for(long long i =0;i<sizeMD5;i++){
|
||
|
fichero<<result[i]<<endl;
|
||
|
}
|
||
|
fichero.close();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void outputFileSHA256(string *result, long long &sizeMD5){
|
||
|
srand((unsigned)time(NULL) * getpid());
|
||
|
string salt = gen_random(12);
|
||
|
SHA256 sha256;
|
||
|
ofstream fichero("new_passwords.txt");
|
||
|
if(fichero.is_open()){
|
||
|
for(long long i =0;i<sizeMD5;i++){
|
||
|
if(result[i]==""){
|
||
|
fichero<<""<<endl;
|
||
|
}
|
||
|
else{
|
||
|
string salt = gen_random(12);
|
||
|
string resultString = result[i] + salt;
|
||
|
fichero<<sha256(resultString)<<":"<<salt<<endl;
|
||
|
}
|
||
|
}
|
||
|
fichero.close();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
long long GetFileSize(string filename)
|
||
|
{
|
||
|
struct stat stat_buf;
|
||
|
int rc = stat(filename.c_str(), &stat_buf);
|
||
|
return rc == 0 ? stat_buf.st_size : -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int main(int argc,char *argv[])
|
||
|
{
|
||
|
// create a new hashing object
|
||
|
//SHA256 sha256;
|
||
|
//std::cout << sha256("Hello World") << std::endl;
|
||
|
|
||
|
//Parametros de entrada.
|
||
|
string nameFileMD5="";
|
||
|
string nameFileDict="";
|
||
|
bool trace=false;
|
||
|
int numThreads = 0;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//Args
|
||
|
int args = 0;
|
||
|
while(args < argc){
|
||
|
if(strcmp(argv[args], "--check") == 0){
|
||
|
info(CHECK_SYS);
|
||
|
return -1;
|
||
|
}
|
||
|
if(strcmp(argv[args], "--help") == 0){
|
||
|
if(args+1<argc){
|
||
|
error(ERR_ARGS,"");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
if(strcmp(argv[args], "-f") == 0){
|
||
|
if(args+1<argc){
|
||
|
nameFileMD5=argv[args+1];
|
||
|
}
|
||
|
}
|
||
|
if(strcmp(argv[args], "--trace") == 0){
|
||
|
trace=true;
|
||
|
}
|
||
|
if(strcmp(argv[args], "-d") == 0){
|
||
|
if(args+1<argc){
|
||
|
nameFileDict=argv[args+1];
|
||
|
}
|
||
|
}
|
||
|
if(strcmp(argv[args], "-t") == 0){
|
||
|
if(args+1<argc){
|
||
|
numThreads=stoi(argv[args+1]);
|
||
|
const auto processor_count = std::thread::hardware_concurrency();
|
||
|
if(numThreads == 0 || processor_count<numThreads){
|
||
|
error(ERR_THREADS,"");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
args++;
|
||
|
}
|
||
|
if(nameFileMD5=="" || nameFileDict=="" || numThreads<=0){
|
||
|
error(ERR_ARGS,"");
|
||
|
return -1;
|
||
|
}
|
||
|
if(!checkIfExist(nameFileMD5)){
|
||
|
error(ERR_CANT_OPEN_FILE, nameFileMD5);
|
||
|
return -1;
|
||
|
}
|
||
|
if(!checkIfExist(nameFileDict)){
|
||
|
error(ERR_CANT_OPEN_FILE, nameFileDict);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
//Files Size
|
||
|
long long sizeMD5 = countLines(nameFileMD5);
|
||
|
long long sizeWordsDICT = GetFileSize(nameFileDict);
|
||
|
|
||
|
//Struct and params
|
||
|
string *wordsMD5;
|
||
|
char* dict = (char*)malloc(sizeWordsDICT);
|
||
|
string *result; result=new string[sizeMD5];
|
||
|
std::vector<std::thread> ThreadVector;
|
||
|
long long **rangs;
|
||
|
rangs = new long long*[numThreads];
|
||
|
int recovered = 0;
|
||
|
|
||
|
//Read hashes to crack, read dict and caculate ranges
|
||
|
readFile(wordsMD5,nameFileMD5,sizeMD5);
|
||
|
readFileDict(dict,nameFileDict,sizeWordsDICT);
|
||
|
fillSplit(rangs,sizeWordsDICT,numThreads);
|
||
|
|
||
|
cout<<"Running process with "<<numThreads<<" threads..."<<endl;
|
||
|
|
||
|
auto begin=high_resolution_clock::now();
|
||
|
|
||
|
|
||
|
for(int thread=0; thread<numThreads; thread++){
|
||
|
int core = thread;
|
||
|
ThreadVector.emplace_back([&wordsMD5,&dict,&result,&rangs,core,&sizeWordsDICT,&sizeMD5,&recovered, &trace](){crackPasswords(ref(wordsMD5),ref(dict),ref(result),rangs[core], ref(sizeMD5), ref(sizeWordsDICT), core, ref(recovered), ref(trace));});
|
||
|
}
|
||
|
for(auto&t :ThreadVector){
|
||
|
t.join();
|
||
|
}
|
||
|
|
||
|
auto end=high_resolution_clock::now();
|
||
|
|
||
|
if(trace){
|
||
|
loadingFunction(1);
|
||
|
cout<<endl;
|
||
|
}
|
||
|
|
||
|
int time = duration_cast<milliseconds>(end-begin).count();
|
||
|
|
||
|
cout<<"Time to execution: "<<time<<" ms."<<endl;
|
||
|
cout<<"Recovered passwords: "<<recovered<<endl;
|
||
|
|
||
|
ThreadVector.clear();
|
||
|
delete [] dict;
|
||
|
delete [] wordsMD5;
|
||
|
for (int i=0; i<numThreads; i++){
|
||
|
delete[] rangs[i];
|
||
|
}
|
||
|
delete[] rangs;
|
||
|
|
||
|
cout<<"Writing in file the recovered passwords..."<<endl;
|
||
|
outputFileCrack(result,sizeMD5);
|
||
|
cout<<"Writing in file the hash passwords in SHA256 with salt..."<<endl;
|
||
|
outputFileSHA256(result,sizeMD5);
|
||
|
|
||
|
delete [] result;
|
||
|
|
||
|
return 0;
|
||
|
}
|