Skip to content

Commit

Permalink
some updates
Browse files Browse the repository at this point in the history
  • Loading branch information
ShutdownRepo committed Mar 19, 2024
1 parent 9580ea9 commit 41cbeb3
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 11 deletions.
27 changes: 24 additions & 3 deletions impacket/krb5/crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
from Cryptodome.Util.number import GCD as gcd
from six import b, PY3, indexbytes, binary_type

from R2Log import logger
import hexdump


def get_random_bytes(lenBytes):
# We don't really need super strong randomness here to use PyCrypto.Random
Expand Down Expand Up @@ -223,11 +226,13 @@ def encrypt(cls, key, keyusage, plaintext, confounder, integrity_blob=None):
hmac = HMAC.new(ki.contents, integrity_blob, cls.hashmod).digest()
else:
hmac = HMAC.new(ki.contents, basic_plaintext, cls.hashmod).digest()
logger.info("full hmac in crypto encrypt")
hexdump.hexdump(hmac)
enc = cls.basic_encrypt(ke, basic_plaintext) + hmac[:cls.macsize]
return enc

@classmethod
def decrypt(cls, key, keyusage, ciphertext, ignore_integrity=False):
def decrypt(cls, key, keyusage, ciphertext, ignore_integrity=False, dce_rpc_header=None, auth_data_header=None):
ki = cls.derive(key, pack('>IB', keyusage, 0x55))
ke = cls.derive(key, pack('>IB', keyusage, 0xAA))
if len(ciphertext) < cls.blocksize + cls.macsize:
Expand All @@ -236,13 +241,29 @@ def decrypt(cls, key, keyusage, ciphertext, ignore_integrity=False):
if len(basic_ctext) % cls.padsize != 0:
raise ValueError('ciphertext does not meet padding requirement')
basic_plaintext = cls.basic_decrypt(ke, bytes(basic_ctext))
hmac = bytearray(HMAC.new(ki.contents, basic_plaintext, SHA).digest())
expmac = hmac[:cls.macsize]
plaintext, confounder = bytes(basic_plaintext[cls.blocksize:]), bytes(basic_plaintext[:cls.blocksize])
# For Kerberos SSP: blob for HMAC calculation is different from blob for encryption.
# This is undocumented, and was identified by reversing cryptodll.dll
# in that case, integrity_blob to send to HMAC
# = confounder + dce_rpc_header + data + auth_data_header + filler + wrap_token
# no need to implement, assuming the other client is legit
if dce_rpc_header is not None and auth_data_header is not None:
plaintext_data, plaintext_filler_and_wrap_token_header = plaintext[:-8-16], plaintext[-8-16:] # FIXME dynamically set the filler size
integrity_blob = confounder + dce_rpc_header + plaintext_data + auth_data_header + plaintext_filler_and_wrap_token_header
logger.info("integrity blob in crypto decrypt")
hexdump.hexdump(confounder)
hexdump.hexdump(dce_rpc_header)
hexdump.hexdump(plaintext_data)
hexdump.hexdump(auth_data_header)
hexdump.hexdump(plaintext_filler_and_wrap_token_header)
hmac = bytearray(HMAC.new(ki.contents, integrity_blob, SHA).digest())
logger.info("HMAC calculated")
hexdump.hexdump(hmac)
else:
hmac = bytearray(HMAC.new(ki.contents, basic_plaintext, SHA).digest())
logger.info("HMAC from packet")
hexdump.hexdump(mac)
expmac = hmac[:cls.macsize]
if not _mac_equal(mac, expmac) and not ignore_integrity:
raise InvalidChecksum('ciphertext integrity failure')
return bytes(basic_plaintext[cls.blocksize:]), bytes(basic_plaintext[:cls.blocksize])
Expand Down
23 changes: 15 additions & 8 deletions impacket/krb5/gssapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import random
import string
import hexdump
from R2Log import logger

from six import b

Expand Down Expand Up @@ -255,24 +256,24 @@ def GSS_Wrap(self, sessionKey, data, sequenceNumber, direction='init', encrypt=T
cipher = self.cipherType()

if confounder is None:
confounder = b(''.join([rand.choice(string.ascii_letters) for _ in range(8)]))
confounder = b(''.join([rand.choice(string.ascii_letters) for _ in range(16)]))

if padding:
padStr = padding
pad = len(padding)
else:
#Let's pad the data
pad = (cipher.blocksize - (len(data) % cipher.blocksize)) & 15
padStr = b'\xFF' * pad
pad = (cipher.blocksize - (len(data) % cipher.blocksize)) & 16
padStr = b'\x00' * pad

# The RRC field ([RFC4121] section 4.2.5) is 12 if no encryption is requested or 28 if encryption
# is requested. The RRC field is chosen such that all the data can be encrypted in place.
rrc = 28

if direction != 'init':
token['Flags'] = 7
token['Flags'] = 3
else:
token['Flags'] = 6
token['Flags'] = 2
token['EC'] = pad
# (RFC4121 section 4.2.4) the RRC field (as
# defined in section 4.2.5) in the to-be-encrypted header contains the
Expand All @@ -285,6 +286,12 @@ def GSS_Wrap(self, sessionKey, data, sequenceNumber, direction='init', encrypt=T
integrity_blob = None
if dce_rpc_header is not None and auth_data_header is not None:
integrity_blob = confounder + dce_rpc_header + data + auth_data_header + padStr + token.getData()
logger.info("integrity blob in gssapi wrap")
hexdump.hexdump(confounder)
hexdump.hexdump(dce_rpc_header)
hexdump.hexdump(data)
hexdump.hexdump(auth_data_header)
hexdump.hexdump(padStr + token.getData())

data += padStr

Expand All @@ -299,7 +306,7 @@ def GSS_Wrap(self, sessionKey, data, sequenceNumber, direction='init', encrypt=T

return ret1, ret2

def GSS_Unwrap(self, sessionKey, data, sequenceNumber, direction='init', encrypt=True, authData=None, keyUsage=KG_USAGE_ACCEPTOR_SEAL, dcerpcheader=None):
def GSS_Unwrap(self, sessionKey, data, sequenceNumber, direction='init', encrypt=True, authData=None, keyUsage=KG_USAGE_ACCEPTOR_SEAL, dce_rpc_header=None, auth_data_header=None, ignore_integrity=False):
# implementation as per [MS-KILE] Section 4.3
from impacket.dcerpc.v5.rpcrt import SEC_TRAILER

Expand All @@ -310,11 +317,11 @@ def GSS_Unwrap(self, sessionKey, data, sequenceNumber, direction='init', encrypt
enc2 = data

cipherText = self.unrotate(enc1 + enc2, token['RRC'] + token['EC'])

# For Kerberos SSP: blob for HMAC calculation is different from blob for encryption.
# This is undocumented, and was identified by reversing cryptodll.dll
# no need to implement, assuming the other client is legit
plainText, confounder = cipher.decrypt(sessionKey, keyUsage, cipherText, ignore_integrity=True)
plainText, confounder = cipher.decrypt(sessionKey, keyUsage, cipherText, dce_rpc_header=dce_rpc_header, auth_data_header=auth_data_header, ignore_integrity=ignore_integrity)

encdata, enchdr = plainText[:-len(self.WRAP())], plainText[-len(self.WRAP()):]
encdata, filler = encdata[:-token['EC']], encdata[-token['EC']:]
Expand Down

0 comments on commit 41cbeb3

Please sign in to comment.