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# Impacket - Collection of Python classes for working with network protocols. 

2# 

3# SECUREAUTH LABS. Copyright (C) 2021 SecureAuth Corporation. All rights reserved. 

4# 

5# This software is provided under a slightly modified version 

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

7# for more information. 

8# 

9# Description: 

10# DPAPI and Windows Vault parsing structures and manipulation 

11# 

12# Author: 

13# Alberto Solino (@agsolino) 

14# 

15# References: 

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

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

18# - https://github.com/jordanbtucker/dpapick 

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

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

21# - https://www.passcape.com/windows_password_recovery_vault_explorer 

22# - https://www.passcape.com/windows_password_recovery_dpapi_master_key 

23# 

24 

25from __future__ import division 

26from __future__ import print_function 

27import sys 

28 

29from struct import unpack 

30from datetime import datetime 

31from binascii import unhexlify, hexlify 

32from struct import pack 

33from Cryptodome.Hash import HMAC, SHA512, SHA1 

34from Cryptodome.Cipher import AES, DES3 

35from Cryptodome.Util.Padding import unpad 

36from Cryptodome.PublicKey import RSA 

37from Cryptodome.Util.number import bytes_to_long 

38from six import PY3 

39 

40from impacket.ese import getUnixTime 

41from impacket.structure import Structure, hexdump 

42from impacket.uuid import bin_to_string 

43from impacket.dcerpc.v5.enum import Enum 

44from impacket.dcerpc.v5.dtypes import RPC_SID 

45 

46# Algorithm classes 

47ALG_CLASS_ANY = (0) 

48ALG_CLASS_SIGNATURE = (1 << 13) 

49ALG_CLASS_MSG_ENCRYPT = (2 << 13) 

50ALG_CLASS_DATA_ENCRYPT = (3 << 13) 

51ALG_CLASS_HASH = (4 << 13) 

52ALG_CLASS_KEY_EXCHANGE = (5 << 13) 

53ALG_CLASS_ALL = (7 << 13) 

54 

55# Algorithm types 

56ALG_TYPE_ANY = (0) 

57ALG_TYPE_DSS = (1 << 9) 

58ALG_TYPE_RSA = (2 << 9) 

59ALG_TYPE_BLOCK = (3 << 9) 

60ALG_TYPE_STREAM = (4 << 9) 

61ALG_TYPE_DH = (5 << 9) 

62ALG_TYPE_SECURECHANNEL = (6 << 9) 

63ALG_SID_ANY = (0) 

64ALG_SID_RSA_ANY = 0 

65ALG_SID_RSA_PKCS = 1 

66ALG_SID_RSA_MSATWORK = 2 

67ALG_SID_RSA_ENTRUST = 3 

68ALG_SID_RSA_PGP = 4 

69ALG_SID_DSS_ANY = 0 

70ALG_SID_DSS_PKCS = 1 

71ALG_SID_DSS_DMS = 2 

72ALG_SID_ECDSA = 3 

73 

74# Block cipher sub ids 

75ALG_SID_DES = 1 

76ALG_SID_3DES = 3 

77ALG_SID_DESX = 4 

78ALG_SID_IDEA = 5 

79ALG_SID_CAST = 6 

80ALG_SID_SAFERSK64 = 7 

81ALG_SID_SAFERSK128 = 8 

82ALG_SID_3DES_112 = 9 

83ALG_SID_CYLINK_MEK = 12 

84ALG_SID_RC5 = 13 

85ALG_SID_AES_128 = 14 

86ALG_SID_AES_192 = 15 

87ALG_SID_AES_256 = 16 

88ALG_SID_AES = 17 

89ALG_SID_SKIPJACK = 10 

90ALG_SID_TEK = 11 

91 

92CRYPT_MODE_CBCI = 6 # ANSI CBC Interleaved 

93CRYPT_MODE_CFBP = 7 # ANSI CFB Pipelined 

94CRYPT_MODE_OFBP = 8 # ANSI OFB Pipelined 

95CRYPT_MODE_CBCOFM = 9 # ANSI CBC + OF Masking 

