|
WARNING: The code segments, tutorial, and any source
files provided are meant for educational use only. I will not be held
liable for any illegal activity that results from the use of this material.
This is provided as is, having no warranty or support of any kind, and
is used entirely at your own risk.
Bruteforce Password Recovery
Written by Tony Bhimani
August 6, 2004
Requirements
*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.
someuser:$1$Ua/y3BAI$2mzjA3mqUxqw07CmvdR7v.:12627:0:99999:7:::
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".
" `~!@#\$%^&*()-_=+[{]}\\|;:'\",<.>/?";
# 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!
|
This page has been viewed 12,525 times |
|