Demystifying Kerberos
Last updated
Last updated
In this article, I'll discuss the Windows Kerberos authentication process in a detailed manner. I often found some concepts not accurately documented while reviewing this topic, so I decided to write this article demystifying Kerberos authentication in a clear and precise way.
In a Windows Active Directory environment, when a client wants to access a specific application (or service) over the network, the client authenticates with the domain controller, which acts as the centralized authentication management server.
Before Kerberos, when authenticating over an untrusted network, sending passwords in plaintext or transmitting password hashes (like LM/NTLM) is insecure, as they can be intercepted (either stealing the plaintext password, or the LM/NTLM hash) and used for unauthorized access.
And if sending the hash over the network logs you in, it means that anyone who has the hash can log in the same as you, this is called hash spoofing or Pass-the-Hash (PtH).
Kerberos is considered to be the most secure form of authentication exchange in the Windows environment, but the way it’s facilitated with the use of tickets is its own idea of authentication.
It’s designed to provide reliable authentication over open and insecure networks, where communications may be intercepted. This can help protect your authentication process in transit, even if sniffed and observed off the network.
Kerberos addresses the weaknesses of other authentication methods by providing end-to-end protection using ticket-based authentication, mutual authentication between the client and server, and strong cryptography.
We need to understand some of the aims that the protocol wishes to achieve before getting into details about the Kerberos authentication system. Some of the aims are:
The user's password must never travel over the network.
The user's password must never be stored in any form on the client machine, and it must be immediately discarded after being used.
The user's password should never be stored in an unencrypted form, even in the authentication server (or KDC) database (refer to section 4.1).
Achieving Single Sign-On (SSO), where the user is prompted to enter a password only once per work session, allowing the user to access all the services he/she is allowed to access, without having to re-enter the password during this session.
Before getting into the details of the Kerberos authentication process, we need to understand core components and terms, which will be used later when discussing more details about it.
The authentication server in a Kerberos environment is called KDC. Since it resides entirely on a single physical server, it can be logically considered divided into three parts:
Database
Authentication Server (AS)
Ticket Granting Server (TGS)
It’s a container for entries associated with users and services. As an abstract, each entry contains a principal (which can be either a client or a service) and the corresponding long-term secret key (described in section 4.4).
The Authentication Server (AS) and Ticket Granting Server (TGS) verify the principals (entries) and the secret keys by checking them in the KDC database during the authentication process.
The AS and TGS do not actually contain this information included in Figure 3. This information is included in the KDC database, and the AS and TGS only check it by accessing the KDC database and checking the information needed to be verified. It's just visualized like that for simplicity and clearer understanding.
The Authentication Server (AS) is the part of KDC that replies to the initial authentication request from the client. In response to the initial authentication request, the AS issues a special known ticket which is known as Ticket Granting Ticket (TGT).
If users are actually who they say they are, they can use the TGT to request other service tickets (which the user wants to access) from TGS, without having to re-enter passwords. This achieves the concept of Single Sign-On (SSO).
The Ticket Granting Server (TGS) is the KDC component that distributes the service tickets to clients with valid TGT, guaranteeing the authenticity of the identity that requests access to resources on the application servers.
It can be considered as an application server that provides the issuing of service tickets as a service (TaaS).
A ticket is something a client presents to an application server (either the KDC or a service) to demonstrate the authenticity of its identity. Tickets are issued by the KDC (AS and TGS), and are encrypted using a secret key of the service they’re intended for.
Since the shared secret is only shared between the KDC and the server providing the service, not even the client can know or change the contents of the ticket.
Keep in mind, a principal usually refers to the username of that specific client or service. For example:
Default Format — Name[/Instance]@REALM
User — moex0@EXAMPLE.COM
Admin — moex0/admin@EXAMPLE.COM
Where moex0
is the username, and admin
is the instance to differentiate between a normal user and an admin.
Default Format — Service/Hostname@REALM
FTP Service — ftp/server.example.com@EXAMPLE.COM
Where ftp
is the service name, and server.example.com
is the FQDN (Fully Qualified Domain Name) of the machine providing the requested service.
The main information contained in a ticket includes:
: The requesting user's principal
: The principal of the service the request it is intended for
The IP address of the client machine from which the ticket can be used, included in the .
: The date and time (in timestamp format).
: The ticket's maximum lifetime.
: The session key (this has a fundamental role in authentication, described in section 4.4).
Each ticket has a lifetime, which is by default 10 hours (600 minutes). This is essential since the authentication server no longer has control over any issued ticket. Even though the realm admin can prevent the issuing of new tickets for a certain user at any time, it cannot prevent users from using the tickets they already posses. This is the reason for limiting the lifetime of the tickets in order to limit any abuse over time.
KRBTGT is a default account that exists in all domains of an Active Directory. Its purpose is to act as a KDC service account (acting as the authentication service for a given domain) for domain controllers.
A key derived from the KRBTGT account’s password (refer to section 4.5 for KRBTGT service account secret key generation) is used to encrypt the Ticket Granting Ticket (TGS) before being sent to the client, in order to protect it from tampering.
The password of the KRBTGT account should be strong and highly protected because if compromised by an adversary, they would be able to forge arbitrary TGTs, known as Golden Tickets.
The KRBTGT account is disabled by default, as only its password is used to derive the encryption key, that will be used to encrypt the TGT. This adds a layer of protection to the account.
The KRBTGT service has a unique principal, which differs from the users and services principals mentioned above.
KRBTGT — krbtgt/REALM@REALM
Why is the hostname and realm for the KRBTGT service REALM@REALM
?
Because the KRBTGT exists in the KDC, and as the TGT is issued from the AS and handed by the client to the TGS, this means that it goes from the KDC to the KDC (refer to section 5).
Users and services share a secret with the KDC, which is stored in the KDC database.
For users, the secret is the key derived from their password (refer to section 4.5).
For services, it’s their secret key (set by the administrator).
KRBTGT service account secret key (refer to section 4.3).
These keys are called long-term keys (we'll call them secret keys), since they do not change when the work session changes.
The user's secret key is not stored on the client in Kerberos because it is stored securely on the KDC. The KDC is responsible for managing and distributing the keys used for authentication and encryption in Kerberos. This ensures that the keys are not compromised if the client is compromised or if the client's storage is accessed by an unauthorized party.
Meanwhile, for services, they do not need to type in a password because the secret key is already set by the administrator and shared between the KDC and the service pre-authentication (Pre-shared Key).
It's also necessary that a user shares a secret with the service (KRBTGT and application servers), at least for the time in which the client has a work session open on a server. This key is generated by the KDC when a ticket is issued, and it’s called a Session Key.
Session keys are generated for:
Securing Communications: The session key is used to encrypt communications between the client and the server, ensuring that the data exchanged during the session is protected from eavesdropping and tampering by unauthorized parties.
Authentication: The session key is generated, encrypted with the client's secret key (long-term key), and sent back to the client, ensuring that only the legitimate user can decrypt and access the session key. This process helps authenticate the client to the server (discussed more in-depth in section 5).
Session keys play a fundamental role in proving the authenticity of the user.
As we mentioned in section 3, one of the aims of Kerberos protocol is to prevent the user's password from being stored in an unencrypted form, not even in the KDC database. Therefore, string2key
function has been introduced.
string2key
is a one-way hash function, which means that it's irreversible. It transforms the unencrypted user's password into an encryption key, which will further be used for encrypting data. The encryption key cannot determine the password (unless by brute force), which adds a layer of security in case the encryption key gets compromised.
The string2key
function is called every time the user changes the password or enters it for authentication.
In Kerberos 5, the concept of password salt has been introduced. A string (salt) is to be concatenated to the unencrypted password before applying the string2key
function to obtain the encryption key. Kerberos 5 uses the same principal of the user principal as salt:
Where, is the encryption key of the user, and is the unencrypted password of the user.
Adding salt also ensures that even if two different principals have the same unencrypted password, will still have different encryption keys.
The KRBTGT service account secret key undergoes the same process as the generation of the user's secret key, which will only be used to encrypt/decrypt the Ticket Granting Ticket (TGT).
Even if the user principal is present in the ticket, it’s not enough to guarantee the authenticity of the client (refer to the authentication process in section 5). Why?
An attacker could capture the ticket when it’s sent by a legitimate client, and send it illegitimately to obtain unauthorized access to the service. Even if we include the IP addresses of the machine in the ticket, it is known that in an open and insecure network, addresses can be easily spoofed.
To solve this problem, we can take advantage of the fact that the client and the server have a session key ( or ) in common that only they know (and also the KDC since it generated it, but it's trusted by default). Therefore, along with the request containing the ticket, the client adds another packet, called the authenticator.
The authenticator includes the and , and encrypts them with the session key. An example of the authenticator in case of client requests a service ticket from the TGS is shown below (refer to section 5.3):
The server which offers the service will decrypt the ticket upon receiving the request, and extract the session key. If the server is actually who he/she says, the server will be able to decrypt the authenticator, using the extracted session key, and extracting the timestamp. If the timestamp differs from the server time by less than 2 minutes (tolerance can be configured), then the authentication is successful (refer to section 5.4). This shows the criticality of synchronization between machines belonging to the same realm.
What if there’s a possibility that the attacker can steal both the ticket and the authenticator and use them during the 2 minutes of validity? Here comes the concept of Replay Cache.
Although this is very difficult to happen that the attacker steal both, the ticket and the authenticator, it’s not impossible. To solve this problem, Replay cache has been introduced in Kerberos 5.
In application servers and also in TGS, there exists a capacity to remember the authenticators that have arrived within the last 2 minutes and reject them if they’re replicas. Accordingly, the attacker wouldn’t be able to replay the request. Even if the attacker reached the server before the original user, the user access to the server would be denied, and this would indicate a breach.
The client never keeps the user's password , nor does it memorize the secret key obtained by applying string2key
. They are used to decrypt the replies from KDC and are immediately discarded.
However, to implement the Single Sign-On (SSO) characteristic, where the user is asked to enter the password just once per work session, it is necessary to memorize the ticket ( ) and the related session ( ) key. The place where this data is stored is called the Credential Cache.
To streamline the explanation of the authentication process, we'll give a simple abstract example of how Kerberos works, then we'll get into more details later on.
Let's assume Bob decided to visit an amusement park. He went to the ticket booth () at the front door (), and bought an admission ticket (), which will give him access to the front door () only for that day (or a limited timestamp). Bob went past the front door into the park and found an amazing ride called the "file server ride" (the service).
Bob reached out to the person at the ride's gate (the service) and asked him if he could try the file server ride and showed him the admission ticket (), the person told him that he needed another ticket () specifically for the file server ride in order to have to access it.
Bob went back to the ticket booth () and asked the person at the ticket booth to give him a file server ride ticket ( ). The person asked to show him the ticket from the front gate (the admission ticket ) before he could give him the file server ride ticket (). Bob shows him the admission ticket () and puts it back into his pocket. The person at the ticket booth asked him some other questions to verify that the admission ticket belonged to him and that he didn't steal it ( ). After verification, the person at the ticket booth () then gives Bob the file server ride ticket (). This means that Bob can request any ride he wants to access using this admission ticket (), as long as it's valid and didn't expire ( lifetime).
Bob goes to the file server ride gate and shows the person the file server ride ticket (), granted access to the ride. Bob can access the file server ride as long as the ticket is valid and didn't expire ( lifetime).
This abstraction was an inspiration from @BryanOnSecurity.
To demonstrate the Kerberos authentication process, we'll assume that a specific user wants to access resources on a specific application server, let's say an FTP server, from a specific client.
The user sends an initial authentication request to the Authentication Server (AS), requesting a Ticket Granting Ticket ( ). This request is not necessarily encrypted (discussed later in section 6).
Where:
: The principal of the user requesting authentication (e.g. moex0@EXAMPLE.COM
).
: The principal of the service the ticket is being asked for, which would generally be krbtgt/REALM@REALM
in the initial authentication.
: The list of IP addresses that are allowed to use the ticket.
: The maximum ticket validity time requested by the user.
There’s a special case where the isn’t krbtgt/REALM@REALM
. When the user wants to just use one service during a work session, they wouldn’t need Single Sign-On and may ask Authentication Server (AS) directly for the service ticket, skipping the request to the TGS .
Upon receiving the previous request, the AS checks if the and exist in the KDC database. If they exist, AS will start creating the reply , which consists of two parts:
The AS will randomly create a session key, let’s say , which will be used for protecting subsequent communications between the client and the TGS.
The AS will issue a TGT which will include: and (which's still krbtgt/REALM@REALM
, as the user will subsequently communicate with TGS), IP list, data and time in timestamp format, ticket's lifetime, TGS session key .
The is then generated containing the TGT, encrypted using the KRBTGT service account secret (discussed in section 4.5), sent with the session key and some other information, encrypted with the user’s secret , as described in the equation below:
At this point, when the client receives , it’ll ask the user to enter the password. As described in section 4.5, the salt is concatenated with the password and passed to string2key
function, resulting in , which will be used to decrypt the part of the message that was encrypted by the KDC using the stored in the KDC database. If it’s decrypted successfully, this indicates that the user is really who he/she says.
In order to achieve Single Sign-On, the client will then extract the session key from the decrypted part of the reply, and store it and the TGT in the user’s credential cache (refer to section 4.8).
Why information already included in the TGT is sent again for the user in the session key part of the reply?
As we want to protect the information inside the TGT from tampering, the TGT is encrypted using the KRBTGT service account secret . If the TGT were to be encrypted using the user’s secret , the user would be able to see what's inside the TGT and could tamper with the information included (such as setting the lifetime to 10 years). Similarly, if the client was compromised, the adversary would be able to tamper with the information inside the TGT and use it to gain unauthorized access. That’s why, another part of the reply (session key part) is encrypted and sent to the user to protect the TGT, as well as provide the user’s authenticity using the session key and the .
It’s important to note that the application server never communicates directly with the KDC. It only receives the Service Ticket through the client wishing to access it.
At this point, the user authenticated with the AS, but still doesn’t have the ticket to access the requested service. The user sends a request to the Ticket Granting Server (TGS) by:
Creating an authenticator (refer to section 4.6) with the , , and encrypt them both using :
Creating a request packet containing the of the service the ticket is needed for, , the just created, and the (which's already encrypted using ):
When the TGS receives the request , it first verifies that exists in the KDC database. If it exists, it decrypts the TGT using the KRBTGT secret key , and extracts the session key , which is subsequently used to decrypt the authenticator in order to verify the user. Before issuing the requested service ticket , the following conditions have to be checked and verified:
The TGT has not expired.
The which exists in the authenticator matches the one present in the TGT.
The is not already present in the replay cache and has not expired.
If the is not null, it checks that the source IP of the request packet is one of those contained in the list.
These conditions are being checked to prove that the TGT really belongs to the user who made the request. If verified, the TGS will start forging the reply:
Randomly creates a session key , which will be used for encrypting subsequent communications between client and service.
Creates a service ticket , with mostly similar information to that included in the TGT. What's different is the service principal , which will be the requested service principal, and the session key included , which will be the service session key.
It then sends the reply message containing the requested service ticket encrypted with the service secret key , along with the other part of the reply message which includes the session key and other information all encrypted with the TGS session key :
It then sends the reply message containing the requested service ticket encrypted with the service secret key , along with the other part of the reply message which includes the session key and other information all encrypted with the TGS session key :
At this point, when the client receives the , it'll decrypt the session key part using , and extract the new service session key . It'll then cache both the service ticket and the service session key in the credential cache. This will achieve SSO with the requested service, as long as the ticket didn't expire.
As the client now has the service ticket and the service session key , it can now ask the service for access to whatever resources it needs via a message. uses a similar strategy to the one used in the (refer to section 5.3):
Creates an authenticator (refer to section 4.6) with the , , both encrypted using service session key :
Creates a request packet containing the just created, and the service ticket (which's already encrypted using ):
When the application server receives the request , it decrypts the ticket using the requested service secret key , and extracts the service session key , which is subsequently used to decrypt the to prove the user's authenticity.
Before granting access to the user, the conditions (similarly mentioned in section 5.3) should be positive to verify the user's authenticity:
The service ticket has not expired.
The which exists in the authenticator matches the one present in the ticket.
The is not already present in the replay cache and has not expired.
If the is not null, it checks that the source IP of the request packet is one of those contained in the list.
It's not surprising that the previous strategy is very similar to the one used in the TGS to check the authenticity of the user, as the TGS can be considered as an application server whose service is to provide tickets to users (as mentioned in section 4.1.3).
Since Kerberos doesn’t require the AS to authenticate the user before sending the TGT (only checks if the client and server principals exist in the KDC database), a client doesn’t provide its password or any method to provide authenticity. Therefore, the AS cannot validate the client’s identity and doesn’t provide any assurance of the identity. Accordingly, an attacker can send legitimate client/server principals (impersonate a user), requesting a TGT.
The attacker would request a TGT, and the TGT will be issued (after verifying the client and service principals), encrypted with the KRBTGT secret key , and sent as a reply (refer to section 5.2) to the attacker requesting it. The attacker would then perform an offline brute-force or dictionary attack on the TGT. This process wouldn’t appear in the KDC logs except only as a single request for TGT. After successfully decrypting the TGT, the attacker now has the , which he can use to decrypt any TGT.
The attacker then would simply request another TGT, to have a valid timestamp and lifetime, and decrypt it with the secret key he obtained. This would give him the ability to tamper with the information included in the TGT and gain unauthorized access.
With pre-authentication enabled, the AS will request the user to send a , encrypted with the user’s secret as the encryption key. If the AS reads a valid timestamp by decrypting it with the user's secret key (which’s available in the KDC database), the AS knows that this request isn’t a replay of a previous request and that it’s included within the timestamp tolerance period. This ensures that the attacker cannot directly ask the KDCs for the encrypted tickets to brute force offline.
In order for the attacker to have a TGT, the attacker has to encrypt a timestamp with a password and offer it to the KDC to request the TGT. This process would be repeated over and over while trying to brute-force the pre-authentication packet. However, the KDC log will record the entry every time the pre-authentication fails.
Keep in mind that pre-authentication doesn’t prevent the attacker from sniffing the client’s encrypted timestamp message to the KDC, which if sniffed, the attacker can brute force it offline. Pre-authentication just adds an extra layer of security, where the attacker cannot request a ticket without authentication, which makes the attacker's attempts more visible and easier to detect.
To add one more layer of security, it’s recommended to use lengthy passwords and have a good password rotation policy in the domain in order to make offline brute-forcing ineffective.