Analyzing Mimikatz
Source: gentilkiwi/mimikatz @
306bc6b
How It Works
Mimikatz is a modular Windows security tool best known for credential extraction from LSASS memory, but its scope extends far beyond that — Kerberos ticket manipulation, DPAPI decryption, certificate theft, Active Directory remote attacks, and kernel-level interaction. Written in pure C targeting Visual Studio 2010+, it operates through a command-line REPL where users type module::command /option:value to invoke capabilities.
The tool is structured around a static module registry and a shared utility library called “kulluk” (a play on the French word “cul” and author Benjamin Delpy’s handle “gentilkiwi”). All 26 built-in modules register themselves at compile time via a mimikatz_modules[] array. Commands are dispatched by splitting input on ::, scanning the module table linearly, then scanning the command table within the matched module. There is no dynamic loading — every capability is compiled in.
The project also ships sister sub-projects: mimidrv (a kernel driver for memory reads and SSDT hooks), mimilib (a multi-purpose DLL with an SSP that logs credentials, a password filter, and DNS/DHCP/print hooks), and mimispool (a print spooler driver exploiting PrintNightmare, CVE-2021-34527).
Architecture
┌─────────────────────────────────────────────────┐
│ mimikatz.exe │
│ wmain() → REPL → mimikatz_dispatchCommand() │
│ │
│ ┌─────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ ! prefix │ │ * prefix │ │ no prefix │ │
│ │ kernel │ │ rpc │ │ local module │ │
│ └────┬─────┘ └────┬─────┘ └──────┬────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ kulluk shared library │ │
│ │ kull_m_memory | kull_m_patch | crypto │ │
│ │ kull_m_string | kull_m_process | etc. │ │
│ └──────────────────────────────────────────┘ │
│ │ │
│ ┌───────────┼───────────┐ │
│ ▼ ▼ ▼ │
│ LSASS Kernel (drv) Remote (RPC) │
│ (process) (mimidrv) (MimiCom protocol) │
└─────────────────────────────────────────────────┘
Key modules and their purpose:
| Module | Purpose |
|---|---|
sekurlsa | LSASS memory parsing — extracts credentials from msv1_0, wdigest, tspkg, kerberos, cloudap, livessp, etc. |
kerberos | Ticket manipulation — pass-the-ticket, golden tickets, list/purge/ask, ccache support |
lsadump | SAM/LSA Secrets/CACHE parsing, DCSync, DCShadow, zerologon exploitation |
crypto | Certificate and key extraction from CAPI/CNG stores |
dpapi | DPAPI master key decryption with sub-packages for Chrome, SSH, WLAN, SCCM, Citrix, Vault, etc. |
rpc | Remote control via custom MimiCom RPC protocol (Diffie-Hellman key exchange, RFC 2409) |
kernel | Interaction with mimidrv kernel driver for privileged memory reads |
token, privilege, process, service | Windows security object manipulation |
The Spine
The entry point is mimikatz.c → wmain(). It iterates over command-line arguments, dispatching each through mimikatz_dispatchCommand(). If no arguments are provided, it enters an interactive REPL loop reading from stdin.
Command dispatch logic:
// Prefix routing
if(command[0] == L'!')
mimikatz_doLocal(...); // Actually still local; ! routes to kernel module
else if(command[0] == L'*')
mimikatz_doRpc(...); // Remote execution via RPC
else
mimikatz_doLocal(...); // Standard local module dispatchThe local dispatch splits on ::, linearly scans mimikatz_modules[] by short name, then linearly scans the module’s KUHL_M_C[] command table. Each command handler receives the argument string and uses kull_m_string_args_byName() to parse /name:value option pairs.
Three build targets exist: standalone EXE, DLL (via _WINDLL define), and PowerShell reflective DLL (via _POWERKATZ).
Key Patterns
Unified memory abstraction. The most important architectural decision in mimikatz is kull_m_memory. It defines a KULL_M_MEMORY_TYPE enum (Process, MiniDump, File, Kernel) and a KULL_M_MEMORY_HANDLE struct with function pointers for read/write/alloc/close operations. The same credential extraction code in sekurlsa works against a live LSASS process, a minidump file on disk, or memory read through the kernel driver — with zero code changes in the extraction logic.
Per-build binary patching. LSA key material locations change with every Windows build. The kull_m_patch system stores byte-pattern/patch pairs keyed by minimum build number (KULL_M_PATCH_GENERIC structs). Sekurlsa maintains massive tables mapping Windows build numbers (from XP build 2600 through Windows 10 2004 build 19041) to specific offsets and structures needed to find credentials in LSASS memory.
Module self-registration. Modules define themselves as KUHL_M structs and are collected into a static array at link time. Each module has optional init/clean callbacks, a short name, description, and a command table. Adding a new capability means adding a struct — no registration function calls needed.
Global mutable state. The codebase relies heavily on globals: cLsass (handle to LSASS process), g_hLSA (loaded advapi32), MIMIKATZ_PRIMARY_COMMAND_NAME. This works for a single-threaded CLI tool but precludes safe concurrent use.
Non-Obvious Details
The
ANTI_MIMIKATZstructuresSekurlsa includes a variant of its Windows 10 1607 structures labeled
ANTI_MIMIKATZ— this directly counters Microsoft’s Credential Guard and other anti-credential-theft measures. The author tracks defensive changes and ships workarounds.
The patch system is the maintenance bottleneck. Every Windows feature update can shift internal LSASS structures, requiring new byte patterns in sekurlsa. This is why mimikatz sometimes “breaks” after Patch Tuesday — the patterns no longer match. The globals.h file contains an extensive Windows build number lookup table used throughout for version-specific branching.
RPC module rolls its own crypto. The remote control module implements its own Diffie-Hellman key exchange using the Second Oakley Group from RFC 2409, providing encrypted command channels even without Kerberos authentication. This is separate from the CNG/CAPI wrappers in kull_m_crypto.
Compile-time capability flags. LSASS_DECRYPT enables additional credential decryption routines. KERBEROS_TOOLS enables extended Kerberos functionality. These gates exist presumably for legal/compliance reasons — the default build ships with everything enabled.
The SSP in mimilib is devastatingly simple. kssp.c (the “kssp” SSP — another pun) is ~200 lines that intercepts every authentication call and writes credentials to kiwissp.log. Deployed as an SSP DLL, it captures all interactive logins on a machine with no additional tooling required.
Multiple build outputs from one codebase. The same source compiles to three targets: a standard EXE, a standard DLL, and a reflective DLL for PowerShell injection (_POWERKATZ). The reflective loading is done inline rather than through an external loader.
Assessment
Strengths. The unified memory abstraction is genuinely elegant — writing credential extraction once that works across live process, minidump, and kernel driver is a non-trivial design achievement. The per-build pattern matching is a pragmatic approach to the fundamentally undocumented problem of locating Windows internal structures. The module system is simple and effective for the tool’s purpose.
Concerns. Zero test infrastructure. Global mutable state throughout. Linear command lookup (irrelevant at this scale, but reflects the tool’s origins). Memory management is raw LocalAlloc/LocalFree with no RAII — though acceptable for C on Windows. The deep coupling to Windows internal structures means a single OS update can break multiple modules simultaneously, making maintenance a perpetual cat-and-mouse game.
Long-term viability
Microsoft has progressively locked down LSASS access (Credential Guard, RunAsPPL, encrypted LSASS in recent builds). The fundamental approach of reading LSASS memory directly is becoming increasingly restricted at the platform level.
Developer experience. Poor for external contributors. Minimal comments, no documentation of internal data structures, and undocumented argument parsing conventions (/name:value syntax is inferred, not explained). The code is readable if you know Windows internals well — inscrutable otherwise.
Related
- analyzing-sharphound — complementary AD security tool; BloodHound (via SharpHound) maps attack paths while mimikatz exploits them