96CRYPT_MODE_CBCOFMI = 10 # ANSI CBC + OFM Interleaved 

97 

98ALG_SID_RC2 = 2 

99ALG_SID_RC4 = 1 

100ALG_SID_SEAL = 2 

101 

102# Diffie - Hellman sub - ids 

103ALG_SID_DH_SANDF = 1 

104ALG_SID_DH_EPHEM = 2 

105ALG_SID_AGREED_KEY_ANY = 3 

106ALG_SID_KEA = 4 

107ALG_SID_ECDH = 5 

108 

109# Hash sub ids 

110ALG_SID_MD2 = 1 

111ALG_SID_MD4 = 2 

112ALG_SID_MD5 = 3 

113ALG_SID_SHA = 4 

114ALG_SID_SHA1 = 4 

115ALG_SID_MAC = 5 

116ALG_SID_RIPEMD = 6 

117ALG_SID_RIPEMD160 = 7 

118ALG_SID_SSL3SHAMD5 = 8 

119ALG_SID_HMAC = 9 

120ALG_SID_TLS1PRF = 10 

121ALG_SID_HASH_REPLACE_OWF = 11 

122ALG_SID_SHA_256 = 12 

123ALG_SID_SHA_384 = 13 

124ALG_SID_SHA_512 = 14 

125 

126# secure channel sub ids 

127ALG_SID_SSL3_MASTER = 1 

128ALG_SID_SCHANNEL_MASTER_HASH = 2 

129ALG_SID_SCHANNEL_MAC_KEY = 3 

130ALG_SID_PCT1_MASTER = 4 

131ALG_SID_SSL2_MASTER = 5 

132ALG_SID_TLS1_MASTER = 6 

133ALG_SID_SCHANNEL_ENC_KEY = 7 

134ALG_SID_ECMQV = 1 

135 

136def getFlags(myenum, flags): 

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

138 

139class FLAGS(Enum): 

140 CRYPTPROTECT_UI_FORBIDDEN = 0x1 

141 CRYPTPROTECT_LOCAL_MACHINE = 0x4 

142 CRYPTPROTECT_CRED_SYNC = 0x8 

143 CRYPTPROTECT_AUDIT = 0x10 

144 CRYPTPROTECT_VERIFY_PROTECTION = 0x40 

145 CRYPTPROTECT_CRED_REGENERATE = 0x80 

146 CRYPTPROTECT_SYSTEM = 0x20000000 

147 

148# algorithm identifier definitions 

149class ALGORITHMS(Enum): 

150 CALG_MD2 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD2) 

151 CALG_MD4 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD4) 

152 CALG_MD5 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5) 

153 CALG_SHA = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA) 

154 CALG_SHA1 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1) 

155 CALG_RSA_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY) 

156 CALG_DSS_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY) 

157 CALG_NO_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | ALG_SID_ANY) 

158 CALG_RSA_KEYX = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_RSA|ALG_SID_RSA_ANY) 

159 CALG_DES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_DES) 

160 CALG_3DES_112 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_3DES_112) 

161 CALG_3DES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_3DES) 

162 CALG_DESX = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_DESX) 

163 CALG_RC2 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC2) 

164 CALG_RC4 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_STREAM|ALG_SID_RC4) 

165 CALG_SEAL = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_STREAM|ALG_SID_SEAL) 

166 CALG_DH_SF = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_DH_SANDF) 

167 CALG_DH_EPHEM = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_DH_EPHEM) 

168 CALG_AGREEDKEY_ANY = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_AGREED_KEY_ANY) 

169 CALG_KEA_KEYX = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_KEA) 

170 CALG_HUGHES_MD5 = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_ANY|ALG_SID_MD5) 

171 CALG_SKIPJACK = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_SKIPJACK) 

172 CALG_TEK = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_TEK) 

173 CALG_SSL3_SHAMD5 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5) 

174 CALG_SSL3_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SSL3_MASTER) 

175 CALG_SCHANNEL_MASTER_HASH = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_MASTER_HASH) 

176 CALG_SCHANNEL_MAC_KEY = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_MAC_KEY) 

