Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 

2# 

3# This software is provided under under a slightly modified version 

4# of the Apache Software License. See the accompanying LICENSE file 

5# for more information. 

6# 

7# Author: 

8# Alberto Solino (@agsolino) 

9# 

10# Description: 

11# DPAPI and Windows Vault parsing structures and manipulation 

12# 

13# References: All of the work done by these guys. I just adapted their work to my needs. 

14# https://www.passcape.com/index.php?section=docsys&cmd=details&id=28 

15# https://github.com/jordanbtucker/dpapick 

16# https://github.com/gentilkiwi/mimikatz/wiki/howto-~-credential-manager-saved-credentials (and everything else Ben did ) 

17# http://blog.digital-forensics.it/2016/01/windows-revaulting.html 

18# https://www.passcape.com/windows_password_recovery_vault_explorer 

19# https://www.passcape.com/windows_password_recovery_dpapi_master_key 

20# 

21from __future__ import division 

22from __future__ import print_function 

23import sys 

24 

25from struct import unpack 

26from datetime import datetime 

27from binascii import unhexlify, hexlify 

28from struct import pack 

29from Cryptodome.Hash import HMAC, SHA512, SHA1 

30from Cryptodome.Cipher import AES, DES3 

31from Cryptodome.Util.Padding import unpad 

32from Cryptodome.PublicKey import RSA 

33from Cryptodome.Util.number import bytes_to_long 

34from six import PY3 

35 

36from impacket.ese import getUnixTime 

37from impacket.structure import Structure, hexdump 

38from impacket.uuid import bin_to_string 

39from impacket.dcerpc.v5.enum import Enum 

40from impacket.dcerpc.v5.dtypes import RPC_SID 

41 

42# Algorithm classes 

43ALG_CLASS_ANY = (0) 

44ALG_CLASS_SIGNATURE = (1 << 13) 

45ALG_CLASS_MSG_ENCRYPT = (2 << 13) 

46ALG_CLASS_DATA_ENCRYPT = (3 << 13) 

47ALG_CLASS_HASH = (4 << 13) 

48ALG_CLASS_KEY_EXCHANGE = (5 << 13) 

49ALG_CLASS_ALL = (7 << 13) 

50 

51# Algorithm types 

52ALG_TYPE_ANY = (0) 

53ALG_TYPE_DSS = (1 << 9) 

54ALG_TYPE_RSA = (2 << 9) 

55ALG_TYPE_BLOCK = (3 << 9) 

56ALG_TYPE_STREAM = (4 << 9) 

57ALG_TYPE_DH = (5 << 9) 

58ALG_TYPE_SECURECHANNEL = (6 << 9) 

59ALG_SID_ANY = (0) 

60ALG_SID_RSA_ANY = 0 

61ALG_SID_RSA_PKCS = 1 

62ALG_SID_RSA_MSATWORK = 2 

63ALG_SID_RSA_ENTRUST = 3 

64ALG_SID_RSA_PGP = 4 

65ALG_SID_DSS_ANY = 0 

66ALG_SID_DSS_PKCS = 1 

67ALG_SID_DSS_DMS = 2 

68ALG_SID_ECDSA = 3 

69 

70# Block cipher sub ids 

71ALG_SID_DES = 1 

72ALG_SID_3DES = 3 

73ALG_SID_DESX = 4 

74ALG_SID_IDEA = 5 

75ALG_SID_CAST = 6 

76ALG_SID_SAFERSK64 = 7 

77ALG_SID_SAFERSK128 = 8 

78ALG_SID_3DES_112 = 9 

79ALG_SID_CYLINK_MEK = 12 

80ALG_SID_RC5 = 13 

81ALG_SID_AES_128 = 14 

82ALG_SID_AES_192 = 15 

83ALG_SID_AES_256 = 16 

84ALG_SID_AES = 17 

85ALG_SID_SKIPJACK = 10 

86ALG_SID_TEK = 11 

87 

88CRYPT_MODE_CBCI = 6 # ANSI CBC Interleaved 

89CRYPT_MODE_CFBP = 7 # ANSI CFB Pipelined 

90CRYPT_MODE_OFBP = 8 # ANSI OFB Pipelined 

91CRYPT_MODE_CBCOFM = 9 # ANSI CBC + OF Masking 

92CRYPT_MODE_CBCOFMI = 10 # ANSI CBC + OFM Interleaved 

93 

94ALG_SID_RC2 = 2 

95ALG_SID_RC4 = 1 

96ALG_SID_SEAL = 2 

97 

98# Diffie - Hellman sub - ids 

99ALG_SID_DH_SANDF = 1 

100ALG_SID_DH_EPHEM = 2 

101ALG_SID_AGREED_KEY_ANY = 3 

102ALG_SID_KEA = 4 

103ALG_SID_ECDH = 5 

104 

105# Hash sub ids 

106ALG_SID_MD2 = 1 

107ALG_SID_MD4 = 2 

108ALG_SID_MD5 = 3 

109ALG_SID_SHA = 4 

110ALG_SID_SHA1 = 4 

111ALG_SID_MAC = 5 

112ALG_SID_RIPEMD = 6 

113ALG_SID_RIPEMD160 = 7 

114ALG_SID_SSL3SHAMD5 = 8 

115ALG_SID_HMAC = 9 

116ALG_SID_TLS1PRF = 10 

117ALG_SID_HASH_REPLACE_OWF = 11 

118ALG_SID_SHA_256 = 12 

119ALG_SID_SHA_384 = 13 

120ALG_SID_SHA_512 = 14 

121 

122# secure channel sub ids 

123ALG_SID_SSL3_MASTER = 1 

124ALG_SID_SCHANNEL_MASTER_HASH = 2 

125ALG_SID_SCHANNEL_MAC_KEY = 3 

126ALG_SID_PCT1_MASTER = 4 

127ALG_SID_SSL2_MASTER = 5 

128ALG_SID_TLS1_MASTER = 6 

129ALG_SID_SCHANNEL_ENC_KEY = 7 

130ALG_SID_ECMQV = 1 

131 

132def getFlags(myenum, flags): 

133 return '|'.join([name for name, member in myenum.__members__.items() if member.value & flags]) 

134 

135class FLAGS(Enum): 

136 CRYPTPROTECT_UI_FORBIDDEN = 0x1 

137 CRYPTPROTECT_LOCAL_MACHINE = 0x4 

138 CRYPTPROTECT_CRED_SYNC = 0x8 

139 CRYPTPROTECT_AUDIT = 0x10 

140 CRYPTPROTECT_VERIFY_PROTECTION = 0x40 

