Greetings fellow hackers! Last here, today we will take a look at a well known technique used by attackers in AD environments, the infamous overpass-the-hash.
“BuT lAsT, pAsS tHe HaSh iS sO 1997!11!1!!” you could say. And you would be right, partly. Time for an anecdote! It was the beginning of 2018 and I was attending a conference with some teammates. A guy was giving a talk about attacking Active Directory and at some point he talked about the pass-the-hash attack. One of my mates (who definitely was not G, I swear!) said “Come on, 2018 and people are still talking about passing the hash?”.
Well G, here I am, Anno Domini 2020 and still talking about (over)passing the hash!
|I was hoping for another kind of “internals”|
Jokes aside, pass-the-hash (PtH) and overpass-the-hash (OPtH) are actually two different attack techniques: the old PtH involved directly authenticating to a host by literally sending the password’s hash to the host during the authentication process, while OPtH is way more subtle as it abuses Kerberos authentication.
The shared secret problem
Quick recap: as we discussed in the last post, Kerberos is built upon shared secrets. When implementing Kerberos in Active Directory, Microsoft decided the shared secret would be the NTLM hash of the user trying to authenticate. So when a user wants to authenticate, the client machine takes the timestamp, encrypts it using the user’s NTLM hash and sends it to the DC, alongside the unencrypted username and domain. Upon receiving the packet, the DC reads the username, fetches his password’s NTLM hash from its local database and uses it to decrypt the timestamp. If it’s valid, the DC generates a TGT for that user, encrypts it with krbtgt’s password’s NTLM hash and sends it back to the client, who can use that TGT to request TGSs on behalf of the user and authenticate to services.
As you may have realized by now, the entire security of this step relies on the secrecy of the NTLM hash of the user’s password. I will repeat it, here security relies on the secrecy of the hash, not of the password. But hashes are secure right? They are only stored on the DC right? And on clients they are not stored but calculated on the fly when the user inputs his password, right? Wrong.
beasts hashes and where to find them
In the Marvelous Cybersecurity Universe (not to be confused with the other and more famous MCU) hashes can be collected pretty much anywhere: data leaks, breaches, etc. However, the type of hash we are concerned with can actually be found inside domain-joined compromised machines on which we have administrative privileges. I’ll skip the privilege escalation process, as it’s out of scope for this post and as there are tons of ways to end up SYSTEM on a machine. For now, let’s limit ourselves to think we have compromised a client inside our target network. Where are them hashes, yo? A very special process called Local Security Authority Subsystem Service (LSASS) can help us.
To quote the official and omniscient Microsoft documentation:
The Local Security Authority Subsystem Service (LSASS) stores credentials in memory on behalf of users with active Windows sessions. This allows users to seamlessly access network resources, such as file shares, Exchange Server mailboxes, and SharePoint sites, without re-entering their credentials for each remote service. LSASS can store credentials in multiple forms, including:
- Reversibly encrypted plaintext
- Kerberos tickets (TGTs, service tickets)
- NT hash
- LM hash
So basically, Windows’ Local Security Authority (LSA) uses the LSASS process’ address space to store the credentials of logged in users. That allows users with sufficiently high privileges to dump the address space of LSASS and extract the credentials of all the users who logged on the machine since the last restart. If that’s not the definition of “goldmine”, I don’t know what is! ¯ \_(ツ)_/¯
The LSASS process can be spotted using Task Manager (or Process Explorer) if you head to the “Details” tab.
|Kids, I’m a trained professional and this is a virtualized lab environment. Never ever log in as your Domain’s Administrator.|
One way to obtain the credentials stored in memory would be to dump the entire machine’s memory, but that would be noisy and would generate a big DMP file. The cleaner way is to just target the LSASS process and selectively dump it. Still noisy and sketchy, but still way less than
cat /dev/motherfuckingeverything > memory.txt
As we said before, to dump LSASS address space we need administrative privileges (life sucks, I know). One way it can be achieved is through Task Manager itself, by right clicking on
lsass.exe and selecting “Create dump file”. In this way we don’t need to upload any suspicious executable on the target machine, as we can then download the DMP file and extract the credentials offline. This can be achieved through the Volatility Framework, Mimikatz or your own custom tools.
Let’s see an example: I dumped the credentials on my lab machine using Task Manager and exported the resulting lsass.DMP file on a Windows VM on which I have Mimikatz.
To extract credentials from the dump file we first have to tell Mimikatz to switch its context and target the dump. After that, we run the usual logon passwords dumping command. Here are the commands to execute:
mimikatz # sekurlsa::minidump <path_to_file> mimikatz # sekurlsa::logonpasswords
In my case the path to file was
C:\Users\last\Desktop\lsass.DMP. That’s the end result:
On a normal domain-joined machine, Mimikatz’s
sekurlsa::logonpassword often returns a lot of output, so you need to sort through it to find what you are really looking for:
Now that’s the kind of stuff you, as an attacker, want to see. Let’s dissect this output and see what we have here:
Authentication Id : 0 ; 301367 (00000000:00049937) Session : Interactive from 1 User Name : Administrator Domain : TARGETNET Logon Server : DC1 Logon Time : 5/9/2020 4:35:15 AM SID : S-1-5-21-2283460142-4117294090-2784357223-500 msv :  Primary * Username : Administrator * Domain : TARGETNET * NTLM : 007461b27da66eded419e8db22307c4f * SHA1 : 5cf7a0c33b82ffe9f95ff8ed364b665aa2d1df93 * DPAPI : 6b52635072d946e875936739e00bf004 tspkg : wdigest : * Username : Administrator * Domain : TARGETNET * Password : (null) kerberos : * Username : Administrator * Domain : TARGETNET.NOTSO.PRO * Password : (null) ssp : credman :
So here, what we really need to focus is:
- Session: “Interactive” means this the user is physically logged on the machine. If you saw “RemoteInteractive” for example it could mean someone might have logged in using RDP
- User Name: this is the UI rendered username, which can be different from the effective username used to login
- Domain: this is the Kerberos realm we talked about in the last post.
- Logon Server: this tells us the netbios name of the Domain Controller to which the user authenticated
- Logon Time: this is the time at which the user authenticated
- SID: this is the user Security Identifier of the account. You can read more about SIDs on the official documentation. We will talk about them more in depth in later posts, for now you just need to know it’s a unique ID assigned to each object and used by Windows to manage security stuff
- Username: this is the string used as username
- NTLM: this is the NTLM hash of the password, the data we were looking for :D
By the way, check out Mimikatz’s wiki as it’s full of really useful information :)
Piecing it all together
Let’s recap what we needed to authenticate as a user:
- Domain name
- NTLM hash
There are many ways to spawn a process as a new user, the quickest and most common is to use Mimikatz once again. Here’s the syntax:
mimikatz # sekurlsa::pth /user:<username> /domain:<domain> /ntlm:<hash> /run:<exe> EXAMPLE: mimikatz # sekurlsa::pth /user:Administrator /domain:targetnet.notso.pro /ntlm:007461b27da66eded419e8db22307c4f /run:powershell.exe
pth command of Mimikatz’s
sekurlsa module is the one responsible for executing overpass-the-hash attacks. How does it do it? To quote Mimikatz’s wiki:
Mimikatz can perform the well-known operation ‘Pass-The-Hash’ to run a process under another credentials with NTLM hash of the user’s password, instead of its real password. For this, it starts a process with a fake identity, then replaces fake information (NTLM hash of the fake password) with real information (NTLM hash of the real password).
So basically it injects the identity we provide inside a freshly spawned process. Here is how to do it: first we open an administrative level powershell (or cmd, it’s the same) on the domain compromised machine and execute Mimikatz. Once inside it, we execute the command listed above:
Mimikatz ran just fine and presented us with some information about the newly spawned process:
- user: the username of the user owning the new process
- domain: the domain of the user owning the new process
- program: the executable that has been ran
- impers.: this field tells us we didn’t specify the
/impersonateoption, which doesn’t spawn a new process, but directly injects the process running Mimikatz (the first powershell)
- NTLM: the NTLM hash of the user owning the new process
- PID: the Process Identifier of the new process
- TID: the Thread Identifier of the main thread of the new process
After running the command, a new powershell console is opened.
As you can see, the PID of the new powershell process (contained within the
$PID environment variable) is the same as the one specified by the previous screenshot.
You may have noticed the output of the
whoami command running locally is different from the output of the
whoami command ran through
dc1.targetnet.notso.pro (the DC). That’s because local
whoami returns information on the user currently logged on, which is
targetnet\last, while the remote one runs in the context of the user authenticated through Kerberos on the DC, which is
targetnet\administrator. When at the beginning of my journey I remember I ran Mimikatz a thousand times, only to get angry and immediately close the new process as
whoami returned the wrong user. That happened because I did not know the difference and what was happening behind the scenes. To quote LiveOverflow:
As you may have seen I also ran the
klist command, which lists imported Kerberos tickets. The first and the second are TGTs (don’t ask me why I have two, I’ll ping a friend of mine who surely knows it), while the third one is a TGS.
|The TGS issued to run PS Remoting commands|
Let’s break them down:
- Client: the user who requested the ticket. We can see it’s
Administrator @ TARGETNET.NOTSO.PRO, the Domain’s Administrator account
- Server: in the first and the second tickets it’s
krbtgt/TARGETNET.NOTSO.PRO @ TARGETNET.NOTSO.PROwhich is the krbtgt’s service, the one responsible for Kerberos authentication and TGT issuing. In the third ticket it’s
HTTP/dc1.targetnet.notso.pro @ TARGETNET.NOTSO.PRO, meaning it’s a TGS for the HTTP service of the DC. This has been issued because we ran
Invoke-Command, which is a Powershell Remoting command, and PS Remoting uses HTTP as protocol for trasmission of commands and output. Sometimes you may also see a TGS for the HOST service, always because of PS Remoting
- Start Time: the time from which the ticket will become valid
- End Time: the time on which the ticket will expire unless renewed
- Renew Time: the time on which renewed tickets will finally expire
- Kdc Called: the Key Distribution Center (aka the Domain Controller) which issued the ticket
Ok, I think it’s enough as explaination for this attack. Attacks like this are “easy” because great professionals (like Gentilkiwi) go to great lengths to allow us to wield tools like this and perform operations with ease. As you may have seen there is always more than meets the eye and I’m convinced that knowing the basics behind attacks as “simple” as this one will always make us better professionals. And it also allows us to replicate the attack by writing our own custom
and undetectable tools :)
See you soon,