177 CALG_SCHANNEL_ENC_KEY = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_ENC_KEY) 

178 CALG_PCT1_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_PCT1_MASTER) 

179 CALG_SSL2_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SSL2_MASTER) 

180 CALG_TLS1_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_TLS1_MASTER) 

181 CALG_RC5 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC5) 

182 CALG_HMAC = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) 

183 CALG_TLS1PRF = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_TLS1PRF) 

184 CALG_HASH_REPLACE_OWF = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HASH_REPLACE_OWF) 

185 CALG_AES_128 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_128) 

186 CALG_AES_192 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_192) 

187 CALG_AES_256 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_256) 

188 CALG_AES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES) 

189 CALG_SHA_256 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) 

190 CALG_SHA_384 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) 

191 CALG_SHA_512 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) 

192 CALG_ECDH = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH) 

193 CALG_ECMQV = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV) 

194 CALG_ECDSA = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA) 

195 

196class CREDENTIAL_FLAGS(Enum): 

197 CRED_FLAGS_PASSWORD_FOR_CERT = 0x1 

198 CRED_FLAGS_PROMPT_NOW = 0x2 

199 CRED_FLAGS_USERNAME_TARGET = 0x4 

200 CRED_FLAGS_OWF_CRED_BLOB = 0x8 

201 CRED_FLAGS_REQUIRE_CONFIRMATION = 0x10 

202 CRED_FLAGS_WILDCARD_MATCH = 0x20 

203 CRED_FLAGS_VSM_PROTECTED = 0x40 

204 CRED_FLAGS_NGC_CERT = 0x80 

205 

206class CREDENTIAL_TYPE(Enum): 

207 CRED_TYPE_GENERIC = 0x1 

208 CRED_TYPE_DOMAIN_PASSWORD = 0x2 

209 CRED_TYPE_DOMAIN_CERTIFICATE = 0x3 

210 CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 0x4 

211 CRED_TYPE_GENERIC_CERTIFICATE = 0x5 

212 CRED_TYPE_DOMAIN_EXTENDED = 0x6 

213 CRED_TYPE_MAXIMUM = 0x7 

214 CRED_TYPE_MAXIMUM_EX = 0x8 

215 

216class CREDENTIAL_PERSIST(Enum): 

217 CRED_PERSIST_NONE = 0x0 

218 CRED_PERSIST_SESSION = 0x1 

219 CRED_PERSIST_LOCAL_MACHINE = 0x2 

220 CRED_PERSIST_ENTERPRISE = 0x3 

221 

222ALGORITHMS_DATA = { 

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

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

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

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

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

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

229} 

230 

231class MasterKeyFile(Structure): 

232 structure = ( 

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

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

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

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

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

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

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

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

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

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

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

244 ) 

245 

246 def dump(self): 

247 print("[MASTERKEYFILE]") 

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

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

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

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

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

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

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

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

256 print() 

257 

258class MasterKey(Structure): 

259 structure = ( 

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

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

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

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

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

265 ('data', ':'), 

266 ) 

267 

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

269 Structure.__init__(self, data, alignment) 

270 self.decryptedKey = None 

271 

272 def dump(self): 

273 print("[MASTERKEY]") 

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

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

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

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

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

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

280 print() 

281 

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

283 keyMaterial = b"" 

284 i = 1 

285 while len(keyMaterial) < keylen: 

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

287 i += 1 

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

289 for r in range(count - 1): 

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

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

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

293 else: 

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

295 keyMaterial += derived 

296 

297 return keyMaterial[:keylen] 

298 

299 def decrypt(self, key): 

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

301 hashModule = SHA1 

302 else: 

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

304 

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

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

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

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

309 

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

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

312 

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

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

315 

316 decryptedKey = cleartext[-64:] 

317 hmacSalt = cleartext[:16] 

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

319 

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

321 

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

323 

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

325 self.decryptedKey = decryptedKey 

326 return decryptedKey 

327 else: 

328 return None 

329 

330class CredHist(Structure): 

331 structure = ( 

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

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

334 ) 

335 def dump(self): 

