Added py3 and py2 compatibility + many bugfix

This commit is contained in:
lgandx
2020-01-09 14:47:56 -03:00
parent c52843a535
commit b510b2bb25
49 changed files with 2771 additions and 2058 deletions

View File

@@ -21,14 +21,14 @@
from framework.win32.rawreg import *
from framework.addrspace import HiveFileAddressSpace
#from framework.win32.hashdump import get_bootkey
from framework.win32.hashdump import get_bootkey
from framework.win32.lsasecrets import get_secret_by_name,get_lsa_key
from Crypto.Hash import HMAC
from Crypto.Cipher import ARC4
from Crypto.Cipher import ARC4, AES
from struct import unpack
def get_nlkm(secaddr, lsakey):
return get_secret_by_name(secaddr, 'NL$KM', lsakey)
def get_nlkm(secaddr, lsakey, vista):
return get_secret_by_name(secaddr, 'NL$KM', lsakey, vista)
def decrypt_hash(edata, nlkm, ch):
hmac_md5 = HMAC.new(nlkm,ch)
@@ -38,6 +38,21 @@ def decrypt_hash(edata, nlkm, ch):
data = rc4.encrypt(edata)
return data
def decrypt_hash_vista(edata, nlkm, ch):
"""
Based on code from http://lab.mediaservice.net/code/cachedump.rb
"""
aes = AES.new(nlkm[16:32], AES.MODE_CBC, ch)
out = bytearray()
for i in range(0, len(edata), 16):
buf = edata[i : i+16]
if len(buf) < 16:
buf += (16 - len(buf)) * b"\00"
out += aes.decrypt(buf)
return out
def parse_cache_entry(cache_data):
(uname_len, domain_len) = unpack("<HH", cache_data[:4])
(domain_name_len,) = unpack("<H", cache_data[60:62])
@@ -48,9 +63,9 @@ def parse_cache_entry(cache_data):
def parse_decrypted_cache(dec_data, uname_len,
domain_len, domain_name_len):
uname_off = 72
pad = 2 * ( ( uname_len / 2 ) % 2 )
pad = 2 * ( ( uname_len // 2 ) % 2 )
domain_off = uname_off + uname_len + pad
pad = 2 * ( ( domain_len / 2 ) % 2 )
pad = 2 * ( ( domain_len // 2 ) % 2 )
domain_name_off = domain_off + domain_len + pad
hash = dec_data[:0x10]
@@ -63,16 +78,16 @@ def parse_decrypted_cache(dec_data, uname_len,
return (username, domain, domain_name, hash)
def dump_hashes(Key, secaddr):
bootkey = Key
def dump_hashes(sysaddr, secaddr, vista):
bootkey = get_bootkey(sysaddr)
if not bootkey:
return []
lsakey = get_lsa_key(secaddr, bootkey)
lsakey = get_lsa_key(secaddr, bootkey, vista)
if not lsakey:
return []
nlkm = get_nlkm(secaddr, lsakey)
nlkm = get_nlkm(secaddr, lsakey, vista)
if not nlkm:
return []
@@ -86,7 +101,7 @@ def dump_hashes(Key, secaddr):
hashes = []
for v in values(cache):
if v.Name == "NL$Control": continue
if v.Name == b"NL$Control": continue
data = v.space.read(v.Data.value, v.DataLength.value)
@@ -97,7 +112,11 @@ def dump_hashes(Key, secaddr):
if uname_len == 0:
continue
dec_data = decrypt_hash(enc_data, nlkm, ch)
if vista:
dec_data = decrypt_hash_vista(enc_data, nlkm, ch)
else:
dec_data = decrypt_hash(enc_data, nlkm, ch)
(username, domain, domain_name,
hash) = parse_decrypted_cache(dec_data, uname_len,
@@ -107,11 +126,10 @@ def dump_hashes(Key, secaddr):
return hashes
def dump_file_hashes(Key, sechive_fname):
sysaddr = Key
def dump_file_hashes(syshive_fname, sechive_fname, vista):
sysaddr = HiveFileAddressSpace(syshive_fname)
secaddr = HiveFileAddressSpace(sechive_fname)
for (u, d, dn, hash) in dump_hashes(sysaddr, secaddr):
print "%s:%s:%s:%s" % (u.lower(), hash.encode('hex'),
d.lower(), dn.lower())
for (u, d, dn, hash) in dump_hashes(sysaddr, secaddr, vista):
print("%s:%s:%s:%s" % (u.lower(), hash.hex(),
d.lower(), dn.lower()))

View File

@@ -13,82 +13,89 @@
# You should have received a copy of the GNU General Public License
# along with creddump. If not, see <http://www.gnu.org/licenses/>.
# pylint: disable=invalid-name,missing-docstring
"""
@author: Brendan Dolan-Gavitt
@license: GNU General Public License 2.0 or later
@contact: bdolangavitt@wesleyan.edu
"""
from framework.win32.rawreg import *
from struct import unpack, pack
import binascii
from Crypto.Hash import MD5
from Crypto.Cipher import ARC4, DES, AES
from framework.win32.rawreg import get_root, open_key, values, subkeys
from framework.addrspace import HiveFileAddressSpace
try:
from Crypto.Hash import MD5
from Crypto.Cipher import ARC4,DES
except ImportError:
pass
from struct import unpack,pack
odd_parity = [
1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254
1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
97, 97, 98, 98, 100, 100, 103, 103, 104, 104, 107, 107, 109, 109, 110, 110,
112, 112, 115, 115, 117, 117, 118, 118, 121, 121, 122, 122, 124, 124, 127, 127,
128, 128, 131, 131, 133, 133, 134, 134, 137, 137, 138, 138, 140, 140, 143, 143,
145, 145, 146, 146, 148, 148, 151, 151, 152, 152, 155, 155, 157, 157, 158, 158,
161, 161, 162, 162, 164, 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174,
176, 176, 179, 179, 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191, 191,
193, 193, 194, 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206, 206,
208, 208, 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223, 223,
224, 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239, 239,
241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254, 254
]
# Permutation matrix for boot key
p = [ 0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3,
0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7 ]
p = [0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3,
0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7]
# Constants for SAM decrypt algorithm
aqwerty = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0"
anum = "0123456789012345678901234567890123456789\0"
antpassword = "NTPASSWORD\0"
almpassword = "LMPASSWORD\0"
aqwerty = b"!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0"
anum = b"0123456789012345678901234567890123456789\0"
antpassword = b"NTPASSWORD\0"
almpassword = b"LMPASSWORD\0"
empty_lm = binascii.unhexlify("aad3b435b51404eeaad3b435b51404ee")
empty_nt = binascii.unhexlify("31d6cfe0d16ae931b73c59d7e0c089c0")
empty_lm = "aad3b435b51404eeaad3b435b51404ee".decode('hex')
empty_nt = "31d6cfe0d16ae931b73c59d7e0c089c0".decode('hex')
def str_to_key(s):
key = []
key.append( ord(s[0])>>1 )
key.append( ((ord(s[0])&0x01)<<6) | (ord(s[1])>>2) )
key.append( ((ord(s[1])&0x03)<<5) | (ord(s[2])>>3) )
key.append( ((ord(s[2])&0x07)<<4) | (ord(s[3])>>4) )
key.append( ((ord(s[3])&0x0F)<<3) | (ord(s[4])>>5) )
key.append( ((ord(s[4])&0x1F)<<2) | (ord(s[5])>>6) )
key.append( ((ord(s[5])&0x3F)<<1) | (ord(s[6])>>7) )
key.append( ord(s[6])&0x7F )
key = bytearray()
key.append(s[0] >> 1)
key.append(((s[0] & 0x01) << 6) | ((s[1]) >> 2))
key.append(((s[1] & 0x03) << 5) | ((s[2]) >> 3))
key.append(((s[2] & 0x07) << 4) | ((s[3]) >> 4))
key.append(((s[3] & 0x0F) << 3) | ((s[4]) >> 5))
key.append(((s[4] & 0x1F) << 2) | ((s[5]) >> 6))
key.append(((s[5] & 0x3F) << 1) | ((s[6]) >> 7))
key.append(s[6] & 0x7F)
for i in range(8):
key[i] = (key[i]<<1)
key[i] = (key[i] << 1)
key[i] = odd_parity[key[i]]
return "".join(chr(k) for k in key)
return key
def sid_to_key(sid):
s1 = ""
s1 += chr(sid & 0xFF)
s1 += chr((sid>>8) & 0xFF)
s1 += chr((sid>>16) & 0xFF)
s1 += chr((sid>>24) & 0xFF)
s1 += s1[0];
s1 += s1[1];
s1 += s1[2];
s2 = s1[3] + s1[0] + s1[1] + s1[2]
s2 += s2[0] + s2[1] + s2[2]
s1 = bytearray()
s1.append(sid & 0xFF)
s1.append((sid >> 8) & 0xFF)
s1.append((sid >> 16) & 0xFF)
s1.append((sid >> 24) & 0xFF)
s1.append(s1[0])
s1.append(s1[1])
s1.append(s1[2])
s2 = bytearray([s1[3], s1[0], s1[1], s1[2]])
s2.append(s2[0])
s2.append(s2[1])
s2.append(s2[2])
return str_to_key(s1), str_to_key(s2)
return str_to_key(s1),str_to_key(s2)
def find_control_set(sysaddr):
root = get_root(sysaddr)
if not root:
@@ -99,122 +106,206 @@ def find_control_set(sysaddr):
return 1
for v in values(csselect):
if v.Name == "Current": return v.Data.value
if v.Name == b"Current":
return v.Data.value
return 1
def get_bootkey(sysaddr):
cs = find_control_set(sysaddr)
lsa_base = ["ControlSet%03d" % cs, "Control", "Lsa"]
lsa_keys = ["JD", "Skew1", "GBG", "Data"]
root = get_root(sysaddr)
if not root:
return None
lsa = open_key(root, lsa_base)
if not lsa:
return None
bootkey = []
for lk in lsa_keys:
key = open_key(lsa, [lk])
class_data = sysaddr.read(key.Class.value, key.ClassLength.value)
hex_string = class_data.decode('utf-16-le')
hex_data = binascii.unhexlify(hex_string)
for h in hex_data:
bootkey.append(h)
bootkey_scrambled = []
for i in range(len(bootkey)):
bootkey_scrambled.append(bootkey[p[i]])
return bytes(bootkey_scrambled)
def get_hbootkey(samaddr, bootkey):
sam_account_path = ["SAM", "Domains", "Account"]
root = get_root(samaddr)
if not root: return None
if not root:
return None
sam_account_key = open_key(root, sam_account_path)
if not sam_account_key: return None
if not sam_account_key:
return None
F = None
for v in values(sam_account_key):
if v.Name == 'F':
if v.Name == b'F':
F = samaddr.read(v.Data.value, v.DataLength.value)
if not F: return None
if not F:
return None
md5 = MD5.new()
md5.update(F[0x70:0x80] + aqwerty + bootkey + anum)
rc4_key = md5.digest()
revision = F[0x00]
if revision == 2:
md5 = MD5.new()
md5.update(F[0x70:0x80] + aqwerty + bootkey + anum)
rc4_key = md5.digest()
rc4 = ARC4.new(rc4_key)
hbootkey = rc4.encrypt(F[0x80:0xA0])
return hbootkey
rc4 = ARC4.new(rc4_key)
hbootkey = rc4.encrypt(F[0x80:0xA0])
return hbootkey
if revision == 3:
iv = F[0x78:0x88]
encryptedHBootKey = F[0x88:0xA8]
cipher = AES.new(bootkey, AES.MODE_CBC, iv)
hbootkey = cipher.decrypt(encryptedHBootKey)
return hbootkey[:16]
print("Unknown revision: %d" % revision)
return None
def get_user_keys(samaddr):
user_key_path = ["SAM", "Domains", "Account", "Users"]
root = get_root(samaddr)
if not root: return []
if not root:
return []
user_key = open_key(root, user_key_path)
if not user_key: return []
if not user_key:
return []
return [k for k in subkeys(user_key) if k.Name != b"Names"]
return [k for k in subkeys(user_key) if k.Name != "Names"]
def decrypt_single_hash(rid, hbootkey, enc_hash, lmntstr):
(des_k1,des_k2) = sid_to_key(rid)
if enc_hash == "":
return ""
(des_k1, des_k2) = sid_to_key(rid)
d1 = DES.new(des_k1, DES.MODE_ECB)
d2 = DES.new(des_k2, DES.MODE_ECB)
md5 = MD5.new()
md5.update(hbootkey[:0x10] + pack("<L",rid) + lmntstr)
md5.update(hbootkey[:0x10] + pack("<L", rid) + lmntstr)
rc4_key = md5.digest()
rc4 = ARC4.new(rc4_key)
obfkey = rc4.encrypt(enc_hash)
hash = d1.decrypt(obfkey[:8]) + d2.decrypt(obfkey[8:])
return d1.decrypt(obfkey[:8]) + d2.decrypt(obfkey[8:])
return hash
def decrypt_hashes(rid, enc_lm_hash, enc_nt_hash, hbootkey):
# LM Hash
if enc_lm_hash:
lmhash = decrypt_single_hash(rid, hbootkey, enc_lm_hash, almpassword)
else:
lmhash = ""
# NT Hash
if enc_nt_hash:
nthash = decrypt_single_hash(rid, hbootkey, enc_nt_hash, antpassword)
else:
nthash = ""
def decrypt_single_salted_hash(rid, hbootkey, enc_hash, salt):
if enc_hash == "":
return ""
(des_k1, des_k2) = sid_to_key(rid)
d1 = DES.new(des_k1, DES.MODE_ECB)
d2 = DES.new(des_k2, DES.MODE_ECB)
cipher = AES.new(hbootkey[:16], AES.MODE_CBC, salt)
obfkey = cipher.decrypt(enc_hash)
return d1.decrypt(obfkey[:8]) + d2.decrypt(obfkey[8:16])
return lmhash,nthash
def get_user_hashes(user_key, hbootkey):
# pylint: disable=too-many-locals
samaddr = user_key.space
rid = int(user_key.Name, 16)
try:
rid = int(user_key.Name.decode(), 16)
except ValueError:
print("Could not decode rid from key name %s" % (user_key.Name.decode()))
return None, None
V = None
for v in values(user_key):
if v.Name == 'V':
if v.Name == b'V':
V = samaddr.read(v.Data.value, v.DataLength.value)
if not V: return None
if not V:
return None, None
hash_offset = unpack("<L", V[0xa8:0xa8 + 4])[0] + 0xCC
hash_offset = unpack("<L", V[0x9c:0x9c+4])[0] + 0xCC
lm_offset_bytes = V[0x9c:0x9c + 4]
nt_offset_bytes = V[0x9c + 12:0x9c + 16]
lm_offset = unpack("<L", lm_offset_bytes)[0] + 204
nt_offset = unpack("<L", nt_offset_bytes)[0] + 204
lm_exists = True if unpack("<L", V[0x9c+4:0x9c+8])[0] == 20 else False
nt_exists = True if unpack("<L", V[0x9c+16:0x9c+20])[0] == 20 else False
lmhash = None
nthash = None
enc_lm_hash = V[hash_offset+4:hash_offset+20] if lm_exists else ""
enc_nt_hash = V[hash_offset+(24 if lm_exists else 8):hash_offset+(24 if lm_exists else 8)+16] if nt_exists else ""
lm_revision_bytes = V[lm_offset + 2:lm_offset + 3]
lm_revision = unpack('<B', lm_revision_bytes)[0]
if lm_revision == 1:
lm_exists = unpack("<L", V[0x9c + 4:0x9c + 8])[0] == 20
enc_lm_hash = V[hash_offset + 4:hash_offset + 20] if lm_exists else ""
lmhash = decrypt_single_hash(rid, hbootkey, enc_lm_hash, almpassword)
elif lm_revision == 2:
lm_exists = unpack("<L", V[0x9c + 4:0x9c + 8])[0] == 56
lm_salt = V[hash_offset + 4:hash_offset + 20] if lm_exists else ""
enc_lm_hash = V[hash_offset + 20:hash_offset + 52] if lm_exists else ""
lmhash = decrypt_single_salted_hash(rid, hbootkey, enc_lm_hash, lm_salt)
nt_revision_bytes = V[nt_offset + 2:nt_offset + 3]
nt_revision = unpack('<B', nt_revision_bytes)[0]
if nt_revision == 1:
nt_exists = unpack("<L", V[0x9c + 16:0x9c + 20])[0] == 20
enc_nt_hash = V[nt_offset + 4:nt_offset + 20] if nt_exists else ""
nthash = decrypt_single_hash(rid, hbootkey, enc_nt_hash, antpassword)
elif nt_revision == 2:
nt_exists = unpack("<L", V[0x9c + 16:0x9c + 20])[0] == 56
nt_salt = V[nt_offset + 8:nt_offset + 24] if nt_exists else ""
enc_nt_hash = V[nt_offset + 24:nt_offset + 56] if nt_exists else ""
nthash = decrypt_single_salted_hash(rid, hbootkey, enc_nt_hash, nt_salt)
return lmhash, nthash
return decrypt_hashes(rid, enc_lm_hash, enc_nt_hash, hbootkey)
def get_user_name(user_key):
samaddr = user_key.space
V = None
for v in values(user_key):
if v.Name == 'V':
if v.Name == b'V':
V = samaddr.read(v.Data.value, v.DataLength.value)
if not V: return None
if not V:
return None
name_offset = unpack("<L", V[0x0c:0x10])[0] + 0xCC
name_length = unpack("<L", V[0x10:0x14])[0]
username = V[name_offset:name_offset+name_length].decode('utf-16-le')
username = V[name_offset:name_offset + name_length].decode('utf-16-le')
return username
def dump_hashes(Key, samaddr):
bootkey = Key
hbootkey = get_hbootkey(samaddr,bootkey)
Output = ""
for user in get_user_keys(samaddr):
lmhash,nthash = get_user_hashes(user,hbootkey)
if not lmhash: lmhash = empty_lm
if not nthash: nthash = empty_nt
hashes = "%s:%d:%s:%s:::" % (get_user_name(user), int(user.Name,16),
lmhash.encode('hex'), nthash.encode('hex'))
hashesdump = "%s:%d:%s:%s:::\n" % (get_user_name(user), int(user.Name,16),
lmhash.encode('hex'), nthash.encode('hex'))
print hashes
Output += hashesdump
return Output
def dump_file_hashes(Key, samhive_fname):
def dump_hashes(sysaddr, samaddr):
bootkey = get_bootkey(sysaddr)
hbootkey = get_hbootkey(samaddr, bootkey)
for user in get_user_keys(samaddr):
lmhash, nthash = get_user_hashes(user, hbootkey)
if not lmhash:
lmhash = empty_lm
if not nthash:
nthash = empty_nt
try:
print("%s:%d:%s:%s:::" % (get_user_name(user), int(user.Name, 16),
lmhash.hex(), nthash.hex()))
except ValueError:
pass # skip if user.Name cannot be converted to an int, since its a "false" rid like the "Names" key
def dump_file_hashes(syshive_fname, samhive_fname):
sysaddr = HiveFileAddressSpace(syshive_fname)
samaddr = HiveFileAddressSpace(samhive_fname)
Output = dump_hashes(Key, samaddr)
return Output
dump_hashes(sysaddr, samaddr)

View File

@@ -13,26 +13,33 @@
# You should have received a copy of the GNU General Public License
# along with creddump. If not, see <http://www.gnu.org/licenses/>.
# pylint: disable=missing-docstring
"""
@author: Brendan Dolan-Gavitt
@license: GNU General Public License 2.0 or later
@contact: bdolangavitt@wesleyan.edu
"""
from framework.win32.rawreg import *
from framework.addrspace import HiveFileAddressSpace
#from framework.win32.hashdump import get_bootkey,str_to_key
from Crypto.Hash import MD5
from Crypto.Cipher import ARC4,DES
from Crypto.Hash import MD5, SHA256
from Crypto.Cipher import ARC4, DES, AES
def get_lsa_key(secaddr, bootkey):
from framework.win32.rawreg import get_root, open_key, subkeys, unpack
from framework.addrspace import HiveFileAddressSpace
from framework.win32.hashdump import get_bootkey, str_to_key
def get_lsa_key(secaddr, bootkey, vista):
root = get_root(secaddr)
if not root:
return None
enc_reg_key = open_key(root, ["Policy", "PolSecretEncryptionKey"])
if vista:
enc_reg_key = open_key(root, ["Policy", "PolEKList"])
else:
enc_reg_key = open_key(root, ["Policy", "PolSecretEncryptionKey"])
if not enc_reg_key:
exit(1)
return None
enc_reg_value = enc_reg_key.ValueList.List[0]
@@ -40,48 +47,73 @@ def get_lsa_key(secaddr, bootkey):
return None
obf_lsa_key = secaddr.read(enc_reg_value.Data.value,
enc_reg_value.DataLength.value)
enc_reg_value.DataLength.value)
if not obf_lsa_key:
return None
md5 = MD5.new()
md5.update(bootkey)
for i in range(1000):
md5.update(obf_lsa_key[60:76])
rc4key = md5.digest()
if not vista:
md5 = MD5.new()
md5.update(bootkey)
for __ in range(1000):
md5.update(obf_lsa_key[60:76])
rc4key = md5.digest()
rc4 = ARC4.new(rc4key)
lsa_key = rc4.decrypt(obf_lsa_key[12:60])
lsa_key = lsa_key[0x10:0x20]
else:
lsa_key = decrypt_aes(obf_lsa_key, bootkey)
lsa_key = lsa_key[68:100]
rc4 = ARC4.new(rc4key)
lsa_key = rc4.decrypt(obf_lsa_key[12:60])
return lsa_key
return lsa_key[0x10:0x20]
def decrypt_secret(secret, key):
"""Python implementation of SystemFunction005.
Decrypts a block of data with DES using given key.
Note that key can be longer than 7 bytes."""
decrypted_data = ''
j = 0 # key index
for i in range(0,len(secret),8):
enc_block = secret[i:i+8]
block_key = key[j:j+7]
decrypted_data = bytearray()
j = 0 # key index
for i in range(0, len(secret), 8):
enc_block = secret[i:i + 8]
block_key = key[j:j + 7]
des_key = str_to_key(block_key)
des = DES.new(des_key, DES.MODE_ECB)
decrypted_data += des.decrypt(enc_block)
j += 7
if len(key[j:j+7]) < 7:
j = len(key[j:j+7])
if len(key[j:j + 7]) < 7:
j = len(key[j:j + 7])
(dec_data_len,) = unpack("<L", decrypted_data[:4])
return decrypted_data[8:8+dec_data_len]
return decrypted_data[8:8 + dec_data_len]
def get_secret_by_name(secaddr, name, lsakey):
def decrypt_aes(secret, key):
sha = SHA256.new()
sha.update(key)
for _i in range(1, 1000 + 1):
sha.update(secret[28:60])
aeskey = sha.digest()
data = bytearray()
for i in range(60, len(secret), 16):
aes = AES.new(aeskey, AES.MODE_CBC, b"\x00" * 16)
buf = secret[i: i + 16]
if len(buf) < 16:
buf += (16 - len(buf)) * b"\00"
data += aes.decrypt(buf)
return data
def get_secret_by_name(secaddr, name, lsakey, vista):
root = get_root(secaddr)
if not root:
return None
enc_secret_key = open_key(root, ["Policy", "Secrets", name, "CurrVal"])
if not enc_secret_key:
return None
@@ -91,47 +123,57 @@ def get_secret_by_name(secaddr, name, lsakey):
return None
enc_secret = secaddr.read(enc_secret_value.Data.value,
enc_secret_value.DataLength.value)
enc_secret_value.DataLength.value)
if not enc_secret:
return None
return decrypt_secret(enc_secret[0xC:], lsakey)
if vista:
secret = decrypt_aes(enc_secret, lsakey)
else:
secret = decrypt_secret(enc_secret[0xC:], lsakey)
def get_secrets(Key, secaddr):
return secret
def get_secrets(sysaddr, secaddr, vista):
root = get_root(secaddr)
if not root:
return None
bootkey = Key
lsakey = get_lsa_key(secaddr, bootkey)
bootkey = get_bootkey(sysaddr)
lsakey = get_lsa_key(secaddr, bootkey, vista)
secrets_key = open_key(root, ["Policy", "Secrets"])
if not secrets_key:
print "no secret"
return None
secrets = {}
for key in subkeys(secrets_key):
sec_val_key = open_key(key, ["CurrVal"])
if not sec_val_key:
continue
enc_secret_value = sec_val_key.ValueList.List[0]
if not enc_secret_value:
continue
enc_secret = secaddr.read(enc_secret_value.Data.value,
enc_secret_value.DataLength.value)
enc_secret_value.DataLength.value)
if not enc_secret:
continue
secret = decrypt_secret(enc_secret[0xC:], lsakey)
if vista:
secret = decrypt_aes(enc_secret, lsakey)
else:
secret = decrypt_secret(enc_secret[0xC:], lsakey)
secrets[key.Name] = secret
return secrets
def get_file_secrets(Key, secfile):
def get_file_secrets(sysfile, secfile, vista):
sysaddr = HiveFileAddressSpace(sysfile)
secaddr = HiveFileAddressSpace(secfile)
return get_secrets(Key, secaddr)
return get_secrets(sysaddr, secaddr, vista)

View File

@@ -23,9 +23,9 @@ from framework.newobj import Obj,Pointer
from struct import unpack
ROOT_INDEX = 0x20
LH_SIG = unpack("<H","lh")[0]
LF_SIG = unpack("<H","lf")[0]
RI_SIG = unpack("<H","ri")[0]
LH_SIG = unpack("<H",b"lh")[0]
LF_SIG = unpack("<H",b"lf")[0]
RI_SIG = unpack("<H",b"ri")[0]
def get_root(address_space):
return Obj("_CM_KEY_NODE", ROOT_INDEX, address_space)
@@ -34,11 +34,11 @@ def open_key(root, key):
if key == []:
return root
keyname = key.pop(0)
keyname = key.pop(0).encode()
for s in subkeys(root):
if s.Name.upper() == keyname.upper():
return open_key(s, key)
print "ERR: Couldn't find subkey %s of %s" % (keyname, root.Name)
print("ERR: Couldn't find subkey %s of %s" % (keyname, root.Name))
return None
def subkeys(key,stable=True):