Mimikatz Under The Hood

The ability of Mimikatz to extract the NTLM hash of users at runtime from Windows has always fascinated me. Although alternatives exist (as explored in previous blog posts here and here, there may still be situations during Red Team engagements where live credential extraction from LSASS is wanted. In those situations, defense evasion tactics such as heavily modifying Mimikatz or using another implementation of Mimikatz are common.

As I’m interested in defense evasion techniques and always wanted to know more about how Mimikatz work and become better at programming in C, I figured it was time to try and see how hard/easy it would be implementing the credential dumping (sekurlsa::logonpasswords) from LSASS that Mimikatz is probably most known for. I did so by mostly reading the source code of the Python implementation of Mimkatz by skelsec, Pypykatz, and implementing roughly the same approach myself in a C++ project, with almost solely using C features, instead of C++.

During the process, I also ending up applying a user-mode API hook bypass technique, of performing direct system calls, instead of using the Win32 API. I did so by copying the opcodes of the NtReadVirtualMemory function from ntdll.dll (using Ghidra) into my own source code, and calling those at runtime.

This project was made solely for Windows 10 version 1909, as that was the OS used during development, but has been tested to also work on version 2004 as well. It should be noted that my implementation is not meant for production use as-is, and no attempts have been made to ensure stability. It is not pretty, and I’m sure it can be written both better, more readable and with less memleaks. It is solely a research project for learning purposes. That being said, I hope to inspire others to do the same, as I learned a lot about LSASS and C programming.

In short, my implementation works by:

1.     Opening the LSASS process

2.     Opening LSASS’ loaded lsasrv.dll module

3.     Searching for a known pattern in the memory of the lsasrv.dll module

4.     Following certain offsets from the pattern and pointers to the IV and AES/DES keys

5.     Searching for another known pattern

6.     Following certain offsets from that pattern the logon sessions stored in memory

7.   Iterating through the logon sessions, and for each logon session identify domain, username and
encrypted NTLM hash

8. Decrypt the encrypted NTLM hash using the previously obtained IV and AES/DES keys

“MagnusKatz” in action:

Mimikatz Under The Hood

Interestingly, without any obfuscation or other techniques, only one of the 71 engines on VirusTotal detect it as being malicious:

Mimikatz Under The Hood

The full source code is available on GitHub.

User-mode API hook bypass by doing Direct Syscalls

I’d like to point out that the user-mode API hook bypass technique used doesn’t really have anything to do with Mimikatz, and is not needed at all. I simply added it, as I was looking into it at the same time as this project.

The purpose of bypassing user-mode API hooks is to evade detection that rely on adding hooks to processes’ instances of DLLs for detection, such as e.g. certain AV/EDR/EPP products. The goal is the same as the goal for the Dumpert tool, but with a different way of getting the job done.

Here’s how it works:

1.     Get the opcodes of the NtReadVirtualMemory function from ntdll.dll, e.g. with Ghidra

Mimikatz Under The Hood

2.     Allocate memory that is executable, meaning that we can use it to hold code that we execute later.

Mimikatz Under The Hood

3.     Move the opcodes into the executable memory:

Mimikatz Under The Hood

4.     Make a function pointer that points to the executable memory, that contains the opcodes from ntdll.dll, such that we can call it the same way we call any other function:

Mimikatz Under The Hood

Thus, we end up with the ability to read other processes’ memory by doing direct syscalls, instead of using functionality from DLLs.

Takeaways

The biggest takeaway for me is that it’s worth the effort to become sufficiently good at programming that custom tools can be made, instead of using various public tools. Both for the sake of defense evasion but also for learning more and being better at Red Teaming or penetration testing, as writing your own tools force you to actually understand the details. I’m sure that what I learned doing this project will definitely make me better at the next.

 I learned a lot and recommend others to do the same!