summaryrefslogtreecommitdiff
path: root/foreign/client_handling/lazagne/config/dpapi_structure.py
blob: 7d6080b4d1fa0dac92a0528edf66d024c5bf4f07 (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/python
# -*- coding: utf-8 -*- 
import codecs
import os

from foreign.client_handling.lazagne.config.DPAPI.masterkey import MasterKeyPool
from foreign.client_handling.lazagne.config.DPAPI.credfile import CredFile
from foreign.client_handling.lazagne.config.DPAPI.vault import Vault
from foreign.client_handling.lazagne.config.DPAPI.blob import DPAPIBlob
from foreign.client_handling.lazagne.config.write_output import print_debug
from foreign.client_handling.lazagne.config.constant import constant
from foreign.client_handling.lazagne.softwares.windows.lsa_secrets import LSASecrets


def are_masterkeys_retrieved():
    """
    Before running modules using DPAPI, we have to retrieve masterkeys
    otherwise, we do not realize these checks
    """
    current_user = constant.username
    if constant.pypykatz_result.get(current_user, None):
        password = constant.pypykatz_result[current_user].get('Password', None)
        pwdhash = constant.pypykatz_result[current_user].get('Shahash', None)

        # Create one DPAPI object by user
        constant.user_dpapi = UserDpapi(password=password, pwdhash=pwdhash)

    if not constant.user_dpapi or not constant.user_dpapi.unlocked:
        # constant.user_password represents the password entered manually by the user
        constant.user_dpapi = UserDpapi(password=constant.user_password)

        # Add username to check username equals passwords
        constant.user_dpapi.check_credentials([constant.username] + constant.password_found)

    # Return True if at least one masterkey has been decrypted
    return constant.user_dpapi.unlocked


def manage_response(ok, msg):
    if ok:
        return msg
    else:
        print_debug('DEBUG', u'{msg}'.format(msg=msg))
        return False


class UserDpapi(object):
    """
    User class for DPAPI functions
    """

    def __init__(self, password=None, pwdhash=None):
        self.sid = None
        self.umkp = None
        self.unlocked = False

        protect_folder = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Protect')
        credhist_file = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Protect', u'CREDHIST')

        if os.path.exists(protect_folder):
            for folder in os.listdir(protect_folder):
                if folder.startswith('S-'):
                    self.sid = folder
                    break

            if self.sid:
                masterkeydir = os.path.join(protect_folder, self.sid)
                if os.path.exists(masterkeydir):
                    self.umkp = MasterKeyPool()
                    self.umkp.load_directory(masterkeydir)
                    self.umkp.add_credhist_file(sid=self.sid, credfile=credhist_file)

                    if password:
                        for ok, r in self.umkp.try_credential(sid=self.sid, password=password):
                            if ok:
                                self.unlocked = True
                                print_debug('OK', r)
                            else:
                                print_debug('ERROR', r)

                    elif pwdhash:
                        for ok, r in self.umkp.try_credential_hash(self.sid, pwdhash=codecs.decode(pwdhash, 'hex')):
                            if ok:
                                self.unlocked = True
                                print_debug('OK', r)
                            else:
                                print_debug('ERROR', r)

    def check_credentials(self, passwords):
        if self.umkp:
            for password in passwords:
                for ok, r in self.umkp.try_credential(sid=self.sid, password=password):
                    if ok:
                        self.unlocked = True
                        print_debug('OK', r)
                    else:
                        print_debug('ERROR', r)

    def decrypt_blob(self, dpapi_blob):
        """
        Decrypt DPAPI Blob
        """
        if self.umkp:
            blob = DPAPIBlob(dpapi_blob)
            ok, msg = blob.decrypt_encrypted_blob(mkp=self.umkp)
            return manage_response(ok, msg)

    def decrypt_cred(self, credfile):
        """
        Decrypt Credential Files
        """
        if self.umkp:
            with open(credfile, 'rb') as f:
                c = CredFile(f.read())
            ok, msg = c.decrypt(self.umkp, credfile)
            return manage_response(ok, msg)

    def decrypt_vault(self, vaults_dir):
        """
        Decrypt Vault Files
        """
        if self.umkp:
            v = Vault(vaults_dir=vaults_dir)
            ok, msg = v.decrypt(mkp=self.umkp)
            return manage_response(ok, msg)

    def decrypt_encrypted_blob(self, ciphered, entropy_hex=False):
        """
        Decrypt encrypted blob
        """
        if self.umkp:
            blob = DPAPIBlob(ciphered)
            ok, msg = blob.decrypt_encrypted_blob(mkp=self.umkp, entropy_hex=entropy_hex)
            return manage_response(ok, msg)

    def get_dpapi_hash(self, context='local'):
        """
        Retrieve DPAPI hash to bruteforce it using john or hashcat.
        """
        if self.umkp:
            return self.umkp.get_dpapi_hash(sid=self.sid, context=context)

    def get_cleartext_password(self):
        """
        Retrieve cleartext password associated to the preferred user maskterkey.
        This password should represent the windows user password.
        """
        if self.umkp:
            return self.umkp.get_cleartext_password()


class SystemDpapi(object):
    """
    System class for DPAPI functions
    Need to have high privilege
    """

    def __init__(self):
        self.smkp = None
        self.unlocked = False

        if not constant.lsa_secrets:
            # Retrieve LSA secrets
            LSASecrets().run()

        if constant.lsa_secrets:
            masterkeydir = u'C:\\Windows\\System32\\Microsoft\\Protect\\S-1-5-18\\User'
            if os.path.exists(masterkeydir):
                self.smkp = MasterKeyPool()
                self.smkp.load_directory(masterkeydir)
                self.smkp.add_system_credential(constant.lsa_secrets[b'DPAPI_SYSTEM'])
                for ok, r in self.smkp.try_system_credential():
                    if ok:
                        print_debug('OK', r)
                        self.unlocked = True
                    else:
                        print_debug('ERROR', r)

    def decrypt_wifi_blob(self, key_material):
        """
        Decrypt wifi password
        """
        if self.smkp:
            blob = DPAPIBlob(key_material.decode('hex'))
            ok, msg = blob.decrypt_encrypted_blob(mkp=self.smkp)
            return manage_response(ok, msg)