Beispiel #1
0
    def MAC(self, handle, signingKey, seqNum, message):
        if self.is_extended_security() == True:
            msg = NTLMSSP_MESSAGE_SIGNATURE()
            if NegotiateFlags.NEGOTIATE_KEY_EXCH in self.ntlmChallenge.NegotiateFlags:
                tt = struct.pack('<i', seqNum) + message
                t = hmac.new(signingKey, digestmod='md5')
                t.update(tt)

                msg.Checksum = handle(t.digest()[:8])
                msg.SeqNum = seqNum
                seqNum += 1
            else:
                t = hmac.new(signingKey, digestmod='md5')
                t.update(struct.pack('<i', seqNum) + message)
                msg.Checksum = t.digest()[:8]
                msg.SeqNum = seqNum
                seqNum += 1

        else:
            raise Exception('Not implemented!')
            #t = struct.pack('<I',binascii.crc32(message)& 0xFFFFFFFF)
            #randompad = 0
            #msg = NTLMSSP_MESSAGE_SIGNATURE_NOEXT()
            #msg.RandomPad = handle(struct.pack('<I',randompad))
            #msg.Checksum = struct.unpack('<I',handle(messageSignature['Checksum']))[0]

        return msg.to_bytes()
Beispiel #2
0
def NTOWFv2(Passwd, User, UserDom, PasswdHash = None):
	if PasswdHash is not None:
		fp = hmac.new(PasswdHash, digestmod='md5')
	else:
		fp = hmac.new(NTOWFv1(Passwd), digestmod='md5')
	fp.update((User.upper() + UserDom).encode('utf-16le'))
	return fp.digest()
Beispiel #3
0
 def encrypt(cls, key, keyusage, plaintext, confounder):
     if confounder is None:
         confounder = get_random_bytes(8)
     ki = HMAC.new(key.contents, cls.usage_str(keyusage), MD5).digest()
     cksum = HMAC.new(ki, confounder + plaintext, MD5).digest()
     ke = HMAC.new(ki, cksum, MD5).digest()
     return cksum + ARC4(ke).encrypt(confounder + plaintext)
