How to write a brute-force password cracker

If you have access to a password's hash and salt, if applicable, a brute force attempt to crack it is a guaranteed method if you have the CPU cycles available to compute it in a reasonable amount of time.  Unfortunately, guessing every single permutation of characters takes exponentially longer with the length of the password used so often times you are facing months if not years of processing time on a single PC.  While there are methods to distribute the work across multiple PCs, I am only going to go over a simple brute force algorithm and will hold off on the distributed processing model for a later article.

Learn the hashing algorithm used

Before you can do anything, you must know what algorithm was used to hash the password.  For many products, this is know and you can find it either by searching the web or by looking through the code the product uses if it's open-source.  In my example, the algorithm is md5(concat(md5(password), salt)).  What this means is that a hexadecimal md5 digest was created for the password, then a random salt was concatenated onto it to form a new string, which was then md5 digested again and the resulting hex digest and salt are stored to be checked against later.  This is not necessarily the most secure method in the world, but for 10+ character passwords it takes months or years of CPU time on a decent PC to guess.

Test your hashing implementation before running

Within the product, put in a test password then extract the hash and salt.  Run your code with your password in and make sure it generates a matching hash and salt.  This will be your evaluation method and it is crucial that you have no bugs in it, as you will skip right over the correct password and potentially might end up at a false positive.

Write your password generation method and tie it all together

Obviously a dictionary-based approach would be faster to execute, but we're not talking about that today.  You will want to generate every permutation of the test character set, generate a hash of each one and test it against the target hash, then print out a positive result.  I used a recursive method that generates all permutations for a given width of password.  I then call that from a loop that starts at a width of 1 and works up to a maximum of 13.  Again, my PC would never be able to finish all 13 character perms in time but that's a different issue.

The code

Here is my code written in python, which should be easily portable to any other language.

import md5
import sys

easyRange = [32,33,36,42,43] + range(48, 58) + range(65, 91) + range(97, 123)
allRange = range(32,127)

hash = "<16 hex pairs here>"
salt = "<salt>"

def checkPassword(password):
    m = md5.new(password)
    m = md5.new(m.hexdigest() + salt)
    if (m.hexdigest() == hash):
        print "match [" + password + "]"
        sys.exit()

def recurse(width, position, baseString):
    #current position
    for char in easyRange:
        if (position < width - 1):
            recurse(width, position + 1, baseString + "%c" % char)
        checkPassword(baseString + "%c" % char)

print "Target Hash [" + hash + "] Salt [" + salt + "]"
maxChars = 13
for baseWidth in range(1, maxChars + 1):
    print "checking passwords width [" + `baseWidth` + "]"
    recurse(baseWidth, 0, "")

I have 2 ranges of characters defined.  easyRange, which is most common alphanumerics with a few special characters, then allRange, which is every acceptable character.  If you want a more thorough set of characters, use allRange in the recurse method.

Changes to the algorithm need to be done in checkPassword.  Just call that with the target hash and salt and the known password to confirm that your algorithm works correctly.

Multi-threading
 

This example is single-threaded so it can't take advantage of hyper threading, multiple CPUs or multiple CPU cores.  My recommended threading strategy would be to divide the work into roughly 5 minute chunks (maybe 100m possible numbers) which would be achievable using low memory by starting the threading only at a width of 5 by assigning the lower 4 combinations to a worker thread and then using an even number of threads-to-cores to maximize CPU usage.  Each time a thread joins, get the next available block of work and begin processing again.  This simple approach would only require a manager which watches the placeholder of work, which is sequential.  For example, if the current password guessing iteration were 7-wide, it would hand ABCxxxx off to a thread1, then ABDxxxx to thread2, then ABExxxx to thread3, etc. 

Distributed Computing

