Skip to content

Instantly share code, notes, and snippets.

@linuxluser
Last active June 11, 2016 04:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save linuxluser/166cc1a51048a6cc1510bd769e10a94c to your computer and use it in GitHub Desktop.
Save linuxluser/166cc1a51048a6cc1510bd769e10a94c to your computer and use it in GitHub Desktop.
#!/usr/bin/python2.7
"""Libarary to extract the data from a Kerberos keytab and return a Python dict.
Inspiration taken from https://gist.github.com/liftoff/a7b059198c8dc55ceb81. I
just think my version is simpler and easier to understand. ;)
I also had a little help on the actual structs here: https://goo.gl/fy3DHG
"""
__author__ = 'github.com/linuxluser'
import binascii
import pprint
import struct
import sys
import StringIO
NAME_TYPES = {1: 'KRB5_NT_PRINCIPAL',
2: 'KRB5_NT_SRV_INST',
5: 'KRB5_NT_UID'}
VERSIONS = {0x501: 1,
0x502: 2}
ENCRYPTION_TYPES = {
1: 'des-cbc-crc',
2: 'des-cbc-md4',
3: 'des-cbc-md5',
5: 'des3-cbc-md5',
7: 'des3-cbc-sha1',
9: 'dsaWithSHA1-CmsOID',
10: 'md5WithRSAEncryption-CmsOID',
11: 'sha1WithRSAEncryption-CmsOID',
12: 'rc2CBC-EnvOID',
13: 'rsaEncryption-EnvOID',
14: 'rsaES-OAEP-ENV-OID',
15: 'des-ede3-cbc-Env-OID',
16: 'des3-cbc-sha1',
17: 'aes128-cts-hmac-sha1-96',
18: 'aes256-cts-hmac-sha1-96',
23: 'arcfour-hmac', # aka rc4-hmac
24: 'arcfour-hmac-exp', # aka rc4-hmac-exp
25: 'camellia128-cts-cmac',
26: 'camellia256-cts-cmac'
}
def ReadKeytab(keytab_path):
"""Read a binary keytab file structure and product a Python dict.
"""
version = -1
entries = {}
with open(keytab_path, "rb") as kt_file:
keytab_version = struct.unpack('!h', kt_file.read(2))[0]
version = VERSIONS[keytab_version]
slot = 1
while True:
key_entry_len = kt_file.read(4)
if not key_entry_len:
break
entry = {}
# Load entry bytes into chunk for processing
size = struct.unpack('!i', key_entry_len)[0]
chunk = StringIO.StringIO(kt_file.read(size))
# Get the principal name
num_components = struct.unpack('!h', chunk.read(2))[0]
size = struct.unpack('!h', chunk.read(2))[0]
realm = chunk.read(size) # realm is always first component
components = []
for i in range(num_components):
size = struct.unpack('!h', chunk.read(2))[0]
components.append(chunk.read(size))
principal = '%s@%s' % ('/'.join(components), realm)
# Get other bits of information about entry
name_type = struct.unpack('!i', chunk.read(4))[0]
timestamp = struct.unpack('!i', chunk.read(4))[0]
kvno = struct.unpack('B', chunk.read(1))[0]
enc_type = struct.unpack('!h', chunk.read(2))[0]
# Get the actual key
size = struct.unpack('!h', chunk.read(2))[0]
key = binascii.b2a_hex(chunk.read(size))
entries[slot] = {'Principal': principal,
'Timestamp': timestamp,
'EncType': ENCRYPTION_TYPES[enc_type],
'NameType': name_type,
'KVNO': kvno}
slot += 1
return {'Version': version, 'Entries': entries}
if __name__ == '__main__':
pprint.pprint(ReadKeytab(sys.argv[1]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment