Skip to content

Instantly share code, notes, and snippets.

@dirkjanm
Created September 20, 2021 08:05
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dirkjanm/299f5389f83e4053c51f33fb8da42f9c to your computer and use it in GitHub Desktop.
Save dirkjanm/299f5389f83e4053c51f33fb8da42f9c to your computer and use it in GitHub Desktop.
Small Kerberos tool to use a service ticket in HTTP context
import struct
import os
import datetime
import base64
from binascii import unhexlify
from pyasn1.type.univ import noValue
from pyasn1.codec.der import decoder, encoder
from ldap3 import Server, Connection, NTLM, ALL, SASL, KERBEROS
from ldap3.core.results import RESULT_STRONGER_AUTH_REQUIRED
from ldap3.operation.bind import bind_operation
from impacket.spnego import SPNEGO_NegTokenInit, TypesMech
from impacket.spnego import ASN1_OID, asn1encode, ASN1_AID, asn1decode
from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, SPNEGO_NegTokenResp, ASN1_OID, asn1encode, ASN1_AID
from impacket.krb5.gssapi import KRB5_AP_REQ, GSS_C_DELEG_FLAG
from impacket.krb5.asn1 import AP_REQ, AS_REP, TGS_REQ, Authenticator, TGS_REP, seq_set, seq_set_iter, PA_FOR_USER_ENC, \
Ticket as TicketAsn1, EncTGSRepPart, EncTicketPart, AD_IF_RELEVANT, Ticket as TicketAsn1, KRB_CRED, EncKrbCredPart
from impacket.krb5.crypto import Key, _enctype_table, Enctype
from impacket import LOG
from impacket.krb5.types import Principal, KerberosTime, Ticket
from impacket.krb5 import constants
from impacket.krb5.kerberosv5 import getKerberosTGS
from impacket.krb5.ccache import CCache
from struct import pack, unpack
import logging
def build_auth(principal, domain, user):
thing = struct.pack('B', ASN1_AID) + asn1encode( struct.pack('B', ASN1_OID) + asn1encode(
TypesMech['KRB5 - Kerberos 5'] ) + KRB5_AP_REQ)
# Do we have a TGT cached?
tgt = None
try:
ccache = CCache.loadFile(os.getenv('KRB5CCNAME'))
logging.debug("Using Kerberos Cache: %s" % os.getenv('KRB5CCNAME'))
# For just decoding a TGS, override principal
creds = ccache.getCredential(principal, False)
if creds is not None:
# For just decoding a TGS, use toTGS()
TGS = creds.toTGS()
tgs, cipher, sessionKey = TGS['KDC_REP'], TGS['cipher'], TGS['sessionKey']
oldSessionKey = sessionKey
logging.info('Using TGT from cache')
else:
logging.error("No valid credentials found in cache. ")
return
except:
# No cache present
logging.error("Cache file not valid or not found")
return
blob = SPNEGO_NegTokenInit()
# Kerberos v5 mech
blob['MechTypes'] = [TypesMech['MS KRB5 - Microsoft Kerberos 5']]
# Let's extract the ticket from the TGS
tgs = decoder.decode(tgs, asn1Spec = TGS_REP())[0]
ticket = Ticket()
ticket.from_asn1(tgs['ticket'])
# Now let's build the AP_REQ
apReq = AP_REQ()
apReq['pvno'] = 5
apReq['msg-type'] = int(constants.ApplicationTagNumbers.AP_REQ.value)
opts = list()
apReq['ap-options'] = constants.encodeFlags(opts)
seq_set(apReq,'ticket', ticket.to_asn1)
authenticator = Authenticator()
authenticator['authenticator-vno'] = 5
authenticator['crealm'] = domain
userName = Principal(user, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
seq_set(authenticator, 'cname', userName.components_to_asn1)
now = datetime.datetime.utcnow()
authenticator['cusec'] = now.microsecond
authenticator['ctime'] = KerberosTime.to_asn1(now)
encodedAuthenticator = encoder.encode(authenticator)
# Key Usage 11
# AP-REQ Authenticator (includes application authenticator
# subkey), encrypted with the application session key
# (Section 5.5.1)
encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 11, encodedAuthenticator, None)
apReq['authenticator'] = noValue
apReq['authenticator']['etype'] = cipher.enctype
apReq['authenticator']['cipher'] = encryptedEncodedAuthenticator
blob['MechToken'] = pack('B', ASN1_AID) + asn1encode(pack('B', ASN1_OID) + asn1encode(
TypesMech['KRB5 - Kerberos 5']) + KRB5_AP_REQ + encoder.encode(apReq))
return blob.getData()
def main():
# Change stuff here!
principal = 'http/aadg.windows.net.nsatc.net@OFFICE.LOCAL'
domain = 'OFFICE.LOCAL'
user = 'vince'
auth = build_auth(principal, domain, user)
print(base64.b64encode(auth))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment