Inside Kerberos – 6: Conversations

Inside Kerberos – 6: Conversations

We have covered a lot of ground so far, and we have touched on the Kerberos conversations that go on, but let’s take a deeper look at exactly how these messages are made up and how they are protected.

Kerberos Overview

Elements to protect the transmission

Secret Keys

Secret keys are stored inside the Security Account Manager (SAM) database on the Domain Controllers.  The following keys are stored based on passwords using a One Way Hash function.  The secret keys in Active Directory include:

  • User Key
  • krbtgt Key
  • Service Key
  • Trust Key

Session Keys

Session keys are generated by one party and security transmitted to another party, often secured using a secret key.  Session keys are not stored long term and are only used between a given set of actors.  The session keys used by Kerberos include:

  • TGS Session Key
  • Session Key
  • Application Sub-key
  • Application Reply Sub-key

Encryption

Most often we see Kerberos communication protected by AES256 based encryption, which is negotiated between the KDC and the client.  However, by default Windows Domain Controllers support RC4 as an encryption method, and the bad thing about this is that the encryption key is the NT Hash itself…  This means that anyone with another user’s NT Hash can get a Kerberos ticket as that user and therefore access any resources as that user.

As long as you don’t have any pre-Vista/2008 OSes and you don’t have any applications that rely on RC4 then you can look to disabled this via Group Policy (Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options > Network Security: Configure encryption types allowed for Kerberos)   Note that DES is disabled by default since Windows 7, Windows 2008, however RC4 is still available.

Of course before you make this change in production you need to test this change in a non-production environment first.

Network Flows

Authentication Service

The Authentication Service flow is part of the KDC and is all about surprise, surprise…  authentication.  This flow verifies the user and returns to them the TGT and the TGS Session Key.  Picking this flow a part we see:

Kerberos Authentication Service

1. Client to KDC – KRB_AS_REQ

The client locates a KDC for it’s own realm and creates a KRB_AS_REQ message.  This initial message contains:

  • padata structure for PA-PAC-REQUEST
  • kdc-options flags: typically forwardable, renewable, canonicalize, reneable-old
  • cname: left part of the user principal name
  • realm: the user’s FQDN
  • sname: the krbtgt service and FQDN
  • till/rtime: expiry and renewal times both set to around 20 years
  • nonce: client generated random value
  • etype: ordered list of preferred encryption methods
  • addresses: device host name

2. KDC to Client – KRB_ERROR: Pre Authentication Require

Kerberos v5 requires pre-authentication and so the KDC responds asking for that pre-authentication.  It creates a KRB_ERROR message with the following main fields:

  • error-code: ERR_PREAUTH_REQUIRED
  • realm: The KDC realm
  • sname: the krbtgt service and FQDN
  • e-data: contains multiple padata structures, an offer of encryption method plus a set of acceptable pre-authentication data structures
    • an ordered list of encryption types supported, including information about any salt required
    • Request for encrypted timestamp
    • Request for password
    • Request for Private Key

3. Client to KDC – KRB_AS_REQ (with pre authentication)

The client re-creates the KRB_AS_REQ but this time add the encrypted pre-authentication data.  For a standard Windows 10 client with a standard password logon, the main fields are:

  • padata structure for PA-ENC-TIMESTAMP, which includes a timestamp encrypted with the user’s secret key (a one way hash of the user’s password)
  • padata structure for PA-PAC-REQUEST
  • kdc-options flags: typically forwardable, renewable, canonicalize, reneable-old
  • cname: left part of the user principal name
  • realm: the user’s FQDN
  • sname: the krbtgt service and FQDN
  • till/rtime: expiry and renewal times both set to around 20 years
  • nonce: client generated random value
  • etype: ordered list of preferred encryption methods
  • addresses: device host name

4. KDC to Client – KRB_AS_REP

The KDC uses it’s stored value of the user’s secret key to decrypt the pre-authentication data and validates that it is correct (in the case of a timestamp it needs to be within the tolerance set for Active Directory)  Assuming the validation succeeds then a KRB_AS_REP is constructed with the following main fields:

  • padata structure for encryption info, informing the client the encryption method and the salt used
  • crealm: the user’s FQDN
  • cname: left part of the user principal name
  • ticket: the TGT, which includes the krbtgt service and realm of the issuer as well as information encrypted with the krbtgt secret key
  • enc-part: the TGS Session Key, and information about the TGT as well as the original nonce, all encrypted with the user’s secret key.  The client uses this information to validate the TGT as well as cache the TGT and TGS Session Key

At the end of this conversation the client has a TGT that is encrypted with the krbtgt secret key, and a TGS Session Key that can be used to secure the Ticket Granting Service flow.

Ticket Granting Service

The Ticket Granting Service flow is also part of the KDC and I bet you can guess what this is aiming to do…  Grant Tickets to Services.  This flow verifies the TGT and returns to user the ST and the Session Key.  Picking this flow a part we see:

