Abusing Kerberos to NTLM fallback to defeat BitLocker FDE

Intro

This vulnerability is related to the initial vulnerbility which I and my collegue Tom found back in February, namely the Microsoft Security Bulletin MS16-014.
More information about the MS16-014 attack can be found in my earlier blog post here.

TL;DR

Windows login screen can be bypassed using NTLM and a "rogue" domain controller, essentially defeating BitLocker FDE.

Bypassing patch MS16-014

Past experience tells me that Microsoft doesn't always properly patch the vulnerabilities correctly. (see MS15-122 and MS16-014)
That being said I was rather sceptic if they fixed it well this time. So I starting thinking of different scenarios which could lead to new exploitation ways.

After spending a few days testing out different scenarios I was coming up empty handed. Well maybe they did fix it well this time? =)
The last scenario that was on my list was "What would happen if a KDC goes down in the middle of a password change process?".

I had setup a rogue DC which was untrusted by the client and would not allow me to perform the password change. However it still allowed me to get to the password change step.

So I reset the password of the user on the fake domain controller, the user corresponds with the user that has been logged on in the past (credentials are cached!).

I go back to the client machine and type in the password I just set as "expired" and you get the following:

Followed by:

At this point I decided to block all Kerberos traffic from reaching the "rogue" Domain Controller by using Window Firewall:

Went back to the client and pressed "Enter" to start the password change procedure:

And I waited... and waited...

Then suddenly...after 6 minutes...

It worked!??

How/Why did it work?

To get the answer to the question I had to look at the traffic.
So again I reset the account and went to all the steps and started to look at the Wireshark captures.

After going quickly through the wireshark capture, I can see that the client machine is sending a bunch of retransmissions on port 88 which is the port used for Kerberos communication. After 6 minutes it falls back to NTLM and tries to change the password.
So Microsoft fixed the trust relationship issue with Kerberos (MS15-122/MS16-014) but didn't change it for NTLM.

But why 6 minutes? As an attacker you want the attack to be completed as fast as possible to avoid detection of some sorts!
The 6 minutes has to do with the TCP Connect Timeout value, for Windows the default is set to 72 seconds for initial connections and has a default of 5 retransmissions before timing a connection out.

72 sec x 5 = 360 sec / 6 minutes.

So I started playing around with the timeout, in the hope there is some sort of improper handling on the client side that makes it fallback much faster.
So i tried 30 seconds, blocked the ports 88 and 464 in Windows Firewall.
Continued with the password change on the client machine and allowed the ports again.
No luck :( So stepped it up to 1 minute... and it worked!??

Now I needed to know why it falls back to NTLM after just 1 minute?
I don't have a clear answer to that question and Microsoft has been very vague about the details. However I think it is some sort of race-condition, when it sends the 5th retransmission it starts to look for other ways to complete the password change request.
So when I enable the Kerberos ports again it skips Kerberos and goes into NTLM eventhough the TCP Connect Timeout value is has only been expired for the first retransmission.

However for my point of view it's still unclear what exactly is causing the speed up the Kerberos to NTLM fallback procedure. If you think you know the answer feel free to contact me on Twitter or send me an email.

Again this vulnerability wasn't too complex to find but still required some out-of-the-box thinking. It's a sneaky and dirty way to defeat BitLocker FDE, especially like this.

PoC Demo

Timeline

  • Vulnerability discovered (23rd of February 2016)
  • Disclosed vulnerability details to MSRC (4th of April 2016)
  • Vulnerability acknowledged (25th of June 2016)
  • Vulnerability patched (9th of August 2016)