|
#!/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() |