Kerberos Ticket Granting Service

1. Client to KDC – KRB_TGS_REQ

The client locates a KDC in its own realm and looks up the TGT and TGS Session Key in its cache.  If not found then it starts an Authentication Service flow first.  Once it has the TGT and TGS Session Key then the KRB_TGS_REQ is crafted with the following main fields:

  • padata structure with a PA-TGS-REQ structure which in turn includes:
    • the TGT
    • an authenticator (encrypted with the TGS Session Key).  This authenticator includes:
      • crealm: the user’s realm
      • cname: the left part of the user principal name
      • cksum: A checksum of the req_body structure below
      • cusec/ctime: time information to prevent replaying
      • subkey: The client can optionally add an encryption key to use for any responses
  • req_body structure including:
    • kdc-options: forwardable, renewable, canonicalize
    • realm: the realm we’re trying to contact
    • sname: the service principal name for the service we’re trying to consume
    • till: The ideal duration of the Session Ticket (set to around 20 years)
    • nonce: a random value generated by the client
    • etype: an ordered list of preferred encryption types

2. KDC to Client – KRB_TGS_REP (in this case a cross-realm referral)

The response the KDC gives depends on whether the service principal is in it’s own domain or a trusting domain.  In this case we’re assuming that it is in a trusting domain, and so the KDC returns a referral, which includes:

  • crealm: the user’s realm
  • cname: the left part of the user principal name
  • ticket: a TGT with realm and sname set to the krbtgt service and FQDN to contact next, as well as information encrypted using the trust secret key
  • enc-part: the TGS Session Key, and information about the TGT as well as the original nonce, all encrypted with the subkey from the KRB_TGT_REQ (if present) or the user’s secret key.  The client uses this information to validate the TGT as well as cache the TGT and TGS Session Key

3. Client to KDC – KRB_TGS_REQ

Given that we got a referral a new KRB_TGS_REQ is created to be sent to the krbtgt we got in step 2, with the following main fields:

  • padata structure with a PA-TGS-REQ structure which in turn includes:
    • the TGT (from step 2) but with realm set to the user’s realm (so that the receiving KDC knows which trust secret key to use to decrypt)
    • an authenticator (encrypted with the TGS Session Key).  This authenticator includes:
      • crealm: the user’s realm
      • cname: the left part of the user principal name
      • cksum: A checksum of the req_body structure below
      • cusec/ctime: time information to prevent replaying
      • subkey: The client can optionally add an encryption key to use for any responses
  • req_body structure including:
    • kdc-options: forwardable, renewable, canonicalize
    • realm: the realm we’re trying to contact
    • sname: the service principal name for the service we’re trying to consume
    • till: The ideal duration of the Session Ticket (set to around 20 years)
    • nonce: a random value generated by the client
    • etype: an ordered list of preferred encryption types

4. KDC to Client – KRB_TGS_REP

Assuming the TGS Request validates, i.e. ticket is valid, authenticator can be decrypted, cksum matches the req_body, then the KDC creates a KRB_TGS_REP and returns to the client the following fields:

  • crealm: the user’s realm
  • cname: the left part of user principal name
  • ticket: the Service Ticket with realm and sname set to the service we’re trying to contact, and information encrypted using the service secret key
  • enc-part: The Session Key and information about the Service Ticket as well as the original nonce, all encrypted using the subkey in the request (if present) or the user’s secret key.  The client uses this information to validate the response and cache the Service Ticket and Session Key

Application

The application flow is embedded within whatever application the user is trying to access.  In the screenshot below we’ve requested access to an SMB share

Kerberos Application within SMB

1. Client to Server: SMB2 Session Request with an embedded KRB_AP_REQ

SMB uses the Generic Security Service (GSS) API to encapsulate Kerberos authentication/authorization information. The information inside the GSS structure includes:

  • ap-options: mutual-required
  • ticket: the Service Ticket, including the realm and service principal name and information encrypted with the service secret key
  • authenticator: a structure encrypted using the Session Key.  This authenticator includes:
    • crealm: the user’s realm
    • cname: the left part of the user principal name
    • cksum: A checksum of the req_body structure below
    • cusec/ctime: time information to prevent replaying
    • subkey: The client can optionally add an encryption key to use for any responses

2. Server to Client: SMB2 Session Response with an embedded KRB_AP_REP

The Server validates the ticket, decrypts the authenticator and assuming the user is authorized then it will reply with an SMB Session Response which again includes a GSS-API structure, this time encrypted either using the Session key, or using the subkey from the request:

  • cusec/ctime: returned from the client’s request (to validate that the server was the one how managed to decrypt the authenticator)
  • subkey: an optional server generated encryption key to use for all future communication in this session

 

Right so that covers the basic Kerberos flows in a little more detail.  Now let’s wrap up this series by going back to our original questions and answering them to the best of our ability.