I'm trying to crack a password, given its hash and a dictionary of words. For this, I'm basically doing an exhaustive search, of all the words in the dictionary.
#include <iostream>
#include <list>
#include <cstring>
#include <crypt.h>
//this is an example line from the shadow file:
//tom:$6$9kfonWC7$gzqmM9xD7V3zzZDo.3Fb5mAdM0GbIR2DYTtjYpcGkXVWatTC0pa/XVvKTXLb1ZP0NG9cinGRZF7gPLdhJsHDM/:16471:0:99999:7:::
// the salt and password values are extracted as
std::string target_salt = "$6$9kfonWC7$";
std::string target_pw_hash = "$6$9kfonWC7$gzqmM9xD7V3zzZDo.3Fb5mAdM0GbIR2DYTtjYpcGkXVWatTC0pa/XVvKTXLb1ZP0NG9cinGRZF7gPLdhJsHDM/";
// define a null string which is returned in case of failure to find the password
char null[] = {'\0'};
// define the maximum length for the password to be searched
#define MAX_LEN 5
std::list<char**> pwlist;
// check if the pw and salt are matching the hash
int check_password(char* pw, char* salt, char* hash)
{
char* res = crypt(pw, salt);
std::cout << "password " << pw << "\n";
std::cout << "hashes to " << res << "\n";
std::cout << "hash: " << hash << "\n";
std::cout << "hash: " << res << "\n";
std::cout << strlen(hash) << std::endl;
if(strlen(hash) == strlen(res))
std::cout << "equal" << std::endl;
for (int i = 0; i < strlen(hash); i++) {
if (res[i] != hash[i]) // the problem is here
return 0;
//std::cout << hash[i] << " ";
}
std::cout << "match !!!" << "\n";
return 1;
}
// builds passwords from the given character set
// and verifies if they match the target
char* exhaustive_search(char** wordset, char* salt, char* target)
{
char** current_password = (char**)malloc(MAX_LEN*sizeof(char *));
char** new_password;
int i, current_len;
// begin by adding each character as a potential 1 character password
for (i = 0; i < sizeof(wordset)/sizeof(wordset[0]); i++){
new_password = (char **)malloc(2*sizeof(char*));
new_password[0] = wordset[i];
new_password[1] = 0;
pwlist.push_back(new_password);
}
while(true){
// test if queue is not empty and return null if so
if (pwlist.empty())
return null;
// get the current current_password from queue
current_password = pwlist.front();
current_len = sizeof(current_password)/sizeof(current_password[0]);
//std::cout << *current_password << " " << current_len << std::endl;
// break;
// check if current password is the target password, if yes return the current_password
if (check_password(*current_password, salt, target))
{
return *current_password;
}
// else generates new passwords from the current one by appending each character from the charlist
// only if the current length is less than the maxlength
if(current_len < MAX_LEN){
for (i = 0; i < sizeof(wordset)/sizeof(wordset[0]); i++){
new_password = (char **)realloc(new_password ,(current_len + 2)*sizeof(char **));
for(int j = 0; j < current_len; j++) {
strncpy(new_password[j], current_password[j], current_len);
}
new_password[current_len] = wordset[i];
new_password[current_len+1] = 0;
pwlist.push_back(new_password);
}
}
// now remove the front element as it didn't match the password
pwlist.pop_front();
}
}
int main(int argc, char const *argv[])
{
char* salt;
char* target;
char* password;
// define the character set from which the password will be built
char *words[] = {"red", "green", "blue", "orange", "pink"};
//convert the salt from string to char*
salt = new char[target_salt.length()+1];
copy(target_salt.begin(), target_salt.end(), salt);
//convert the hash from string to char*
target = new char[target_pw_hash.length()+1];
copy(target_pw_hash.begin(), target_pw_hash.end(), target);
// std::cout << "hash: " << target << std::endl;
//start the search
password = exhaustive_search(words, salt, target);
if (strlen(password)!= 0)
std::cout << "Password successfuly recovered: " << password << " \n";
else
std::cout << "Failure to find password, try distinct character set of size \n";
return 0;
}
I know the problem is at line 38, however, I can't seem to understand why, but I am guessing it is related to dynamic memory allocation. Any thoughts?