vrijdag 23 november 2012

Cracking Redmine passwords

As I am running Redmine on my server and I wanted to test security I wanted to see if I could crack some passwords of my users.

Redmine uses sha1 to store passwords, salted with a random uhm.. salt.

In pseudo code the algorithm to create a password hash would look like this:
sha1(salt + sha1(password))

I made a dump of the users table in the format "login:password_hash:salt" and wrote a small Python based cracker that could parse this and iterate through a dictionary file.

Out of the 16 users in the table 2 of them used their login as their password.. 1 used his first name and 1 used a password that was cracked within seconds.
Needless to say, I locked their accounts [insert evil laugh] and I'm going to do this more often. (Maybe automated, with email notifications or something.)

O, and for those who want to do this sort of unethical thing too, here's the script:
#!/usr/bin/env python

from optparse import OptionParser
import hashlib

parser = OptionParser(usage="usage: %prog [options] userfile wordlist")
(options, args) = parser.parse_args()

if len(args) != 2:
    parser.error("Incorrect number of arguments")

def import_users():
    user_file = open(args[0], 'r')
    users = [] # format: (login, password_hash, salt)
    for line in user_file.readlines():
        if not line.startswith('#'):
            users.append(line.strip().split(':'))
    user_file.close()
    return users

def calculate_hash(password, salt):
    hashed_password = hashlib.sha1(password).hexdigest()
    hash = hashlib.sha1(salt+hashed_password).hexdigest()
    return hash


users = import_users()

# Try username as password
cracked = []
for user in users:
    word = user[0].strip()
    if user[1] == calculate_hash(word, user[2]):
        print "Password of user '%s' is '%s'" % (user[0], word)
        cracked.append(user)
for user in cracked:
    users.remove(user)

wordlist = open(args[1], 'r')
for word in wordlist:
    cracked = []
    for user in users:
        if user[1] == calculate_hash(word, user[2]):
            print "Password of user '%s' is '%s'" % (user[0], word)
            cracked.append(user)
    for user in cracked:
        users.remove(user)
wordlist.close()

1 opmerking:

  1. I needed to modify it so it stripped the line feeds of the wordlist, so maybe you might find some more passwords once fixed.

    BeantwoordenVerwijderen