DonPAPI/lazagne/config/DPAPI/credhist.py

143 lines
4.2 KiB
Python
Raw Normal View History

2021-09-27 09:20:43 +00:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Code based from these two awesome projects:
- DPAPICK : https://bitbucket.org/jmichel/dpapick
- DPAPILAB : https://github.com/dfirfpi/dpapilab
"""
import struct
import hashlib
from . import crypto
from .eater import DataStruct
class RPC_SID(DataStruct):
"""
Represents a RPC_SID structure. See MSDN for documentation
"""
def __init__(self, raw=None):
self.version = None
self.idAuth = None
self.subAuth = None
DataStruct.__init__(self, raw)
def parse(self, data):
self.version = data.eat("B")
n = data.eat("B")
self.idAuth = struct.unpack(">Q", b"\0\0" + data.eat("6s"))[0]
self.subAuth = data.eat("%dL" % n)
def __str__(self):
s = ["S-%d-%d" % (self.version, self.idAuth)]
s += ["%d" % x for x in self.subAuth]
return "-".join(s)
class CredhistEntry(DataStruct):
def __init__(self, raw=None):
self.pwdhash = None
self.hmac = None
self.revision = None
self.hashAlgo = None
self.rounds = None
self.cipherAlgo = None
self.shaHashLen = None
self.ntHashLen = None
self.iv = None
self.userSID = None
self.encrypted = None
self.revision2 = None
self.guid = None
self.ntlm = None
DataStruct.__init__(self, raw)
def parse(self, data):
self.revision = data.eat("L")
self.hashAlgo = crypto.CryptoAlgo(data.eat("L"))
self.rounds = data.eat("L")
data.eat("L")
self.cipherAlgo = crypto.CryptoAlgo(data.eat("L"))
self.shaHashLen = data.eat("L")
self.ntHashLen = data.eat("L")
self.iv = data.eat("16s")
self.userSID = RPC_SID()
self.userSID.parse(data)
n = self.shaHashLen + self.ntHashLen
n += -n % self.cipherAlgo.blockSize
self.encrypted = data.eat_string(n)
self.revision2 = data.eat("L")
self.guid = b"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x" % data.eat("L2H8B")
def decrypt_with_hash(self, pwdhash):
"""
Decrypts this credhist entry with the given user's password hash.
Simply computes the encryption key with the given hash
then calls self.decrypt_with_key() to finish the decryption.
"""
self.decrypt_with_key(crypto.derivePwdHash(pwdhash, str(self.userSID)))
def decrypt_with_key(self, enckey):
"""
Decrypts this credhist entry using the given encryption key.
"""
cleartxt = crypto.dataDecrypt(self.cipherAlgo, self.hashAlgo, self.encrypted, enckey,
self.iv, self.rounds)
self.pwdhash = cleartxt[:self.shaHashLen]
self.ntlm = cleartxt[self.shaHashLen:self.shaHashLen + self.ntHashLen].rstrip(b"\x00")
if len(self.ntlm) != 16:
self.ntlm = None
class CredHistFile(DataStruct):
def __init__(self, raw=None):
self.entries_list = []
self.entries = {}
self.valid = False
self.footmagic = None
self.curr_guid = None
DataStruct.__init__(self, raw)
def parse(self, data):
while True:
l = data.pop("L")
if l == 0:
break
self.addEntry(data.pop_string(l - 4))
self.footmagic = data.eat("L")
self.curr_guid = b"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x" % data.eat("L2H8B")
def addEntry(self, blob):
"""
Creates a CredhistEntry object with blob then adds it to the store
"""
x = CredhistEntry(blob)
self.entries[x.guid] = x
self.entries_list.append(x)
def decrypt_with_hash(self, pwdhash):
"""
Try to decrypt each entry with the given hash
"""
if self.valid:
return
for entry in self.entries_list:
entry.decrypt_with_hash(pwdhash)
def decrypt_with_password(self, password):
"""
Decrypts this credhist entry with the given user's password.
Simply computes the password hash then calls self.decrypt_with_hash()
"""
self.decrypt_with_hash(hashlib.sha1(password.encode("UTF-16LE")).digest())