336 print("[CREDHIST]") 

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

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

339 print() 

340 

341class DomainKey(Structure): 

342 structure = ( 

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

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

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

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

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

348 ('SecretData', ':'), 

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

350 ('AccessCheck', ':'), 

351 ) 

352 def dump(self): 

353 print("[DOMAINKEY]") 

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

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

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

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

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

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

360 print() 

361 

362class DPAPI_SYSTEM(Structure): 

363 structure = ( 

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

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

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

367 ) 

368 

369 def dump(self): 

370 print("[DPAPI_SYSTEM]") 

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

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

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

374 print() 

375 

376class CredentialFile(Structure): 

377 structure = ( 

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

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

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

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

382 ('Data', ':'), 

383 ) 

384 #def dump(self): 

385 # print("[CREDENTIAL FILE]") 

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

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

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

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

390 # print() 

391 

392 

393class DPAPI_BLOB(Structure): 

394 structure = ( 

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

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

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

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

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

400 

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

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

403 ('Description', ':'), 

404 

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

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

407 

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

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

410 ('Salt', ':'), 

411 

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

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

414 ('HMacKey', ':'), 

415 

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

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

418 

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

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

421 ('HMac', ':'), 

422 

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

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

425 ('Data', ':'), 

426 

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

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

429 ('Sign', ':'), 

430 

431 ) 

432 

433 def dump(self): 

434 print("[BLOB]") 

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

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

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

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

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

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

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

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

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

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

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

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

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

448 print() 

449 

450 

451 def deriveKey(self, sessionKey): 

452 def fixparity(deskey): 

453 from six import indexbytes, b 

454 temp = b'' 

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

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

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

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

459 else: 

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

461 return temp 

462 

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

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

465 else: 

466 derivedKey = sessionKey 

467 

468 

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

470 # Extend the key 

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

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

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

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

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

476 derivedKey = fixparity(derivedKey) 

477 

478 return derivedKey 

479 

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

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

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

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

484 sessionKey.update(entropy) 

485 

486 sessionKey = sessionKey.digest() 

487 

488 # Derive the key 

489 derivedKey = self.deriveKey(sessionKey) 

490 

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

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

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

494 

495 # Now check the signature 

496 

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

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

499 

500 # Calculate the different HMACKeys 

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

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

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

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

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

506 

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

508 hmacCalculated1.update(a.digest()) 

509 

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

511 hmacCalculated1.update(entropy) 

512 

513 hmacCalculated1.update(toSign) 

514 

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

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

517 hmacCalculated3.update(entropy) 

518 

519 hmacCalculated3.update(toSign) 

520 

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

522 return cleartext 

523 else: 

524 return None 

525 

526class VAULT_ATTRIBUTE(Structure): 

527 structure = ( 

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

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

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

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

532 ) 

533 

534 padding = ( 

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

536 ) 

537 

538 id100 = ( 

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

540 ) 

541 

542 extended = ( 

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

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

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

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

547 ('IV', ':'), 

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

549 ('Data',':'), 

550 ) 

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

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

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

554 self.structure += self.padding 

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

556 self.structure += self.id100 

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

558 self.structure += self.extended 

559 Structure.__init__(self, data, alignment) 

560 

561 

562 def dump(self): 

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

564 if len(self.rawData) > 28: 

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

566 if self['IVPresent'] > 0: 

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

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

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

570 

571class VAULT_ATTRIBUTE_MAP_ENTRY(Structure): 

572 structure = ( 

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

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

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

576 ) 

577 def dump(self): 

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

579 

580class VAULT_VCRD(Structure): 

581 structure = ( 

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

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

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

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

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

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

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

589 ('FriendlyName', ':'), 

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

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

592 ('AttributeMaps', ':'), 

593 ('Data', ':'), 

594 ) 

595 

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

597 Structure.__init__(self, data, alignment) 

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

599 # Process the MAP entries 

600 self.mapEntries = list() 

601 data = self['AttributeMaps'] 

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

603 entry = VAULT_ATTRIBUTE_MAP_ENTRY(data) 

