Bruteforce perl

Bruteforce Password Recovery

Written by Tony Bhimani
August 6, 2004

*nix based Operating System
Perl 5.6.1 or higher & these modules
• Getopt::Std
• Crypt::PasswdMD5

Download the source code: bruteforce.tar.gz

I have been using Perl for roughly six months, so it is still very new to me. In an attempt to sharpen my skills I sat down and thought about a nifty utility I could write. I decided upon a utility to recover lost passwords. Of course I could always change the password as root, but where's the fun in that? This script performs brute force attempts at recovering a md5 crypted password which you can find in /etc/shadow.

I have only tested this on RedHat 7.3 and cannot confirm nor deny that it will work on other distributions. FreeBSD may do the encryption differently than Fedora and so on. So my advice is if you try and recover a password, run the bruteforce script on the system your recovering the password from.

Here is a line from an example /etc/shadow file.


The md5 crypt password is $1$Ua/y3BAI$2mzjA3mqUxqw07CmvdR7v.

The salt is after the second $ and the encrypted password is after the third $.

salt        = Ua/y3BAI  crypted pwd = 2mzjA3mqUxqw07CmvdR7v.

To have bruteforce recover the password, you would execute it like so.

./bruteforce -v Ua/y3BAI 2mzjA3mqUxqw07CmvdR7v.

After it does some crunching it would find (after a very long time) the password and display it.

This may take a very long time...please be patient
Found the password -> 123456

So someuser has a password of 123456.

Let's take a look at some code snippets.

# define our alphabet (later I may put this in a text file so the user can change it if they want)  $alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".              " `[email protected]#\$%^&*()-_=+[{]}\\|;:'\",<.>/?";        # get the salt and encrypted password  $encSalt = $ARGV[0];  $encPass = $ARGV[1];    # build the encrypted password for comparisons  $crypted_password = "\$1\$$encSalt\$$encPass";    # number of attempts at guessing the password  $attempts = 0;    # this  our starting point  print "This may take a very long time...please be patient\n\n";  while (1) {    $bfpass = bruteforce($alphabet, $options{p});    $attempts++;    # if verbose is turned on, display the current password attempt    if ($options{v}) {      print "$bfpass  attempt # $attempts\r";    }    # check if the encrypted passwords match...if so then we found it!    if (unix_md5_crypt($bfpass, $encSalt) eq $crypted_password) {      print "Found the password -> $bfpass\n";      print "It took $attempts attempt(s)\n";      last;    }  }

The while loop is where the script starts and stays till it finds the right password. The bruteforce function's job is to generate the next password sequence using the supplied alphabet. Once bruteforce is done generating the password it returns it as a string. That generated password is then passed to the unix_md5_crypt function available from the Crypt::PasswdMD5 module. A comparison is made between the crypted password supplied from the command line and the crypted generated password. If they match then the correct password has been found and it is displayed to the user and the while loop ends. If the crypted passwords do not match, then the loop starts over and the next password sequence is generated, crypted, and compared.

sub bruteforce {    @tmpPWD = ();        ($ab,$startPWD) = (shift,shift);      $firstChar = substr($ab, 0, 1);      $lastChar = substr($ab, length($ab) - 1, 1);        # start with an assigned password from the command line    if ($startPWD ne "" && $currentPWD eq "") {      $currentPWD = $startPWD;      return $currentPWD;    }          # no password so start with the first character in our alphabet    if ($currentPWD eq "") {      $currentPWD = $firstChar;      return $currentPWD;    }        # if the current password is all of the last character in the alphabet    # then reset it with the first character of the alphabet plus 1 length greater    if ($currentPWD eq fillString(length($currentPWD), $lastChar)) {      $currentPWD = fillString(length($currentPWD) + 1, $firstChar);      return $currentPWD;    }        # convert the password to an array    @tmpPWD = split(//, $currentPWD);        # get the length of the password - 1 (zero based index)    $x = @tmpPWD - 1;          # this portion adjusts the characters    # we go through the array starting with the end of the array and work our way backwords    # if the character is the last one in the alphabet, we change it to the first character    # then move to the next array character    # if we aren't looking at the last alphabet character then we change the array character    # to the next higher value and exit the loop    while (1) {      $iTemp = getPos($ab, $tmpPWD[$x]);          if ($iTemp == getPos($ab, $lastChar)) {        @tmpPWD[$x] = $firstChar;        $x--;      } else {              @tmpPWD[$x] = substr($ab, $iTemp + 1, 1);        last;      }    }        # convert the array back into a string and return the new password to try    $currentPWD = join("", @tmpPWD);          return $currentPWD;  }

The bruteforce function is the brains of the operation. It iterates through the alphabet and generates the next password in the sequence. It accepts two arguments: the alphabet string and a start password. The start password defines a starting point to generate from. This is useful in case we want to split the task of recovering a single password across multiple machines (distribute the load if you will). For example, we could have one machine start from a empty password to "????" and another start from "aaaaa" to "?????????" and so on. This speeds up the recover process.

The code is very straightforward. We get the first and last characters from the alphabet and store those in variables. Then test to see if a start password is defined and if it is to return that. Next we test for an empty password and start with the first character of the alphabet. If the password contains all end alphabet characters, then the password is resized for one extra character and filled entirely with the first character of the alphabet. The password is then converted to an array and the size of the array - 1 is stored in a variable. This variable controls the position within the array as we step through it. We enter another while loop and its job is to increment each character starting from the end of the string. If the array character is the same as the end character of the alphabet, then we change it to the first character and decrement our index by 1 (effectively moving backwards through the array). If the array character is not the same as the last character, then we change it to the next character in the alphabet and exit the loop. The array is converted back into a string and returned by bruteforce.

In plain English, starting with "a" it moves up to "?". It sees the "?" as the last alphabet character and resizes the string to its current length + 1 and changes it to "aa". "aa" eventually gets to "a?" and changes the "?" to "a" and changes the starting "a" to "b" to become "ba", etc... It's the same as counting numbers and carrying them over. If you count from 0 to 9 and next comes 10. After so many iterations you reach 99 and then comes 100. It's the same concept.

The code is available for download from the link at the top of the page. Be sure to chmod it to 755 so it will execute. Enjoy!

0 pensamientos:

Post a Comment