Beispiel #4
0
	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
		"""

		# print('Creds: %s' % creds)
		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':
			lm_hash = LMOWFv2(creds[self.domain][self.username], self.username, self.domain)
		elif credtype == 'hash':
			lm_hash = LMOWFv2(None, self.username, self.domain, bytes.fromhex(creds[self.domain][self.username]))
		else:
			raise Exception('Unknown cred type!')

		hm = hmac.new(lm_hash, digestmod='md5')
		hm.update(bytes.fromhex(self.ServerChallenge))
		hm.update(bytes.fromhex(self.ChallengeFromClinet))

		return self.ClientResponse == hm.hexdigest()
Beispiel #5
0
 def encrypt(cls, key, keyusage, plaintext, confounder):
     ki = cls.derive(key, pack('>IB', keyusage, 0x55))
     ke = cls.derive(key, pack('>IB', keyusage, 0xAA))
     if confounder is None:
         confounder = get_random_bytes(cls.blocksize)
     basic_plaintext = confounder + _zeropad(plaintext, cls.padsize)
     hmac = HMAC.new(ki.contents, basic_plaintext, cls.hashmod).digest()
     return cls.basic_encrypt(ke, basic_plaintext) + hmac[:cls.macsize]
Beispiel #6
0
 def decrypt(cls, key, keyusage, ciphertext):
     if len(ciphertext) < 24:
         raise ValueError('ciphertext too short')
     cksum, basic_ctext = ciphertext[:16], ciphertext[16:]
     ki = HMAC.new(key.contents, cls.usage_str(keyusage), MD5).digest()
     ke = HMAC.new(ki, cksum, MD5).digest()
     basic_plaintext = ARC4(ke).decrypt(basic_ctext)
     exp_cksum = HMAC.new(ki, basic_plaintext, MD5).digest()
     ok = _mac_equal(cksum, exp_cksum)
     if not ok and keyusage == 9:
         # Try again with usage 8, due to RFC 4757 errata.
         ki = HMAC.new(key.contents, pack('<I', 8), MD5).digest()
         exp_cksum = HMAC.new(ki, basic_plaintext, MD5).digest()
         ok = _mac_equal(cksum, exp_cksum)
     if not ok:
         raise InvalidChecksum('ciphertext integrity failure')
     # Discard the confounder.
     return basic_plaintext[8:]
Beispiel #7
0
	def construct(server_challenge, client_challenge, server_details, credentials, timestamp = None):
		ntlm_creds = netntlmv2()
		ntlm_creds.credentials = credentials
		ntlm_creds.ServerChallenge = server_challenge
		
		if not credentials.nt_hash and not credentials.password:
			raise Exception('Password or NT hash must be supplied!')
			
		if credentials.password:
			nt_hash_v2 = NTOWFv2(credentials.password, credentials.username, credentials.domain)
		else:
			nt_hash_v2 = NTOWFv2(None, credentials.username, credentials.domain, bytes.fromhex(credentials.nt_hash))
		
		if not timestamp:
			timestamp = datetime.datetime.utcnow()
		
		cc = NTLMv2ClientChallenge.construct(timestamp, client_challenge, server_details)
		temp = cc.to_bytes()
		
		hm = hmac.new(nt_hash_v2, digestmod='md5')
		hm.update(server_challenge)
		hm.update(temp)
		
		NTProofStr = hm.digest()
		
		ntlm_creds.NTResponse = NTLMv2Response()
		ntlm_creds.NTResponse.Response = NTProofStr
		ntlm_creds.NTResponse.ChallengeFromClinet = cc
		
			
		hm = hmac.new(nt_hash_v2, digestmod='md5')
		hm.update(server_challenge)
		hm.update(client_challenge)
		
		ntlm_creds.LMResponse = LMv2Response()
		ntlm_creds.LMResponse.Response = hm.digest()
		ntlm_creds.LMResponse.ChallengeFromClinet = client_challenge
		
		
		hm = hmac.new(nt_hash_v2, digestmod='md5')
		hm.update(NTProofStr)
		ntlm_creds.SessionBaseKey = hm.digest()
		
		return ntlm_creds
Beispiel #8
0
	def calc_key_exchange_key(self):
		if not self.credentials.nt_hash:
			nt_hash = NTOWFv1(self.credentials.password)
		else:
			nt_hash = bytes.fromhex(self.credentials.nt_hash)
		
		hm = hmac.new(self.SessionBaseKey, digestmod='md5')
		hm.update(self.ServerChallenge)
		hm.update(self.LMResponse.to_bytes()[:8])
				
		return hm.digest()
Beispiel #9
0
    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()
Beispiel #10
0
 def decrypt(cls, key, keyusage, ciphertext):
     ki = cls.derive(key, pack('>IB', keyusage, 0x55))
     ke = cls.derive(key, pack('>IB', keyusage, 0xAA))
     if len(ciphertext) < cls.blocksize + cls.macsize:
         raise ValueError('ciphertext too short')
     basic_ctext, mac = ciphertext[:-cls.macsize], ciphertext[-cls.macsize:]
     if len(basic_ctext) % cls.padsize != 0:
         raise ValueError('ciphertext does not meet padding requirement')
     basic_plaintext = cls.basic_decrypt(ke, basic_ctext)
     hmac = HMAC.new(ki.contents, basic_plaintext, cls.hashmod).digest()
     expmac = hmac[:cls.macsize]
     if not _mac_equal(mac, expmac):
         raise InvalidChecksum('ciphertext integrity failure')
     # Discard the confounder.
     return basic_plaintext[cls.blocksize:]
Beispiel #11
0
    def dump_dcc(self):
        logger.debug('[SECURITY] dump_dcc invoked')
        cache_reg = self.hive.find_key('Cache', False)
        if cache_reg is None:
            logger.debug('[SECURITY] No DCC secrets found')
            return
        values = self.hive.list_values(cache_reg)

        if values == []:
            logger.debug('[SECURITY] No DCC secrets found')
            return

        if b'NL$Control' in values:
            values.remove(b'NL$Control')

        if b'NL$IterationCount' in values:
            logger.debug('[SECURITY] DCC Setting iteration count')
            values.remove(b'NL$IterationCount')
            record = self.hive.get_value('Cache\\NL$IterationCount')[1]
            if record > 10240:
                self.dcc_iteration_count = record & 0xfffffc00
            else:
                self.dcc_iteration_count = record * 1024

        self.get_lsa_key()
        self.get_NKLM_key()

        for value in values:
            logger.debug('[SECURITY] DCC Checking value: %s' % value)
            record_data = self.hive.get_value('Cache\\%s' % value.decode())[1]
            record = NL_RECORD.from_bytes(record_data)

            if record.IV != b'\x00' * 16:
                if record.Flags & 1 == 1:
                    # Encrypted
                    if self.lsa_secret_key_vista_type is True:
                        plaintext = b''
                        cipher = AES(self.NKLM_key[16:32],
                                     MODE_CBC,
                                     IV=record.IV)
                        n = 16
                        for block in [
                                record.EncryptedData[i:i + n]
                                for i in range(0, len(record.EncryptedData), n)
                        ]:  #terrible, terrible workaround
                            if len(block) < 16:
                                block += b'\x00' * (16 - len(block))
                            plaintext += cipher.decrypt(block)

                    else:
                        key = hmac.new(self.NKLM_key,
                                       record.IV,
                                       digestmod='md5').digest()
                        cipher = RC4(key)
                        plaintext = cipher.decrypt(record.EncryptedData)

                else:
                    # Plain! Until we figure out what this is, we skip it
                    #plainText = record['EncryptedData']
                    logger.debug(
                        '[SECURITY] DCC Skipping value %s, unknown formet' %
                        value)
                    continue

                dcc_hash = plaintext[:0x10]
                blob = io.BytesIO(plaintext[0x48:])
                username = blob.read(record.UserLength).decode('utf-16-le')
                blob.seek(
                    self.__pad(record.UserLength) +
                    self.__pad(record.DomainNameLength))
                domain = blob.read(
                    record.DnsDomainNameLength).decode('utf-16-le')

                version = 2 if self.lsa_secret_key_vista_type is True else 1
                secret = LSADCCSecret(version,
                                      domain,
                                      username,
                                      dcc_hash,
                                      iteration=self.dcc_iteration_count)
                self.dcc_hashes.append(secret)

        return self.dcc_hashes
Beispiel #12
0
    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
Beispiel #13
0
    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
Beispiel #14
0
 def checksum(cls, key, keyusage, text):
     ksign = HMAC.new(key.contents, b'signaturekey\x00', MD5).digest()
     md5hash = MD5(_RC4.usage_str(keyusage) + text).digest()
     return HMAC.new(ksign, md5hash, MD5).digest()
Beispiel #15
0
 def checksum(cls, key, keyusage, text):
     kc = cls.enc.derive(key, pack('>IB', keyusage, 0x99))
     hmac = HMAC.new(kc.contents, text, cls.enc.hashmod).digest()
     return hmac[:cls.macsize]
Beispiel #16
0
 def prf(cls, key, string):
     return HMAC.new(key.contents, string, SHA).digest()