Quick note here, this blog does not dive into the details of how kerberos operates. If that’s what you’re looking for, see this excellent post.
Background
When I was studying for the CISSP, I was chatting away in the Discord server recommended here, when I saw the gem “Kerberos encrypts the username to authenticate” fly past. Having played with Kerberos a little myself, I knew this was incorrect, and lively debate followed. The original messager pointed to the Sybex CISSP Official Study Guide as their source. Intruiged, I cracked open my own copy, and saw the Kerberos steps listed below.
(as an aside, I withdrew from the debate at this time. While I know technically how Kerberos works, if that’s how ISC2 reports Kerberos works, that’s probably how they test it too. I’d hate for someone to fail an exam because they learnt how the real world works instead of what ISC2 want you to know).
For reference, below are the steps listed in the study guide as how Kerberos performs authentication:
|
|
Logically, steps two and three can’t co-exist. If the username is encrypted, either it needs to be encrypted with a Pre-shared key (PSK) that is NOT the users password, or a PSK that IS a hash of the users password.
If the username is encrypted with a hash of the users password, then when it gets to the KDC, the KDC needs to bruteforce this auth attempt with the password for EVERY user in it’s database, unless another piece of identifying information is passed with the encrypted username.
Alternatively, the PSK is NOT based on the users password, but in this case, the AES password needs to be sent to the requesting system across the network in either cleartext, or using something like Diffie Hellman Key Exchange. I’ve never read this being the case, nor observed it. Nontheless, we allow for this in our testing environment.
Process
On to the research! First, I like to start with a problem statement, which is effectively “What am I trying to prove / disprove”. In this example, my problem statement read:
The listed Kerberos logon process, step 2: 2. The client encrypts the username with AES for transmission to the KDC (as taken from CISSP Official study guide, Sybex, 8e, p. 604; Chapple, M. Stewart, JM. & Gibson, D.) is incorrect.
Now I’m generally looking for three investigative avenues I try and persue independently of each other, whenever possible:
- Does the assertion pass the sniff test?
- How does the documentation say it should work?
- How does it actually work?
We’ve already documented one above. It doesn’t pass the sniff test (ie, it can’t work that way) because of the intense burden it would place on kerberos servers with many users.
For two, we dive into the RFC, or request for comments. This is a document that is effectively where a bunch of very smart people get together and agree on how a given system / protocol / other should work by design. In this particular case, RFC4120 states:
In the request, the client sends (in cleartext) its own identity and the identity of the server for which it is requesting credentials, other information about the credentials it is requesting, and a randomly generated nonce, which can be used to detect replays and to associate replies with the matching requests.
Happy days! This reads to me that, at least by design, the username should not be encrypted when it’s shipped to the server. Better, this isn’t because there’s an omission of specification, it explicitly calls out “in cleartext”. No ambiguity here! Great, this aligns with our sniff test. There’s no guarantee that this is how it’s been implemented though, so let’s move on to point three.
Sounds like labbing time! When I’m doing this research, I’ll record and report how the lab is built and justification, so that people reviewing my work in the future can replicate it should they so desire.
Lab Setup
The Network
Here’s a high level view of the network I set up in two seperate testing instances (which is why the IP addresses overlap)
Router
This machine was set up to emulate a stupid network tap. It hasn’t been added to any domain, and has no contextual awareness of the hosts on either side. IF this machine can see credentials passing over the network in plaintext, then we know that PSK passing for AES can’t be in place, because if it was, this machine wouldn’t know what it was, OR tcpdump wouldn’t apply it automatically.
Router was set up following this process.
iptables was configured with the below settings:
|
|
Here’s a complete view of the host’s network interfaces post configuration:
|
|
Finally, for each test, tcpdump was executed with this command: tcpdump -i ens35 -w ~/<relevant pcap name>
Windows
Server Setup
Use Server Manager to add the Role “Active Directory Domain Services” and dependencies only. Promote server to domain controller, creating a new forest called mydomain.hidden Accept forest and domain functional lecels of Windows Server 2016 Password: Accept netbios name of mydomain
Once installed and rebooted, create a user called plaintextusername. Add this user to domain administrators, because we’re lazy and don’t want hiccups.
Client Setup
Join to the domain, prior to logging packets. This is because when I didn’t, NTLM authentication was used, and I hadn’t the time to work out how to force kerberos.
Restart machine.
Windows Test
On the client, attempt to authenticate as mydomain\plaintextusername
and mydomain\unknownuser
.
For the known user test, we’re attempting to authenticate with a valid credential. If you want to follow along, the pcap is here. To generate this traffic, we had the client booted up, and attempted to sign in to the machine with the correct credentials for mydomain\plaintextusername
. As shown below the CNameString plaintextusername and the realm mydomain are being passed across the network in clear text in packet 4.
For the unknown user test, we’re attempting to authenticate with an invalid username (this user doesn’t exist in the domain). If you want to follow along, the pcap is here. To generate this traffic, we had the client booted up, and attempted to sign in to the machine with the invalid username mydomain\unknownuser
. As shown below the CNameString unknownuser and the realm mydomain are being passed across the network in clear text in packet 4.
This looks pretty great, right? Our sniff test is appears correct, and it looks like the windows configuration I’ve tested is RFC compliant! But what about Linux?! I hate being adamantly wrong, so best to cover our bases.
Linux
Server Setup
I followed this guide, running the below commands (relevant output is recorded too, because I’m fancy like that)
|
|
Client Setup
For the client, I followed this guide, running the below commands:
|
|
Linux Test
On the client, attempt to authenticate as mydomain\plaintextusername
and mydomain\unknownuser
.
For the known user test, we’re attempting to authenticate with a valid credential. If you want to follow along, the pcap is here. To generate this traffic, we ran the below commands:
|
|
As shown below the CNameString plaintextusername and the realm mydomain are being passed across the network in clear text in packet 4.
For the known user test, we’re attempting to authenticate with a valid credential. If you want to follow along, the pcap is here. To generate this traffic, we ran the below commands:
|
|
As shown below the CNameString unknownuser and the realm mydomain are being passed across the network in clear text in packet 4.
Interestingly, ubuntu doesn’t ask for a password when you run kinit until AFTER it receives the response from the server indicating the username was valid or not. This makes sense as far as our research goes, but was interesting to me, and it could be used to enumerate valid usernames.
Conclusion
This doesn’t need to be fluffy, it should be concise and report your findings and conclusion. In this case “As the RFC quoted and testing undertaken have shown, neither in theory nor practice is the Authors assertion that at step two of kerberos authentication “The client encrypts the username with AES for transmission to the KDC” acccurate.” is sufficient.
Conclusive Conclusion
Different publishers have different formats for their errata, so format it how they want it. Unfortunately, in this case, I submitted and had my submission acknowledged, but the publisher and authors never provided closure on why the errata wasn’t implemented. So it goes, I guess.
I did provide my findings to the server for the benefit of people who wanted to understand how the real world works, however.