Skip to content

Instantly share code, notes, and snippets.

@cjavad
Last active February 26, 2018 11:43
Show Gist options
  • Select an option

  • Save cjavad/d5592c725ed5690e23506b8354639791 to your computer and use it in GitHub Desktop.

Select an option

Save cjavad/d5592c725ed5690e23506b8354639791 to your computer and use it in GitHub Desktop.
Python tool for cross-referencing macos passwords with a wordlist either by itself or with hashcat

Crack.py is a macos "password-finder" tool that can either go over a wordlist by itself or generate hashcat output for macos 10.8+ passwords (mode 7100).

Usage

To generate the required xml file, use the following command

sudo defaults read /var/db/dslocal/nodes/Default/users/<username>.plist ShadowHashData|tr -dc 0-9a-f|xxd -r -p|plutil -convert xml1 - -o <username>.xml

Where <username> is your target username.

Then you can run

./crack.py [-X, --xml <username>.xml] [-H, --hashcat] [-w, --wordlist <list>]
#!/usr/bin/env python3.6
"""
Generate the xml files with this command:
sudo defaults read /var/db/dslocal/nodes/Default/users/<username>.plist ShadowHashData|tr -dc 0-9a-f|xxd -r -p|plutil -convert xml1 - -o <username>.xml
"""
import hashlib
import base64
import sys # for sys.argv
import argparse # use argparse
# use Beautifulsoup to parse the xml/plist file
from bs4 import BeautifulSoup
def CheckPass(password, salt, iterations, hashtype="sha512"):
return hashlib.pbkdf2_hmac(hashtype, password, salt, int(iterations))
def Crack(hashdata, password_list, total):
for i,password in enumerate(password_list):
h = CheckPass(password.encode(), base64.b64decode(hashdata["salt"]), hashdata["iterations"], "sha512")
if h in base64.b64decode(hashdata["hash"]):
return password
else:
print("[*] Password:", password, "is not valid. (" + str(i) + "/" + str(total) + ")")
def GetHash(xmldump):
xml = BeautifulSoup(xmldump, "html.parser")
dicts = xml.dict.find_all("dict")
salt = dicts[0].find_all("data")[1].text.replace("\n", "").replace("\t", "")
entropy = dicts[0].find_all("data")[0].text.replace("\n", "").replace("\t", "")
iterations = int(dicts[0].find("integer").text)
return {"hash":entropy, "salt":salt, "iterations":iterations}
def hashcat(xmldump):
hashdata = GetHash(xmldump)
return "$ml$" + str(hashdata["iterations"]) + "$" + base64.b64decode(hashdata["salt"]).hex()\
+ "$" + base64.b64decode(hashdata["hash"]).hex()
def main(args=None):
if args is None:
args = sys.argv[1:]
parser = argparse.ArgumentParser(description="Crack.py can parse macos password files and generate output for hashcat/try to crack it", \
epilog="sudo defaults read /var/db/dslocal/nodes/Default/users/<username>.plist ShadowHashData|tr -dc 0-9a-f|xxd -r -p|plutil -convert xml1 - -o <username>.xml")
parser.add_argument("-X", "--xml-file", help="input xml file")
parser.add_argument("-H", "--hashcat", action="store_true", help="hashcat output")
parser.add_argument("-w", "--wordlist", help="Only use if you want to crack it using this script (only use for small wordlists)")
options = parser.parse_args(args)
XML = None
if options.xml_file:
XML = open(options.xml_file, "r").read()
if options.hashcat:
print(hashcat(XML))
else:
hashdata = GetHash(XML)
if options.wordlist:
wordlist = [s.strip("\n") for s in open(options.wordlist).readlines()]
c = Crack(hashdata, wordlist, len(wordlist))
if c:
print("[+] Password found!:", c)
else:
print("[-] Could not find password in wordlist")
else:
print("[*] Printing data from", options.xml_file)
print("[+] Iterations:", hashdata["iterations"])
print("[+] Salt:", hashdata["salt"])
print("[+] Hash:", hashdata["hash"])
else:
print("[-] No xml file specified")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment