Kerberos Wireshark Captures: A SPNEGO Example

Robert Broeckelmann
10 min readMay 16, 2018

--

This is the second post that presents a real world example of the use of Kerberos. The first post captured the Kerberos protocol details of a Windows domain user login. Both of these posts are part of a series I created about Kerberos and Windows Security. In this post, we will look at the use of Kerberos authentication in SPNEGO that allows Kerberos to be used with the HTTP protocol to protect a web site.

These network traces were captured with Wireshark v2.6.0 on a set of Windows Server 2016 instances running on AWS. There were three servers: a domain controller, a test server where IE was run, and a web server running IIS. The network traces were captured on the test server where Internet Explorer was running.

What is SPNEGO?

The Simple and Protected Generic Security Service Application Program Interface (GSS-API) Negotiation Mechanism (or SPNEGO) is defined by RFC 4178. This functionality is extended by RFC 4559 entitled “SPNEGO-based Kerberos and NTLM HTTP Authenticationin Microsoft Windows.” RFC 4559 defines the “SPNEGO” behavior most Windows users are familiar with in corporate settings. This RFC extends the Windows authentication negotiate concept to the HTTP(S) protocols — let’s call it HTTP Negotiate or Microsoft’s HTTP Negotiate. Microsoft created the concept. It was later formally defined in the RFC. It was originally implemented in Internet Explorer 5.x and Internet Information Server 5.0.

At one point, if you wanted Single Sign On to web applications in a corporate setting, you were configuring SPNEGO and the users had to use Internet Explorer. Luckily, the industry has moved on since then. Today, most of the major browsers support SPNEGO, but more importantly there are several other identity protocols that can be used in its place. It has been several years since I have seen SPNEGO in use at a client site; even then, it was a legacy system that no one had touched in several years.

I’m using it as an example here because it demonstrates Kerberos very nicely with something that everyone can relate to — accessing a web site.

Environment Setup

  • The Windows Domain was setup as described in this post.
  • IIS was installed and configured as described here.
  • Kerberos was configured on IIS as described here. Note, a few small things changed for Windows Server 2016.

Assumptions

  • I skip most of the details of what each actor is doing and instead focus on the messages exchanged by the protocol here. See this post for more information about the processing done by each Kerberos actor.
  • Likewise, I skip most of the introductory material in this post and jump straight to what is needed in order to understand the network traces. If you are having trouble following, please see this post.
  • The network traces captured for this post were generated with Windows Server 2016 running on AWS.
  • No effort was made to obfuscate any of the information in these screenshots. All traffic was generated in a test environment that will no longer exist by the time this post is published.

Import Data Structures

This information is being repeated from the first Kerberos example I published for completeness.

Structure of a Kerberos Ticket

A Kerberos Ticket includes the following information:

Unencrypted Part:

  • Version number of ticket format.
  • Service realm
  • Service principal

Encrypted Part:

  • Ticket flags*
  • Session key
  • Client realm
  • Client principal (username)
  • List of Kerberos realms that took part in authenticating the user to whom this ticket was issued.
  • Timestamp and other meta data about last initial request.
  • Time client was authenticated.
  • Validity period start time (optional).
  • Validity period end time.
  • Ticket Granting Server (TGS) Name/ID
  • Timestamp
  • Client (workstation) Address
  • Lifetime
  • Authorization-data — used to pass authorization data from the principal on whose behalf a ticket was issued to the application service ( see Section 5.3 of RFC4120 for more information)

*The following flags can be used in a ticket:

  • reserved(0)
  • forwardable(1)
  • forwarded(2)
  • proxiable(3)
  • proxy(4)
  • may-postdate(5)
  • postdated(6)
  • invalid(7)
  • renewable(8)
  • initial(9)
  • pre-authent(10)
  • hw-authent(11)
  • transited-policy-checked(12)
  • ok-as-delegate(13)

