In: Computer Science
scan1.cpp
/*
* This program takes the name of a password file and some guessing
parameters
* and tries to guess the passwords by simple enumeration. Command
line
* is the
* filename charset short long
* Where charset is either a string of characters from which the
password
* is drawn, or one of these special names:
* ASCII Printable ascii, 32-126
* DIGITS 0-9
* ALNUM Alphanumeric characters, 0-9A-Za-z
* Short and long are range of lengths of the passwords to
try.
*/
#include <crypt.h>
#include <errno.h>
#include <pthread.h>
#include <cstring>
#include <cstdlib>
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <list>
#include <memory>
#include "enum.h"
using std::string;
// Create an appropriate enumerator object.
std::unique_ptr<pwd_enum> enumerator;
pthread_mutex_t lock;
/* The Program's critical section data structure is 'passwords', which will be protected using mutex_lock */
std::list<std::pair<string,string>> passwords;
/*
* Try the indicated password against each recorded password in the
file.
* Return true if any matched, false otw.
*/
bool scan(const std::list<std::pair<string,string>>
&passwords, string pass)
{
struct crypt_data pass_data; // Password
data area.
string line;
// Input line.
bool found = false; //
We found something.
// Clear the data area.
memset(&pass_data, 0, sizeof pass_data);
// Try each of the passwords.
/* Take the mutex lock */
pthread_mutex_lock(&lock);
for(auto p: passwords) {
// Encrypt the guess using the
method recorded for the existing.
// (crypt_r only reads the
encryption type and salt from the
// exiting password, not the hash
itself.)
char *ret = crypt_r(pass.c_str(),
p.second.c_str(), &pass_data);
// See if we got a match.
if(ret && ret == p.second)
{
std::cout
<< p.first << ": " << pass <<
std::endl;
found =
true;
}
}
/* release the mutex lock */
pthread_mutex_unlock(&lock);
return found;
}
void *read_thread(void * arg)
{
// Try to open the file.
std::ifstream passfile(argv[1],
std::fstream::binary);
if(!passfile) {
std::cerr << "Unable to open
" << argv[1] << std::endl;
exit(1);
}
// Read the passwords from the file.
string line;
while(std::getline(passfile, line)) {
// Extract account
int loc = line.find(":");
if(loc == string::npos)
continue;
string acct =
line.substr(0,loc);
// Extract crypted password,
leaving it in line.
line.erase(0,loc+1);
loc = line.find(":");
if(loc != string::npos) {
acct.erase(loc);
}
// Add the account and password to the list.
/* Take the mutex lock */
pthread_mutex_lock(&lock);
passwords.push_back(std::make_pair(acct, line));
/* release the mutex lock */
pthread_mutex_unlock(&lock);
}
// This will happen at the end anyway, but we're
going to spend a
// long time in the next loop, so let's release the
resource now.
passfile.close();
}
void *scan_thread(void * arg)
{
// Run through the passwords.
string pw;
bool found = false;
while((pw = enumerator->next()) != "") {
found = scan(passwords, pw) ||
found;
//std::cout << pw <<
std::endl;
}
if(!found)
std::cout << "No passwords
matched." << std::endl;
}
int main(int argc, char **argv)
{
pthread_t t1, t2;
// Check args.
if(argc != 5) {
std::cerr << "Usage: "
<< argv[0]
<< "
filename charset min max" << std::endl;
std::cerr << " charset is
DIGITS, ALNUM, ASCII or a set of "
<<
"characters." << std::endl;
exit(1);
}
// Size range.
int min = atoi(argv[3]);
int max = atoi(argv[4]);
string charset = argv[2];
if(charset == "DIGITS") {
enumerator.reset(new pwd_enum('0',
'9', min, max));
} else if(charset == "ALNUM") {
enumerator.reset
(new
pwd_enum("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz", min, max));
} else if(charset == "ASCII") {
enumerator.reset(new pwd_enum(' ',
'~', min, max));
} else {
enumerator.reset(new
pwd_enum(charset, min, max));
}
/* Initialize the mute lock for use with
multi-threading */
pthread_mutex_init(&lock);
/* Create the two threads prime_thread and print_thread */
pthread_create( &t1, NULL, read_thread, (void *) passfile);
pthread_create( &t2, NULL, scan_thread, NULL);
/* Wait for the threads to finish */
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_exit(0);
}