604 self.mapEntries.append(entry) 

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

606 

607 self.attributesLen = list() 

608 

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

610 if i > 0: 

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

612 

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

614 

615 self.attributes = list() 

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

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

618 self.attributes.append(attribute) 

619 

620 # Do we have remaining data? 

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

622 

623 def dump(self): 

624 print("[VCRD]") 

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

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

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

628 print() 

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

630 entry.dump() 

631 self.attributes[i].dump() 

632 print() 

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

634 print() 

635 

636class VAULT_VPOL(Structure): 

637 structure = ( 

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

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

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

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

642 ('Description', ':'), 

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

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

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

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

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

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

649 ('Blob', ':', DPAPI_BLOB), 

650 ) 

651 

652 def dump(self): 

653 print("[VAULT_VPOL]") 

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

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

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

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

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

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

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

661 self['Blob'].dump() 

662 print() 

663 

664# from bcrypt.h 

665class BCRYPT_KEY_DATA_BLOB_HEADER(Structure): 

666 structure = ( 

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

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

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

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

671 ('bKey',':'), 

672 ) 

673 

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

675class BCRYPT_KSSM_DATA_BLOB_HEADER(Structure): 

676 structure = ( 

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

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

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

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

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

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

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

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

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

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

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

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

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

690 ) 

691 

692class BCRYPT_KEY_WRAP(Structure): 

693 structureKDBM = ( 

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

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

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

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

698 ('bKeyBlob',':', BCRYPT_KEY_DATA_BLOB_HEADER), 

699 ) 

700 structureKSSM = ( 

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

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

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

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

705 ('bKeyBlob',':'), 

706 ) 

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

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

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

710 self.structure = self.structureKDBM 

711 else: 

712 self.structure = self.structureKSSM 

713 Structure.__init__(self, data, alignment) 

714 

715class VAULT_VPOL_KEYS(Structure): 

716 structure = ( 

717 ('Key1',':', BCRYPT_KEY_WRAP), 

718 ('Key2',':', BCRYPT_KEY_WRAP), 

719 ) 

720 def dump(self): 

721 print("[VAULT_VPOL_KEYS]") 

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

723 print('Key1:') 

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

725 print('Key2:') 

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

727 else: 

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

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

730 print() 

731 

732class VAULT_INTERNET_EXPLORER(Structure): 

733 structure = ( 

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

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

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

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

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

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

740 ('Username', ':'), 

741 

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

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

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

745 ('Resource', ':'), 

746 

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

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

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

750 ('Password', ':'), 

751 ) 

752 def fromString(self, data): 

753 Structure.fromString(self, data) 

754 

755 def dump(self): 

756 print("[Internet Explorer]") 

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

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

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

760 print() 

761 

762class VAULT_WIN_BIO_KEY(Structure): 

763 structure = ( 

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

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

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

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

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

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

770 ('Sid', ':'), 

771 

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

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

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

775 ('Name', ':'), 

776 

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

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

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

780 ('BioKey', ':'), 

781 ) 

782 def fromString(self, data): 

783 Structure.fromString(self, data) 

784 if data is not None: 

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

786 self['BioKey'] = bioKey 

787 

788 def dump(self): 

789 print("[WINDOWS BIOMETRIC KEY]") 

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

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

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

793 print() 

794 

795class NGC_LOCAL_ACCOOUNT(Structure): 

796 structure = ( 

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

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

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

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

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

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

803 ('UnlockKey', ':'), 

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

805 ('IV', ':'), 

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

807 ('CipherText', ':'), 

808 ) 

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

810# hexdump(data) 

811 def dump(self): 

812 print("[NGC LOCAL ACCOOUNT]") 

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

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

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

816 

817class VAULT_NGC_ACCOOUNT(Structure): 

818 structure = ( 

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

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

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

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

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

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

825 ('Sid', ':'), 

826 

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

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

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

830 ('Name', ':'), 

831 

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

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

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

835 ('Blob', ':', NGC_LOCAL_ACCOOUNT), 

836 ) 

837 def dump(self): 

838 print("[NGC VAULT]") 

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

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

