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 = AES(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 construct(server_challenge, client_challenge, credentials): ntlm_creds = netntlm_ess() ntlm_creds.credentials = credentials ntlm_creds.ServerChallenge = server_challenge if credentials.password: nt_hash = NTOWFv1(credentials.password) lm_hash = LMOWFv1(credentials.password) else: nt_hash = bytes.fromhex(credentials.nt_hash) lm_hash = bytes.fromhex(credentials.lm_hash) if credentials.lm_hash else None ntlm_creds.LMResponse = LMResponse() ntlm_creds.LMResponse.Response = client_challenge + b'\x00' * 16 temp_1 = md5(server_challenge + client_challenge[:8]).digest() data = DESL(nt_hash, temp_1[:8]) ntlm_creds.NTResponse = NTLMv1Response() ntlm_creds.NTResponse.Response = data ntlm_creds.SessionBaseKey = md4(nt_hash).digest() return ntlm_creds
def verify(self, creds, credtype='plain'): """ Verifies the authentication data against the user credentials :param creds: dictionary containing the domain, user, hash/password :param credtype: can be 'plain' or 'hash' this indicates what type of credential lookup to perform :return: bool """ if creds is None: return True if self.domain not in creds: return False if self.username not in creds[self.domain]: return False if credtype == 'plain': nt_hash = NTOWFv1(creds[self.domain][self.username]) elif credtype == 'hash': nt_hash = bytes.fromhex(creds[self.domain][self.username]) else: raise Exception('Unknown cred type!') # print('Server chall: %s' % self.ServerChallenge) # print('Client chall: %s' % self.ChallengeFromClinet) temp_1 = md5(bytes.fromhex(self.ServerChallenge) + bytes.fromhex(self.ChallengeFromClinet)[:8]).digest() calc_response = DESL(nt_hash, temp_1[:8]) # print('calc_response: %s' % calc_response.hex()) # print('ClientResponse: %s' % self.ClientResponse) return calc_response == bytes.fromhex(self.ClientResponse)
def decrypt_hash(self, rid, hashobj, constant): key1, key2 = SAM.rid_to_key(rid) des1 = DES(key1) des2 = DES(key2) if isinstance(hashobj, SAM_HASH): rc4key = hashlib.md5( self.hashed_bootkey[:0x10] + int(rid, 16).to_bytes(4, 'little', signed=False) + constant).digest() key = RC4(rc4key).encrypt(hashobj.hash) else: key = b'' cipher = AES(self.hashed_bootkey[:0x10], MODE_CBC, IV=hashobj.salt) n = 16 for block in [ hashobj.data[i:i + n] for i in range(0, len(hashobj.data), n) ]: #terrible, terrible workaround key += cipher.decrypt(block) key = key[:16] dec_hash = des1.decrypt(key[:8]) + des2.decrypt(key[8:]) return dec_hash
def construct_apreq(self, tgs, encTGSRepPart, sessionkey, flags = None, seq_number = 0, ap_opts = [], cb_data = None): now = datetime.datetime.now(datetime.timezone.utc) authenticator_data = {} authenticator_data['authenticator-vno'] = krb5_pvno authenticator_data['crealm'] = Realm(self.kerberos_TGT['crealm']) authenticator_data['cname'] = self.kerberos_TGT['cname'] authenticator_data['cusec'] = now.microsecond authenticator_data['ctime'] = now.replace(microsecond=0) if flags is not None: ac = AuthenticatorChecksum() ac.flags = flags ac.channel_binding = b'\x00'*16 if cb_data is not None: ac.channel_binding = hashlib.md5(cb_data).digest() chksum = {} chksum['cksumtype'] = 0x8003 chksum['checksum'] = ac.to_bytes() authenticator_data['cksum'] = Checksum(chksum) authenticator_data['seq-number'] = seq_number cipher = _enctype_table[encTGSRepPart['key']['keytype']] authenticator_data_enc = cipher.encrypt(sessionkey, 11, Authenticator(authenticator_data).dump(), None) ap_req = {} ap_req['pvno'] = krb5_pvno ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value ap_req['ticket'] = Ticket(tgs['ticket']) ap_req['ap-options'] = APOptions(set(ap_opts)) ap_req['authenticator'] = EncryptedData({'etype': self.kerberos_cipher_type, 'cipher': authenticator_data_enc}) return AP_REQ(ap_req).dump()
def construct_apreq_from_ticket(ticket_data, sessionkey, crealm, cname, flags=None, seq_number=0, ap_opts=[], cb_data=None): """ ticket: bytes of Ticket """ now = datetime.datetime.now(datetime.timezone.utc) authenticator_data = {} authenticator_data['authenticator-vno'] = krb5_pvno authenticator_data['crealm'] = Realm(crealm) authenticator_data['cname'] = PrincipalName({ 'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': [cname] }) authenticator_data['cusec'] = now.microsecond authenticator_data['ctime'] = now.replace(microsecond=0) if flags is not None: ac = AuthenticatorChecksum() ac.flags = flags ac.channel_binding = b'\x00' * 16 if cb_data is not None: ac.channel_binding = hashlib.md5(cb_data).digest() chksum = {} chksum['cksumtype'] = 0x8003 chksum['checksum'] = ac.to_bytes() authenticator_data['cksum'] = Checksum(chksum) authenticator_data['seq-number'] = seq_number cipher = _enctype_table[sessionkey.enctype] authenticator_data_enc = cipher.encrypt( sessionkey, 11, Authenticator(authenticator_data).dump(), None) ap_req = {} ap_req['pvno'] = krb5_pvno ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value ap_req['ticket'] = Ticket.load(ticket_data) ap_req['ap-options'] = APOptions(set(ap_opts)) ap_req['authenticator'] = EncryptedData({ 'etype': sessionkey.enctype, 'cipher': authenticator_data_enc }) return AP_REQ(ap_req).dump()
async def get_HBoot_key(self): logger.debug('SAM parsing hashed bootkey') QWERTY = b"!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0" DIGITS = b"0123456789012345678901234567890123456789\0" F = await self.hive.get_value(r'SAM\Domains\Account\F') F = F[1] logger.log(1, '[SAM] F key value: %s' % F) domain_properties = DOMAIN_ACCOUNT_F.from_bytes(F) if isinstance(domain_properties.key_0, SAM_KEY_DATA): rc4_key = hashlib.md5(domain_properties.key_0.salt + QWERTY + self.bootkey + DIGITS).digest() self.hashed_bootkey = RC4(rc4_key).encrypt( domain_properties.key_0.key + domain_properties.key_0.checksum) checksum = hashlib.md5(self.hashed_bootkey[:16] + DIGITS + self.hashed_bootkey[:16] + QWERTY).digest() if checksum != self.hashed_bootkey[16:]: logger.error('[SAM] HBootkey checksum verification failed!') raise Exception('[SAM] HBootkey checksum verification failed!') elif isinstance(domain_properties.key_0, SAM_KEY_DATA_AES): self.hashed_bootkey = b'' cipher = AES(self.bootkey, MODE_CBC, IV=domain_properties.key_0.salt) n = 16 for block in [ domain_properties.key_0.data[i:i + n] for i in range(0, len(domain_properties.key_0.data), n) ]: #terrible, terrible workaround self.hashed_bootkey += cipher.decrypt(block) logger.debug('[SAM] HBootkey: %s' % self.hashed_bootkey.hex()) return self.hashed_bootkey
def GSS_GetMIC(self, data, sequenceNumber, direction='init'): raise Exception('Not tested! Sure it needs some changes') GSS_GETMIC_HEADER = b'\x60\x23\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02' # Let's pad the data pad = (4 - (len(data) % 4)) & 0x3 padStr = bytes([pad]) * pad data += padStr mic = GSSMIC_RC4() if direction == 'init': mic.SND_SEQ = sequenceNumber.to_bytes(4, 'big', signed=False) + b'\x00' * 4 else: mic.SND_SEQ = sequenceNumber.to_bytes(4, 'big', signed=False) + b'\xff' * 4 Ksign_ctx = hmac.new(self.session_key.contents, digestmod='md5') Ksign_ctx.update(b'signaturekey\0') Ksign = Ksign_ctx.digest() id = 15 temp = md5( id.to_bytes(4, 'little', signed=False) + mic.to_bytes()[:8]).digest() chksum_ctx = hmac.new(Ksign, digestmod='md5') chksum_ctx.update(temp) mic.SGN_CKSUM = chksum_ctx.digest()[:8] id = 0 temp = hmac.new(self.session_key.contents, digestmod='md5') temp.update(id.to_bytes(4, 'little', signed=False)) Kseq_ctx = hmac.new(temp.digest(), digestmod='md5') Kseq_ctx.update(mic.SGN_CKSUM) Kseq = Kseq_ctx.digest() mic.SGN_CKSUM = RC4(Kseq).encrypt(mic.SND_SEQ) return GSS_GETMIC_HEADER + mic.to_bytes()
def GSS_Wrap(self, data, seq_num, direction='init', encrypt=True, auth_data=None): GSS_WRAP_HEADER = b'\x60\x2b\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02' pad = (8 - (len(data) % 8)) & 0x7 padStr = bytes([pad]) * pad data += padStr token = GSSWRAP_RC4() token.SEAL_ALG = b'\x10\x00' if direction == 'init': token.SND_SEQ = seq_num.to_bytes(4, 'big', signed=False) + b'\x00' * 4 else: token.SND_SEQ = seq_num.to_bytes(4, 'big', signed=False) + b'\xff' * 4 token.Confounder = os.urandom(8) temp = hmac.new(self.session_key.contents, digestmod='md5') temp.update(b'signaturekey\0') Ksign = temp.digest() id = 13 Sgn_Cksum = md5( id.to_bytes(4, 'little', signed=False) + token.to_bytes()[:8] + token.Confounder + data).digest() temp = hmac.new(Ksign, digestmod='md5') temp.update(Sgn_Cksum) token.SGN_CKSUM = temp.digest()[:8] klocal = b'' for b in self.session_key.contents: klocal += bytes([b ^ 0xf0]) id = 0 temp = hmac.new(klocal, digestmod='md5') temp.update(id.to_bytes(4, 'little', signed=False)) temp = hmac.new(temp.digest(), digestmod='md5') temp.update(seq_num.to_bytes(4, 'big', signed=False)) Kcrypt = temp.digest() id = 0 temp = hmac.new(self.session_key.contents, digestmod='md5') temp.update(id.to_bytes(4, 'little', signed=False)) temp = hmac.new(temp.digest(), digestmod='md5') temp.update(token.SGN_CKSUM) Kseq = temp.digest() token.SND_SEQ = RC4(Kseq).encrypt(token.SND_SEQ) if auth_data is not None: wrap = GSSWRAP_RC4.from_bytes(auth_data[8 + len(GSS_WRAP_HEADER):]) id = 0 temp = hmac.new(self.session_key.contents, digestmod='md5') temp.update(id.to_bytes(4, 'little', signed=False)) temp = hmac.new(temp.digest(), digestmod='md5') temp.update(wrap.SGN_CKSUM) snd_seq = RC4(temp.digest()).encrypt(wrap.SND_SEQ) id = 0 temp = hmac.new(klocal, digestmod='md5') temp.update(id.to_bytes(4, 'little', signed=False)) temp = hmac.new(temp.digest(), digestmod='md5') temp.update(snd_seq[:4]) Kcrypt = temp.digest() rc4 = RC4(Kcrypt) cipherText = rc4.decrypt(token.Confounder + data)[8:] elif encrypt is True: rc4 = RC4(Kcrypt) token.Confounder = rc4.encrypt(token.Confounder) cipherText = rc4.encrypt(data) else: cipherText = data finalData = GSS_WRAP_HEADER + token.to_bytes() return cipherText, finalData
def GSS_Wrap(self, data, seq_num, direction='init', encrypt=True, cofounder=None): #direction = 'a' #seq_num = 0 #print('[GSS_Wrap] data: %s' % data) #print('[GSS_Wrap] seq_num: %s' % seq_num.to_bytes(4, 'big', signed = False).hex()) #print('[GSS_Wrap] direction: %s' % direction) #print('[GSS_Wrap] encrypt: %s' % encrypt) # #print('[GSS_Wrap] auth_data: %s' % auth_data) #pad = 0 if encrypt is True: data += b'\x01' #pad = (8 - (len(data) % 8)) & 0x7 #padStr = bytes([pad]) * pad #data += padStr # ##data += b'\x08' * 8 #print('[GSS_Wrap] pad: %s' % pad) #print('[GSS_Wrap] data padded: %s' % data) token = GSSWRAP_RC4() token.SEAL_ALG = b'\x10\x00' # RC4 if direction == 'init': token.SND_SEQ = seq_num.to_bytes(4, 'big', signed=False) + b'\x00' * 4 else: token.SND_SEQ = seq_num.to_bytes(4, 'big', signed=False) + b'\xff' * 4 token.Confounder = os.urandom(8) #if cofounder is not None: # token.Confounder = cofounder # #testing purposes only, pls remove temp = hmac.new(self.session_key.contents, digestmod='md5') temp.update(b'signaturekey\0') Ksign = temp.digest() id = 13 Sgn_Cksum = md5( id.to_bytes(4, 'little', signed=False) + token.to_bytes()[:8] + token.Confounder + data).digest() klocal = b'' for b in self.session_key.contents: klocal += bytes([b ^ 0xf0]) id = 0 temp = hmac.new(klocal, digestmod='md5') temp.update(id.to_bytes(4, 'little', signed=False)) temp = hmac.new(temp.digest(), digestmod='md5') temp.update(seq_num.to_bytes(4, 'big', signed=False)) Kcrypt = temp.digest() temp = hmac.new(Ksign, digestmod='md5') temp.update(Sgn_Cksum) token.SGN_CKSUM = temp.digest()[:8] id = 0 temp = hmac.new(self.session_key.contents, digestmod='md5') temp.update(id.to_bytes(4, 'little', signed=False)) temp = hmac.new(temp.digest(), digestmod='md5') temp.update(token.SGN_CKSUM) Kseq = temp.digest() token.SND_SEQ = RC4(Kseq).encrypt(token.SND_SEQ) #if auth_data is not None: if encrypt is False: #print('Unwrap sessionkey: %s' % self.session_key.contents.hex()) #print('Unwrap data : %s' % data.hex()) sspi_wrap = KRB5_MECH_INDEP_TOKEN.from_bytes(data) hdr = sspi_wrap.data[:32] data = sspi_wrap.data[32:] wrap = GSSWRAP_RC4.from_bytes(hdr) id = 0 temp = hmac.new(self.session_key.contents, digestmod='md5') temp.update(id.to_bytes(4, 'little', signed=False)) temp = hmac.new(temp.digest(), digestmod='md5') temp.update(wrap.SGN_CKSUM) Kseq = temp.digest() snd_seq = RC4(Kseq).encrypt(wrap.SND_SEQ) id = 0 temp = hmac.new(klocal, digestmod='md5') temp.update(id.to_bytes(4, 'little', signed=False)) temp = hmac.new(temp.digest(), digestmod='md5') temp.update(snd_seq[:4]) Kcrypt = temp.digest() rc4 = RC4(Kcrypt) dec_cofounder = rc4.decrypt(wrap.Confounder) dec_data = rc4.decrypt(data) id = 13 Sgn_Cksum_calc = md5( id.to_bytes(4, 'little', signed=False) + wrap.to_bytes()[:8] + dec_cofounder + dec_data).digest() temp = hmac.new(Ksign, digestmod='md5') temp.update(Sgn_Cksum_calc) Sgn_Cksum_calc = temp.digest()[:8] if wrap.SGN_CKSUM != Sgn_Cksum_calc[:8]: return None, Exception('Integrity verification failed') pad = 1 return dec_data[:-pad], None elif encrypt is True: rc4 = RC4(Kcrypt) token.Confounder = rc4.encrypt(token.Confounder) cipherText = rc4.encrypt(data) finalData, cipherText = KRB5_MECH_INDEP_TOKEN( token.to_bytes() + cipherText, '1.2.840.113554.1.2.2').to_bytes() #print('cipherText %s' % cipherText.hex()) #print('finalData %s' % finalData.hex()) #print('sessionkey %s' % self.session_key.contents.hex()) return cipherText, finalData