141 CRYPTPROTECT_CRED_REGENERATE = 0x80 

142 CRYPTPROTECT_SYSTEM = 0x20000000 

143 

144# algorithm identifier definitions 

145class ALGORITHMS(Enum): 

146 CALG_MD2 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD2) 

147 CALG_MD4 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD4) 

148 CALG_MD5 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5) 

149 CALG_SHA = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA) 

150 CALG_SHA1 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1) 

151 CALG_RSA_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY) 

152 CALG_DSS_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY) 

153 CALG_NO_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | ALG_SID_ANY) 

154 CALG_RSA_KEYX = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_RSA|ALG_SID_RSA_ANY) 

155 CALG_DES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_DES) 

156 CALG_3DES_112 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_3DES_112) 

157 CALG_3DES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_3DES) 

158 CALG_DESX = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_DESX) 

159 CALG_RC2 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC2) 

160 CALG_RC4 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_STREAM|ALG_SID_RC4) 

161 CALG_SEAL = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_STREAM|ALG_SID_SEAL) 

162 CALG_DH_SF = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_DH_SANDF) 

163 CALG_DH_EPHEM = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_DH_EPHEM) 

164 CALG_AGREEDKEY_ANY = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_AGREED_KEY_ANY) 

165 CALG_KEA_KEYX = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_KEA) 

166 CALG_HUGHES_MD5 = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_ANY|ALG_SID_MD5) 

167 CALG_SKIPJACK = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_SKIPJACK) 

168 CALG_TEK = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_TEK) 

169 CALG_SSL3_SHAMD5 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5) 

170 CALG_SSL3_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SSL3_MASTER) 

171 CALG_SCHANNEL_MASTER_HASH = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_MASTER_HASH) 

172 CALG_SCHANNEL_MAC_KEY = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_MAC_KEY) 

173 CALG_SCHANNEL_ENC_KEY = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_ENC_KEY) 

174 CALG_PCT1_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_PCT1_MASTER) 

175 CALG_SSL2_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SSL2_MASTER) 

176 CALG_TLS1_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_TLS1_MASTER) 

177 CALG_RC5 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC5) 

178 CALG_HMAC = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) 

179 CALG_TLS1PRF = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_TLS1PRF) 

180 CALG_HASH_REPLACE_OWF = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HASH_REPLACE_OWF) 

181 CALG_AES_128 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_128) 

182 CALG_AES_192 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_192) 

183 CALG_AES_256 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_256) 

184 CALG_AES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES) 

185 CALG_SHA_256 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) 

186 CALG_SHA_384 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) 

187 CALG_SHA_512 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) 

188 CALG_ECDH = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH) 

189 CALG_ECMQV = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV) 

190 CALG_ECDSA = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA) 

191 

192class CREDENTIAL_FLAGS(Enum): 

193 CRED_FLAGS_PASSWORD_FOR_CERT = 0x1 

194 CRED_FLAGS_PROMPT_NOW = 0x2 

195 CRED_FLAGS_USERNAME_TARGET = 0x4 

196 CRED_FLAGS_OWF_CRED_BLOB = 0x8 

197 CRED_FLAGS_REQUIRE_CONFIRMATION = 0x10 

198 CRED_FLAGS_WILDCARD_MATCH = 0x20 

199 CRED_FLAGS_VSM_PROTECTED = 0x40 

200 CRED_FLAGS_NGC_CERT = 0x80 

201 

202class CREDENTIAL_TYPE(Enum): 

203 CRED_TYPE_GENERIC = 0x1 

204 CRED_TYPE_DOMAIN_PASSWORD = 0x2 

205 CRED_TYPE_DOMAIN_CERTIFICATE = 0x3 

206 CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 0x4 

207 CRED_TYPE_GENERIC_CERTIFICATE = 0x5 

208 CRED_TYPE_DOMAIN_EXTENDED = 0x6 

209 CRED_TYPE_MAXIMUM = 0x7 

210 CRED_TYPE_MAXIMUM_EX = 0x8 

211 

212class CREDENTIAL_PERSIST(Enum): 

213 CRED_PERSIST_NONE = 0x0 

214 CRED_PERSIST_SESSION = 0x1 

215 CRED_PERSIST_LOCAL_MACHINE = 0x2 

216 CRED_PERSIST_ENTERPRISE = 0x3 

217 

