An Empire Case Study

This post is part of the ‘Empire Series’, with some background and an ongoing list of series posts [kept here]. 

Empire has gotten a lot of use since its initial release at BSides Las Vegas. Most of the public articles we’ve seen on Empire are quick-start guides that cover initial setup and a few common features. To really emphasize the full capability of Empire we wanted to do a walk through of a fictional case-study from initial access to complete forest ownership. This post is the second in the “Empire Series”, and is an expanded version of the demo given at BSides D.C that shows how Empire can be used in real world networks.

Initial Access

Empire has a variety of ways to execute the stager code that loads the main agent, including Office macros, .war files, HTAs, etc. We will dive in depth into phishing in a future blog post, so for now we will assume you have obtained access into a corporate environment via an Office macro. For this case study, we have landed on a user’s workstation in the “DEV” domain, which is a subdomain of the primary “CORP” domain.


The first thing we notice about our initial access is that we are not in elevated context. You can determine this by viewing the main agents menu – agents with a (*) are elevated. You can also determine the integrity context by typing info in an agent menu (‘high_integrity = 1’ means the agent is elevated).


Since we need elevated privileges to dump credentials, we’ll first try to privesc. Before we can start to identify possible privilege escalation paths we should do a bit of host situational awareness. Empire’s shell command allows us to execute normal Windows commands on the system and we are able to identify that our current user “dfm” is in the local administrators group.


With this knowledge we assume that since “dfm” is in the local administrators group but not elevated within our agent, UAC could be in play. In order to elevate up, we can use Empire’s “bypassuac” command to bypass the User Access Control prompt and elevate to Administrator.


As you can see, our new agent now contains the (*), indicating that it is elevated.

Gathering Credentials

Now that we have elevated access on our compromised host we can extract credentials from memory. By issuing a ps command, we are able to see all of the running processes on this particular host. If we look closely, we are able to see that the domain user “Mike” has a process running.


Running the mimikatz command within our elevated agent will let us extract Mike’s credentials:


The output for Mimikatz will be displayed back to you for your viewing pleasure. Empire will also automatically parse the output and add any scraped credentials to its backend data model. This can be viewed by typing creds.


If you want to filter the credential output you can type creds <filter> to only display the information you want. For example, you can type creds plaintext to get only the plaintext credentials from the database or you can type creds Mike to only get credentials that apply to the user “Mike”.


User Enumeration

Since we have the user “Mike”, we should probably find out who he is and what he does. This can be done in a few different ways, such as through PowerView or the built-in Windows net commands. Empire also has the get_user module that will return all sorts of juicy information on the user(s) specified. You can jump to this module with usemodule situational_awareness/network/powerview/get_user.


By setting the “UserName” field to “Mike”, the module will execute and return us Mike’s user properties:


If you use PowerView for normal situational awareness you may see that the output for this module looks much like the output of the Get-NetUser function in PowerView. This is because Empire has many abstracted functions from PowerView built in as modules under situational_awareness/network/powerview/* that let you execute large parts of PowerView’s functionality without loading up the complete script.


We see that the module output indicates that Mike is a part of the “Workstation Admins” group. By viewing the net localgroup Administrators output that was displayed previously we also see that the “Workstation Admins” group is a local administrator on the host we landed on. This means that we may be able to reuse these credentials to access other workstations in the enterprise.


With that information in our back pocket we can now start to hunt for interesting users (instead of just hitting random boxes and hoping for the best). We can kick this off by using the situational_awareness/network/powerview/user_hunter module. This module takes the Invoke-UserHunter function from PowerView and abstracts it into its own module within Empire. When running this with the default options, it will query your current domain for any machines with Domain Admins logged in and display it back to you.


It looks like the Domain Admin “DEV\will-da” has a session from Let’s see if Mike’s compromised credentials will get us access to that host. We can get the hostname of this target with Empire’s shell command:

Now we can check and see what users/groups are a part of the local administrators group on that host by running the situational_awareness/network/powerview/get_localgroup module. This particular module is an abstracted version of Get-NetLocalGroup from PowerView.

The output from this module will let us know exactly who can access the host we’re targeting:


In the output above we can see that the group “Workstation Admins” is one of the groups added to the local administrators group on our target. Since we also set the -Recurse flag the backend PowerView code resolved the members of any resulting groups as well, giving us the effective set of users who can access the host. With this output we can verify that Mike’s credentials will give us access to our target host.

Lateral Movement

Since we now know that “Mike” should give us access to the host with the Domain Admin “will-da” logged in, let’s verify the access by stealing one of Mike’s process tokens and trying to access the host remotely. Since we saw that Mike had a process of “cmd” running, we can filter the ps output for just those processes with ps cmd.


We can steal its token by using the steal_token <PID> command and then attempt to access “C$” of the target host:


Now that we’ve confirmed access, let’s trigger an agent on the remote system. Empire has a variety of lateral movement options, but for this case study we’ll stick to WMI. Let’s load it up with usemodule lateral_movement/invoke_wmi:


After setting the Listener and the ComputerName fields we can kick off execution. In situations where you can’t get into the context of a user that has access to a target, but you have their credentials, you can set the CredID field to the entry that corresponds to that particular credential set.


Success, we have a new agent! Let’s pillage this new host with mimikatz:


W00t, we now have plaintext domain administrator credentials!


It is important to note that after moving laterally via WMI you will face something called the “double-hop problem”, meaning your new agent context can’t be used to jump to additional machines. We can resolve this by injecting into another process or stealing the token of another user. In our case we can easily inject into a process by using the management/psinject module. Let’s find a process owned by “will-da”:


The psinject module has 2 required arguments- the listener you want the new agent to stage from and the PID of the process you wish to inject into.


With an agent running in the context of the domain admin in dev.lab.local we can verify our access by executing a shell dir on C$ of a domain controller. First let’s identify the domain controllers for our current domain with the situational_awareness/network/powerview/get_domain_controller module:


Now let’s verify the access:


Hopping the Trust

Domain Admin credentials for DEV are fun and all, but what we really want is Enterprise Admin access in the parent lab.local domain. To verify that the dev->lab trust relationship exists, let’s first use the situational_awareness/network/powerview/get_domain_trust module:


The output confirms that there is a Bidirectional trust between dev.lab.local and its parent lab.local. Since this is a forest trust we can leverage our DA credentials in the child to compromise the entire forest! But before we do, we need a few pieces of information.

First we need to get the SID of the parent domain by resolving the LAB\krbtgt account to its security identifier with the management/user_to_sid module:


Next, we need to get the hash of the krbtgt account for the dev.lab.local child domain. Benjamin Delpy and Vincent Le Toux have us covered with Mimikatz’ DCSync functionality, which is implemented in Empire’s credentials/mimikatz/dcsync module. All we need to do is fill in the UserName option:


Empire nicely parsed the output for us and threw it into the credential store:


We now have all the information we need to execute the external SID history Golden Ticket attack which will allow us to compromise the root of the forest. Empire implements Mimikatz’ Golden Ticket functionality in credentials/mimikatz/golden_ticket. Since the hash of DEV\krbtgt was scraped and thrown into the credential store we can simply enter the credential ID in the CredID field within the Golden Ticket module. Then all we need to do is specify a user and an external SID for the ticket. When specifying the SID, we need to take the “502” off the end and add a “519” to construct the full SID of lab.local\Enterprise Admins.


With the ticket created, we can now use DCSync to extract the krbtgt hash of the parent lab.local domain:


Now we have both hashes of the krbtgt accounts for both domains:


It’s not really necessary, but let’s go ahead and repeat the Golden Ticket process with the krbtgt hash of lab.local. We just have to specify the CredID for the lab.local krbtgt account, the username and the domain (lab.local) since the module remembers the sid options:



As you can see above, we were able to successfully create another Golden ticket using the krbtgt from the parent (lab.local) domain.

Just to make sure everything went smoothly, we can test access to the lab.local Domain Controller by hitting C$:


Hopefully this post showed you how Empire can help execute a complete engagement from initial access to complete forest compromise. Stay tuned for additional posts in the “Empire Series” where we’ll dive into more of Empire’s functionality!