async def get_NKLM_key(self): logger.debug('[SECURITY] Fetching NK$LM key...') if self.lsa_key is None: await self.get_lsa_key() value = await self.hive.get_value( 'Policy\\Secrets\\NL$KM\\CurrVal\\default') if value is None: logger.error('[SECURITY] Could not find NL$KM in registry') raise Exception('Could not find NL$KM in registry :(') if self.lsa_secret_key_vista_type is True: self.NKLM_key = b'' record = LSA_SECRET.from_bytes(value[1]) key = SECURITY.sha256_multi(self.lsa_key, record.data[:32]) cipher = AESModeOfOperationECB(key) n = 16 for block in [ record.data[32:][i:i + n] for i in range(0, len(record.data[32:]), n) ]: #terrible, terrible workaround if len(block) < n: block += b'\x00' * (16 - len(block)) self.NKLM_key += cipher.decrypt(block) else: self.NKLM_key = self.decrypt_secret(self.lsa_key, value[1]) logger.debug('[SECURITY] NL$KM key: %s' % self.NKLM_key.hex()) return self.NKLM_key
def decrypt_lsa_key(self, data): logger.debug('[SECURITY] Decrypting LSA key...') if self.lsa_secret_key_vista_type is True: record = LSA_SECRET.from_bytes(data) key = SECURITY.sha256_multi(self.bootkey, record.data[:32]) secret_dec = b'' cipher = AESModeOfOperationECB(key) n = 16 for block in [ record.data[32:][i:i + n] for i in range(0, len(record.data[32:]), n) ]: #terrible, terrible workaround if len(block) < n: block += b'\x00' * (n - len(block)) secret_dec += cipher.decrypt(block) record = LSA_SECRET_BLOB.from_bytes(secret_dec) self.lsa_key = record.secret[52:][:32] else: ctx = hashlib.md5(self.bootkey) for i in range(1000): ctx.update(data[60:76]) cipher = RC4(ctx.digest()) record = cipher.decrypt(data[12:60]) self.lsa_key = record[0x10:0x20] logger.debug('[SECURITY] LSA key value: %s' % self.lsa_key.hex()) return self.lsa_key
def decrypt_lsa_key(self, data): if self.lsa_secret_key_vista_type is True: record = LSA_SECRET.from_bytes(data) key = SECURITY.sha256_multi(self.bootkey, record.data[:32]) secret_dec = b'' cipher = AESModeOfOperationECB(key) n = 16 for block in [ record.data[32:][i:i + n] for i in range(0, len(record.data[32:]), n) ]: #terrible, terrible workaround secret_dec += cipher.decrypt(block) record = LSA_SECRET_BLOB.from_bytes(secret_dec) self.lsa_key = record.secret[52:][:32] else: ctx = hashlib.md5(self.bootkey) for i in range(1000): ctx.update(value[60:76]) cipher = RC4.new(ctx.digest()) record = rc4.decrypt(value[12:60]) self.lsa_key = record[0x10:0x20] return self.lsa_key
def get_secrets(self): logger.debug('[SECURITY] get_secrets') self.get_lsa_key() self.dump_dcc() # Let's first see if there are cached entries keys = self.hive.enum_key('Policy\\Secrets') if keys is None: logger.debug('[SECURITY] No cached secrets found in hive') return if b'NL$Control' in keys: keys.remove(b'NL$Control') for key_name in keys: for vl in ['CurrVal', 'OldVal']: key_path = 'Policy\\Secrets\\{}\\{}\\default'.format( key_name, vl) logger.debug('[SECURITY] Parsing secrets in %s' % key_path) v = self.hive.get_value(key_path, False) if v and v[1] != 0: logger.log(1, '[SECURITY] Key %s Value %s' % (key_path, v[1])) if self.lsa_secret_key_vista_type is True: record = LSA_SECRET.from_bytes(v[1]) key = SECURITY.sha256_multi(self.lsa_key, record.data[:32]) secret_dec = b'' cipher = AESModeOfOperationECB(key) n = 16 for block in [ record.data[32:][i:i + n] for i in range(0, len(record.data[32:]), n) ]: #terrible, terrible workaround if len(block) < n: block += b'\x00' * (n - len(block)) secret_dec += cipher.decrypt(block) record = LSA_SECRET_BLOB.from_bytes(secret_dec) dec_blob = record.secret else: dec_blob = self.decrypt_secret(self.lsa_key, v[1]) secret = LSASecret.process(key_name, dec_blob, vl == 'OldVal', self.system_hive) if secret is not None: self.cached_secrets.append(secret) else: logger.debug('[SECURITY] Could not open %s, skipping!' % key_path)
def setup(self): if self.mode == SYMMETRIC_MODE.ECB: self.ctx = AESModeOfOperationECB(self.key) elif self.mode == SYMMETRIC_MODE.CBC: self.ctx = AESModeOfOperationCBC(self.key, iv=self.iv) else: raise Exception('Unknown mode!')
def change_key(self, master_key): #if len(master_key) != 16: # raise InvalidInputException('Master key should be 128-bit') self.__master_key = master_key self.__aes_ecb = AESModeOfOperationECB(self.__master_key) self.__auth_key = int.from_bytes(self.__aes_ecb.encrypt(b'\x00' * 16), byteorder='big', signed=False) # precompute the table for multiplication in finite field table = [] # for 8-bit for i in range(16): row = [] for j in range(256): row.append(gf_2_128_mul(self.__auth_key, j << (8 * i))) table.append(tuple(row)) self.__pre_table = tuple(table) self.prev_init_value = None # reset
def dump_secrets(self): self.get_lsa_key() self.get_NKLM_key() # Let's first see if there are cached entries keys = self.hive.enum_key('Policy\\Secrets') if keys is None: # No entries return if b'NL$Control' in keys: keys.remove(b'NL$Control') for key_name in keys: for vl in ['CurrVal', 'OldVal']: key_path = 'Policy\\Secrets\\{}\\{}\\default'.format( key_name, vl) print(key_path) v = self.hive.get_value(key_path) if v and v[1] != 0: if self.lsa_secret_key_vista_type is True: record = LSA_SECRET.from_bytes(v[1]) key = SECURITY.sha256_multi(self.lsa_key, record.data[:32]) secret_dec = b'' cipher = AESModeOfOperationECB(key) n = 16 for block in [ record.data[32:][i:i + n] for i in range(0, len(record.data[32:]), n) ]: #terrible, terrible workaround secret_dec += cipher.decrypt(block) record = LSA_SECRET_BLOB.from_bytes(secret_dec) dec_blob = record.secret else: dec_blob = self.decrypt_secret(self.lsa_key, v[1]) secret = LSASecret.process(key_name, dec_blob, vl == 'OldVal') print(str(secret))
def get_NKLM_key(self): if self.lsa_key is None: self.get_lsa_secret_key() value = self.hive.get_value('Policy\\Secrets\\NL$KM\\CurrVal\\default') if value is None: raise Exception('Could not find NL$KM in registry :(') if self.lsa_secret_key_vista_type is True: self.NKLM_key = b'' record = LSA_SECRET.from_bytes(value[1]) key = SECURITY.sha256_multi(self.lsa_key, record.data[:32]) cipher = AESModeOfOperationECB(key) n = 16 for block in [ record.data[32:][i:i + n] for i in range(0, len(record.data[32:]), n) ]: #terrible, terrible workaround self.NKLM_key += cipher.decrypt(block) else: self.NKLM_key = self.decrypt_secret(self.lsa_key, value[1]) return self.NKLM_key
class AES_GCM: def __init__(self, master_key): self.change_key(master_key) def change_key(self, master_key): #if len(master_key) != 16: # raise InvalidInputException('Master key should be 128-bit') self.__master_key = master_key self.__aes_ecb = AESModeOfOperationECB(self.__master_key) self.__auth_key = int.from_bytes(self.__aes_ecb.encrypt(b'\x00' * 16), byteorder='big', signed=False) # precompute the table for multiplication in finite field table = [] # for 8-bit for i in range(16): row = [] for j in range(256): row.append(gf_2_128_mul(self.__auth_key, j << (8 * i))) table.append(tuple(row)) self.__pre_table = tuple(table) self.prev_init_value = None # reset def __times_auth_key(self, val): res = 0 for i in range(16): res ^= self.__pre_table[i][val & 0xFF] val >>= 8 return res def __ghash(self, aad, txt): len_aad = len(aad) len_txt = len(txt) # padding if 0 == len_aad % 16: data = aad else: data = aad + b'\x00' * (16 - len_aad % 16) if 0 == len_txt % 16: data += txt else: data += txt + b'\x00' * (16 - len_txt % 16) tag = 0 assert len(data) % 16 == 0 for i in range(len(data) // 16): tag ^= int.from_bytes(data[i * 16:(i + 1) * 16], byteorder='big', signed=False) tag = self.__times_auth_key(tag) # print 'X\t', hex(tag) tag ^= ((8 * len_aad) << 64) | (8 * len_txt) tag = self.__times_auth_key(tag) return tag def encrypt(self, init_value, plaintext, auth_data=b''): if len(init_value) != 12: raise InvalidInputException('IV should be 96-bit') # a naive checking for IV reuse if init_value == self.prev_init_value: raise InvalidInputException('IV must not be reused!') self.prev_init_value = init_value len_plaintext = len(plaintext) if len_plaintext > 0: ctrval_init = init_value + b'\x00' * 4 ctrval = int.from_bytes(ctrval_init, byteorder='big', signed=False) counter = Counter(initial_value=ctrval + 2) #+2 ???? aes_ctr = AESModeOfOperationCTR(self.__master_key, counter=counter) if 0 != len_plaintext % 16: padded_plaintext = plaintext + \ b'\x00' * (16 - len_plaintext % 16) else: padded_plaintext = plaintext ciphertext = aes_ctr.encrypt(padded_plaintext)[:len_plaintext] else: ciphertext = b'' auth_tag = self.__ghash(auth_data, ciphertext) iv_int = int.from_bytes(init_value, byteorder='big', signed=False) iv_int = (iv_int << 32) | 1 iv_int = iv_int.to_bytes(16, byteorder='big', signed=False) iv_int_enc = self.__aes_ecb.encrypt(iv_int) iv_int_enc = int.from_bytes(iv_int_enc, byteorder='big', signed=False) auth_tag ^= iv_int_enc assert auth_tag < (1 << 128) return ciphertext, auth_tag.to_bytes(16, byteorder='big', signed=False) def decrypt(self, init_value, ciphertext, auth_tag, auth_data=b''): if len(init_value) != 12: raise InvalidInputException('IV should be 96-bit') if len(auth_tag) != 16: raise InvalidInputException('Tag should be 128-bit') iv_int = int.from_bytes(init_value, byteorder='big', signed=False) iv_int = (iv_int << 32) | 1 iv_int = iv_int.to_bytes(16, byteorder='big', signed=False) iv_int_enc = self.__aes_ecb.encrypt(iv_int) iv_int_enc = int.from_bytes(iv_int_enc, byteorder='big', signed=False) auth_tag_verify = self.__ghash(auth_data, ciphertext) ^ iv_int_enc auth_tag_verify = auth_tag_verify.to_bytes(16, byteorder='big', signed=False) if auth_tag != auth_tag_verify: raise InvalidTagException len_ciphertext = len(ciphertext) if len_ciphertext > 0: ctrval_init = init_value + b'\x00' * 4 ctrval = int.from_bytes(ctrval_init, byteorder='big', signed=False) counter = Counter(initial_value=ctrval + 2) #+2 ???? aes_ctr = AESModeOfOperationCTR(self.__master_key, counter=counter) if 0 != len_ciphertext % 16: padded_ciphertext = ciphertext + \ b'\x00' * (16 - len_ciphertext % 16) else: padded_ciphertext = ciphertext plaintext = aes_ctr.decrypt(padded_ciphertext)[:len_ciphertext] else: plaintext = b'' return plaintext