218ALGORITHMS_DATA = { 

219 # Algorithm: key/SaltLen, CryptHashModule, Mode, IVLen, BlockSize 

220 ALGORITHMS.CALG_SHA.value: (160//8, SHA1, None, None, 512//8), 

221 ALGORITHMS.CALG_HMAC.value: (160//8, SHA512, None, None, 512//8), 

222 ALGORITHMS.CALG_3DES.value: (192//8, DES3, DES3.MODE_CBC, 64//8), 

223 ALGORITHMS.CALG_SHA_512.value: (128//8, SHA512, None, None, 1024//8), 

224 ALGORITHMS.CALG_AES_256.value: (256//8, AES, AES.MODE_CBC, 128//8), 

225} 

226 

227class MasterKeyFile(Structure): 

228 structure = ( 

229 ('Version', '<L=0'), 

230 ('unk1', '<L=0'), 

231 ('unk2', '<L=0'), 

232 ('Guid', "72s=b''"), 

233 ('Unkown', '<L=0'), 

234 ('Policy', '<L=0'), 

235 ('Flags', '<L=0'), 

236 ('MasterKeyLen', '<Q=0'), 

237 ('BackupKeyLen', '<Q=0'), 

238 ('CredHistLen', '<Q=0'), 

239 ('DomainKeyLen', '<Q=0'), 

240 ) 

241 

242 def dump(self): 

243 print("[MASTERKEYFILE]") 

244 print("Version : %8x (%d)" % (self['Version'], self['Version'])) 

245 print("Guid : %s" % self['Guid'].decode('utf-16le')) 

246 print("Flags : %8x (%d)" % (self['Flags'], self['Flags'])) 

247 print("Policy : %8x (%d)" % (self['Policy'], self['Policy'])) 

248 print("MasterKeyLen: %.8x (%d)" % (self['MasterKeyLen'], self['MasterKeyLen'])) 

249 print("BackupKeyLen: %.8x (%d)" % (self['BackupKeyLen'], self['BackupKeyLen'])) 

250 print("CredHistLen : %.8x (%d)" % (self['CredHistLen'], self['CredHistLen'])) 

251 print("DomainKeyLen: %.8x (%d)" % (self['DomainKeyLen'], self['DomainKeyLen'])) 

252 print() 

253 

254class MasterKey(Structure): 

255 structure = ( 

256 ('Version', '<L=0'), 

257 ('Salt', '16s=b""'), 

258 ('MasterKeyIterationCount', '<L=0'), 

259 ('HashAlgo', "<L=0"), 

260 ('CryptAlgo', '<L=0'), 

261 ('data', ':'), 

262 ) 

263 

264 def __init__(self, data = None, alignment = 0): 

265 Structure.__init__(self, data, alignment) 

266 self.decryptedKey = None 

267 

268 def dump(self): 

269 print("[MASTERKEY]") 

270 print("Version : %8x (%d)" % (self['Version'], self['Version'])) 

271 print("Salt : %s" % hexlify(self['Salt'])) 

272 print("Rounds : %8x (%d)" % (self['MasterKeyIterationCount'], self['MasterKeyIterationCount'])) 

273 print("HashAlgo : %.8x (%d) (%s)" % (self['HashAlgo'], self['HashAlgo'], ALGORITHMS(self['HashAlgo']).name)) 

274 print("CryptAlgo : %.8x (%d) (%s)" % (self['CryptAlgo'], self['CryptAlgo'], ALGORITHMS(self['CryptAlgo']).name)) 

275 print("data : %s" % (hexlify(self['data']))) 

276 print() 

277 

278 def deriveKey(self, passphrase, salt, keylen, count, hashFunction): 

279 keyMaterial = b"" 

280 i = 1 

281 while len(keyMaterial) < keylen: 

282 U = salt + pack("!L", i) 

283 i += 1 

284 derived = bytearray(hashFunction(passphrase, U)) 

285 for r in range(count - 1): 

286 actual = bytearray(hashFunction(passphrase, derived)) 

287 if PY3: 287 ↛ 290line 287 didn't jump to line 290, because the condition on line 287 was never false

288 derived = (int.from_bytes(derived, sys.byteorder) ^ int.from_bytes(actual, sys.byteorder)).to_bytes(len(actual), sys.byteorder) 

289 else: 

290 derived = bytearray([ chr((a) ^ (b)) for (a,b) in zip(derived, actual) ]) 

291 keyMaterial += derived 

292 

293 return keyMaterial[:keylen] 

294 

295 def decrypt(self, key): 

296 if self['HashAlgo'] == ALGORITHMS.CALG_HMAC.value: 296 ↛ 297line 296 didn't jump to line 297, because the condition on line 296 was never true

297 hashModule = SHA1 

298 else: 

299 hashModule = ALGORITHMS_DATA[self['HashAlgo']][1] 

300 

301 prf = lambda p, s: HMAC.new(p, s, hashModule).digest() 

302 derivedBlob = self.deriveKey(key, self['Salt'], 

303 ALGORITHMS_DATA[self['CryptAlgo']][0] + ALGORITHMS_DATA[self['CryptAlgo']][3], 

304 count=self['MasterKeyIterationCount'], hashFunction=prf) 

305 

306 cryptKey = derivedBlob[:ALGORITHMS_DATA[self['CryptAlgo']][0]] 

307 iv = derivedBlob[ALGORITHMS_DATA[self['CryptAlgo']][0]:][:ALGORITHMS_DATA[self['CryptAlgo']][3]] 

308 

309 cipher = ALGORITHMS_DATA[self['CryptAlgo']][1].new(cryptKey, mode = ALGORITHMS_DATA[self['CryptAlgo']][2], iv = iv) 

310 cleartext = cipher.decrypt(self['data']) 

311 

312 decryptedKey = cleartext[-64:] 

313 hmacSalt = cleartext[:16] 

314 hmac = cleartext[16:][:ALGORITHMS_DATA[self['HashAlgo']][0]] 

315 

316 hmacKey = HMAC.new(key, hmacSalt, hashModule).digest() 

317 

318 hmacCalculated = HMAC.new(hmacKey, decryptedKey, hashModule ).digest() 

319 

320 if hmacCalculated[:ALGORITHMS_DATA[self['HashAlgo']][0]] == hmac: 320 ↛ 324line 320 didn't jump to line 324, because the condition on line 320 was never false

321 self.decryptedKey = decryptedKey 

322 return decryptedKey 

323 else: 

324 return None 

325 

326class CredHist(Structure): 

327 structure = ( 

328 ('Version', '<L=0'), 

329 ('Guid', "16s=b''"), 

330 ) 

331 def dump(self): 

332 print("[CREDHIST]") 

333 print("Version : %8x (%d)" % (self['Version'], self['Version'])) 

334 print("Guid : %s" % bin_to_string(self['Guid'])) 

335 print() 

336 

337class DomainKey(Structure): 

338 structure = ( 

339 ('Version', '<L=0'), 

340 ('SecretLen', '<L=0'), 

341 ('AccessCheckLen', '<L=0'), 

342 ('Guid', "16s=b"""), 

343 ('_SecretData', '_-SecretData', 'self["SecretLen"]'), 

344 ('SecretData', ':'), 

345 ('_AccessCheck', '_-AccessCheck', 'self["AccessCheckLen"]'), 

346 ('AccessCheck', ':'), 

347 ) 

348 def dump(self): 

349 print("[DOMAINKEY]") 

350 print("Version : %8x (%d)" % (self['Version'], self['Version'])) 

351 print("Guid : %s" % bin_to_string(self['Guid'])) 

352 print("SecretLen : %8x (%d)" % (self['SecretLen'], self['SecretLen'])) 

353 print("AccessCheckLen: %.8x (%d)" % (self['AccessCheckLen'], self['AccessCheckLen'])) 

354 print("SecretData : %s" % (hexlify(self['SecretData']))) 

355 print("AccessCheck : %s" % (hexlify(self['AccessCheck']))) 

356 print() 

357 

358class DPAPI_SYSTEM(Structure): 

359 structure = ( 

360 ('Version', '<L=0'), 

361 ('MachineKey', '20s=b""'), 

362 ('UserKey', '20s=b""'), 

363 ) 

364 

365 def dump(self): 

366 print("[DPAPI_SYSTEM]") 

367 print("Version : %8x (%d)" % (self['Version'], self['Version'])) 

368 print("MachineKey : 0x%s" % hexlify(self['MachineKey']).decode('latin-1')) 

369 print("UserKey : 0x%s" % hexlify(self['UserKey']).decode('latin-1')) 

370 print() 

371 

372class CredentialFile(Structure): 

373 structure = ( 

374 ('Version', '<L=0'), 

375 ('Size', '<L=0'), 

376 ('Unknown', '<L=0'), 

377 ('_Data', '_-Data', 'self["Size"]'), 

378 ('Data', ':'), 

379 ) 

380 #def dump(self): 

381 # print("[CREDENTIAL FILE]") 

382 # print("Version : %8x (%d)" % (self['Version'], self['Version'])) 

383 # print("MachineKey : %s" % hexlify(self['MachineKey'])) 

384 # print("UserKey : %s" % hexlify(self['UserKey'])) 

385 # print("CryptAlgo : %.8x (%d) (%s)" % (self['CryptAlgo'], self['CryptAlgo'], ALGORITHMS(self['CryptAlgo']).name)) 

386 # print() 

387 

388 

389class DPAPI_BLOB(Structure): 

390 structure = ( 

391 ('Version', '<L=0'), 

392 ('GuidCredential', "16s=b"""), 

393 ('MasterKeyVersion', '<L=0'), 

394 ('GuidMasterKey', "16s=b"""), 

395 ('Flags', '<L=0'), 

396 

397 ('DescriptionLen', '<L=0'), 

398 ('_Description', '_-Description', 'self["DescriptionLen"]'), 

399 ('Description', ':'), 

400 

401 ('CryptAlgo', '<L=0'), 

402 ('CryptAlgoLen', '<L=0'), 

403 

404 ('SaltLen', '<L=0'), 

405 ('_Salt', '_-Salt', 'self["SaltLen"]'), 

406 ('Salt', ':'), 

407 

408 ('HMacKeyLen', '<L=0'), 

409 ('_HMacKey', '_-HMacKey', 'self["HMacKeyLen"]'), 

410 ('HMacKey', ':'), 

411 

412 ('HashAlgo', '<L=0'), 

413 ('HashAlgoLen', '<L=0'), 

414 

415 ('HMac', '<L=0'), 

416 ('_HMac', '_-HMac', 'self["HMac"]'), 

417 ('HMac', ':'), 

418 

419 ('DataLen', '<L=0'), 

420 ('_Data', '_-Data', 'self["DataLen"]'), 

421 ('Data', ':'), 

422 

423 ('SignLen', '<L=0'), 

424 ('_Sign', '_-Sign', 'self["SignLen"]'), 

425 ('Sign', ':'), 

426 

427 ) 

428 

429 def dump(self): 

430 print("[BLOB]") 

431 print("Version : %8x (%d)" % (self['Version'], self['Version'])) 

432 print("Guid Credential : %s" % bin_to_string(self['GuidCredential'])) 

433 print("MasterKeyVersion : %8x (%d)" % (self['MasterKeyVersion'], self['MasterKeyVersion'])) 

434 print("Guid MasterKey : %s" % bin_to_string(self['GuidMasterKey'])) 

435 print("Flags : %8x (%s)" % (self['Flags'], getFlags(FLAGS, self['Flags']))) 

436 print("Description : %s" % (self['Description'].decode('utf-16le'))) 

437 print("CryptAlgo : %.8x (%d) (%s)" % (self['CryptAlgo'], self['CryptAlgo'], ALGORITHMS(self['CryptAlgo']).name)) 

438 print("Salt : %s" % (hexlify(self['Salt']))) 

439 print("HMacKey : %s" % (hexlify(self['HMacKey']))) 

440 print("HashAlgo : %.8x (%d) (%s)" % (self['HashAlgo'], self['HashAlgo'], ALGORITHMS(self['HashAlgo']).name)) 

441 print("HMac : %s" % (hexlify(self['HMac']))) 

442 print("Data : %s" % (hexlify(self['Data']))) 

443 print("Sign : %s" % (hexlify(self['Sign']))) 

444 print() 

445 

446 

447 def deriveKey(self, sessionKey): 

448 def fixparity(deskey): 

449 from six import indexbytes, b 

450 temp = b'' 

451 for i in range(len(deskey)): 

452 t = (bin(indexbytes(deskey,i))[2:]).rjust(8,'0') 

453 if t[:7].count('1') %2 == 0: 

454 temp+= b(chr(int(t[:7]+'1',2))) 

455 else: 

456 temp+= b(chr(int(t[:7]+'0',2))) 

457 return temp 

458 

459 if len(sessionKey) > ALGORITHMS_DATA[self['HashAlgo']][4]: 459 ↛ 460line 459 didn't jump to line 460, because the condition on line 459 was never true

460 derivedKey = HMAC.new(sessionKey, digestmod = ALGORITHMS_DATA[self['HashAlgo']][1]).digest() 

461 else: 

462 derivedKey = sessionKey 

463 

464 

465 if len(derivedKey) < ALGORITHMS_DATA[self['CryptAlgo']][0]: 

466 # Extend the key 

467 derivedKey += b'\x00'*ALGORITHMS_DATA[self['HashAlgo']][4] 

468 ipad = bytearray([ i ^ 0x36 for i in bytearray(derivedKey)][:ALGORITHMS_DATA[self['HashAlgo']][4]]) 

469 opad = bytearray([ i ^ 0x5c for i in bytearray(derivedKey)][:ALGORITHMS_DATA[self['HashAlgo']][4]]) 

470 derivedKey = ALGORITHMS_DATA[self['HashAlgo']][1].new(ipad).digest() + \ 

471 ALGORITHMS_DATA[self['HashAlgo']][1].new(opad).digest() 

472 derivedKey = fixparity(derivedKey) 

473 

474 return derivedKey 

475 

476 def decrypt(self, key, entropy = None): 

477 keyHash = SHA1.new(key).digest() 

478 sessionKey = HMAC.new(keyHash, self['Salt'], ALGORITHMS_DATA[self['HashAlgo']][1]) 

479 if entropy is not None: 479 ↛ 480line 479 didn't jump to line 480, because the condition on line 479 was never true

480 sessionKey.update(entropy) 

481 

482 sessionKey = sessionKey.digest() 

483 

484 # Derive the key 

485 derivedKey = self.deriveKey(sessionKey) 

486 

487 cipher = ALGORITHMS_DATA[self['CryptAlgo']][1].new(derivedKey[:ALGORITHMS_DATA[self['CryptAlgo']][0]], 

488 mode=ALGORITHMS_DATA[self['CryptAlgo']][2], iv=b'\x00'*ALGORITHMS_DATA[self['CryptAlgo']][3]) 

489 cleartext = unpad(cipher.decrypt(self['Data']), ALGORITHMS_DATA[self['CryptAlgo']][1].block_size) 

490 

491 # Now check the signature 

492 

493 # ToDo Fix this, it's just ugly, more testing so we can remove one 

494 toSign = (self.rawData[20:][:len(self.rawData)-20-len(self['Sign'])-4]) 

495 

496 # Calculate the different HMACKeys 

497 keyHash2 = keyHash + b"\x00"*ALGORITHMS_DATA[self['HashAlgo']][1].block_size 

498 ipad = bytearray([i ^ 0x36 for i in bytearray(keyHash2)][:ALGORITHMS_DATA[self['HashAlgo']][1].block_size]) 

499 opad = bytearray([i ^ 0x5c for i in bytearray(keyHash2)][:ALGORITHMS_DATA[self['HashAlgo']][1].block_size]) 

500 a = ALGORITHMS_DATA[self['HashAlgo']][1].new(ipad) 

501 a.update(self['HMac']) 

502 

503 hmacCalculated1 = ALGORITHMS_DATA[self['HashAlgo']][1].new(opad) 

504 hmacCalculated1.update(a.digest()) 

505 

506 if entropy is not None: 506 ↛ 507line 506 didn't jump to line 507, because the condition on line 506 was never true

507 hmacCalculated1.update(entropy) 

508 

509 hmacCalculated1.update(toSign) 

510 

511 hmacCalculated3 = HMAC.new(keyHash, self['HMac'], ALGORITHMS_DATA[self['HashAlgo']][1]) 

512 if entropy is not None: 512 ↛ 513line 512 didn't jump to line 513, because the condition on line 512 was never true

513 hmacCalculated3.update(entropy) 

514 

515 hmacCalculated3.update(toSign) 

516 

517 if hmacCalculated1.digest() == self['Sign'] or hmacCalculated3.digest() == self['Sign']: 517 ↛ 520line 517 didn't jump to line 520, because the condition on line 517 was never false

518 return cleartext 

519 else: 

520 return None 

521 

522class VAULT_ATTRIBUTE(Structure): 

523 structure = ( 

524 ('Id', '<L=0'), 

525 ('Unknown1', '<L=0'), 

526 ('Unknown2', '<L=0'), 

527 ('Unknown3', '<L=0'), 

528 ) 

529 

530 padding = ( 

531 ('Pad', '6s=b""'), 

532 ) 

533 

534 id100 = ( 

535 ('Unknown5', '<L=0'), 

536 ) 

537 

538 extended = ( 

539 ('Size','<L=0'), 

540 ('IVPresent', '<B=?&IVSize'), 

541 ('IVSize', '<L=0'), 

542 ('_IV', '_-IV', 'self["IVSize"] if self["IVSize"] is not None else 0'), 

543 ('IV', ':'), 

544 ('_Data','_-Data', 'self["Size"]-self["IVSize"]-5 if self["IVPresent"] else self["Size"]-1'), 

545 ('Data',':'), 

546 ) 

547 def __init__(self, data = None, alignment = 0): 

548 if len(data) > 20: 548 ↛ 555line 548 didn't jump to line 555, because the condition on line 548 was never false

549 if data[16:][:6] == b'\x00'*6: 549 ↛ 550line 549 didn't jump to line 550, because the condition on line 549 was never true

550 self.structure += self.padding 

551 if unpack('<L',data[:4])[0] >= 100: 

552 self.structure += self.id100 

553 if len(data[16:]) >= 9: 

554 self.structure += self.extended 

555 Structure.__init__(self, data, alignment) 

556 

557 

558 def dump(self): 

559 print("[ATTRIBUTE %d]" % self['Id']) 

560 if len(self.rawData) > 28: 

561 print("Size : 0x%x" % self['Size']) 

562 if self['IVPresent'] > 0: 

563 print("IVSize : 0x%x" % self['IVSize']) 

564 print("IV : %s" % hexlify(self['IV'])) 

565 print("Data : %s" % hexlify(self['Data'])) 

566 

567class VAULT_ATTRIBUTE_MAP_ENTRY(Structure): 

568 structure = ( 

569 ('Id', '<L=0'), 

570 ('Offset', '<L=0'), 

571 ('Unknown1', '<L=0'), 

572 ) 

573 def dump(self): 

574 print("[MAP ENTRY %d @ 0x%.8x]" % (self['Id'], self['Offset'])) 

575 

576class VAULT_VCRD(Structure): 

577 structure = ( 

578 ('SchemaGuid', "16s=b"""), 

579 ('Unknown0', '<L=0'), 

580 ('LastWritten', '<Q=0'), 

581 ('Unknown1', '<L=0'), 

582 ('Unknown2', '<L=0'), 

583 ('FriendlyNameLen', '<L=0'), 

584 ('FriendlyNameL', '_-FriendlyName', 'self["FriendlyNameLen"]'), 

585 ('FriendlyName', ':'), 

586 ('AttributesMapsSize', '<L=0'), 

587 ('AttributeL', '_-AttributeMaps', 'self["AttributesMapsSize"]'), 

588 ('AttributeMaps', ':'), 

589 ('Data', ':'), 

590 ) 

591 

592 def __init__(self, data = None, alignment = 0): 

593 Structure.__init__(self, data, alignment) 

594 if data is not None: 594 ↛ exitline 594 didn't return from function '__init__', because the condition on line 594 was never false

595 # Process the MAP entries 

596 self.mapEntries = list() 

597 data = self['AttributeMaps'] 

598 for i in range(self['AttributesMapsSize']//len(VAULT_ATTRIBUTE_MAP_ENTRY())): 

599 entry = VAULT_ATTRIBUTE_MAP_ENTRY(data) 

600 self.mapEntries.append(entry) 

601 data = data[len(VAULT_ATTRIBUTE_MAP_ENTRY()):] 

602 

603 self.attributesLen = list() 

604 

605 for i in range(len(self.mapEntries)): 

606 if i > 0: 

607 self.attributesLen.append(self.mapEntries[i]['Offset']-self.mapEntries[i-1]['Offset']) 

608 

609 self.attributesLen.append(len(self.rawData) - self.mapEntries[i]['Offset'] ) 

610 

611 self.attributes = list() 

612 for i, entry in enumerate(self.mapEntries): 

613 attribute = VAULT_ATTRIBUTE(self.rawData[entry['Offset']:][:self.attributesLen[i]]) 

614 self.attributes.append(attribute) 

615 

616 # Do we have remaining data? 

617 self['Data'] = self.rawData[self.mapEntries[-1]['Offset']+len(self.attributes[-1].getData()):] 

618 

619 def dump(self): 

620 print("[VCRD]") 

621 print("SchemaGuid : %s" % bin_to_string(self['SchemaGuid'])) 

622 print("LastWritten : %s" % (datetime.utcfromtimestamp(getUnixTime(self['LastWritten'])))) 

623 print("FriendlyName: %s" % (self['FriendlyName'].decode('utf-16le'))) 

624 print() 

625 for i,entry in enumerate(self.mapEntries): 

626 entry.dump() 

627 self.attributes[i].dump() 

628 print() 

629 print("Remaining : %s" % (hexlify(self['Data']))) 

630 print() 

631 

632class VAULT_VPOL(Structure): 

633 structure = ( 

634 ('Version', '<L=0'), 

635 ('Guid', "16s=b"""), 

636 ('DescriptionLen', '<L=0'), 

637 ('_Description', '_-Description', 'self["DescriptionLen"]'), 

638 ('Description', ':'), 

639 ('Unknown', '12s=b""'), 

640 ('Size', '<L=0'), 

641 ('Guid2', "16s=b"""), 

642 ('Guid3', "16s=b"""), 

643 ('KeySize','<L=0'), 

644 ('_Blob', '_-Blob', 'self["KeySize"]'), 

645 ('Blob', ':', DPAPI_BLOB), 

646 ) 

647 

648 def dump(self): 

649 print("[VAULT_VPOL]") 

650 print("Version : %8x (%d)" % (self['Version'], self['Version'])) 

651 print("Guid : %s" % bin_to_string(self['Guid'])) 

652 print("Description : %s" % (self['Description'].decode('utf-16le'))) 

653 print("Size : 0x%.8x (%d)" % (self['Size'], self['Size'])) 

654 print("Guid2 : %s" % bin_to_string(self['Guid2'])) 

655 print("Guid3 : %s" % bin_to_string(self['Guid3'])) 

656 print("KeySize : 0x%.8x (%d)" % (self['KeySize'], self['KeySize'])) 

657 self['Blob'].dump() 

658 print() 

659 

660# from bcrypt.h 

661class BCRYPT_KEY_DATA_BLOB_HEADER(Structure): 

662 structure = ( 

663 ('dwMagic','<L=0'), 

664 ('dwVersion','<L=0'), 

665 ('cbKeyData','<L=0'), 

666 ('_bKey','_-bKey', 'self["cbKeyData"]'), 

667 ('bKey',':'), 

668 ) 

669 

670# from https://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEFCON-24-Jkambic-Cunning-With-Cng-Soliciting-Secrets-From-Schannel-WP.pdf 

671class BCRYPT_KSSM_DATA_BLOB_HEADER(Structure): 

672 structure = ( 

673 ('cbLength','<L=0'), 

674 ('dwKeyMagic','<L=0'), 

675 ('dwUnknown2','<L=0'), 

676 ('dwUnknown3','<L=0'), 

677 ('dwKeyBitLen','<L=0'), 

678 ('cbKeyLength','<L=0'), 

679 #('_bKey','_-bKey', 'self["cbKeyData"]'), 

680 #('AesKey','32s=""'), 

681 #('dwUnknown4','<L=0'), 

682 #('KeySchedule','448s=""'), 

683 #('dwUnknown5','<L=0'), 

684 #('cbScheduleLen','<L=0'), 

685 #('Unknown6','16s=""'), 

686 ) 

687 

688class BCRYPT_KEY_WRAP(Structure): 

689 structureKDBM = ( 

690 ('Size','<L=0'), 

691 ('Version','<L=0'), 

692 ('Unknown2','<L=0'), 

693 ('_bKeyBlob','_-bKeyBlob', 'self["Size"]'), 

694 ('bKeyBlob',':', BCRYPT_KEY_DATA_BLOB_HEADER), 

695 ) 

696 structureKSSM = ( 

697 ('Size','<L=0'), 

698 ('Version','<L=0'), 

699 ('Unknown2','<L=0'), 

700 ('_bKeyBlob','_-bKeyBlob', 'self["Size"]-8'), 

701 ('bKeyBlob',':'), 

702 ) 

703 def __init__(self, data = None, alignment = 0): 

704 if len(data) >=16: 704 ↛ 709line 704 didn't jump to line 709, because the condition on line 704 was never false

705 if data[0:1] == b'\x24' or data[0:1] == b'\x34': 705 ↛ 708line 705 didn't jump to line 708, because the condition on line 705 was never false

706 self.structure = self.structureKDBM 

707 else: 

708 self.structure = self.structureKSSM 

709 Structure.__init__(self, data, alignment) 

710 

711class VAULT_VPOL_KEYS(Structure): 

712 structure = ( 

713 ('Key1',':', BCRYPT_KEY_WRAP), 

714 ('Key2',':', BCRYPT_KEY_WRAP), 

715 ) 

716 def dump(self): 

717 print("[VAULT_VPOL_KEYS]") 

718 if self['Key1']['Size'] > 0x24: 718 ↛ 719line 718 didn't jump to line 719, because the condition on line 718 was never true

719 print('Key1:') 

720 hexdump(self['Key1']['bKeyBlob']) 

721 print('Key2:') 

722 hexdump(self['Key2']['bKeyBlob']) 

723 else: 

724 print('Key1: 0x%s' % hexlify(self['Key1']['bKeyBlob']['bKey']).decode('latin-1')) 

725 print('Key2: 0x%s' % hexlify(self['Key2']['bKeyBlob']['bKey']).decode('latin-1')) 

726 print() 

727 

728class VAULT_INTERNET_EXPLORER(Structure): 

729 structure = ( 

730 ('Version','<L=0'), 

731 ('Count','<L=0'), 

732 ('Unknown','<L=0'), 

733 ('Id1', '<L=0'), 

734 ('UsernameLen', '<L=0'), 

735 ('_Username', '_-Username','self["UsernameLen"]'), 

736 ('Username', ':'), 

737 

738 ('Id2', '<L=0'), 

739 ('ResourceLen', '<L=0'), 

740 ('_Resource', '_-Resource', 'self["ResourceLen"]'), 

741 ('Resource', ':'), 

742 

743 ('Id3', '<L=0'), 

744 ('PasswordLen', '<L=0'), 

745 ('_Password', '_-Password', 'self["PasswordLen"]'), 

746 ('Password', ':'), 

747 ) 

748 def fromString(self, data): 

749 Structure.fromString(self, data) 

750 

751 def dump(self): 

752 print("[Internet Explorer]") 

753 print('Username : %s' % self['Username'].decode('utf-16le')) 

754 print('Resource : %s' % self['Resource'].decode('utf-16le')) 

755 print('Password : %s' % (hexlify(self['Password']))) 

756 print() 

757 

758class VAULT_WIN_BIO_KEY(Structure): 

759 structure = ( 

760 ('Version','<L=0'), 

761 ('Count','<L=0'), 

762 ('Unknown','<L=0'), 

763 ('Id1', '<L=0'), 

764 ('SidLen', '<L=0'), 

765 ('_Sid', '_-Sid','self["SidLen"]'), 

766 ('Sid', ':'), 

767 

768 ('Id2', '<L=0'), 

769 ('NameLen', '<L=0'), 

770 ('_Name', '_-Name', 'self["NameLen"]'), 

771 ('Name', ':'), 

772 

773 ('Id3', '<L=0'), 

774 ('BioKeyLen', '<L=0'), 

775 ('_BioKey', '_-BioKey', 'self["BioKeyLen"]'), 

776 ('BioKey', ':'), 

777 ) 

778 def fromString(self, data): 

779 Structure.fromString(self, data) 

780 if data is not None: 

781 bioKey = BCRYPT_KEY_DATA_BLOB_HEADER(unhexlify(self['BioKey'].decode('utf-16le')[:-1])) 

782 self['BioKey'] = bioKey 

783 

784 def dump(self): 

785 print("[WINDOWS BIOMETRIC KEY]") 

786 print('Sid : %s' % RPC_SID(b'\x05\x00\x00\x00'+self['Sid']).formatCanonical()) 

787 print('Friendly Name: %s' % self['Name'].decode('utf-16le')) 

788 print('Biometric Key: 0x%s' % (hexlify(self['BioKey']['bKey'])).decode('latin-1')) 

789 print() 

790 

791class NGC_LOCAL_ACCOOUNT(Structure): 

792 structure = ( 

793 ('Version','<L=0'), 

794 ('UnlockKeySize','<L=0'), 

795 ('IVSize','<L=0'), 

796 ('CipherTextSize','<L=0'), 

797 ('MustBeZeroTest','<L=0'), 

798 ('_UnlockKey', '_-UnlockKey', 'self["UnlockKeySize"]'), 

799 ('UnlockKey', ':'), 

800 ('_IV', '_-IV', 'self["IVSize"]'), 

801 ('IV', ':'), 

802 ('_CipherText', '_-CipherText', 'self["CipherTextSize"]'), 

803 ('CipherText', ':'), 

804 ) 

805# def __init__(self, data=None, alignment = 0): 

806# hexdump(data) 

807 def dump(self): 

808 print("[NGC LOCAL ACCOOUNT]") 

809 print('UnlockKey : %s' % hexlify(self["UnlockKey"])) 

810 print('IV : %s' % hexlify(self["IV"])) 

811 print('CipherText : %s' % hexlify(self["CipherText"])) 

812 

813class VAULT_NGC_ACCOOUNT(Structure): 

814 structure = ( 

815 ('Version','<L=0'), 

816 ('Count','<L=0'), 

817 ('Unknown','<L=0'), 

818 ('Id1', '<L=0'), 

819 ('SidLen', '<L=0'), 

820 ('_Sid', '_-Sid','self["SidLen"]'), 

821 ('Sid', ':'), 

822 

823 ('Id2', '<L=0'), 

824 ('NameLen', '<L=0'), 

825 ('_Name', '_-Name', 'self["NameLen"]'), 

826 ('Name', ':'), 

827 

828 ('Id3', '<L=0'), 

829 ('BlobLen', '<L=0'), 

830 ('Blob', '_-Blob', 'self["BlobLen"]'), 

831 ('Blob', ':', NGC_LOCAL_ACCOOUNT), 

832 ) 

833 def dump(self): 

834 print("[NGC VAULT]") 

835 print('Sid : %s' % RPC_SID(b'\x05\x00\x00\x00'+self['Sid']).formatCanonical()) 

836 print('Friendly Name: %s' % self['Name'].decode('utf-16le')) 

837 self['Blob'].dump() 

838 print() 

839 

840VAULT_KNOWN_SCHEMAS = { 

841 'WinBio Key': VAULT_WIN_BIO_KEY, 

842 'NGC Local Accoount Logon Vault Credential': VAULT_NGC_ACCOOUNT, 

843 'Internet Explorer': VAULT_INTERNET_EXPLORER, 

844} 

845 

846class CREDENTIAL_ATTRIBUTE(Structure): 

847 # some info here https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credential_attributea 

848 structure = ( 

849 ('Flags','<L=0'), 

850 

851 ('KeyWordSize', '<L=0'), 

852 ('_KeyWord', '_-KeyWord', 'self["KeyWordSize"]'), 

853 ('KeyWord', ':'), 

854 

855 ('DataSize', '<L=0'), 

856 ('_Data', '_-Data', 'self["DataSize"]'), 

857 ('Data', ':'), 

858 ) 

859 

860 def dump(self): 

861 print("KeyWord : %s" % (self['KeyWord'].decode('utf-16le'))) 

862 #print("Flags : %8x (%s)" % (self['Flags'], getFlags(CREDENTIAL_FLAGS, self['Flags']))) 

863 print("Data : ") 

864 hexdump(self['Data']) 

865 

866class CREDENTIAL_BLOB(Structure): 

867 # some info here https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credentiala 

868 structure = ( 

869 ('Flags','<L=0'), 

870 ('Size','<L=0'), 

871 ('Unknown0','<L=0'), 

872 ('Type','<L=0'), 

873 ('Flags2','<L=0'), 

874 ('LastWritten','<Q=0'), 

875 ('Unknown2','<L=0'), 

876 ('Persist','<L=0'), 

877 ('AttrCount','<L=0'), 

878 ('Unknown3','<Q=0'), 

879 

880 ('TargetSize','<L=0'), 

881 ('_Target','_-Target','self["TargetSize"]'), 

882 ('Target',':'), 

883 

884 ('TargetAliasSize', '<L=0'), 

885 ('_TargetAliast', '_-TargetAlias', 'self["TargetAliasSize"]'), 

886 ('TargetAlias', ':'), 

887 

888 ('DescriptionSize', '<L=0'), 

889 ('_Description', '_-Description', 'self["DescriptionSize"]'), 

890 ('Description', ':'), 

891 

892 ('UnknownSize', '<L=0'), 

893 ('_Unknown', '_-Unknown', 'self["UnknownSize"]'), 

894 ('Unknown', ':'), 

895 

896 ('UsernameSize', '<L=0'), 

897 ('_Username', '_-Username', 'self["UsernameSize"]'), 

898 ('Username', ':'), 

899 

900 ('Unknown3Size', '<L=0'), 

901 ('_Unknown3', '_-Unknown3', 'self["Unknown3Size"]'), 

902 ('Unknown3', ':'), 

903 

904 ('Remaining', ':'), 

905 ) 

906 def __init__(self, data = None, alignment = 0): 

907 Structure.__init__(self, data, alignment) 

908 self.attributes = 0 

909 if data is not None: 909 ↛ exitline 909 didn't return from function '__init__', because the condition on line 909 was never false

910 # Unpack the attributes 

911 remaining = self['Remaining'] 

912 self.attributes = list() 

913 for i in range(self['AttrCount']): 913 ↛ 914line 913 didn't jump to line 914, because the loop on line 913 never started

914 attr = CREDENTIAL_ATTRIBUTE(remaining) 

915 self.attributes.append(attr) 

916 remaining = remaining[len(attr):] 

917 

918 def dump(self): 

919 print("[CREDENTIAL]") 

920 print("LastWritten : %s" % (datetime.utcfromtimestamp(getUnixTime(self['LastWritten'])))) 

921 print("Flags : 0x%.8x (%s)" % (self['Flags'], getFlags(CREDENTIAL_FLAGS, self['Flags']))) 

922 print("Persist : 0x%.8x (%s)" % (self['Persist'], CREDENTIAL_PERSIST(self['Persist']).name)) 

923 print("Type : 0x%.8x (%s)" % (self['Type'], CREDENTIAL_PERSIST(self['Type']).name)) 

924 print("Target : %s" % (self['Target'].decode('utf-16le'))) 

925 print("Description : %s" % (self['Description'].decode('utf-16le'))) 

926 print("Unknown : %s" % (self['Unknown'].decode('utf-16le'))) 

927 print("Username : %s" % (self['Username'].decode('utf-16le'))) 

928 try: 

929 print("Unknown : %s" % (self['Unknown3'].decode('utf-16le'))) 

930 except UnicodeDecodeError: 

931 print("Unknown : %s" % (self['Unknown3'].decode('latin-1'))) 

932 

933 print() 

934 for entry in self.attributes: 934 ↛ 935line 934 didn't jump to line 935, because the loop on line 934 never started

935 entry.dump() 

936 

937ALG_ID = '<L=0' 

938 

939class P_BACKUP_KEY(Structure): 

940 structure = ( 

941 ('Version', '<L=0'), 

942 ('Data', ':'), 

943 ) 

944 

945class PREFERRED_BACKUP_KEY(Structure): 

946 structure = ( 

947 ('Version', '<L=0'), 

948 ('KeyLength', '<L=0'), 

949 ('CertificateLength', '<L=0'), 

950 ('Data', ':'), 

951 ) 

952 

953class PVK_FILE_HDR(Structure): 

954 structure = ( 

955 ('dwMagic', '<L=0'), 

956 ('dwVersion', '<L=0'), 

957 ('dwKeySpec', '<L=0'), 

958 ('dwEncryptType', '<L=0'), 

959 ('cbEncryptData', '<L=0'), 

960 ('cbPvk', '<L=0'), 

961 ) 

962 

963class PUBLICKEYSTRUC(Structure): 

964 structure = ( 

965 ('bType', '<B=0'), 

966 ('bVersion', '<B=0'), 

967 ('reserved', '<H=0'), 

968 ('aiKeyAlg', ALG_ID), 

969 ) 

970 

971class RSAPUBKEY(Structure): 

972 structure = ( 

973 ('magic', '<L=0'), 

974 ('bitlen', '<L=0'), 

975 ('pubexp', '<L=0'), 

976 ) 

977 

978class PUBLIC_KEY_BLOB(Structure): 

979 structure = ( 

980 ('publickeystruc', ':', PUBLICKEYSTRUC), 

981 ('rsapubkey', ':', RSAPUBKEY), 

982 ('_modulus', '_-modulus', 'self["rsapubkey"]["bitlen"] // 8'), 

983 ) 

984 

985class PRIVATE_KEY_BLOB(Structure): 

986 structure = ( 

987 ('publickeystruc', ':', PUBLICKEYSTRUC), 

988 ('rsapubkey', ':', RSAPUBKEY), 

989 ('_modulus', '_-modulus', 'self["rsapubkey"]["bitlen"] // 8'), 

990 ('modulus', ':'), 

991 ('_prime1', '_-prime1', 'self["rsapubkey"]["bitlen"] // 16'), 

992 ('prime1', ':'), 

993 ('_prime2', '_-prime2', 'self["rsapubkey"]["bitlen"] // 16'), 

994 ('prime2', ':'), 

995 ('_exponent1', '_-exponent1', 'self["rsapubkey"]["bitlen"] // 16'), 

996 ('exponent1', ':'), 

997 ('_exponent2', '_-exponent2', 'self["rsapubkey"]["bitlen"] // 16'), 

998 ('exponent2', ':'), 

999 ('_coefficient', '_-coefficient', 'self["rsapubkey"]["bitlen"] // 16'), 

1000 ('coefficient', ':'), 

1001 ('_privateExponent', '_-privateExponent', 'self["rsapubkey"]["bitlen"] // 8'), 

1002 ('privateExponent', ':'), 

1003 ) 

1004 

1005class SIMPLE_KEY_BLOB(Structure): 

1006 structure = ( 

1007 ('publickeystruc', ':', PUBLICKEYSTRUC), 

1008 ('algid', ALG_ID), 

1009 ('encryptedkey', ':'), 

1010 ) 

1011 

1012class DPAPI_DOMAIN_RSA_MASTER_KEY(Structure): 

1013 structure = ( 

1014 ('cbMasterKey', '<L=0'), 

1015 ('cbSuppKey', '<L=0'), 

1016 ('buffer', ':'), 

1017 ) 

1018 

1019def privatekeyblob_to_pkcs1(key): 

1020 ''' 

1021 parse private key into pkcs#1 format 

1022 :param key: 

1023 :return: 

1024 ''' 

1025 modulus = bytes_to_long(key['modulus'][::-1]) # n 

1026 prime1 = bytes_to_long(key['prime1'][::-1]) # p 

1027 prime2 = bytes_to_long(key['prime2'][::-1]) # q 

1028 exp1 = bytes_to_long(key['exponent1'][::-1]) 

1029 exp2 = bytes_to_long(key['exponent2'][::-1]) 

1030 coefficient = bytes_to_long(key['coefficient'][::-1]) 

1031 privateExp = bytes_to_long(key['privateExponent'][::-1]) # d 

1032 if PY3: 

1033 long = int 

1034 pubExp = long(key['rsapubkey']['pubexp']) # e 

1035 # RSA.Integer(prime2).inverse(prime1) # u 

1036 

1037 r = RSA.construct((modulus, pubExp, privateExp, prime1, prime2)) 

1038 return r