Брутфорс пароля c++
Есть задание, сделать брутфорс пароля используя словарь. Есть код генератора паролей:
#include <fstream>
#include <vector>
#include <string>
#include <iostream>
#include <random>
#include <cstdlib>
using namespace std;
int main(int argc, char* argv[])
{
const char* fname = "wordlist.txt";
/* Parse command-line arguments */
int max = 1;
int key;
if(argc == 2)
{
max = atoi(argv[1]);
}
/* Open word list file */
ifstream input;
input.open(fname);
if(input.fail())
{
cerr << "ERROR: Failed to open " << fname << endl;
}
/* Read to end and load words */
vector<string> wordList;
string line;
while(getline(input, line))
{
wordList.push_back(line);
}
/* Seed from random device */
random_device rd;
default_random_engine gen;
gen.seed(rd());
uniform_int_distribution<int> dist(0, wordList.size() - 1);
/* Output as many passwords as required */
const int pwLen = 3;
int wordId, i, j;
for (i = 0; i < max; i++)
{
for (j = 0; j < pwLen; j++)
{
cout << wordList[dist(gen)] << ((j != pwLen - 1) ? "_" : "");
}
cout << endl;
}
return 0;
}
Собственно, на выходе получаем что-то типа sdf_a_safasfasfasdf. Как можно реализовать с этого подбор пароля?
Ответы (3 шт):
Ну давайте разберемся как именно генерируется пароль
сначала выбирается сколько слов из словаря будет выбрано для пароля - переменная
max(по умолчанию 1)далее из словаря выбирается слово
слово дублируется 3 раза, причем после последнего дублирования ставится "_"
Правда sdf_a_safasfasfasdf с таким алгоритмом не получится, скорее должно было бы получиться sdfsdfsdf_aa_
Чтобы забрутформить надо воспроизвести тот же самый алгоритм, только перебрать все слова из словаря:
// формируем очередное звено пароля
void prepare(std::string& text, const std::string& pass, const int level, const int max_level, const std::vector<std::string>& dict) {
// если сформировано уже максимальное кол-во звеньев - проверить пароль и - выйти
if (level >= max_level) {
if (gen == pass)
std::cout << "Пароль найден!";
return;
}
// перебрать все слова в словаре для данного звена пароля:
const int pwLen = 3;
for (const std::string& word: dict) {
std::string tmp_res = res;
for (int index = 0; index < 3; index ++)
res += word + ((index < pwLen - 1) ? "" : "_");
// сформировать следующее звено пароля
prepare(tmp_res, pass, level + 1, max_level, dict);
}
}
std::string res = "";
prepare(res, "sdfsdfsdf_aa_xxx_", 0, 3, dict);
Если размер пароля (кол-во слов из словаря) не фиксировано, тогда будет выглядеть чуть по другому:
Надо проверять пароль после генерации всегда, а max_level использовать просто для ограничения максимального размера пароля
// формируем очередное звено пароля
void prepare(std::string& text, const std::string& pass, const int level, const int max_level, const std::vector<std::string>& dict) {
// проверить пароль
if (gen == pass) {
std::cout << "Пароль найден!";
return;
}
// если сформировано уже максимальное кол-во звеньев - выйти
if (level >= max_level) {
return;
}
// перебрать все слова в словаре для данного звена пароля:
const int pwLen = 3;
for (const std::string& word: dict) {
std::string tmp_res = res;
for (int index = 0; index < 3; index ++)
res += word + ((index < pwLen - 1) ? "" : "_");
// сформировать следующее звено пароля
prepare(tmp_res, pass, level + 1, max_level, dict);
}
}
std::string res = "";
prepare(res, "sdfsdfsdf_aa_xxx_", 0, 1000, dict);
Для оптимизации надо сделать так, чтобы если пароль найден на каком-то этапе, то дальше не продолжать работу:
// формируем очередное звено пароля
bool prepare(std::string& text, const std::string& pass, const int level, const int max_level, const std::vector<std::string>& dict) {
// проверить пароль
if (gen == pass) {
std::cout << "Пароль найден!";
return true;
}
// если сформировано уже максимальное кол-во звеньев - выйти
if (level >= max_level) {
return false;
}
// перебрать все слова в словаре для данного звена пароля:
const int pwLen = 3;
for (const std::string& word: dict) {
std::string tmp_res = res;
for (int index = 0; index < 3; index ++)
res += word + ((index < pwLen - 1) ? "" : "_");
// сформировать следующее звено пароля
const bool is_success = prepare(tmp_res, pass, level + 1, max_level, dict);
// если пароль был найден - ничего уже не делать
if (is_success == true)
return true;
}
return false;
}
да, это задание на лабораторную работу. Код можно и используя рекурсивные функции, но к сожалению, я в них не силен. Скорее всего я неправильно объяснил суть задания. Первоначально, надо создать брутфорс, который берет из словаря 3 слова. Между словами вместо пробела ставит "". И сравнивает с введенным паролем (он генерируется по такому же принципу, 3 слова из словаря и ""). Генератор то есть, но как реализовать брут - не могу понять. Извините если неправильно выразился в первый раз ;) – Boredix 5 минут назад
Для удобства вынес в другой комментарий
Итак, теперь задание стало более понятным и более узким
есть словарь слов
из словаря выбирается ТОЛЬКО 3 слова, которые соединяются разделителем (пустой символ? или все таки "_" было в коде?)
сравнивается с тестовым паролем и определяется - могло ли оно быть сгенерировано из словаря согласно установленным правилам
Если так, то код будет простым и без рекурсий:
// заполнить массив слов
std::vector<std::string> wordList;
// пароль с которым надо сравнивать
const std::string password = "password";
// непосредственно алгоритм брутфорса
for (const std::string& word1 : wordList)
{
for (const std::string& word2 : wordList)
{
for (const std::string& word3 : wordList)
{
// собрать слово через разделитель "_"
const std::string brutforced = word1 + std::string("_") + word2 + std::string("_") + word3;
// сравнить с паролем и в случае совпадения - выйти
if (password == brutforced)
{
std::cout << "Пароль удовлетворяет требованиям" << std::endl;
return;
}
}
}
}
в каком виде код принимается я не знаю - так что область сравнения надо допиливать (надо возвращать значение или писать на экране что-то - в общем зависит от задачи)
данный код можно существенно соптимизировать - если часть строки уже не соответствует слову из словаря, то не продолжать поиск дальше, тогда код будет таким (он даже более универсальный будет (если не ограничиваться только 3 словами в пароле):
// заполнить массив слов
std::vector<std::string> wordList;
// пароль с которым надо сравнивать
const std::string password = "password";
// непосредственно алгоритм брутфорса
// подбирать слова из словаря к паролю будем продвигаясь слева направо по паролю, пока не достигнем его края
int pos = 0;
while (pos < password.size())
{
// ищем слово в словаре, которое совпадает с частью пароля начиная с позиции pos
int new_pos = -1;
for (const std::string& word : wordList)
{
// если текущее слово не является частью пароля - перейти к следующему
if (strncmp(password.c_str() + pos, word.c_str(), word.size()) != 0)
continue;
new_pos = pos + word.size();
// если найденным словом пароль не заканчивается, то проверить на наличие соединяющего символа '_' и если символ не найден - считать найденное слово неподходящим
// это защита от ситуации, когда password = 'abc_xyz', а в словаре есть слова 'ab' и 'abc'
if (new_pos < password.size() && password[new_pos] != '_')
new_pos = -1;
else
break;
}
// если слово не было найдено - выйти
if (new_pos == -1)
break;
pos = new_pos;
}
// если удалось дойти до конца пароля, значит успех
if ((pos == password.size())
{
std::cout << "Пароль удовлетворяет требованиям" << std::endl;
}
Слегка изменил код чтобы учесть возможные ошибки
// заполнить массив слов
std::vector<std::string> wordList;
wordList.push_back("abc");
wordList.push_back("def");
// пароль с которым надо сравнивать
const std::string password = "abc_def_def";
// непосредственно алгоритм брутфорса
// подбирать слова из словаря к паролю будем продвигаясь слева направо по паролю, пока не достигнем его края
int pos = 0;
while (pos < password.size())
{
// ищем слово в словаре, которое совпадает с частью пароля начиная с позиции pos
int new_pos = -1;
for (const std::string& word : wordList)
{
// если текущее слово не является частью пароля - перейти к следующему
if (strncmp(password.c_str() + pos, word.c_str(), word.size()) != 0)
continue;
new_pos = pos + word.size();
if ((new_pos < password.size() - 1) && (password[new_pos] == '_'))
{
new_pos += 1;
break;
}
}
// если слово не было найдено - выйти
if (new_pos == -1)
break;
pos = new_pos;
}
// если удалось дойти до конца пароля, значит успех
std::cout << ((pos == password.size()) ? "success" : "failed") << std::endl;
_getch();
Вот код с дополнениями. Проверка работает исключительно в дебаг режиме, никаких результатов в конце не выводит.
#include <fstream>
#include <vector>
#include <string>
#include <iostream>
#include <random>
using namespace std;
int main(int argc, char* argv[]) {
const char* fname = "wordlist.txt";
/* Parse command-line arguments */
int max = 1;
int key;
if(argc == 2) {
max = atoi(argv[1]);
}
/* Open word list file */
ifstream input;
input.open(fname);
if(input.fail()) {
cerr << "ERROR: Failed to open " << fname << endl;
}
/* Read to end and load words */
vector<string> wordList;
string line;
while(getline(input, line)) {
wordList.push_back(line);
}
/* Seed from random device */
random_device rd;
default_random_engine gen;
gen.seed(rd());
uniform_int_distribution<int> dist(0, wordList.size() - 1);
/* Output as many passwords as required */
const int pwLen = 3;
string password = "";
for(int i = 0; i < max; i++) {
for(int j = 0; j < pwLen; j++) {
password += (string)(wordList[dist(gen)] + ((j != pwLen - 1) ? "_" : ""));
}
cout << endl;
}
cout << password;
// подбирать слова из словаря к паролю будем продвигаясь слева направо по паролю, пока не достигнем его края
int pos = 0;
while (pos < password.size())
{
// ищем слово в словаре, которое совпадает с частью пароля начиная с позиции pos
int new_pos = -1;
for (const std::string& word : wordList)
{
// если текущее слово не является частью пароля - перейти к следующему
if (strncmp(password.c_str() + pos, word.c_str(), word.size()) != 0)
continue;
new_pos = pos + word.size();
// если найденным словом пароль не заканчивается, то проверить на наличие соединяющего символа '_' и если символ не найден - считать найденное слово неподходящим
// это защита от ситуации, когда password = 'abc_xyz', а в словаре есть слова 'ab' и 'abc'
if (new_pos < password.size() && password[new_pos] != '_')
new_pos = -1;
else
break;
}
// если слово не было найдено - выйти
if (new_pos == -1)
break;
pos = new_pos;
}
// если удалось дойти до конца пароля, значит успех
if ((pos == password.size()))
{
std::cout << "Пароль удовлетворяет требованиям" << std::endl;
}
return 0;
}