HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Python Hash-Cracker

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
crackerpythonhash

Problem

This is my first actual python tool I've written and I'm certainly happy with the way it works, but I'm sure there's better ways to do things in the code. Any ideas on how to speed it up would also be nice too!

Code:

```
#!/usr/bin/python
import StringIO
import getopt
import hashlib
import sys
import os
print " "
print "Python Hash-Cracker"
print "Version 3.0-2 Stable"

def info():
print " "
print "Information:"
print "[*]Options:"
print "* Hash"
print "* Type [See supported hashes]"
print "* Wordlist"
print "* Numbers bruteforce"
print "* Verbose [{WARNING}Slows cracking down!]"
print "[*]Examples:"
print "[>]./Hash-Cracker.py -h -t md5 -w DICT.txt"
print "[>]./Hash-Cracker.py -h -t sha384 -n -v"
print "[*]Supported Hashes:"
print "[>]md5, sha1, sha224, sha256, sha384, sha512"
print "[*]Thats all folks!\n"

def check_os():
if os.name == "nt":
operating_system = "windows"
if os.name == "posix":
operating_system = "posix"
return operating_system

class hash:
def hashcrack(self, hash, type):
self.num = 0
if (type == "md5"):
h = hashlib.md5
elif (type == "sha1"):
h = hashlib.sha1
elif (type == "sha224"):
h = hashlib.sha224
elif (type == "sha256"):
h = hashlib.sha256
elif (type == "sha384"):
h = hashlib.sha384
elif (type == "sha512"):
h = hashlib.sha512
else:
print "[-]Is %s a supported hash type?" % type
exit()
wordlist1 = open(wordlist, "r")
wordlist2 = wordlist1.read()
buf = StringIO.StringIO(wordlist2)
while True:
line = buf.readline().strip()
if (line == ""):
print "\n[-]Hash not cracked:"
print "[*]Reached end of wordlist"
print "[*]Try another wordlist"
print "[*]Words tryed: %s" % self.num
break
hash2 = h(line).hexdigest()
if (ver == "yes"):
sys.stdout.write('\r' + str(line) +

Solution

Summary:

  • Better comments and docstrings.



  • Separate code that prints messages and computes values.



  • Try not to do too much in a single function.



Big things:

-
First time I tried to run the program, it immediately hit an error:

$ tail -n 1 /usr/share/dict/words
Zyzzogeton

$ md5 -s "Zyzzogeton"
MD5 ("Zyzzogeton") = 4f9c55496b14676f23f40117cc89e641

$ python hashcrack.py -h "4f9c55496b14676f23f40117cc89e641" -t md5 /usr/share/dict/words

Python Hash-Cracker
Version 3.0-2 Stable
[Running on posix]

[*]Hash: 4f9c55496b14676f23f40117cc89e641
[*]Hash type: md5
[*]Wordlist: None
[+]Cracking...
Traceback (most recent call last):
File "hashcrack.py", line 172, in
main(sys.argv[1:])
File "hashcrack.py", line 157, in main
h.hashcrack(hash1, type)
File "hashcrack.py", line 52, in hashcrack
wordlist1 = open(wordlist, "r")
TypeError: coercing to Unicode: need string or buffer, NoneType found


Turns out I’d forgotten the -w flag – your program should be better about handling malformed user input.

-
You should read PEP 8, the Python style guide. Among other things: indentation is inconsistent (Python standard is 4 spaces, but this file uses 2, 3 and 4 interchangeably); class names should be CamelCase, two blank lines between functions.

-
I would consider using something like docopt to do the command-line argument parsing. Even if you don’t use docopt, it’s worth looking at the style of usage message it requires:

  • There’s a standard format for usage messages on command-line tools. Sticking to this format will make it easier for other people to quickly pick up using your tool.



  • There’s a long-standing convention of using -h or --help to print help information. Using -i to get info is fairly unusual.



  • And using docopt would allow you to simplify a big chunk of your argument-parsing code.



-
There are no comments or docstrings in this code, which makes it hard to work out what something is doing (and by extension, whether it’s doing it correctly).

-
A function should either do something (e.g. print to the screen) or return a value. Your functions tend to intersperse printing with computation. If I want to get the result of a function but without the printing, that's quite hard to do. Separating the two will make it easier to reuse your code.

(You could use something like the logging module for messages you want to print mid-computation, as logging is easier to turn off than printing to stdout.)

More generally, I’d consider breaking your code down into smaller functions. Each function can be written and tested individually, and it tends to make it easier to see what’s going on.

And smaller comments:

-
Common convention is that if a program runs successfully, it exits with code 0; any other outcome is a non-zero exit code. If I ask to check with a non-existent hash, the exit() on line 91 will print an error, then exit with code 0. Also, errors should be printed to stderr, not stdout.

-
Rather than a big branch of if … elif statements in hashcracknum(), use a dict for the lookup of hash name to hash function. Python hash tables are very efficient.

-
Your code could be better about handling user input. For example, this command:

python hashcrack.py -h notahash -t MD5 -w /usr/share/dict/words


I claim that the hash function I want to use is obvious to a human reader, but this causes the script to error.

-
Don’t use type as a variable name; overriding built-in functions is a recipe for weirdness.

-
You definitely shouldn’t name a class hash. This overrides a builtin Python function (that’s used in quite a few places), classes should have CamelCase names, and it’s not particularly descriptive.

-
Your check_os() function will throw a NameError if called on a platform where os.name isn't nt or posix. If you want a human-readable platform name, you might want to look at the platform module, which tends to have more granular names.

-
Don’t print anything at the module level outside the main() function – if anybody tries to import this file, those prints will be executed no matter what. That makes it very annoying to reuse your code.

-
It’s common practice for Python modules/libraries to present a __version__ attribute – it would be good to do that for your version string.

Code Snippets

python hashcrack.py -h notahash -t MD5 -w /usr/share/dict/words

Context

StackExchange Code Review Q#135110, answer score: 8

Revisions (0)

No revisions yet.