MEDIA NOTE: This is not a new flaw, just a good write-up! I don’t know why media reporting this as a new flaw.
Kerberos is an authentication protocol that is used by default in Windows networks and provide mutual authentication and authorization for clients and servers. It does not require you to send a password or a hash on the wire, it is instead rely on a trusted third party for handling all the details.
Although, it is considered a secure protocol, it has some flaws in Windows environments with devastating consequences.
How does it work?
Kerberos is a rather complex protocol, so let’s just have a look at how a typical authentication looks like:
So, we have the following components:
User – which is called User Principal in Kerberos terminology.
Service – which is called Service Principal in Kerberos terminology.
KDC(Key Distribution Center) – which is a central entity responsible for all the authentication tasks. It is itself consists of Authentication Server(AS) and Ticket Granting Server(TGS). This service is run on domain controllers.
Ticket-Granting Ticket(TGT) – this ticket is granted by AS for user after initial authentication and is necessary to request service tickets. It is cached on user PC and valid for 10 hours by default. Basically, it is an object that represent a user in kerberos after he is authenticated. It is also include information about user group membership in so called Privileged Attribute Certificate(PAC).
Service Ticket – this ticket is granted by TGS when user want to access a particular service and used to authenticate to this service. It is cached and valid for 10 hours too.
Here is the important facts to us:
Secret keys derived from user passwords, this includes KDC secrets and service secrets too.
Secret keys as well as tickets is stored in memory.
Secret keys that use RC4 algorithm is not salted and use NTLM hash of the user as a key, so NTLM hash = RC4 secret key. Yeah, this will be your WTF moment.
KDC use secret key derived from krbtgt user password, although account itself is disabled and not used.
krbtgt user password is rarely changed(only when domain functional level changes, sometimes) after initial installation, so it stay valid for years. What is more interesting, is that previous password is valid too. By the way, transition from 2008 to 2012 is not changing a password, only from 2003 to 2008\2012.
TGT ticket is encrypted and PAC data is signed by krbtgt secret key.
User account validated only after TGT is more than 20 minutes old. For example, if account is disabled or even exist.
Service ticket is encrypted and PAC data is signed by service account secret key, except KDC PAC data which is signed by krbtgt.
PAC data in service ticket is rarely validated. Usually, if service running under SYSTEM it is not validated.
Attacking the Kerberos
How do we prove to KDC, that we who we are and request a TGT? Well, we just encrypt current timestamp with our secret key. That’s how a normal process looks like. So, if we have an access to the key – we can repeat this process on behalf of the user and gain legitimate kerberos tickets, and thus access. Essentially skipping the part of kerberos authentication, where user secret key is created from his password. Recall that rc4 secret key is an NTLM hash of the user account, so we can reuse it any time we want, once we get it. It is very similar to pass-the-hash, hence the name. Of course you can also do this with newer AES keys, just NTLM hash is more convenient and there are multiple ways to obtain it.
Okay, suppose we’ve obtained an NTLM hash, but turns out this system have ntlm disabled:
All hope is lost? We can’t pass-the-hash? Of course not!
Let’s use this NTLM hash in pass-the-key attack:
And what you will see on the wire is the normal kerberos authentication:
You will also see, that we are indeed using RC4 for session key:
Of course, if you are in position and have someone logged on – you could just steal their AES key too:
And then use it the same way:
Even though we’re under local(we’re not even a domain user!) user account on a completely different computer, we have an admin ticket:
This way – as long as we have a valid NTLM hash or aes key – we can impersonate those users anytime we want from any machine! And they will stay valid until password is changed.
By the way, if you have trouble with mimikatz(like in pivoting scenario) on the separate machine to carry out this attack – you could also just spawn any bogus process on any machine in the domain, where you’ve got a shell and then just steal a token of this process via meterpreter or something.
Recall that TGT is representing an authenticated user in kerberos and service ticket is representing an authenticated user for a particular service. Also, recall that they’re cached in memory and valid for 10 hours. This means, if we’re able to steal those tickets and somehow insert them into our own system – we would be able to request any service ticket on behalf of this user or access a service directly with service ticket. Because for the KDC or the service we will look like a legitimate, already authenticated user. This way we can impersonate this user and gain access for the lifetime of the ticket. This will be 10 hours by default, which is plenty of time to do anything we want.
So, let’s do this:
So, we dumped all tickets into files:
As you can see, we got a bunch of service tickets(those with LDAP, HOST and cifs in file name) and even TGT(those are with krbtgt in the file name). So, you can then download them to any other machine and re use – to become an admin.
Here is our machine at the moment:
Let’s try service ticket first:
And here is what happens now:
And we’ve got access – simple as that!
Of course, we can’t access smb service on another machine – because we don’t have a ticket for this service.
And on the wire you will see that we authenticate to SMB service via kerberos:
Notice that we bypassed steps 1-4 of our kerberos scheme and went straight to 5 and 6.Cool, huh? What if we want to access other machines too, but we don’t have service tickets there?
No problem, we also got a TGT ticket, remember?
So, let’s see now:
Awesome! We successfully got a service ticket for another machine with our TGT.
And here is what you see on the wire:
Notice that we bypassed steps 1-2 of our kerberos scheme and went straight to 3-4 and 5-6.
Recall that everyone has a secret key and KDC is using krbtgt user account password to create a key. Recall also, that KDC is encrypting and signing TGT tickets with it’s own key – which means a secret key of a krbtgt user account. And don’t forget that TGT contain all the group membership data. So, if we can obtain a secret key of this user – we can create our own TGT tickets and essentially impersonate KDC service. There’s more, since PAC data is also signed by this key – we can also create any user and group information in our TGT, which means we can grant any user any privileges. Pretty cool, huh?
It is incredibly powerful persistence trick, allowing you full access to the whole domain under any user and do crazy stuff like access resources with disabled or even non-existent users.
How can we do that?
It’s just an account in domain controller database, so your obviously need access to DC or it’s data.
After that, you can:
Dump it from memory on DC
Dump it from ntds.dit database(along with everyone else)
Steal it from backups or volume shadow copy
Steal it from VM infrastructure, like snapshots or whole disk image of the DC, if they are virtualized.
Or just, you know, replicate it by impersonating a DC(all you need is to run mimikatz under admin privileged account). Check this for details.
Okay, suppose we compromised the DC and dump it from memory:
You can use either aes or rc4 key.
You also need a domain SID – just copy a SID of any user and delete last block with user ID.
Let’s create a golden ticket!
So, we created a ticket for user with admin SID and he is also in all the typical admin groups like Domain Admins, Schema Admins and Enterprise Admins.
Note, you can create it on any machine, even offline.
Now, just pass it:
Once again – no tickets:
Now let’s try to access something:
The funny thing is – godmode user is not even exist:
Yet, there are tickets for him:
Of course, you only have 20 minutes to get as much service tickets as possible with such users, after 20 minutes KDC will validate account information. But you can create a new golden ticket again and again to have unlimited time, if you really want.
At this point – you can do anything you want, you can simply reuse existing accounts or be extra sneaky and grant some regular user account admin privileges, even though, if anyone look him up – he will not have any. You can even use other user accounts and add them with /groups option, to create a kind of super user that impersonate several other users at the same time.
Recall that service ticket created with secret key of either computer account or service account. So, if we know a secret key for this account, we can create forged service tickets to access a service. Since service is usually doesn’t validate PAC data and don’t communicate with DC – we can easily impersonate any user. It is a kind of similar to golden ticket, but limited to specific service.
Computer account passwords is randomly generated and change every 30 days automatically, I think previous one is still valid too, but I didn’t test. You can pull secret keys from memory or get an NTLM hash(rc4 key) from lsa secrets.
So, let’s get a password hash for a computer with kerberos::ekeys command:
Now, let’s create a silver ticket:
So, we granting non-existent user silver with domain admin privileges and ticket for this service.
And let’s try to access it:
Once again you can do whatever you want, just like with golden tickets, you just will be limited to this particular service.
There was also a bug(MS14-068), that allowed to create an arbitrary PAC and insert it into a legitimate TGT ticket, so effect was similar to a golden ticket, but you was able to do that with any domain user and krbtgt user key was not needed. Nice write up is here.
Early this year Dell Secureworks reported that they found a so called Skeleton Key malware installed on DC of the victim. This allowed attackers to authenticate as any domain user with a secret password, but it didn’t affect users and they still could logon with their own credentials.
It works by patching lsass.exe process on DC and it was implemented in mimikatz. It is not persistent and reboot of DC will clear it.
To install it, you will need to have an admin rights.
Suppose we got a domain admin creds and want to leave a backdoor, so let’s plant a skeleton key on DC:
So, now we have a secret password – mimikatz(hardcoded), that should allow us to log in as any user!
Let’s try it:
It’s also work for interactive log in, so you could use it for RDP and even physical log in.
Detecting this activity is a very hard challenge, since we deal with legitimate credentials.
You should heavily focus on detecting tools that used to carry out this attacks and manual monitoring for privileged accounts(this include accounts of executive and other regular employees, who have access to information attacker might want to get). So you would at least have an idea where people regularly logon to and it would be easier to spot a difference.
Check my previous article for more details.
There are still value in logs, so don’t forget to enable logging of kerberos – event ids 4768-4773.
One of the inconsistencies I’ve found is with domain name, when attacker accesses resources as a result of various attacks, so aggregating on Domain name and investigating suspicious entries might be a good idea. Usually, domain name in logs will be in capital letters, but mimikatz send them in lower characters. Take a look for domain names aggregated on a week of data:
As you can see, events with low count definitely look suspicious and need to be investigated(they are in fact from attacks). However, after testing on real life data I’ve found that is not a consistent indicator as you will have quite a bit of lowercase realms, because capitalization of realm is merely a recommendation in Kerberos RFC. But it still can be useful to slice data into smaller chunks. On a full day of data I’ve got about half a million uppercase domains and about 35000 lowercase ones. Unfortunately, it is still a lot of data to manually look at and it doesn’t necessary mean this is a result of attack.
Mimikatz also leave a signature string in domain for golden and silver tickets – oe.eo, so definitely add this too.
Another useful thing to look for – is use of RC4 cipher, since modern Windows(from Vista) use AES by default and lots of attacks rely on RC4. For this – you need to aggregate on Ticket Encryption Type. You need to look for 0x17 or 0x18 as this means an RC4. 0x12 means AES-256 and 0x11 AES-128. Don’t mind 0xfffffff – this is some kind of code when error is occurred and seen in legitimate, unsuccessful ticket request.
Full table of codes for all options is here.
So, unless you have a bunch of XP and 2003 machines or some third party systems – you should never see RC4 used.
Another way to get this data is to monitor network traffic, since most of the meta data is not encrypted, however not much systems support Kerberos. The good news is Bro recently added support of Kerberos traffic and produce the following data:
Unfortunately, not everything is parsed, but still very useful, especially when getting logs is not possible. There is also some problems with the parser, sometimes RC4 detected as AES for some reason.
I’ve also created a wrapper around tshark to detect those attacks. It works, but you need to have no gaps in packet capture. Packet loss or just gaps in kerberos packets ruins the detection and produce a lot of FP as a result. It’s on my github here. It works on any linux machine with tshark version 1.12+
Let’s take a closer look for each attack.
It is hard to spot this attack, because it’s looks exactly like a legitimate activity process. However there is still some artifacts we can use.
If RC4 key is used – then it can be easily spotted via logs or traffic as described above, granted you have a modern environment. With AES it won’t be so obvious. As mentioned above it’s also leave domain name in lower case, that can be useful for detection:
Another thing I’ve noticed, is that Encryption Types is set strictly to a ticket algorithm like only AES 256 or only RC4. This is unusual and easily stand out, because normally OS announce support of all algorithms:
And here is legitimate request:
Let’s detect it with our script:
If you got matches on AES, it is a very good chance this a pass-the-key. On RC4 it could also match on some legacy systems, so don’t jump to conclusion with it. I say it is pretty accurate, I didn’t get any FP on real traffic.
Once again detecting this activity is hard. Logs doesn’t help us much here, since there is no obvious artifacts and all you would see a legitimate entries that tickets was requested or access was granted to a particular user. One way to detect it – is to look what people access. If tickets reused somewhere else, you will see, for example, that admin user requesting service tickets from a bob machine and this is weird. So look for a mismatch between user principal and source IP where requests is coming from. If they are reused from the same machine – you’re out of luck, since they look 100% legitimate.
Another thing you can look in logs and in network traffic – is absence of certain Kerberos steps. For stolen TGT tickets there is no AS-REQ and AS-REP steps in traffic and no event 4768 in logs. For service tickets there is no TGS-REQ and TGS-REP steps in traffic and no event 4769 in logs.
Let’s detect them with our script:
The key here is to get a complete packet capture without packet loss, otherwise you will get a bunch of FP. Also keep in mind you will have gaps in traffic when you start capturing in the middle of the sessions. It is pretty accurate, but you may get quite a bit of FP due to packet loss.
For non-existent users it is fairly easy to spot. You could obviously check all users if they exists or not and alert if you see successful logon with non-existent user(or any other impossible state, like disabled or locked). Another thing to look here is mismatch between Security ID field and Account Name and signature mimikatz string oe.eo in Account Domain.
Here is how it looks:
This information is get populated in all kinds of logs where those fields is present.
When legitimate user is impersonated, this leaves only Domain indicator:
Please note, this signature can change in the future and skilled attackers can fix the code, so it would look legitimate.
We can also use similar detection method as with pass-the-ticket, since there is no AS-REQ and AS-REP steps for golden ticket:
It leaves the same artifacts as golden, so the same detection methods apply. Just make sure you’re collecting events from endpoint computers too, as this leaves no records on DC – all events will be on accessed computers and servers.
Once again we can use detection from pass-the-ticket attack, since there is no TGS-REQ and TGS-REP for silver tickets:
This attack also relies on RC4 for getting a forged TGT, so you can look for that. Because it send only rc4-md5-hmac as supported cipher:
Another easy thing to look at, is request without PAC. This will never occur in legitimate traffic:
Let’s detect it with our script:
The simple way to detect it – is to try default password ‘mimikatz’ yourself.
Mimikatz implementation is a kind of downgrade attack, so after installing skeleton key all users will be downgraded to RC4 cipher, so on Kerberos events you will see they will be using 0x17 Encryption Option, so this is already a huge tell. Especially if they used AES keys in the past.
This only relevant to service tickets. Here is how logon with secret password looks like:
So, if you suddenly have a lot of RC4 cipher used – then you’re definitely have a Skeleton Key, especially if it is a modern Windows systems – they will never default to RC4. Other than that, this doesn’t leave any artifacts in logs.
Another way to detect it – is to use the free script provided by Aorato:
Yet another way is with our script:
Mitigation of most of this attacks is not possible, as this is simply how Kerberos work in Windows environment. For some attacks, mitigation discussed in previous articles is useful and recommended. For the most part, you need to focus on protecting privileged accounts at all cost, because this is what attackers are after and protecting everyone is not possible. Otherwise you will lose control of your network really fast. The most effective mitigation at the moment seems to be Protected Users group and Credential Guard.
Let’s see for each attack type in detail:
The Protected Users group prevent storage of keys in memory, so there is nothing to steal for members of this group, but other users will stay vulnerable. Complete mitigation is possible only with Credential Guard. You could also disable RC4 cipher(it is enabled by default even in 8.1/2012) if you don’t have any legacy systems(no XP and 2003) to prevent at least RC4 based pass-the-key, but it is hardly a real mitigation because they can use AES keys just the same. For 7/2008 this requires KB2868725.
Then use the following GPO settings:
Network Security: Configure encryption types allowed for Kerberos
And here is the result:
Credential Guard is the only possible mitigation, Protected Users can’t help with this due to the need to store tickets in memory for normal operation.
Golden & Silver Ticket
Mitigation for this type of attacks is not possible. Only remediation steps – see below.
This bug was fixed in KB3011780, so install it ASAP on each DC. I think 2012 DC is not affected by this.
I think Protected Users should help with this since it deny usage of RC4.
You can also disable RC4 cipher(described above) and it will break skeleton key even if it is installed, however keep in mind that attacker can enable support of RC4 back, so you need to keep monitoring it.
Remediation for those types of incidents is costly and time consuming. Since Kerberos doesn’t allow revocation of tickets, all remediation steps should assume that attacker still have access with tickets and wait out on expiration before any active action. You quickly lose control of domain and your network after compromise, allowing unlimited persistence for an attacker. So, you could take a risk and recover the same domain or rebuild the whole domain and forest, as this is the only way to be sure that attacker doesn’t leave any backdoors.
If you’re suspecting that the key was stolen – you need to change the password(this will invalidate the key) of the account and possibly disable it too. You also need to forcibly logoff all active sessions from this user to be sure. However, it doesn’t affect granted tickets – see below.
The only thing you can do – is to clean cached tickets with this script and wait out expiration time. However, this doesn’t cover cases where attacker could simply reload ticket from file or use it on machine outside your control. Of course, changing password of affected accounts is necessary too in case he got a key.
You need to change a krbtgt user password twice in a rapid succession to prevent any more tickets. You can also change it frequently yourself to limit potential exposure and window of opportunity for an attacker. Please note, this can cause disruption in access, so plan ahead. You can use MS provided script for this, available here.
You need to change a computer password – you can do this via Users and Computers MMC, netdom or Reset-ComputerPassword powershell script. I think previous password is stay valid too, so this means you need to reset it twice. However I didn’t test it. If your service is running under dedicated user account, then reset his password.
Patch DC and use remediation from pass-the-ticket.
Reboot the DC. You might also reboot it time to time, just it case.