841 self['Blob'].dump() 

842 print() 

843 

844VAULT_KNOWN_SCHEMAS = { 

845 'WinBio Key': VAULT_WIN_BIO_KEY, 

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

847 'Internet Explorer': VAULT_INTERNET_EXPLORER, 

848} 

849 

850class CREDENTIAL_ATTRIBUTE(Structure): 

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

852 structure = ( 

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

854 

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

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

857 ('KeyWord', ':'), 

858 

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

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

861 ('Data', ':'), 

862 ) 

863 

864 def dump(self): 

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

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

867 print("Data : ") 

868 hexdump(self['Data']) 

869 

870class CREDENTIAL_BLOB(Structure): 

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

872 structure = ( 

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

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

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

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

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

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

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

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

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

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

883 

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

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

886 ('Target',':'), 

887 

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

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

890 ('TargetAlias', ':'), 

891 

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

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

894 ('Description', ':'), 

895 

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

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

898 ('Unknown', ':'), 

899 

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

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

902 ('Username', ':'), 

903 

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

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

906 ('Unknown3', ':'), 

907 

908 ('Remaining', ':'), 

909 ) 

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

911 Structure.__init__(self, data, alignment) 

912 self.attributes = 0 

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

914 # Unpack the attributes 

915 remaining = self['Remaining'] 

916 self.attributes = list() 

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

918 attr = CREDENTIAL_ATTRIBUTE(remaining) 

919 self.attributes.append(attr) 

920 remaining = remaining[len(attr):] 

921 

922 def dump(self): 

923 print("[CREDENTIAL]") 

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

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

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

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

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

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

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

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

932 try: 

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

934 except UnicodeDecodeError: 

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

936 

937 print() 

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

939 entry.dump() 

940 

941ALG_ID = '<L=0' 

942 

943class P_BACKUP_KEY(Structure): 

944 structure = ( 

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

946 ('Data', ':'), 

947 ) 

948 

949class PREFERRED_BACKUP_KEY(Structure): 

950 structure = ( 

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

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

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

954 ('Data', ':'), 

955 ) 

956 

957class PVK_FILE_HDR(Structure): 

958 structure = ( 

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

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

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

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

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

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

965 ) 

966 

967class PUBLICKEYSTRUC(Structure): 

968 structure = ( 

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

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

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

972 ('aiKeyAlg', ALG_ID), 

973 ) 

974 

975class RSAPUBKEY(Structure): 

976 structure = ( 

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

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

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

980 ) 

981 

982class PUBLIC_KEY_BLOB(Structure): 

983 structure = ( 

984 ('publickeystruc', ':', PUBLICKEYSTRUC), 

985 ('rsapubkey', ':', RSAPUBKEY), 

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

987 ) 

988 

989class PRIVATE_KEY_BLOB(Structure): 

990 structure = ( 

991 ('publickeystruc', ':', PUBLICKEYSTRUC), 

992 ('rsapubkey', ':', RSAPUBKEY), 

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

994 ('modulus', ':'), 

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

996 ('prime1', ':'), 

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

998 ('prime2', ':'), 

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

1000 ('exponent1', ':'), 

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

1002 ('exponent2', ':'), 

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

1004 ('coefficient', ':'), 

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

1006 ('privateExponent', ':'), 

1007 ) 

1008 

1009class SIMPLE_KEY_BLOB(Structure): 

1010 structure = ( 

1011 ('publickeystruc', ':', PUBLICKEYSTRUC), 

1012 ('algid', ALG_ID), 

1013 ('encryptedkey', ':'), 

1014 ) 

1015 

1016class DPAPI_DOMAIN_RSA_MASTER_KEY(Structure): 

1017 structure = ( 

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

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

1020 ('buffer', ':'), 

1021 ) 

1022 

1023def privatekeyblob_to_pkcs1(key): 

1024 ''' 

1025 parse private key into pkcs#1 format 

1026 :param key: 

1027 :return: 

1028 ''' 

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

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

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

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

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

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

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

1036 if PY3: 

1037 long = int 

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

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

1040 

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

1042 return r