summaryrefslogtreecommitdiff
path: root/foreign/client_handling/lazagne/config/DPAPI/credhist.py
blob: 2a1d8d702981606d7e0a98e9c3cc2d3af4810188 (plain)
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())