#!/usr/bin/env python """ Read in a ldap/ldif file and split out a unix-formated password file to run in john the ripper for password auditing. Typical usage (on the ldap server): Dump the ldap database slapcat > ldif.out Convert it to passwd format ldap-passwd-dump.py ldif.out passwd.out Run john to crack passwords john passwd.out Aaron Peterson """ import sys, base64, re, os class Results: """ Keep all user results here """ def __init__(self): self.users = [] def addUser(self, user): # Check for duplicates dupe = 0 for u in self.users: if u.uid == user.uid: dupe = 1 break if not dupe: print " [*] Adding new user [%s, %s] to results" % (user.cn, user.uid) self.users.append(user) else: print " [*] Not adding duplicate user [%s]" % user.cn class User(list): def __init__(self, hash=None, base64=None, password=None, cn=None, uid=None): self.hash = hash self.uid = uid self.base64 = base64 self.password = password self.cn = cn list.__init__(self) class LDIFCrack: def main(self): # Open file f = open(self.ldif, "r") # Load in the first user user = User() isInGroup=0 # Load lines into a "user" for line in f: if re.compile(r"^\s*$").search(line): # Only append the old user if it's in the right group, and has a password set if isInGroup and user.hash: self.results.addUser(user) # Reset user and counter user = User() isInGroup=0 # Make sure we test the right groups if re.compile(self.groupMatch).search(line): isInGroup=1 # Pull out the password match = re.compile(r"userPassword:: (.*)$").search(line) if match: user.base64 = match.group(1) try: user.hash = base64.decodestring(user.base64) except: print " [!] Could not decode string [%s]" % user.base64 continue # Remove {crypt} from hash string if needed match = re.compile("\{.*\}(.*)$").search(user.hash) if match: user.hash = match.group(1) # uid match = re.compile(r"uid: (.*)$").search(line) if match: user.uid= match.group(1) # Grab the common name matchCn = re.compile(r"cn: (.*)$").search(line) if matchCn: user.cn = matchCn.group(1) def printPasswd(self, file): f = open(file, "w") for user in self.results.users: line = "%s:%s:::%s" % (user.uid, user.hash, user.cn) f.write(line + "\n") print " [*] %s" % line f.close() print " [*] Wrote [%s] password lines to [%s] " % (len(self.results.users), file) def __init__(self, ldif, groupMatch): self.ldif = ldif self.results = Results() self.groupMatch = groupMatch self.main() if __name__ == "__main__": if len(sys.argv) < 3: print "\nusage: %s []" % sys.argv[0] print " example: %s ldif.out passwd.txt \"^ou: MyGroup\"" % sys.argv[0] print " (matchString default is \"objectClass: posixAccount\")\n" sys.exit(1) ldif = sys.argv[1] passwdFile = sys.argv[2] if not os.path.exists(ldif): print " [!] LDIF Input file [%s] does not exist..." % ldif sys.exit(1) if os.path.exists(passwdFile): print " [!] Won't overwrite existing passwd file [%s]" % passwdFile sys.exit(1) # Will match the user against this group before cracking it if it's set if len(sys.argv) == 4: groupMatch = sys.argv[3] else: groupMatch = "objectClass: posixAccount" ldifcrack = LDIFCrack(ldif, groupMatch) ldifcrack.printPasswd(passwdFile) print " [*] Done"