While the threading approach is simple, a distributed computing approach would require much more architecture.  I recommend writing a simple distribution server which hands units of work off to clients, keeps track of what's a work-in-progress and what's complete.  A client could interface via a simple SOAP or other XML-based interface (the overhead here is negligible of the units of work are large and # of requests are low).  The client would simply request a unit of work, process it then return a found or not-found result, which, depending on the algorithm, may or may not end the whole search if the algorithm can have collisions (md5 does.)  A simple implementation of the Leader/Follower architectural pattern would make it a snap to scale up handling the remote requests from a number of clients.

Academically, you could have a lot of fun with this just testing out distributed computing approaches and more efficient algorithms.  Practically speaking, though, if the algorithm used is even SHA-1 or anything more complex than MD5 and you don't have thousands of CPUs to process the possibilities, you simply won't be able to crack the password in a reasonable amount of time.

Disclaimer

This is purely educational.  This concept is common-knowledge and provided here for a reference only.  I am not liable for any misuse, even if it does take years of processing for a single password.

14 Comments

Post a comment here or discuss this and other topics in the forums

doesn't work..

print "match [ + password + ]"

The last " doesn't fit

Thanks a ton. Like Sean I

Thanks a ton. Like Sean I didn't have much experience with recursion or hashing algorithms, but I learned alot. Thanks again for putting this out there for the kid who gets bored in school

This is how you melt faces

This is how you melt faces like a pro

import random
import hashlib

key = raw_input("Please enther the MD5 hash\n>")

charset = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9"]

for char1 in charset:
if hashlib.md5(char1).hexdigest() == key:
print "The password is ",char1
print "Currently on",char1
for char2 in charset:
if hashlib.md5(char1+char2).hexdigest() == key:
print "The password is ",char1+char2
for char3 in charset:
if hashlib.md5(char1+char2+char3).hexdigest() == key:
print "The password is ",char1+char2+char3
for char4 in charset:
if hashlib.md5(char1+char2+char3+char4).hexdigest() == key:
print "The password is ",char1+char2+char3+char4
for char5 in charset:
if hashlib.md5(char1+char2+char3+char4+char5).hexdigest() == key:
print "The password is ",char1+char2+char3+char4+char5

Great Job!!!

Your algorithm is really great!!! I've implemented in java but unfortunately i don't have much experience in multithreding....i can't figure out how should i put the manager to place handler the works !
How could i take the next work(ABDxxxx....) and give to the next thread for processing without everything mess up?Could you please give me some directions or an example?
Thanks you!

Code

Actually there are no unnecessary checks that I can see: If you put a print in there it APPEARS as if there are because a space is part of the possible chars, but if you add quotes to your print or if you remove the space, you can see that it works as advertised. I tested this with known salts and passwords, and it works. No idea how long it would take once you get to a certain length, but I can see that years might be likely, even with today's hardware.

Yes, yes it is. It's pretty

Yes, yes it is. It's pretty basic. You should be able to write this and many other things in Java once you learn a little bit of the language.

java

i am a school student who works with java. Is it possible to create such programs as the password cracker
with java as i am not well versed with other programs

Convert

Hi, does anyone know how to convert this to objective c?
thanks

Thanks!

Yep, I was about to go to sleep then it popped in my head, thanks to python it only took 30min and i was actually able to sleep. Thanks for the props.

Distributed Password BruteForcer

I've written a similar tool, but mine is in C++ for efficiency reason. (The purpose of such programs is to be fast non ? So why PHP ? ^^) It use standard socket for the communication between clients and server. The server use a Berkeley DB to store results. Client is multi threaded. A shared object transmitted by the server is used to compute the hash. It's really the beginning (a pre pre pre alpha release), I'm still working on it...

Source code can be found here : http://guillaume.fahrner.biz/demo/C++/DistributedPasswordBruteForcer/

Regards

I know this is very old post,

I know this is very old post, but I think there's a flaw in the code.
You're generating too much text permutations.
Make a test yourself, you'll see that for texts with the width of 2, you also generate all texts with the width of 1. This pattern goes on with larger widths.

That means some unnecessary checks :)

Nice!

I looked at your code to try to figure out how you're distributing the work and then I saw that you used two methods - main1 and main2, to distribute. main1 starts at the bottom of the list, main2 starts at the top. I was thinking of having a manager that reads maybe 100 words at a time from the main list. It initially spawns n processes. Each process asks the manager for another set of words when it runs out. That way you could scale to as many processors as you want. To make that more fun, the manager could be running on a socket and the interface could be "get next word list" and "found match" in some computery form. This would enable a cluster of machines all processing chunks of words until one finds a match. All one would have to do is start the cracker client on any machine and have it pointed to the cracker server/manager machine.

Made multi-processing MD5 cracker

I actually made a Multi-processed MD5 cracker(no salt support), since multithreading in python doesn't spawn another process it cannot utilize more than 1 CPU, but multi-processing spawn a whole new process which is able to use how ever many CPUs you put into your algorithm. Here it is, I hand optimized it and i still am and it can only use 2 CPUs as of now. Check me out on LaunchPad https://launchpad.net/coffee :

"
#! /usr/bin/python
from multiprocessing import Process
from hashlib import md5
try:
import psyco
psyco.full()
except ImportError:
pass
def genHash(hashes): return md5(hashes).hexdigest()
def getwordlist(wlists):
try:
wlist=open(wlists,'r').readlines()
for ij in xrange(len(wlist)):
wlist[ij]=wlist[ij].strip()
except IOError:
print "IOERROR: File",wlist,"cannot be opened."
exit()
return wlist
def main1(crack):
for i in xrange(len(wordlist)):
if crack==genHash(wordlist[i]):
print "\n"+crack+" = "+wordlist[i]
break
def main2(crack):
for k in reversed(xrange(len(wordlist))):
if crack==genHash(wordlist[k]):
print "\n"+crack+" = "+wordlist[k]
break
crackit=raw_input("\nEnter hash to crack: ")
wist=raw_input("\nEnter wordlist: ")
wordlist=getwordlist(wist)
if __name__=='__main__':
p1=Process(target=main1, args=[crackit])
p1.start()
if __name__=='__main__':
p2=Process(target=main2, args=[crackit])
p2.start()
while True:
if p1.is_alive()==False:
p2.terminate()
break
if p2.is_alive()==False:
p1.terminate()
break
raw_input("\npress enter to exit...")
"

re: How to write a brute-force password cracker

Thanks for this. I spent an entire day trying to figure out this algorithm. I have limited experience with recursion, and soon found out the limitation of nested-loops.For anyone interested I created a PHP version.