We will see two tickets in this example: Ticket Granting Ticket (TGT) and Service Ticket.

Structure of a Kerberos Authenticator

A Kerberos Authenticator contains the following information (all encrypted):

  • Timestamp
  • client ID
  • application-specific checksum
  • initial sequence number KRB_SAFE or KRB_PRIV messages)
  • session sub-key (used in negotiations for a session key unique to this particular session)

Authenticators must not be re-used. A server that encounters a replayed authenticator must reject the message.

We will see one authenticator in this request: the authenticator sent with the TGT-REQ message.

SPNEGO Wire Captures

The part of this that is new is really at the bottom in the Client/Server Exchange. Up to that point, everything we see about Kerberos was present in the first example we looked at.

We will not go into a significant amount of detail about the Kerberos messages exchanged between the Kerberos client (server running the browser) and the domain controller (KDC).

Initially the user points the web browser at the web site were Kerberos is enabled. That address would be “http://ec2amaz-ecj43mg.rcbj.net” in this particular example. The browser will send the following request to the web server.

There is nothing particularly special about that HTTP GET request.

After processing the request, IIS will return the following 401 response.

Notice the “WWW-Authenticate: Negotiate” HTTP Response Header. This tells the web browser (Internet Explorer in this case) that it needs to check with the local OS regarding what options it has available from the Negotiate Security Support Provider (SSP) to authenticate the user. From this description, there is a preference for Kerberos if available. So, Windows begins a Kerberos authentication sequence. The browser prompts for the user’s credentials (domain user and password) — we want it to do that in this scenario (see end of the post for an explanation). The credential is then used to derive the user’s secret key as described in my original write up on Kerberos. The server (running IE) then sends the following Kerberos AS-REQ message to the domain controller.

This message is requesting a Ticket Granting Ticket (TGT) for the RCBJ realm that is forwardable, renewable, and canonicalized. The ticket is being requested to valid and renewable until a date far into the future.

Since this request does not contain the desired pre-authentication data (an encrypted timestamp), the following error is returned.

So, the server (where the browser is running) encrypts the current timestamp with the user’s secret key and places it in the padata field in a new AS-REQ message. All other fields are essentially the same as the first request that is sent.

The following AS-REQ message is sent to the domain controller.

The authentication service on the domain controller processes the request and sends back an AS-REP message that is similar to the following.

The AS-REP message contains a session key (encrypted with the user’s secret key) and the TGT (encrypted with the TGS’s secret key). At this point, the session key is decrypted by the client and the TGT is available to be placed in the next message.

The TGS-REQ message is built by placing the TGT and an authenticator into an authentication header in the pre-authentication (padata) field. You can also see in the request body that a Service Ticket is being requested for HTTP@ec2amaz-ecj43mg.rcbj.net. So, a Service Ticket for the HTTP Service at the very server our original request was sent to. The TGS-REQ looks similar to the following:

The TGS processes the request and returns a TGS-REP message that looks similar to the following.

This response contains the Service Ticket (encrypted with the service’s secret key) and a client-server (or service) session key (encrypted with the client-TGS session key).

At this point, the client can decrypt the service session key.

The service session key is used to encrypt a new authenticator that is included with the next message sent to the web server.

The client builds an AP-REQ message that contains the encrypted authenticator and the Service Ticket it just received.

The AP-REQ message contains the following fields:

  • pvno: The Kerberos protocol version number (5).
  • msg-type: Application class tag number(14).
  • padding: Defined by RFC 1964, Section 1.2.2.3. Adds necessary padding to size data structure appropriately for encryption and digital signature algorithms.
  • ap-options: Flags and options that can be set on this type of request (in this case mutual authentication is required, the server must authenticate itself). See below.
  • ticket: The Service Ticket encrypted with the services secret key.
  • ticket->tkt-vno: Ticket format version number (5).
  • ticket->realm: The realm this ticket was issued for (rcbj.net).
  • ticket->sname: The service name this ticket is meant to be used for (HTTP@ec2amaz-ecj43mg.rcbj.net)
  • ticket->enc-part: The encrypted part of the ticket. It is encrypted with the service’s (HTTP@ec2amaz-ecj43mg.rcbj.net) secret key.
  • authenticator: The authenticator for this request (encrypted with the service session key).

