1

I am trying to crack passwords of maximum 4 letters, from a hash. Ideally I can write ./crack 50fkUxYHbnXGw and it returns rofl.

My approach is with a nested for loop. To apply this to strings of varying lengths I have been recommended to use a null terminator in C, but for now I've tried an if statement for every possible length.

Do you know a more elegant way of doing this?

Lastly, I have a bug which doesn't gives me any output.

#define _XOPEN_SOURCE // for crypt
#include <cs50.h> // used for get_string
#include <stdio.h> // used for printf
#include <string.h> // used for strlen
#include <ctype.h> // used for isalpha
#include <stdlib.h> // for atoi
#include <crypt.h> // for crypt

int main(int argc, char* argv[])
{
    // accept only two arguments from command line
    // hash is max 13 characters. First two are the salt.
    // next 11 are the key
    if (argc != 2)
    {
        printf("Usage: ./crack hash \n");
        return 1;
    }

    // make second command line argument into string
    char* hash = argv[1];
    char* salt = argv[1];

    strncpy(salt, hash, 2);
    salt[2] = 0; // null terminates destination

    char* key = hash + 2; // just key without salt

    char* abAB = "abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM";

    for (int i = 0, n = strlen(abAB); i < n; i++)
    {   //check for every length
        char tri1[1] = {abAB[i]};
        // produce my own encrpyted key with salt
        char* cr1 = crypt(tri1, salt);
        // if own key is equal to key provided, print out the string tried.
        int comp1 = strcmp(cr1, key);

        if (comp1 == 0)
        {
            printf("%s", tri1);
        }

        for (int j = 0, m = strlen(abAB); j < m; j++)
        {
                char tri2[2] = {abAB[i],abAB[j]};
                char* cr2 = crypt(tri2, salt);
                int comp2 = strcmp(cr2, key);
                if (comp2 == 0)
                {
                    printf("%s", tri2);
                }

            for (int k = 0, p = strlen(abAB); k < p; k++)
            {
                char tri3[3] = {abAB[i],abAB[j],abAB[k]};
                char* cr3 = crypt(tri3, salt);
                int comp3 = strcmp(cr3, key);
                if (comp3 == 0)
                {
                    printf("%s", tri3);
                }

                for (int l = 0, q = strlen(abAB); l < q; l++)
                {
                    char tri4[4] = {abAB[i],abAB[j],abAB[k],abAB[l]};
                    // produce my own encrpyted key with salt
                    char* cr4 = crypt(tri4, salt);
                    // if own key is equal to key provided, print out the string tried.
                    int comp4 = strcmp(cr4, key);
                    if (comp4 == 0)
                    {
                        printf("%s", tri4);
                    }
                }
            }
        }
    }
    printf("\n");
    return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Tarae
  • 67
  • 2
  • 7
  • You're looking for a DFS. – SLaks Sep 14 '17 at 18:23
  • `char* hash = argv[1]; char* salt = argv[1]; strncpy(salt, hash, 2);` looks like trouble. – yano Sep 14 '17 at 18:32
  • Yes that's right, a salt of two characters from the alphabet ./0-9A-Za-z, and the result of crypt will be those two characters followed by 11 more from the same alphabet, so 13 in total. – Tarae Sep 14 '17 at 18:34
  • 1
    why `strncpy`? That corrupts the input argument `argv[1]` (since `hash`, `salt` and `argv[1]` all point to the same thing) ... and why `strncpy`? `salt` and `hash` already are the same string. If you want to play with substrings from `argv[1]` I'd recommend duplicating it first so as not to corrupt the original. – yano Sep 14 '17 at 18:40
  • If `argv[1]` is only 1 character + 1 _null character_ like `"x"`, then `salt[2] = 0;` is UB. – chux - Reinstate Monica Sep 14 '17 at 18:43
  • In fact it says on the [`strcpy` man page](https://linux.die.net/man/3/strncpy) "The strings may not overlap",, this is probably UB, although it doesn't explicitly say that. – yano Sep 14 '17 at 18:43
  • 1
    `crypt (const char *key, const char *salt)` expects a pointer to _string_ for `key`. With `char tri1[1] = {abAB[i]}; ... crypt(tri1, salt);`, `tri1` does not pointer to a _string_. – chux - Reinstate Monica Sep 14 '17 at 18:45
  • "I have a bug which doesn't gives me any output" --> Does code complete? If not, it might just take a _long_ time with this inefficient code. Try coding and cracking a 2 letter password first. – chux - Reinstate Monica Sep 14 '17 at 18:53
  • @yano you're right there's writing over variables there. I was trying to get the salt from the hash, salt being the first two elements of the string. Will duplicate, thank you. – Tarae Sep 14 '17 at 19:05
  • the function: `strlen()` only works on char arrays that have a NUL terminator byte. I.E. if the char array does not have a NUL terminator byte then the result is undefined behavior and can lead to a seg fault event. – user3629249 Sep 14 '17 at 23:10
  • when outputting an error message, such as: `"Usage: ./crack hash \n"` it should be output to `stderr`, not `stdout` suggest: `fprintf( stderr, "Usage: %s hashValue\n", argv[0] );` – user3629249 Sep 14 '17 at 23:15
  • regarding: `char* salt = argv[1]; strncpy(salt, hash, 2);` this is probably not correct. because 1) `salt` is a pointer, that is already pointing to `argv[2]` and 2) the contents of command line arguments are often in readonly memory and in any case should not be modified 3) `hash` and `salt` already point to the same thing I.E. argv[1] – user3629249 Sep 14 '17 at 23:18
  • regarding: `salt[2] = 0; // null terminates destination char* key = hash + 2; // just key without salt` the first statement sets hash[2] to '\0' so `key` will point to a NUL byte – user3629249 Sep 14 '17 at 23:22
  • this line: `char tri2[2] = {abAB[i],abAB[j]};` sets `tri2` to a pair of characters, no NUL termination byte. then this line: `printf("%s", tri2);` tries to print the NUL terminated string that starts with the two characters in `tri2`. However, since `tri2` is NOT a NUL terminated character array, the '%s' format specifier will keep on printing successive characters in memory until it accesses a NUL byte. This results in undefined behavior and can lead to a seg fault event. There are several other places in the code with this same kind of problem. – user3629249 Sep 14 '17 at 23:32
  • there are lots of other problems in the code, but the above comments should get you thinking in the right direction. – user3629249 Sep 14 '17 at 23:33
  • thanks, I fixed the code of all the bugs. Fixed with `char* hash = argv[1];` `char salt[3];` `strncpy(salt, hash, 2);` `salt[2] = '\0'; // null terminates destination` `char* key = hash + 2; // just key without salt` – Tarae Sep 15 '17 at 12:11

1 Answers1

0

This is what I did in the end for those interested. I'm still not sure how I could have changed the length of the strings with less repetition.

#define _XOPEN_SOURCE // for crypt
#include <cs50.h> // used for get_string
#include <stdio.h> // used for printf
#include <string.h> // used for strlen
#include <ctype.h> // used for isalpha
#include <stdlib.h> // for atoi
#include <crypt.h> // for crypt

int main(int argc, char* argv[])
{

// accept only two arguments from command line
// hash is max 13 characters. First two elements are the salt,
// the other 11 are the key

if (argc != 2)
{
    printf("Usage: ./crack hash \n");
    return 1;
}

// make second command line argument into string
char* hash = argv[1];
char salt[3];
strncpy(salt, hash, 2);
salt[2] = '\0'; // null terminates destination

char* key = hash + 2; // just key without salt

printf("key: %s\n", key);
printf("salt: %s\n", salt);

char* abAB = "abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM";

for (int i = 0, n = strlen(abAB); i < n; i++)
{
    //check for every length
    char tri1[2] = {abAB[i], 0};

    // produce my own encrpyted key with salt
    char* cr1 = crypt(tri1, salt);

    // if own key is equal to key provided, print out the string tried.
    if (strcmp(cr1, hash) == 0)
    {
        printf("%s\n", tri1);
        return 0;
    }

    for (int j = 0, m = strlen(abAB); j < m; j++)
    {
        char tri2[3] = {abAB[i], abAB[j], 0};
        char* cr2 = crypt(tri2, salt);

        if (strcmp(cr2, hash) == 0)
        {
            printf("%s\n", tri2);
            return 0;
        }

        // this didn't work - do you know why???
        // int comp2 = strcmp(cr2, hash);
        // if (comp2 == 0)
        // {
        //     printf("%s", tri2);
        //     printf("test");
        //     return 0;
        // }

        for (int k = 0, p = strlen(abAB); k < p; k++)
        {
            char tri3[4] = {abAB[i],abAB[j],abAB[k], 0};
            char* cr3 = crypt(tri3, salt);

            if (strcmp(cr3, hash) == 0)
            {
                printf("%s\n", tri3);
                return 0;
            }

            for (int l = 0, q = strlen(abAB); l < q; l++)
            {
                char tri4[5] = {abAB[i],abAB[j],abAB[k],abAB[l], 0};
                // produce my own encrpyted key with salt
                char* cr4 = crypt(tri4, salt);

                // if own key is equal to key provided, print out the string tried.
                if (strcmp(cr4, hash) == 0)
                {
                    printf("%s\n", tri4);
                    return 0;
                }
            }
        }
    }
}

printf("\n");
return 1;
}
Tarae
  • 67
  • 2
  • 7