forked from tijldeneut/diana
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdiana-rsadec.py
executable file
·137 lines (121 loc) · 7.38 KB
/
diana-rsadec.py
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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
r'''
Copyright 2022, Tijl "Photubias" Deneut <@tijldeneut>
Source and credits: https://github.com/mis-team/dpapick/blob/master/examples/efs.py
This script converts RSA certs from
%APPDATA%/Microsoft/SystemCertificates/My/Certificates
and (DPAPI encrypted) RSA private keys from
%APPDATA%/Microsoft/Crypto/RSA/<SID>
and turn them into unprotected PFX file(s)
DPAPI decryption needs either:
User MasterKey + User SID + User password or hash
User MasterKey + Domain PVK
Decrypted Masterkey (64bytes, 128 HEX characters)
Prerequirement: DPAPick3
The resulting PFX files can be imported into any Windows machine to read EFS folders, or using Linux:
ntfsdecrypt -k <name.pfx> /dev/sda Users\User\Desktop\Encrypted_Folder\hiddenfile.txt
'''
import argparse, os, warnings, re, OpenSSL, sys
warnings.filterwarnings("ignore")
try:
from dpapick3 import masterkey
from dpapick3.probes import certificate
except ImportError:
raise ImportError('Missing dpapick3, please install via pip install dpapick3')
def parseArgs():
if len(sys.argv)<2 or sys.argv[1].startswith('-h'): print('To decrypt RSA certs, one of three combo\'s is required: \n'
'Decrypted Masterkey / MK file, SID and User Pwd or Hash / MK file and Domain PVK\n'
'RSA public cert path:\n'
'%APPDATA%\\Microsoft\\SystemCertificates\\My\\Certificates\n'
'RSA private key path:\n'
'%APPDATA%\\Microsoft\\Crypto\\RSA\\<SID>')
oParser = argparse.ArgumentParser()
oParser.add_argument('--rsapub', '-r', metavar='FOLDER', help='Folder containing RSA public certs', required=True)
oParser.add_argument('--rsapriv', '-c', metavar='FOLDER', help='Folder containing RSA private keys', required=True)
oParser.add_argument('--outfolder', '-o', metavar='FOLDER', help='Folder to export PFX (optional)')
oParser.add_argument('--masterkey', '-m', metavar='FILE', help='GUID file or folder to get Masterkey(s) from (optional)')
oParser.add_argument('--sid', '-s', metavar='SID', help='User SID (optional)')
oParser.add_argument('--pwdhash', '-a', metavar='HASH', help='User password SHA1 hash (optional)')
oParser.add_argument('--password', '-p', metavar='PASS', help='User password (optional)')
oParser.add_argument('--pvk', '-d', metavar='FILE', help='AD cert in PVK format (optional)')
oParser.add_argument('--verbose', '-v', action = 'store_true', default=False, help='Be more verbose (optional)')
oArgs = oParser.parse_args()
if not os.path.isdir(oArgs.rsapub): exit('[-] Error: Please provide RSA public cert folder')
if not os.path.isdir(oArgs.rsapriv): exit('[-] Error: Please provide RSA private key folder (crypto folder)')
if oArgs.pvk and not os.path.isfile(oArgs.pvk): exit('[-] Error: File not found: ' + oArgs.pvk)
if oArgs.masterkey: oArgs.masterkey = oArgs.masterkey.replace('*','')
if oArgs.masterkey and not os.path.isfile(oArgs.masterkey) and not os.path.isdir(oArgs.masterkey): exit('[-] Error: File/folder not found: ' + oArgs.masterkey)
if oArgs.masterkey and not oArgs.sid:
try:
oArgs.sid = re.findall(r"S-1-\d+-\d+-\d+-\d+-\d+-\d+", oArgs.masterkey)[0]
print('[+] Detected SID: ' + oArgs.sid)
except: pass
if oArgs.masterkey and oArgs.sid and not oArgs.password and not oArgs.pwdhash:
oArgs.pwdhash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
# On older systems: oArgs.pwdhash = '31d6cfe0d16ae931b73c59d7e0c089c0'
print('[+] No password data provided, using empty hash')
if oArgs.pwdhash: oArgs.pwdhash = bytes.fromhex(oArgs.pwdhash)
return oArgs
if __name__ == '__main__':
oArgs = parseArgs()
lstKeys, lstCerts, lstMasterkeys = [], [], []
bMasterkey = oMKP = None
## All other options require one or more MK files, using MK Pool
if oArgs.masterkey:
oMKP = masterkey.MasterKeyPool()
if os.path.isfile(oArgs.masterkey):
oMKP.addMasterKey(open(oArgs.masterkey,'rb').read())
else:
oMKP.loadDirectory(oArgs.masterkey)
if oArgs.verbose: print('[!] Imported {} DPAPI master keys'.format(str(len(list(oMKP.keys)))))
## Option 1: the PVK domain key to decrypt the MK key
if oMKP and oArgs.pvk:
print('[!] Try MK decryption with the PVK domain key')
if oMKP.try_domain(oArgs.pvk) > 0:
for bMKGUID in list(oMKP.keys):
oMK = oMKP.getMasterKeys(bMKGUID)[0]
if oMK.decrypted:
bMasterkey = oMK.get_key()
print('[+] Success, user masterkey decrypted: ' + bMasterkey.hex())
## Option 2: User SID + password (hash)
if oArgs.masterkey and oArgs.sid and (oArgs.password or oArgs.pwdhash):
print('[!] Try MK decryption with user details, might take some time')
if oArgs.password: oMKP.try_credential(oArgs.sid, oArgs.password)
else: oMKP.try_credential_hash(oArgs.sid, oArgs.pwdhash)
for bMKGUID in list(oMKP.keys):
oMK = oMKP.getMasterKeys(bMKGUID)[0]
if oMK.decrypted:
if not oMK.get_key() in lstMasterkeys: lstMasterkeys.append(oMK.get_key())
if oArgs.verbose: print('[+] DPAPI MK decrypted: ' + oMK.get_key().hex())
if not bMasterkey and not oMKP: exit('[-] Error: no masterkeys provided')
## Parse and DPAPI decrypt RSA Private keys
for sFilename in os.listdir(oArgs.rsapriv):
with open(os.path.join(oArgs.rsapriv, sFilename), 'rb') as oFile:
oBlob = certificate.PrivateKeyBlob(oFile.read())
if oBlob.try_decrypt_with_hash(oArgs.pwdhash, oMKP, oArgs.sid):
print('[+] Decrypted private key %s from %s' % (oBlob.description.decode(), os.path.join(oArgs.rsapriv, sFilename)))
#with open('%s.rsa' % str(oBlob.description).rstrip(b'\x00'), 'wb') as rsa_out: rsa_out.write(oBlob.export()); rsa_out.close()
oBlob.description = oBlob.description.rstrip(b'\x00')
lstKeys.append(oBlob)
## Parse RSA Public keys
for sFilename in os.listdir(oArgs.rsapub):
with open(os.path.join(oArgs.rsapub, sFilename), 'rb') as oFile:
oCert = certificate.Cert(oFile.read())
if hasattr(oCert, 'name') and hasattr(oCert, 'certificate'):
lstCerts.append(oCert)
print('[+] Found certificate associated with key %s: %s' % (oCert.name, os.path.join(oArgs.rsapub, sFilename)))
## Create PFX and save as necessary
for oKey in lstKeys:
for oCert in lstCerts:
if oKey.description.decode() == oCert.name:
oP12 = OpenSSL.crypto.PKCS12()
oP12.set_privatekey(OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, oKey.export()))
oP12.set_certificate(OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, oCert.certificate))
print('[+] Successfully reassembled private key and certificate: %s.pfx' % (oCert.name))
if oArgs.outfolder and os.path.isdir(oArgs.outfolder):
print('[+] Writing to ' + os.path.join(oArgs.outfolder, oCert.name+'.pfx'))
with open(os.path.join(oArgs.outfolder, oCert.name+'.pfx'), 'wb') as oPFXFile:
oPFXFile.write(oP12.export())
oPFXFile.close()
print('[!] Install this pfx file into Windows -> Local User, just click "Next"')