Internal penetration tests, as approached by Dionach, are a good exercise to assess the security of the internal networks of our clients. Typically, we spend a few days on-site, starting with a standard low-privileged account - or in many cases with no credentials at all just patching ourselves to the network - and working our way up trying to fully compromise the network, at which point we then carry on auditing the network and its different components.
In a majority of the cases these types of tests, although large in scope, tend to be quite straightforward. The larger the network is, the easier it tends to find that one hole an attacker needs to get in and escalate privileges before taking over the entire network. However, every now and then we run into networks that for a variety of reasons are more resilient than the average, and those are precisely the ones that pose more of a challenge for us, therefore being also much more fun. In a recent test I ran into one of these networks, where by a combination of factors I had to get a bit more creative than usual, and although it took me a while in the end I got there!
This test started without any credentials, just a network connection into a relatively small network. After firing up a quick Nmap and Nessus scan, nothing too helpful came out of it, so I launched Responder (https://github.com/lgandx/Responder) and left it running for a few minutes. When I got back to it, I noticed a few network hashes, one of them seemed to belong to a Local Administrator (RID 500) account.
After trying to crack the network NTLM hash (Net-NTLMv2) for a while without any luck, I decided to try to relay this hash instead. For this, there are a number of tools we can use, but first of all it is necessary to identify hosts where this hash can be relied to. The trick here is that you will not be able to relay hashes to servers that have SMB Signing (https://support.microsoft.com/en-us/help/887429/overview-of-server-message-block-signing) enabled, this feature was introduced in Windows 2000 and since then it has been supported by all versions of Windows operating system. However, it is enabled by default only on domain controllers. If you are wondering why it is enabled on Domain Controllers, it is because SMB is the protocol used by clients to download Group Policy information, and SMB signing ensures that this information is from a genuine source and authentic.
Responder comes with a handy tool that takes a network range and will verify which servers have SMB Signing enabled, which in most cases are just the Domain Controller, but... with this client in particular, there were just a couple of servers that had SMB Signing disabled:
# python RunFinger.py -i 172.16.2.0/24 [...] SMB signing: False Machine name: server1.domain.com [...] SMB signing: False Machine name: server2.domain.com [...]
Combining the fact that I could get network NTLM hashes for what it seemed like a Local Administrator account, and that I had a couple of potential targets where to relay these hashes, I fired up Impacket's NTLMrelayx tool (https://github.com/SecureAuthCorp/impacket) without any parameters. By running it this way, if the connection works and the account has sufficient privileges, the tool will dump local SAM hashes for the targeted server.
Responder running with HTTP and SMB servers disabled:
# python Responder.py -I eth0 -w -r [...]
# ntlmrelayx.py -t 172.16.2.180 -smb2support [*] Authenticating against smb://172.16.2.180 as domain.com\administrator SUCCEED [*] Service RemoteRegistry is in stopped state [*] Starting service RemoteRegistry [*] Target system bootKey: 0xe74***************************9f [*] Dumping local SAM hashes (uid:rid:lmhash:nthash) RENAMED_ACCT:500:aad3b435b51404eeaad3b435b51404ee:73***************************acc::: Guest:501:aad3b435b51404eeaad3b435b51404ee:b8*****************************ba::: [*] Done dumping SAM hashes for host: 172.16.2.180
Alright, now we are getting somewhere! Note that one of the hashes belongs to what seems to be just another renamed Local Administrator account (it still has RID 500). The good thing here is that this is a valid NTLM hash (as opposed to the previous Net-NTLMv2 hash from Responder) that you can use to do Pass-the-Hash attacks. All other local accounts -even privileged ones- do not support this since Microsoft released a patch a few years ago, but the default 500 admin account is still good to go!.
With this newly found hash, and the help of PowerView's Invoke-UserHunter CMDlet (https://github.com/PowerShellMafia/PowerSploit/tree/master/Recon#user-hunting-functions), I located a server where a Domain Admin account was logged in and where the above Local Admin account hash was valid. After trying to go the easy way with Metasploit, Empire and other tools, connection was refused. I assumed that there must have been some sort of decent anti-virus in place blocking the connection, so I went old school and with the help of WMI I ended up connection:
# wmiexec.py -hashes ad3b435b51404eeaad3b435b51404ee:73***************************acc RENAMED_ACCT@172.16.2.180 [*] SMBv3.0 dialect used [!] Launching semi-interactive shell - Careful what you execute [!] Press help for extra shell commands C:\> whoami hostname\RENAMED_ACCT
As this shell is a bit limited, I created a new Local Admin account so I could RDP into the server, but before I had to enable remote sessions via the above shell:
C:\> reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f
After trying again multiple approaches, nothing seemed to work. Then again, the Anti-Virus seemed to be doing a good job, and I didn't want to just kill it, so in the end I used Sysinternal's procdump (https://docs.microsoft.com/en-us/sysinternals/) to dump a copy of the LSASS process memory:
C:\> .\procdump.exe -accepteula -64 -ma lsass.exe lsass.dmp [...] Dump count reached.
This memory dump can then be copied to your local workstation, and processed with Mimikatz:
mimikatz # sekurlsa::Minidump "C:\lsass.dmp" Switching to MINIDUMO : 'C:\lsass.dmp' mimikatz # sekurlsa::logonPasswords Opening : 'C:\lsass.dmp' file for minidump... [...] * Username : Domain_Admin_Account * Domain : DOMAIN.COM * NTLM : 100**********************6a5
Although Mimikatz did not get the clear-text password for the Domain Admin account, it did get the NTLM hash, which was enough to then connect to a Domain Controller, and create a new account that was granted Domain Admin privileges as well.
Despite the fact that in the end I got it all figured out, in the process I tried many things like Passing-the-Hash over RDP, alternatives to Mimikatz, Metasploit payload modification to bypass the Anti-Virus, and a long etcetera. The path to a complete compromise combined the gathering and relaying of network NTLM hashes by abusing how LLMNR and other protocols broadcast traffic to the entire network, the fact that default local administrators (RID 500) accounts were enabled and that there were no defences against Pass-the-Hash type of attacks, and the ability to access sensitive data stored in memory by Windows. Good fun!