Press "Enter" to skip to content

Mimikatz and DCSync and ExtraSids, Oh My

Edit: Benjamin reached out and corrected me on a few points, which I’ve updated throughout the post. Importantly, with the ExtraSids (/sids) for the injected Golden Ticket, you need to specify S-1-5-21domain-516 (“Domain Controllers”) and S-1-5-9 (“Enterprise Domain Controllers”), as well as the SECONDARY$ domain controller SID in order to properly slip by some of the event logging.

Benjamin Delpy is constantly adding new features to Mimikatz. In June, he added the ability to include ExtraSids in golden tickets. This was built in coordination with Sean Metcalf‘s work on the subject, and something I talked about here.

Benjamin and Vincent Le Toux also recently added the ability to abuse the MS-DRSR protocol for domain controller replication, in order to recover hashes from a DC without code execution. I touched on this briefly in the post detailing Empire’s v1.2 release (and in a demonstration video) but I wanted to revisit the subject and show how these two new features can be combined into a single attack chain. If you’re interested in Active Directory attacks, be sure to check out Sean’s “Red vs. Blue: Modern Active Directory Attacks & Defense” talk at Derbycon, Friday at 3:00pm. I hear he’ll be dropping some interesting information applicable to this post :)

Sidenote: if you want to compile the newest version of Mimikatz for PowerSploit’s Invoke-Mimikatz, just grab Benjamin’s source code, open it up in Visual Studio, select the “Second_Release_PowerShell” target option and compile for both Win32 and x64.

powerkatz

Then transform the resulting powerkatz.dlls to a base64 string using base64 -w 0 powerkatz.dll in Linux. You can now replace the $PEBytes32 and $PEBytes64 strings at the bottom of Invoke-Mimikatz.ps1. Empire keeps a separately updated version of Invoke-Mimikatz with a few additional tweaks.

Scenario

Let’s say you’re operating in the following example network:

testlab_domain

You land on a machine in the dev.testlab.local domain, and there is tight network filtering from here to the others in the forest; i.e. you can talk to your SECONDARY.dev.testlab.local domain controller but to few machines in other domains. We’ve seen this setup a few times in the field, where an organization keeps the forest root relatively ‘sparse’ and keeps less trusted subsidiaries/groups in a segmented domain.

After some user-hunting and some lateral spread, you end up on workstation WINDOWS3 with domain administrator credentials for dev.testlab.local. From this point historically, you would often compromise/exfil the NTDS.dit of one of DEV’s domain controllers, and then start the process of hopping through the trust mesh. While we were usually successful in cross-domain compromise, this process often took a good a good bit of time and effort. Let’s see how we can use some of these new school techniques to speed up the process.

Step 1: Enumerate the Forest

First let’s do a bit of network and domain situationalf awareness. We can enumerate the current trusts in the forest in a few different ways- my preference is to use PowerView 2.0 and run Get-NetForestDomain or Invoke-MapDomainTrust -LDAP to recursively map all trust relationships in the forest:

powerview_get_forest_domain

powerview_map_trusts_ldap

This is also possible through Empire with the situational_awareness/network/mapdomaintrusts module.

Step 2: DCSync the Child

Now let’s extract the krbtgt account hash from a dev.testlab.local domain controller. Instead of having to install an agent, we can now use Mimikatz’ DCSync to extract the hash. One thing to note is that you need to specify “<NT4_DOMAINNAME>\krbtgt” for the specified user for this to work properly (you can find the domain shortname easily with whoami or other methods). In this case we’re using DEV.

Here’s how it looks in our environment with Invoke-Mimikatz. Note that you need to use -Command ‘”COMMAND”‘ when running any custom commands through Invoke-Mimikatz (double quotes embedded in single quotes):

dev_dcsync

And here’s how we can execute the same functionality through Empire:

empire_dev_dcsync

One nice note- Empire will now parse the DCSync output and save the output into the credential store:

empire_dcsync_creds

Step 3: ExtraSids to Hop up the Trust

Now let’s use this compromised child DC krbtgt hash to compromise the forest root (and therefore the entire forest). The demo video showed doing this straight from the same original workstation, but in our scenario we run into a problem: we can’t talk directly to the domain controller for the testlab.local root. Happily for us, domain controllers in a forest have to be able to talk to each other for replication and shared authentication, so at a minimum in our scenario, the DC for dev.testlab.local will have communication open to a DC in testlab.local.

To hop up the trust, we need a few pieces of information:

  • the krbtgt hash for the child domain (dev.testlab.local), which we just extracted with DCSync
  • the SID for dev.testlab.local, also in the DCSync output
  • the name of the target DEV user for the ticket
    • In this case it’s going to be SECONDARY$, the name of DEV’s domain controller machine account. More on this shortly.
  • the fully qualified domain name of the forest root (in our PowerView output)
  • the SID of the “Enterprise Admins” group of the root
  • edit: the SID of the “Domain Controllers” group (S-1-5-21domain-516), the SID of “Enterprise Domain Controllers” (S-1-5-9), and the SID of the SECONDARY$ domain controller (which you can get with ‘Get-NetComputer SECONDARY.dev.testlab.local’ from PowerView), in this case S-1-5-21-4275052721-3205085442-2770241942-1002.

To get the FQDN of the forest root, we could use PowerView with Get-NetForestDomain or Get-NetDomainTrust, or the following one-liner:

Then we need the SID of the forest root. I’m sure there are better ways to do this, but one easy one is to resolve the ‘krbtgt’ account for the domain:

Then we just replace the -502 in the SID with -519 to get our Enterprise Admins SID for testlab.local (in this case S-1-5-21-456218688-4216621462-1491369290-519) edit: with the -516 “Domain Controllers” SID (in this case S-1-5-21-456218688-4216621462-1491369290-516). The Mimikatz command we’re going to ultimately use to build our trust-hopping ticket is:

So we have a few options here. We could use Empire to WMI to the DC for dev.testlab.local and then run the credentials/mimikatz/golden_ticket module with the necessary information. For the Golden Ticket creation, we can use the saved krbtgt hash from the DCSync output, setting CredID to 1, the user to SECONDARY$, and the sids to S-1-5-21-456218688-4216621462-1491369290-519 edit: S-1-5-21-456218688-4216621462-1491369290-516,S-1-5-9:

empire_dev_golden_ticket

We could also RDP to the DEV domain controller, use a download cradle to load up Mimikatz, and run our specified command. In either case, we now have administrator access to the domain controller (PRIMARY) for the testlab.local forest root!

primary_access

Step 4: DCSync the Forest Root

We now have all the privileges needed to compromise the krbtgt hash of the forest root. This time our command will be a bit more complex. One thing we need is the domain NT4 shortname of the forest root. You can use this Gist, or you can translate the username to a SID and back again. In our case, the shortname is TESTLAB.

Here is the command we’ll be using:

If testlab.local had multiple domain controllers and we wanted to specify a particular one, we could use the /dc:DC.FQDN flag as well. This is how it looks through Empire:

empire_primary_dcsync

If we want a single Invoke-Mimikatz command to build/inject the Golden Ticket, DCSync the root, and then purge current tickets from the session, we can do that by space separating the double quoted Mimikatz commands:

And if the SECONDARY domain controller allows PSRemoting, we don’t even have to RDP, and can perform the entire attack chain from our WINDOWS3 workstation! Because we’re constructing and injecting a new TGT, we don’t have to worry about the Kerberos double-hop problem:

golden_dcsync_psremoting1golden_dcsync_psremoting2

Now why did we use the SECONDARY$ account (the domain controller for the child) when building our ticket, as opposed to a normal *-500 Administrator account? edit: And why use the “Domain Controllers” and “Enterprise Domain Controllers” SIDs when creating the ticket? @gentilkiwi explains in the following tweets:

delpy_dcsync_dc_acct
delpy_dcsync2

During the execution of our first DCSync, we had to use our current dev.testlab.local Domain Admin credentials, which causes log entries as Delpy describes above. Once we gain the krbtgt hash of the DEV domain controller (through DCSync or other methods), we can be sneakier in attacking the forest root. If we create our Golden Ticket (as we did above) such that the user account in the PAC is the machine account of the DC we’re currently operating from (in our case SECONDARY$), but the ExtraSids contains the “Enterprise Admins” SID for the forest root edit: the Domain Controllers SID for the forest root and the “Enterprise Domain Controllers” SID, we should be able to DCSync the krbtgt hash of the root without creating additional logs! This is something others have already started to touch on.

Edit: because /id defaults to domain-500, the /user and /id for this ticket won’t match, meaning it will only work for 20 minutes. This is all the time we need, but if you would like it to last longer, you can enumerate the full SID of the SECONDARY.dev.testlab.local domain controller and set that for the /id argument. Note: I haven’t tested this thoroughly as far as log generation, so if the described behavior isn’t accurate, please let me know and I will correct the description.

Wrapup

At this point, with the krbtgt hash of the forest root, we can build Golden Tickets on demand to compromise any machine in the testlab.local forest. By taking advantage of Mimikatz’ new features and Sean’s new work, we can quickly and easily turn the compromise of any domain administrator credentials in the forest into a total forest compromise. One interesting defensive note (that reiterates Microsoft’s description that the domain is not a trust boundary): it’s not sufficient to change all domain passwords and roll the krbtgt account hash of just the root domain (or the compromised domain), you need to roll the krbtgt hash for ALL domains in the forest. Or just:

keep_calm

6 Comments

  1. bigf4n bigf4n November 22, 2015

    Assuming you have domain admin creds’, how do you hop from one end point (computer) in a forest domain to another computer in a secondary domain (same forest) while the a the two domains run on separate networks? (separate vlans, both DCs can communicate – bridged).

    • harmj0y harmj0y November 22, 2015

      You would need to establish a way to execute the actions from the DC you have access to, whether through an agent or RDP. In similar situations in the past, we’ve RDP’ed to the first DC, started PowerShell/loaded up Invoke-Mimikatz and executed the functionality from there.

  2. WoW WoW November 30, 2015

    Don’t you think RDP is too noisy?
    Does Empire has the ability to tunnel other empire instances in the network?

    Assuming we have two domains in a Forest and a domain admin in both A & B (with bidirectional trust) is it possible to use DCSync and query a user’s hash saved in Domain A from an end point that is only connected to DC B?
    to illustrate: B -> DC(b) DC(a) <- A
    So B can get user hashes from A by using DCSync on the domain he's connected to (and although B doesn't have direct access to A).
    Is this implemented in PowerView/Empire?

    Thanks!

    • harmj0y harmj0y December 1, 2015

      RDP ‘noise’ depends on the environment. In some environments, RDP is used as the primary remote access method, so using RDP is actually preferred to blend with the noise (in others the opposite is true). Concerning the trust, more information is needed-> “bidirectional trust” meaning an external or inner-forest trust? I’m pretty sure domain hashes are not replicated across external trusts (and I don’t believe so between intra-forest internal trusts), so you would need to communicate to a DC in domain A from the end point in domain B. This distills some of the points of the post, that depending on network segmentation you need to pivot traffic through the DC_A->DC_B communication through RDP or agent tunneling. Empire does have basic ‘pivot listeners‘ but this involves opening up firewall ports on the pivoting machines.

  3. . . December 7, 2015

    If there’s a one-way trust between DEV and the forest root, can you still pop the entire forest by getting DA/krbtgt on DEV?

    • harmj0y harmj0y December 7, 2015

      According to Microsoft, “All domain trusts in an Active Directory forest are two-way, transitive trusts”. So it’s not really possibly (maybe technically in some weird way, but not commonly/practically) to have a one-way or non-transitive trust between two domains within a forest (and the sid hopping approach only works on domains within a forest).

Leave a Reply

Your email address will not be published. Required fields are marked *