Browse Source

windows binaries + Name The Hash

Roman Hergenreder 2 years ago
parent
commit
48727a7aa6
4 changed files with 103 additions and 284 deletions
  1. 91 280
      crack_hash.py
  2. 12 4
      requirements.txt
  3. BIN
      win/Certify.exe
  4. BIN
      win/Rubeus.exe

+ 91 - 280
crack_hash.py

@@ -1,289 +1,100 @@
 #!/usr/bin/env python
 
+import os
 import sys
 import subprocess
-import enum
-import re
+import json
 import tempfile
-import base64
-
-HEX_PATTERN = re.compile("^[a-fA-F0-9]+$")
-B64_PATTERN = re.compile("^[a-zA-Z0-9+/=]+$")
-B64_URL_PATTERN = re.compile("^[a-zA-Z0-9=_-]+$")
-
-class HashType(enum.Enum):
-
-    # MD5
-    RAW_MD4 = 900
-    RAW_MD5 = 0
-    MD5_PASS_SALT = 10
-    MD5_SALT_PASS = 20
-    WORDPRESS = 400
-    DRUPAL7 = 7900
-
-    # SHA1
-    RAW_SHA1 = 100
-    SHA1_PASS_SALT = 110
-    SHA1_SALT_PASS = 120
-    SHA1_SHA1 = 4500
-    SHA1 = 101
-    SSHA1 = 111
-
-    # SHA2
-    RAW_SHA2_224 = 1300
-    RAW_SHA2_256 = 1400
-    SHA256_PASS_SALT = 1410
-    SSHA256 = 1411
-    SHA256_SALT_PASS = 1420
-    HMAC_SHA256_PASS = 1450
-    HMAC_SHA256_SALT = 1460
-    RAW_SHA2_384 = 10800
-    RAW_SHA2_512 = 1700
-    SHA512_PASS_SALT = 1710
-    SSHA512 = 1711
-    SHA512_SALT_PASS = 1720
-
-    # SHA3
-    RAW_SHA3_224 = 17300
-    RAW_SHA3_256 = 17400
-    RAW_SHA3_384 = 17500
-    RAW_SHA3_512 = 17600
-
-    # Keccak
-    RAW_KECCAK_224 = 17700
-    RAW_KECCAK_256 = 17800
-    RAW_KECCAK_384 = 17900
-    RAW_KECCAK_512 = 18000
-
-    # Ripe-MD
-    RAW_RIPEMD_160 = 6000
-
-    # Crypt
-    CRYPT_MD5 = 500
-    CRYPT_BLOWFISH = 3200
-    CRYPT_SHA256 = 7400
-    CRYPT_SHA512 = 1800
-    CRYPT_APACHE = 1600
-
-    # python
-    PYTHON_PBKDF2_SHA256 = 20300
-    PYTHON_PBKDF2_SHA512 = 20200
-    DJANGO_PBKDF2_SHA256 = 10000
-
-    # Windows
-    LM   = 3000
-    NTLM = 1000
-    MSSQL = 1731
-    NTLMV2_SSP = 5600
-
-    # Kerberos
-    KERBEROS_AS_REQ = 7500
-    KERBEROS_TGS_REP = 13100
-    KERBEROS_AS_REP = 18200
-
-    # Keepass
-    KEEPASS = 13400
-
-    # mysql
-    MYSQL_323 = 200
-    MYSQL_41 = 300
-    MySQL_CRAM = 11200
-
-    #
-    IPMI2 = 7300
-
-class Hash:
-
-    def __init__(self, hash):
-        self.hash = hash
-        self.salt = None
-        self.isSalted = False
-        self.type = []
-        self.cracked = None
-        self.findType()
-
-    def findType(self):
-
-        raw_hash = self.hash
-        if raw_hash[0] == "$":
-            crypt_parts = list(filter(None, raw_hash.split("$")))
-            crypt_type = crypt_parts[0]
-            self.isSalted = len(crypt_parts) > 2
-            if crypt_type == "1":
-                self.type.append(HashType.CRYPT_MD5)
-            elif crypt_type.startswith("2"):
-                self.type.append(HashType.CRYPT_BLOWFISH)
-            elif crypt_type == "5":
-                self.type.append(HashType.CRYPT_SHA256)
-            elif crypt_type == "6":
-                self.type.append(HashType.CRYPT_SHA512)
-            elif crypt_type == "apr1":
-                self.type.append(HashType.CRYPT_APACHE)
-            elif crypt_type == "krb5tgs":
-                self.type.append(HashType.KERBEROS_TGS_REP)
-            elif crypt_type == "krb5asreq":
-                self.type.append(HashType.KERBEROS_AS_REQ)
-            elif crypt_type == "krb5asrep":
-                self.type.append(HashType.KERBEROS_AS_REP)
-            elif crypt_type == "P":
-                self.type.append(HashType.WORDPRESS)
-            elif crypt_type == "S":
-                self.type.append(HashType.DRUPAL7)
-            elif crypt_type == "pbkdf2-sha256":
-                self.type.append(HashType.PYTHON_PBKDF2_SHA256)
-            elif crypt_type == "pbkdf2-sha512":
-                self.type.append(HashType.PYTHON_PBKDF2_SHA512)
-            elif crypt_type == "keepass":
-                self.type.append(HashType.KEEPASS)
-            elif crypt_type == "mysqlna":
-                self.type.append(HashType.MySQL_CRAM)
-        elif "$" in raw_hash and raw_hash.startswith("pbkdf2_sha256$"):
-            self.type.append(HashType.DJANGO_PBKDF2_SHA256)
+from name_that_hash import runner
+
+def load_cracked_hashes():
+    potfile_path = os.path.join(os.path.expanduser("~"), ".hashcat", "hashcat.potfile")
+    cracked_hashes = { }
+    if os.path.isfile(potfile_path):
+        with open(potfile_path, "r") as f:
+            for line in f:
+                hash, password = line.strip().rsplit(":",1)
+                cracked_hashes[hash] = password
+
+    return cracked_hashes
+
+if __name__ == "__main__":
+
+    if len(sys.argv) < 2:
+        print("Usage: %s <file>" % sys.argv[0])
+        exit(1)
+
+    hashes = filter(None, [line.strip() for line in open(sys.argv[1],"r").readlines()])
+    potfile = load_cracked_hashes()
+    if potfile:
+        uncracked_hashes = []
+        for hash in hashes:
+            password = potfile.get(hash, potfile.get(hash.rsplit(":", 1)[0], None))
+            if password:
+                print(f"Potfile: {hash}: {password}")
+            else:
+                uncracked_hashes.append(hash)
+    else:
+        uncracked_hashes = hashes
+        
+    hashes = json.loads(runner.api_return_hashes_as_json(uncracked_hashes))
+    wordlist = "/usr/share/wordlists/rockyou.txt" if len(sys.argv) < 3 else sys.argv[2]
+
+    hash_types = { }
+    for hash, types in hashes.items():
+        for t in types:
+            hash_id = t["hashcat"]
+            if hash_id is None:
+                continue
+
+            salted = ":" in hash
+            if salted != t["extended"]:
+                continue
+            
+            if hash_id not in hash_types:
+                hash_types[hash_id] = { "name": t["name"], "hashes": {hash} }
+            else:
+                hash_types[hash_id]["hashes"].add(hash)
+
+    if len(hash_types) > 0:
+        uncracked_types = list(hash_types.keys())
+        num_types = len(uncracked_types)
+        if num_types > 1:
+            print("There are multiple uncracked hashes left with different hash types, choose one to proceed with hashcat:")
+            print()
+
+            i = 0
+            for hash_id, hash_type in hash_types.items():
+                name = (hash_type["name"] + ": ").ljust(max(len(x["name"]) for x in hash_types.values()) + 2)
+                count = len(hash_type["hashes"])
+                index = (f"{i}. ").ljust(len(str(num_types - 1)) + 2)
+                print(f"{index}{name}{count} hashe(s)")
+                i += 1
+
+            # Ask user…
+            selected = None
+            while selected is None or selected < 0 or selected >= num_types:
+                try:
+                    selected = int(input("Your Choice: ").strip())
+                    if selected >= 0 and selected < num_types:
+                        break
+                except Exception as e:
+                    if type(e) in [EOFError, KeyboardInterrupt]:
+                        print()
+                        exit()
+
+                print("Invalid input")
+            selected_type = uncracked_types[selected]
         else:
-            m = re.match("^\{([^}]*)\}.*$", raw_hash)
-            if m:
-                hash_type = m[1]
-                if hash_type == "SHA":
-                    self.type.append(HashType.SHA1)
-                elif hash_type == "SSHA":
-                    self.type.append(HashType.SSHA1)
-                elif hash_type == "SSHA256":
-                    self.type.append(HashType.SSHA256)
-                elif hash_type == "SSHA512":
-                    self.type.append(HashType.SSHA512)
-
-            if ":" in raw_hash:
-                parts = raw_hash.split(":")
-                if len(parts) == 2:
-                    self.isSalted = True
-                    raw_hash, self.salt = raw_hash.split(":")
-                elif len(parts) == 6:
-                    self.type.append(HashType.NTLMV2_SSP)
-
-
-
-        # Base64 -> hex
-        try:
-            if not HEX_PATTERN.match(raw_hash):
-
-                if B64_URL_PATTERN.match(raw_hash):
-                    raw_hash = raw_hash.replace("-","+").replace("_","/")
-                if B64_PATTERN.match(raw_hash):
-                    raw_hash = base64.b64decode(raw_hash.encode("UTF-8")).decode("UTF-8").hex()
-
-                if self.isSalted:
-                    self.hash = raw_hash + ":" + self.salt
-                else:
-                    self.hash = raw_hash
-        except:
-            pass
-
-        if HEX_PATTERN.match(raw_hash):
-            hash_len = len(raw_hash)
-            if hash_len == 16:
-                self.type.append(HashType.MYSQL_323)
-            elif hash_len == 32:
-                if self.isSalted:
-                    self.type.append(HashType.MD5_PASS_SALT)
-                    self.type.append(HashType.MD5_SALT_PASS)
-                else:
-                    self.type.append(HashType.RAW_MD5)
-                    self.type.append(HashType.RAW_MD4)
-                    self.type.append(HashType.NTLM)
-                    self.type.append(HashType.LM)
-            elif hash_len == 40:
-                if self.isSalted:
-                    self.type.append(HashType.SHA1_PASS_SALT)
-                    self.type.append(HashType.SHA1_SALT_PASS)
-                else:
-                    self.type.append(HashType.RAW_SHA1)
-                    self.type.append(HashType.RAW_RIPEMD_160)
-                    self.type.append(HashType.MYSQL_41)
-                    self.type.append(HashType.SHA1_SHA1)
-            elif hash_len == 64:
-                if self.isSalted:
-                    self.type.append(HashType.SHA256_PASS_SALT)
-                    self.type.append(HashType.SHA256_SALT_PASS)
-                    self.type.append(HashType.HMAC_SHA256_PASS)
-                    self.type.append(HashType.HMAC_SHA256_SALT)
-                else:
-                    self.type.append(HashType.RAW_SHA2_256)
-                    self.type.append(HashType.RAW_SHA3_256)
-            elif hash_len == 96:
-                if not self.isSalted:
-                    self.type.append(HashType.RAW_SHA2_384)
-                    self.type.append(HashType.RAW_SHA3_384)
-                    self.type.append(HashType.RAW_KECCAK_384)
-            elif hash_len == 128:
-                if self.isSalted:
-                    self.type.append(HashType.SHA512_PASS_SALT)
-                    self.type.append(HashType.SHA512_SALT_PASS)
-                else:
-                    self.type.append(HashType.RAW_SHA2_512)
-                    self.type.append(HashType.RAW_SHA3_512)
-                    self.type.append(HashType.RAW_KECCAK_256)
-            elif hash_len == 140:
-                if not self.isSalted:
-                    seld.type.append(HashType.MSSQL)
-                    self.hash = "0x" + raw_hash # TODO: MSSQL requires 0x prefix..
-            elif hash_len == 142:
-                if self.isSalted:
-                    self.type.append(HashType.IPMI2)
-        elif raw_hash.startswith("0x") and HEX_PATTERN.match(raw_hash[2:]) and len(raw_hash) == 140+2:
-            seld.type.append(HashType.MSSQL)
+            selected_type = uncracked_types[0]
 
-        if len(self.type) == 0:
-            print("%s: Unknown hash" % self.hash)
+        fp = tempfile.NamedTemporaryFile()
+        for hash in hash_types[selected_type]["hashes"]:
+            fp.write(b"%s\n" % hash.encode("UTF-8"))
+        fp.flush()
 
-if len(sys.argv) < 2:
-    print("Usage: %s <file>" % sys.argv[0])
-    exit(1)
-
-hashes = [Hash(x) for x in filter(None, [line.strip() for line in open(sys.argv[1],"r").readlines()])]
-wordlist = "/usr/share/wordlists/rockyou.txt" if len(sys.argv) < 3 else sys.argv[2]
-
-uncracked_hashes = { }
-for hash in hashes:
-    if hash.type:
-        for t in hash.type:
-            if t not in uncracked_hashes:
-                uncracked_hashes[t] = []
-            uncracked_hashes[t].append(hash)
-
-if len(uncracked_hashes) > 0:
-    uncracked_types = list(uncracked_hashes.keys())
-    num_types = len(uncracked_types)
-    if num_types > 1:
-        print("There are multiple uncracked hashes left with different hash types, choose one to proceed with hashcat:")
-        print()
-
-        i = 0
-        for t,lst in uncracked_hashes.items():
-            print("%d.\t%s:\t%d hashe(s)" % (i, str(t)[len("HashType."):], len(lst)))
-            i += 1
-
-        # Ask user…
-        selected = None
-        while selected is None or selected < 0 or selected >= num_types:
-            try:
-                selected = int(input("Your Choice: ").strip())
-                if selected >= 0 and selected < num_types:
-                    break
-            except Exception as e:
-                if type(e) in [EOFError, KeyboardInterrupt]:
-                    print()
-                    exit()
-
-            print("Invalid input")
-        selected_type = uncracked_types[selected]
+        proc = subprocess.Popen(["hashcat", "-m", str(selected_type), "-a", "0", fp.name, wordlist])
+        proc.wait()
+        fp.close()
     else:
-        selected_type = uncracked_types[0]
-
-    fp = tempfile.NamedTemporaryFile()
-    for hash in uncracked_hashes[selected_type]:
-        fp.write(b"%s\n" % hash.hash.encode("UTF-8"))
-    fp.flush()
-
-    proc = subprocess.Popen(["hashcat", "-m", str(selected_type.value), "-a", "0", fp.name, wordlist])
-    proc.wait()
-    fp.close()
+        print("No uncracked hashes left")

+ 12 - 4
requirements.txt

@@ -1,6 +1,14 @@
+beautifulsoup4==4.10.0
+dnslib==0.9.16
+dulwich==0.20.26
+exif==1.3.4
+impacket==0.9.23
+name_that_hash==1.10.0
 netifaces==0.10.9
-colorama==0.4.3
-requests==2.23.0
-toml==0.10.0
 paramiko==2.7.1
-beautifulsoup4==4.9.1
+Pillow==9.0.0
+pwn==1.0
+pwntools==4.7.0
+requests==2.23.0
+SocksiPy_branch==1.01
+urllib3==1.25.11

BIN
win/Certify.exe


BIN
win/Rubeus.exe