The available ap-options defined by RFC4120 are:

  • reserved(0)
  • use-session-key(1)
  • mutual-required(2)

This ap-req message is stored in the Kerberos field of the krb5_blob field.

The mechTypes field (defines what authentication mechanisms are in play for a particular request), mechToken(the optimistic mechanism token), and krb5_blob (see above) are placed inside of a negTokenInit data structure. These are all defined by RFC 4178.

The negTokenInit message is placed in the Simple Protected Negotation message, which is in turn embedded in the GSS-API Generic Security Service Application Program Interface message.

That outer message is then stored in base64-encoded form in the Authorization header in the form:

Authorization: Negotiate blah_blah_blah

The unencoded message looks like the following:

The base64-encoded message in the Authorization request header looks something like this:

The browser sends the above message to the IIS server it originally tried to communicate with. It’s replaying the request, but with the requested authentication information this time.

Upon receiving this message, IIS extracts the authenticator, service ticket, and meta data that tells it that the provided information is a Kerberos ticket.

IIS uses its secret key to decrypt the service ticket. It uses the session key inside the service ticket to decrypt the authenticator. Then, it compares the username inside the authenticator to the username in the service ticket. If the users match and all other checks are successful, then the request is authenticated and processing proceeds as normal.

IIS builds a SPNEGO data structure that is placed in the WWW-Authenticate response header.

It contains a Kerberos AP-REP message in the krb5_blob field.

The AP-REP message contains the following fields:

  • pvno: The Kerberos protocol version number (5).
  • msg-type: Application class tag number (15).
  • enc-part: contains the timestamp that was sent to the service in the authenticator (in the AP-REQ message). It is encrypted with the service session key.

You will notice that the supported mechanisms (supportedMech) field contains only one entry for “MS KRB5 — Microsoft Kerberos 5”.

The response IIS sends will looks similar to the following:

When the client receives this token, it extracts and decrypts the timestamp using the service session key. If the timestamp matches what it put in the authenticator, the service is authenticated. If the values do not match, an error will be displayed to the user.

Most likely, the web server would set a session cookie in this initial response that is used to track all subsequent requests that are part of this authenticated session. You could likely also keep sending the same Authorization header in subsequent requests. In a SPA (Single Page Application) where an OAuth2 access token is being passed in each API request back to the server, that approach would be undesirable.

In this particular example, Internet Explorer prompted for new user credentials rather than using the cached TGT that was already present for the authenticated user. The web server was not listed in the Local Intranet site list, which is a requirement for the cached Kerberos tokens to be utilized for the current logged in user — see here for more information. This let me capture the entire Kerberos protocol exchange, which is what I was after. If we add the web server URL to the site list, then the server will only make a call to the TGS to obtain a new service ticket for the web server. Or, if there is already a ticket cached for the web server, then that will be used and no Kerberos protocol messages will be exchanged with the domain controller.

This SPNEGO (HTTP Negotiate) example demonstrates an important point very well. While the AS-REQ, AS-REP, TGT-REQ, and TGT-REP messages are exchanged between actors whose function is largely defined by the Kerberos v5 RFC, AP-REQ and AP-RES are passed between actors using a protocol that probably didn’t have Kerberos in mind when it was being developed. So, we end up with Kerberos extensions that map AP-REQ and AP-RES to protocols like HTTP v1.1, which is what SPNEGO and HTTP Negotiate are all about.

--

--

Robert Broeckelmann

My focus within Information Technology is API Management, Integration, and Identity–especially where these three intersect.