C++password brute Force

There is a task to make a brute force password using a dictionary. There is a password generator code:

#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;
}

Actually, the output is something like sdf_a_safasfasfasdf. How can I use this method to select a password?

Author: EOF, 2020-10-06

3 answers

Yes, this is a lab assignment. You can also code using recursive functions, but unfortunately, I'm not good at them. Most likely, I incorrectly explained the essence of the task. Initially, you need to create a brute force that takes 3 words from the dictionary. Puts ""between the words instead of a space. And compares it with the entered password (it is generated according to the same principle, 3 words from the dictionary and ""). The generator that is, but how to implement brutus-I can not understand. Sorry if I put it wrong the first time once ;) - Boredix 5 minutes ago

For convenience, I put it in another comment

So, now the task has become more clear and narrower

  1. There is a dictionary of words

  2. Only 3 words are selected from the dictionary, which are connected by a separator (an empty character? or was "_" still in the code?)

  3. It is compared with the test password and determines whether it could have been generated from the dictionary according to the established parameters. rules

If so, the code will be simple and without recursions:

// заполнить массив слов
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;
            }
        }
    }
}

In what form the code is accepted, I do not know - so the comparison area must be completed (you need to return a value or write something on the screen-in general, it depends on the task)

This code can be significantly optimized - if part of the string does not match the word from the dictionary, then do not continue the search further, then the code will be like this (it will be even more universal (if not limited to only 3 words in the password):

// заполнить массив слов
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;
}

Slightly changed the code to account for possible errors

// заполнить массив слов
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();
 0
Author: Zhihar, 2020-10-06 12:12:28

Well, let's figure out exactly how the password is generated

  1. First, select how many words from the dictionary will be selected for the password-variable max (default 1)

  2. Next, the word{[8] is selected from the dictionary]}

  3. The word is duplicated 3 times, and after the last duplication, put "_"

However, sdf_a_safasfasfasdf with such an algorithm will not work, rather it should have turned out sdfsdfsdf_aa_

To zabrutformit it is necessary reproduce the same algorithm, only iterate through all the words from the dictionary:

// формируем очередное звено пароля
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);

If the password size (number of words from the dictionary) is not fixed, then it will look a little different:

You should always check the password after generation, and use max_level just to limit the maximum password size

// формируем очередное звено пароля
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);

For optimization, it is necessary to make sure that if the password is found at some stage, then do not continue working further:

// формируем очередное звено пароля
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;
}
 1
Author: Zhihar, 2020-10-06 08:11:23

Here is the code with the additions. The check works exclusively in the debug mode, it does not output any results at the end.

#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;
}
 1
Author: Boredix, 2020-10-06 10:53:27