1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
#!/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", "\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 = "%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("\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 = "%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())
|