├── .gitattributes ├── README.md └── keytabextract.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KeyTabExtract 2 | 3 | ## Description 4 | KeyTabExtract is a little utility to help extract valuable information from 502 type .keytab files, which may be used to authenticate Linux boxes to Kerberos. The script will extract information such as the realm, Service Principal, Encryption Type and NTLM Hash. 5 | 6 | ## Usage 7 | 8 | `./keytabextract.py [file.keytab]` 9 | 10 | ## To Do 11 | - Associate keytype values with their encryption type 12 | - Associate Principal Type values with their names 13 | - Add support for 0501 kerberos type files -------------------------------------------------------------------------------- /keytabextract.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import binascii,sys 3 | 4 | # Take argument 1 as keytab file, import and decode the hex 5 | ktfile = sys.argv[1] 6 | f = open(ktfile, 'rb').read() 7 | hex_encoded = binascii.hexlify(f).decode('utf-8') 8 | 9 | def displayhelp(): 10 | print("KeyTabExtract. Extract NTLM Hashes from KeyTab files where RC4-HMAC encryption has been used.") 11 | print("Usage : ./keytabextract.py [keytabfile]") 12 | print("Example : ./keytabextract.py service.keytab") 13 | 14 | def ktextract(): 15 | rc4hmac = False 16 | aes128 = False 17 | aes256 = False 18 | 19 | if '00170010' in hex_encoded: 20 | print("[*] RC4-HMAC Encryption detected. Will attempt to extract NTLM hash.") 21 | rc4hmac = True 22 | else: 23 | print("[!] No RC4-HMAC located. Unable to extract NTLM hashes.") 24 | 25 | if '00120020' in hex_encoded: 26 | print("[*] AES256-CTS-HMAC-SHA1 key found. Will attempt hash extraction.") 27 | aes256 = True 28 | else: 29 | print("[!] Unable to identify any AES256-CTS-HMAC-SHA1 hashes.") 30 | 31 | if '00110010' in hex_encoded: 32 | print("[*] AES128-CTS-HMAC-SHA1 hash discovered. Will attempt hash extraction.") 33 | aes128 = True 34 | else: 35 | print("[!] Unable to identify any AES128-CTS-HMAC-SHA1 hashes.") 36 | 37 | #if proceed != True: 38 | if all( [ rc4hmac != True, aes256 != True, aes128 != True]): 39 | print("Unable to find any useful hashes.\nExiting...") 40 | sys.exit 41 | 42 | # First 16 bits are dedicated to stating the version of Keytab File 43 | ktversion = hex_encoded[:4] 44 | if ktversion == '0502': 45 | print("[+] Keytab File successfully imported.") 46 | else: 47 | print("[!] Only Keytab versions 0502 are supported.\nExiting...") 48 | 49 | # 32 bits indicating the size of the array 50 | arrLen = int(hex_encoded[4:12], 16) 51 | 52 | # Number of counted octet strings representing the realm of the principal 53 | num_components = hex_encoded[12:16] 54 | 55 | # convert the 56 | num_realm = int(hex_encoded[16:20], 16) 57 | 58 | # calculate the offset for the realm 59 | realm_jump = 20 + (num_realm * 2) 60 | 61 | # Determine the realm for the keytab file 62 | realm = hex_encoded[20:realm_jump] 63 | print("\tREALM : " + bytes.fromhex(realm).decode('utf-8')) 64 | 65 | # Calculate the number of bytes for the realm of components 66 | comp_array_calc = realm_jump + 4 67 | comp_array = int(hex_encoded[realm_jump:comp_array_calc], 16) 68 | 69 | # Calculates the realm component (HTTP) 70 | comp_array_offset = comp_array_calc + (comp_array * 2) 71 | comp_array2 = hex_encoded[comp_array_calc:comp_array_offset] 72 | 73 | # calculate number of bytes for the principal 74 | principal_array_offset = comp_array_offset + 4 75 | 76 | # extract the principal 77 | principal_array = hex_encoded[comp_array_offset:principal_array_offset] 78 | principal_array_int = (int(principal_array, 16) * 2) 79 | prin_array_start = principal_array_offset 80 | prin_array_finish = prin_array_start + principal_array_int 81 | principal_array_value = hex_encoded[prin_array_start:prin_array_finish] 82 | print("\tSERVICE PRINCIPAL : " + bytes.fromhex(comp_array2).decode('utf-8') + "/" + bytes.fromhex(principal_array_value).decode('utf-8')) 83 | 84 | # Calculate typename - 32 bits from previous value 85 | typename_offset = prin_array_finish + 8 86 | typename = hex_encoded[prin_array_finish:typename_offset] 87 | 88 | # Calculate Timestamp - 32 bit from typename value 89 | timestamp_offset = typename_offset + 8 90 | timestamp = hex_encoded[typename_offset:timestamp_offset] 91 | 92 | # Calcualte 8 bit VNO Field 93 | vno_offset = timestamp_offset + 2 94 | vno = hex_encoded[timestamp_offset:vno_offset] 95 | #print("\tVersion No : " + vno) 96 | 97 | # Calculate KeyType - 16 bit value 98 | keytype_offset = vno_offset + 4 99 | keytype_hex = hex_encoded[vno_offset:keytype_offset] 100 | keytype_dec = int(keytype_hex, 16) 101 | 102 | # Calculate Length of Key Value - 16 bit value 103 | key_val_offset = keytype_offset + 4 104 | key_val_len = int(hex_encoded[keytype_offset:key_val_offset], 16) 105 | 106 | # Extract Key Value 107 | key_val_start = key_val_offset 108 | key_val_finish = key_val_start + (key_val_len * 2) 109 | key_val = hex_encoded[key_val_start:key_val_finish] 110 | if rc4hmac == True: 111 | NTLMHash = hex_encoded.split("00170010")[1] 112 | print("\tNTLM HASH : " + NTLMHash[:32]) 113 | 114 | if aes256 == True: 115 | aes256hash = hex_encoded.split("00120020")[1] 116 | print("\tAES-256 HASH : " + aes256hash[:64]) 117 | 118 | if aes128 == True: 119 | aes128hash = hex_encoded.split("00110010")[1] 120 | print("\tAES-128 HASH : " + aes128hash[:32]) 121 | 122 | if __name__ == "__main__": 123 | if len(sys.argv) == 1: 124 | displayhelp() 125 | sys.exit() 126 | else: 127 | ktextract() 128 | --------------------------------------------------------------------------------