mirror of
https://github.com/samba-team/samba.git
synced 2025-01-27 14:04:05 +03:00
CVE-2022-37966 python:tests/krb5: test much more etype combinations
This tests work out the difference between - msDS-SupportedEncryptionTypes value or it's default - software defined extra flags for DC accounts - accounts with only an nt hash being stored - the resulting value in the KRB5_PADATA_SUPPORTED_ETYPES announcement BUG: https://bugzilla.samba.org/show_bug.cgi?id=13135 BUG: https://bugzilla.samba.org/show_bug.cgi?id=15237 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org> (cherry picked from commit 1dfa91682efd3b12d7d6af75287efb12ebd9e526)
This commit is contained in:
parent
8e6d2953ba
commit
c8afae7869
@ -32,6 +32,7 @@ from samba.tests.krb5.rfc4120_constants import (
|
||||
ARCFOUR_HMAC_MD5,
|
||||
KDC_ERR_ETYPE_NOSUPP,
|
||||
)
|
||||
import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
|
||||
|
||||
sys.path.insert(0, "bin/python")
|
||||
os.environ["PYTHONUNBUFFERED"] = "1"
|
||||
@ -39,6 +40,7 @@ os.environ["PYTHONUNBUFFERED"] = "1"
|
||||
global_asn1_print = False
|
||||
global_hexdump = False
|
||||
|
||||
des_bits = security.KERB_ENCTYPE_DES_CBC_MD5 | security.KERB_ENCTYPE_DES_CBC_CRC
|
||||
rc4_bit = security.KERB_ENCTYPE_RC4_HMAC_MD5
|
||||
aes128_bit = security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96
|
||||
aes256_bit = security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96
|
||||
@ -62,11 +64,15 @@ class EtypeTests(KdcTgsBaseTests):
|
||||
self.default_supported_enctypes = lp.get(
|
||||
'kdc default domain supported enctypes')
|
||||
|
||||
def _server_creds(self, supported=None):
|
||||
def _server_creds(self, supported=None, force_nt4_hash=False,
|
||||
account_type=None):
|
||||
if account_type is None:
|
||||
account_type= self.AccountType.COMPUTER
|
||||
return self.get_cached_creds(
|
||||
account_type=self.AccountType.COMPUTER,
|
||||
account_type=account_type,
|
||||
opts={
|
||||
'supported_enctypes': supported,
|
||||
'force_nt4_hash': force_nt4_hash,
|
||||
})
|
||||
|
||||
def only_non_etype_bits_set(self, bits):
|
||||
@ -115,14 +121,38 @@ class EtypeTests(KdcTgsBaseTests):
|
||||
fast_bit | aes256_bit,
|
||||
)
|
||||
|
||||
for requested_etypes in requested_etype_cases:
|
||||
for supported_etypes in supported_etype_cases:
|
||||
tname = (f'{supported_etypes}_supported_'
|
||||
f'{requested_etypes}_requested')
|
||||
targs = supported_etypes, requested_etypes
|
||||
cls.generate_dynamic_test('test_etype_as', tname, *targs)
|
||||
for _requested_etypes in requested_etype_cases:
|
||||
_s = str(_requested_etypes)
|
||||
_t = _s.maketrans(",", "_", "( )")
|
||||
requested_etypes = _s.translate(_t)
|
||||
|
||||
def _test_etype_as_with_args(self, supported_bits, requested_etypes):
|
||||
for _supported_etypes in supported_etype_cases:
|
||||
if _supported_etypes is None:
|
||||
supported_etypes = "None"
|
||||
else:
|
||||
supported_etypes = f'0x{_supported_etypes:X}'
|
||||
|
||||
for account_type in ["member", "dc"]:
|
||||
if account_type == "dc":
|
||||
_account_type = cls.AccountType.SERVER
|
||||
elif account_type == "member":
|
||||
_account_type = cls.AccountType.COMPUTER
|
||||
|
||||
for stored_type in ["aes_rc4", "rc4_only"]:
|
||||
if stored_type == "aes_rc4":
|
||||
force_nt4_hash = False
|
||||
elif stored_type == "rc4_only":
|
||||
force_nt4_hash = True
|
||||
|
||||
tname = (f'{supported_etypes}_supported_'
|
||||
f'{requested_etypes}_requested_'
|
||||
f'{account_type}_account_'
|
||||
f'stored_{stored_type}')
|
||||
targs = _supported_etypes, _requested_etypes, _account_type, force_nt4_hash
|
||||
cls.generate_dynamic_test('test_etype_as', tname, *targs)
|
||||
cls.generate_dynamic_test('test_etype_tgs', tname, *targs)
|
||||
|
||||
def _test_etype_as_with_args(self, supported_bits, requested_etypes, account_type, force_nt4_hash):
|
||||
# The ticket will be encrypted with the strongest enctype for which the
|
||||
# server explicitly declares support, falling back to RC4 if the server
|
||||
# has no declared supported encryption types. The enctype of the
|
||||
@ -151,10 +181,17 @@ class EtypeTests(KdcTgsBaseTests):
|
||||
# If our fallback smb.conf option is set, force in RC4 support.
|
||||
virtual_bits |= rc4_bit
|
||||
|
||||
if force_nt4_hash and not (virtual_bits & rc4_bit):
|
||||
virtual_bits |= rc4_bit
|
||||
|
||||
if virtual_bits & aes256_sk_bit:
|
||||
# If strong session keys are enabled, force in the AES bits.
|
||||
virtual_bits |= aes256_bit | aes128_bit
|
||||
|
||||
if account_type == self.AccountType.SERVER:
|
||||
virtual_bits |= etype_bits
|
||||
expected_error = 0
|
||||
|
||||
virtual_etypes = KerberosCredentials.bits_to_etypes(virtual_bits)
|
||||
|
||||
# The enctype of the session key is the first listed in the request
|
||||
@ -169,25 +206,113 @@ class EtypeTests(KdcTgsBaseTests):
|
||||
|
||||
# Get the credentials of the client and server accounts.
|
||||
creds = self.get_client_creds()
|
||||
target_creds = self._server_creds(supported=supported_bits)
|
||||
|
||||
# Perform the TGS-REQ.
|
||||
ticket = self._as_req(creds, expected_error=expected_error,
|
||||
target_creds=target_creds,
|
||||
etype=requested_etypes)
|
||||
if expected_error:
|
||||
# There's no more to check. Return.
|
||||
return
|
||||
target_creds = self._server_creds(supported=supported_bits,
|
||||
account_type=account_type,
|
||||
force_nt4_hash=force_nt4_hash)
|
||||
if account_type == self.AccountType.SERVER:
|
||||
target_supported_etypes = target_creds.tgs_supported_enctypes
|
||||
target_supported_etypes |= des_bits
|
||||
target_supported_etypes |= etype_bits
|
||||
target_creds.set_tgs_supported_enctypes(target_supported_etypes)
|
||||
supported_bits |= (target_supported_etypes & etype_bits)
|
||||
|
||||
# We expect the ticket etype to be the strongest the server claims to
|
||||
# support, with a fallback to RC4.
|
||||
expected_etype = ARCFOUR_HMAC_MD5
|
||||
if supported_bits is not None:
|
||||
if not force_nt4_hash and supported_bits is not None:
|
||||
if supported_bits & aes256_bit:
|
||||
expected_etype = AES256_CTS_HMAC_SHA1_96
|
||||
elif supported_bits & aes128_bit:
|
||||
expected_etype = AES128_CTS_HMAC_SHA1_96
|
||||
|
||||
# Perform the AS-REQ.
|
||||
ticket = self._as_req(creds, expected_error=expected_error,
|
||||
target_creds=target_creds,
|
||||
etype=requested_etypes,
|
||||
expected_ticket_etype=expected_etype)
|
||||
if expected_error:
|
||||
# There's no more to check. Return.
|
||||
return
|
||||
|
||||
# Check the etypes of the ticket and session key.
|
||||
self.assertEqual(expected_etype, ticket.decryption_key.etype)
|
||||
self.assertEqual(expected_session_etype, ticket.session_key.etype)
|
||||
|
||||
def _test_etype_tgs_with_args(self, supported_bits, requested_etypes, account_type, force_nt4_hash):
|
||||
expected_error = 0
|
||||
|
||||
if not supported_bits:
|
||||
# If msDS-SupportedEncryptionTypes is missing or set to zero, the
|
||||
# default value, provided by smb.conf, is assumed.
|
||||
supported_bits = self.default_supported_enctypes
|
||||
|
||||
# If msDS-SupportedEncryptionTypes specifies only non-etype bits, we
|
||||
# expect an error.
|
||||
if self.only_non_etype_bits_set(supported_bits):
|
||||
expected_error = KDC_ERR_ETYPE_NOSUPP
|
||||
|
||||
virtual_bits = supported_bits
|
||||
|
||||
if self.forced_rc4 and not (virtual_bits & rc4_bit):
|
||||
# If our fallback smb.conf option is set, force in RC4 support.
|
||||
virtual_bits |= rc4_bit
|
||||
|
||||
if force_nt4_hash and not (virtual_bits & rc4_bit):
|
||||
virtual_bits |= rc4_bit
|
||||
|
||||
if virtual_bits & aes256_sk_bit:
|
||||
# If strong session keys are enabled, force in the AES bits.
|
||||
virtual_bits |= aes256_bit | aes128_bit
|
||||
|
||||
if account_type == self.AccountType.SERVER:
|
||||
virtual_bits |= etype_bits
|
||||
expected_error = 0
|
||||
|
||||
virtual_etypes = KerberosCredentials.bits_to_etypes(virtual_bits)
|
||||
|
||||
# The enctype of the session key is the first listed in the request
|
||||
# that the server supports, implicitly or explicitly.
|
||||
for requested_etype in requested_etypes:
|
||||
if requested_etype in virtual_etypes:
|
||||
expected_session_etype = requested_etype
|
||||
break
|
||||
else:
|
||||
# If there is no such enctype, expect an error.
|
||||
expected_error = KDC_ERR_ETYPE_NOSUPP
|
||||
|
||||
# Get the credentials of the client and server accounts.
|
||||
creds = self.get_client_creds()
|
||||
tgt = self.get_tgt(creds)
|
||||
target_creds = self._server_creds(supported=supported_bits,
|
||||
account_type=account_type,
|
||||
force_nt4_hash=force_nt4_hash)
|
||||
if account_type == self.AccountType.SERVER:
|
||||
target_supported_etypes = target_creds.tgs_supported_enctypes
|
||||
target_supported_etypes |= des_bits
|
||||
target_supported_etypes |= etype_bits
|
||||
target_creds.set_tgs_supported_enctypes(target_supported_etypes)
|
||||
supported_bits |= (target_supported_etypes & etype_bits)
|
||||
|
||||
# We expect the ticket etype to be the strongest the server claims to
|
||||
# support, with a fallback to RC4.
|
||||
expected_etype = ARCFOUR_HMAC_MD5
|
||||
if not force_nt4_hash and supported_bits is not None:
|
||||
if supported_bits & aes256_bit:
|
||||
expected_etype = AES256_CTS_HMAC_SHA1_96
|
||||
elif supported_bits & aes128_bit:
|
||||
expected_etype = AES128_CTS_HMAC_SHA1_96
|
||||
|
||||
# Perform the TGS-REQ.
|
||||
ticket = self._tgs_req(tgt, expected_error=expected_error,
|
||||
target_creds=target_creds,
|
||||
kdc_options=str(krb5_asn1.KDCOptions('canonicalize')),
|
||||
expected_supported_etypes=target_creds.tgs_supported_enctypes,
|
||||
expected_ticket_etype=expected_etype,
|
||||
etypes=requested_etypes)
|
||||
if expected_error:
|
||||
# There's no more to check. Return.
|
||||
return
|
||||
|
||||
# Check the etypes of the ticket and session key.
|
||||
self.assertEqual(expected_etype, ticket.decryption_key.etype)
|
||||
self.assertEqual(expected_session_etype, ticket.session_key.etype)
|
||||
|
2980
selftest/knownfail.d/kdc-enctypes
Normal file
2980
selftest/knownfail.d/kdc-enctypes
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user