
There are already many articles explaining how Mimikatz works, but I needed to examine the source code to better understand how it attacks the Windows system and steals credentials — specifically, how Mimikatz uses Windows APIs, NT APIs, and undocumented APIs.
Mimikatz Structure
At first, I downloaded mimikatz from the release.
After downloading it, I decompressed it:
7z e .\mimikatz_trunk.7z
And I checked the hash as always:
Get-FileHash -Path .\mimikatz.exe
Algorithm Hash
--------- ----
SHA256 61C0810A23580CF492A6BA4F7654566108331E7A4134C968C2D6A05261B2D8A1
After decompression, the following files were extracted:
- kiwi_passwords.yar: YARA rules for Mimikatz
- mimicom.idl: Definitions of a COM interface
- mimidrv.sys: Kernel driver
- mimikatz.exe: Main executable
- mimilib.dll: DLL which offers some features
- mimilove.exe: Lightweight version of executable which works for Windows 2000 only
- mimispool.dll: DLL related to Print Spooler
- README.md: Description for the project
Mimikatz: Interpreting Commands
Once mimikatz.exe
is executed, it interprets commands entered or passed as arguments through mimikatz_dispatchCommand.
In mimikatz_dispatchCommand
, a different function is called depending on the command prefix (”!”, ”*”, or others).
Mimikatz: Kernel Operations with the ”!” Prefix
If the command prefix is ”!”, kuhl_m_kernel_do
is called to interpret the command following the ”!”. It then searches for the corresponding IOCTL code by comparing it to the third command name of each element in the KUHL_K_C kuhl_k_c_kernel[]
list, which includes codes such as IOCTL_MIMIDRV_PING
, IOCTL_MIMIDRV_BSOD
, and others.
For example, we can input the following commands:
- !+: Install and/or start mimikatz driver (mimidrv)
- !-: Remove mimikatz driver (mimidrv)
- !ping: Ping the driver
- !bsod: Trigger a BSOD
- !process: List processes
- !processProtect: Protect process
- !processToken: Duplicate process token
- !processPrivilege: Set all privilege on process
- !modules: List modules
- !ssdt: List SSDT
- !notifProcess: List process notify callbacks
- !notifThread: List thread notify callbacks
… and others.
From here on, I will analyze the mimidrv.sys
driver to gain a deeper understanding of how it operates in kernel mode.
Mimidrv: Dispatcher
I checked the DriverEntry function in the mimidrv.c
and found the following line:
theDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MimiDispatchDeviceControl;
The IOCTL code provided by the user appears to be handled by MimiDispatchDeviceControl. In this function, different operations are performed depending on the control code, as shown below:
!ping
This command sends the IOCTL_MIMIDRV_PING code to mimidrv.sys
for printing the string “pong”.
status = kprintf(&kOutputBuffer, L"Input : %s\nOutput : %s\n", bufferIn, L"pong");
!bsod
This command sends the IOCTL_MIMIDRV_BSOD code to mimidrv.sys
for triggering a system crash (blue screen) and generating a crash dump.
KeBugCheck(MANUALLY_INITIATED_CRASH);
When this command is actually executed, a blue screen appears as shown below:
!process
This command sends the IOCTL_MIMIDRV_PROCESS_LIST code to mimidrv.sys
, and the following processing is carried out in kkll_m_process_enum:
- References the global variable PsInitialSystemProcess to retrieve a pointer to the EPROCESS structure.
- Obtains a pointer to each process.
- In kkll_m_process_list_callback, retrieves the PID and process name using PsGetProcessId and PsGetProcessImageFileName with the process pointer.
- Displays the retrieved information.
!processToken
This command sends the IOCTL_MIMIDRV_PROCESS_TOKEN code to mimidrv.sys
, and the following processing is carried out in kkll_m_process_token:
- Retrieves a pointer to the specified processusing PsLookupProcessByProcessId.
- Obtains a handle to the access token of the source process via ZwOpenProcessTokenEx.
- Creates a handle for a new access token by duplicating the source token using ZwDuplicateToken with the TokenPrimary type.
- Assigns the duplicated token to the destination process using ZwSetInformationProcess with the ProcessAccessToken information class.
!processProtect
This command sends the IOCTL_MIMIDRV_PROCESS_PROTECT code to mimidrv.sys
, and the following processing is carried out in kkll_m_process_protect:
- Retrieves a pointer to the specified process using PsLookupProcessByProcessId.
- If the Windows version is older than 8, modifies the ProtectedProcess bit in the Flags2 field of the EPROCESS structure using PROTECTED_PROCESS_MASK (0x00000800).
- If the Windows version is 8 or later, modifies the SignatureLevel, SectionSignatureLevel, and optionally Protection fields in the SignatureProtection structure inside the EPROCES structure.
!processPrivilege
This command sends the IOCTL_MIMIDRV_PROCESS_FULLPRIV code to mimidrv.sys
, and the following processing is performed in kkll_m_process_fullprivileges:
- Retrieves a pointer to the specified process using PsLookupProcessByProcessId or PsGetCurrentProcess.
- Obtains the primary token of the process via PsReferencePrimaryToken.
- Uses an offset within the token structure to locate the privilege pointer and forcibly enables all privileges.
!modules
This command sends to the IOCTL_MIMIDRV_MODULE_LIST code to mimidrv.sys
for retrieving module information using AuxKlibQueryModuleInformation, then outputting the data to standard output via the callback function kkll_m_modules_list_callback.
!ssdt
This command sends to the IOCTL_MIMIDRV_SSDT_LIST code to mimidrv.sys
and the following processing is performed in kkll_m_ssdt_list:
- Retrieves a pointer to the KeServiceDescriptorTable structure.
- Iterates through the table to obtain and print the address of each function.
Mimikatz: RPC Operation with the ”*” Prefix
Mimikatz can execute commands on a remote host within the local network via RPC using commands prefixed with ”*”.
To use this feature, it must first connect to an RPC endpoint with a command such as the following:
rpc::connect /remote:192.168.0.100 /noauth
After the above command, when a user executes a command with the prefix ”*”, Mimikatz calls kuhl_m_rpc_do which encrypts the command and invokes NdrClientCall2 to perform the remote call.
Prefixing a command with ”*” causes it to be executed on a remote host.
Mimikatz: Local Operations
A command without a prefix is executed on the local host. When the user inputs such a command, it calls mimikatz_doLocal, which finds the matching command from the list of available modules stored in mimikatz_modules, as shown below.
Here, I will analyze only the commands that are likely to be used frequently.
standard::exit
Simply prints “Bye” and exits as the code below:
kprintf(L"Bye!\n");
return argc ? STATUS_THREAD_IS_TERMINATING : STATUS_PROCESS_IS_TERMINATING;
standard::cls
FillConsoleOutputCaracter is called to fill and clear the entire terminal screen with spaces.
GetConsoleScreenBufferInfo(hStdOut, &csbi);
FillConsoleOutputCharacter(hStdOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
SetConsoleCursorPosition(hStdOut, coord);
standard::sleep
Sleep function is simply called.
DWORD dwMilliseconds = argc ? wcstoul(argv[0], NULL, 0) : 1000;
kprintf(L"Sleep : %u ms... ", dwMilliseconds);
Sleep(dwMilliseconds);
standard::version
The version of mimikatz is displayed.
standard::cd
SetCurrentDirectory is called to switch the current directory to the specified location.
standard::localtime
It retrieves the system local time by calling GetSystemTimeAsFileTime and timezone information by calling GetTimeZoneInformation, then outputs this information.
standard::hostname
It retrieves the system hostname by calling GetComputerNameEx.
crypto::providers
- Enumerates cryptographic service providers (CSPs) by calling CryptEnumProviders.
- Obtains a pointer to the CSP using CryptAcquireContext.
- Retrieves details of each provider by calling CryptGetProvParam with the PP_IMPTYPE parameter.
- Displays the result.
crypto::stores
- Retrieves available System Stores by calling CertEnumSystemStore with the CERT_SYSTEM_STORE_CURRENT_USER flag.
- Outputs the store names.
crypto::certificates
- Opens a handle to the specified certificate store by calling CertOpenStore.
- Retrieves a pointer to a CERT_CONTEXT structure in the store using CertEnumCertificatesInStore.
- Obtains the subject or issuer names from the context by calling CertGetNameString.
- Retrieves additional information from the context via CertGetCertificateContextProperty.
- Retrieves the provider type name as a string by referencing kull_m_crypto_provider_type_to_name.
- Obtains the private key for the certificate by calling CryptAcquireCertificatePrivateKey.
- Retrieves a handle to the user’s public/private key pair using CryptGetUserKey.
- Gets property of the key object by calling NCryptGetProperty.
- Finally, displays this information.
crypto::keys
- Lists CryptAPI keys for the specified provider by calling CryptGetProvParam and CryptAcquireContext.
- Retrieves properties of the keys using NCryptGetProperty and displays the information.
- Initializes a CNG key storage provider by calling NCryptOpenStorageProvider.
- Lists CNG key names by calling NCryptEnumKeys.
- Obtains handles for each key by calling NCryptOpenKey with the key names.
- Retrieves properties for each key by calling NCryptGetProperty.
crypto::sc
This command displays key information for smart cards.
- Establishes a resource manager context by calling SCardEstablishContext.
- Lists smart card reader names using SCardListReaders.
- Establishes a connection to the smart card readers via SCardConnect.
- Retrieves attributes for each reader by calling SCardGetAttrib.
- Obtains provider names for the smart card using SCardGetCardTypeProviderName.
- Retrieves information about CryptAPI keys by calling CryptgetProvParam and CryptAcquireContext, then displays it.
- Retrieves information about CNG keys by calling NCryptEnumkeys and NCryptGetProperty, then displays it.
crypto::hash
- Calculates the NTLM hash for the specified password by calling RtlCalculateNtOwfPassword (SystemFunction007).
- Calculates the DCC1 and DCC2 hashes for the specified username by using RtlCalculateNtOwfPassword, CryptCreateHash, CryptSetHashParam, and CryptGetHashParam, based on the previously calculated NTLM hash.
- Calculates the LM hash for the password by calling RtlCalculateLmOwfPassword (SystemFunction006).
- Calculates the MD5, SHA1, SHA256 hashes for the password by calling CryptCreateHash, CryptSetHashParam, and CryptGetHashParam.
crypto::system
This command extracts certificate information from a specified certificate file.
- If the specified file path is a directory, enumerates files in that directory.
- Extracts certificate information from the certificate file at the specified offset.
sekurlsa::msv
This command lists LM and NTLM credentials for logon sessions.
- Calls kuhl_m_sekurlsa_acquireLSA to initialize access to the LSASS process and locate necessary memory structures for credential extraction.
- Retrieves information such as Logon ID, Session, Username, Credentials, etc., from the logon session list and displays it.
- Obtains credentials by parsing internal structures of the msv1_0 authentication package, located within the
lsasrv.dll
module loaded in the LSASS process. - Formats and prints the extracted credentials to the console.
sekurlsa::wdigest
This command lists WDigest credentials.
- Calls kuhl_m_sekurlsa_acquireLSA to initialize access to the LSASS process and locate necessary memory structures for credential extraction.
- Retrieves and displayes information such as Logon ID, Session, Username, Credentials, etc., from the logon session list.
- If
wdigest.dll
is found in the LSASS memory, locates the WDIGEST_LIST_ENTRY structure and extracts plaintext credentials (if present) by reading memory from that structure. - Formats and prints the extracted credentials to the console.
sekurlsa::kerberos
This command lists Kerberos credentials.
- Calls kuhl_m_sekurlsa_acquireLSA to initialize access to the LSASS process and locate necessary memory structures for credential extraction.
- Retrieves and displays information such as Logon ID, Session, Username, Credentials, etc., from the logon session list.
- If
kerberos.dll
is found in LSASS memory, locates the internal Kerberos logon session list and extracts credentials, including usernames, domains, and passwords. - Formats and prints the extracted credentials to the console.
sekurlsa::tspkg
This command lists TsPkg (Terminal Server) credentials.
- Calls kuhl_m_sekurlsa_acquireLSA to initialize access to the LSASS process and locate necessary memory structures for credential extraction.
- Retrieves and displays information such as Logon ID, Session, Username, Credentials, etc., from the logon session list.
- If
tspkg.dll
is found in LSASS memory, locates the TsPkg credentials structures (e.g. KIWI_TS_CREDENTIAL) using memory offsets and extracts plaintext credentials. - Formats and prints the extracted credentials to the console.
sekurlsa::livessp
This command lists LiveSSP credentials.
- Calls kuhl_m_sekurlsa_acquireLSA to initialize access to the LSASS process and locate necessary memory structures for credential extraction.
- Retrieves and displays information such as Logon ID, Session, Username, Credentials, etc., from the logon session list.
- If
livessp.dll
is found in LSASS memory, locates the KIWI_LIVESSP_LIST_ENTRY structure using version-specific offsets and extracts credentials such as logon ID, username, domain, and password. - Formats and prints the extracted credentials to the console.
sekurlsa::cloudap
This command lists CloudAp credentials.
- Calls kuhl_m_sekurlsa_acquireLSA to initialize access to the LSASS process and locate necessary memory structures for credential extraction.
- Retrieves and displays information such as Logon ID, Session, Username, Credentials, etc., from the logon session list.
- If
cloudap.dll
is found in the LSASS memory, locates the internal CloudApGlobalLogonSessionList and extracts credentials from each KIWI_CLOUDAP_CREDENTIAL_ENTRY, including usernames, domains, and passwords, etc. - Formats and prints the extracted credentials to the console.
sekurlsa::ssp
- Calls kuhl_m_sekurlsa_acquireLSA to initialize access to the LSASS process and locate necessary memory structures for credential extraction.
- Retrieves and displays information such as Logon ID, Session, Username, Credentials, etc., from the logon session list.
- If the
ssp
module is available (handled viamsv1_0.dll
in LSASS memory), locates the KIWI_SSP_CREDENTIAL_LIST_ENTRY structure and extracts credentials including usernames, domains, passwords, and logon IDs. - Formats and prints the extracted credentials to the console.
sekurlsa::logonPasswords
This command lists all providers available credentials.
- Calls kuhl_m_sekurlsa_acquireLSA to initialize access to the LSASS process and locate necessary memory structures for credential extraction.
- Retrieves and displays information such as Logon ID, Session, Username, Credentials, etc., from the logon session list.
- Enumerates provider packages (
msv, wdigest, kerberos, tspkg, livessp, cloudap, ssp
) and invokes the corresponding callback functions for each session.
sekurlsa::process
This command switches to the LSASS process context.
- Closes the handle to the currently attached LSASS memory by calling kull_m_memory_close.
- Frees each KEYLIST_ENTRY structure in the gCandidateKeys list to clean up candidate credential keys.
sekurlsa::minidump
This command switches to LSASS minidump context.
- Same as above the
sekurlsa::process
command, clear the current LSASS memory. - Reteives a pointer to the specified minidump file.
sekurlsa::pth
This command performs Pass-The-Hash.
- Parses the specified keys (either
ntlm
,aes128
oraes256
) for later use.
- If the user specified the
luid
option, calls kuhl_m_sekurlsa_pth_luid to enable Pass-the-Hash operations for the specified logon session (LUID) by obtaining writable access to LSASS and injecting credentials.
-
If the user specified the
user
option, creates a SUSPENDED process by calling CreateProcessWithLogon with the specified parameters including user, domain and empty password. -> It generates a new logon session (LUID) but without valid credentials. And the following processing is executed: -
Obtains a handle to the process token by calling OpenProcessToken.
-
Retrieves the Logon Session ID (LUID) from the token using GetTokenInformation.
-
Reads LSASS process memory to locate the logon session matching the LUID.
-
Finds the MSV1_0 credentials structure for the session and replace the NTLM hash with the one provided in the command.
-
Resumes the suspended process.
sekurlsa::krbtgt
This command retrieves credentials from krbtgt account.
- Checks if the
kdcsvc.dll
module exists in the LSASS process. - Locates the pointer to the internal DUAL_KRBTGT structure (which holds Kerberos keys) depending on the system version.
- Extracts the Kerberos encryption keys from the DUAL_KRBTGT structure. The structure layout and key count depend on the Windows version.
sekurlsa::dpapisystem
This command retrieves DPAPI_SYSTEM secrets.
- Checks if the
dpapisrv.dll
module exists in the LSASS process. - Locates the memory containing credentials data in the LSASS process, depending on the system version.
- Extracts DPAPI secrets, including the machine key and user key used for decryption.
sekurlsa::backupkeys
This command retrieves the preferred Backup Master Keys used to decrypt DPAPI-encrypted data.
- Checks if the
dpapisrv.dll
module exists in the LSASS process.
- Locates the pointer to the internal KIWI_BACKUP_KEY structure containing the backup RSA private keys, depending on the system version.
-
Extracts the RSA private key by calling the following APIs:
- For RSA keys (CNG): NCryptOpenKey, NCryptGetProperty, NCryptExportKey
- For legacy keys (CryptAPI): CryptGetProvParam, CryptExportParam
sekurlsa::tickets
This command lists Kerberos tickets.
- Enumerates all logon sessions by calling kuhl_m_sekurlsa_enum.
- Locates the KIWI_BASIC_SECURITY_LOGON_SESSION_DATA structure in the LSASS process.
- Extracts credentials from the session data, including logon ID, session, username, domain, and others.
- Depending on the Windows version, locates the Kerberos ticket entries in memory either via a linked list or an AVL tree.
- Extracts Kerberos tickets (such as TGT and TGS) from LSASS memory and displays or exports them for reuse in Pass-the-Tickets attacks.
sekurlsa::ekeys
This command lists Kerberos Encryption Keys.
Its process is almost the same as sekurlsa::tickets, except the last callback function is kuhl_m_sekurlsa_enum_kerberos_callback_keys.
- Enumerates all logon sessions and locates the KIWI_BASIC_SECURITY_LOGON_SESSION_DATA structure in LSASS memory.
- For each session, extracts Kerberos encryption keys (such as session keys, TGT keys, and service ticket keys) by reading internal structures at known offsets depending on the OS version.
- Displays the keys in a readable format (e.g., in hex), which can be reused in Kerberos-related attacks or analysis.
sekurlsa::dpapi
This command lists Cached MasterKeys.
- Enumerates all logon sessions by calling kuhl_m_sekurlsa_enum.
- For each session, calls the callback function kuhl_m_sekurlsa_enum_callback_dpapi.
- Prints basic logon data including logon ID, username, SID, etc.
- Locates the internal KIWI_MASTERKEY_CACHE_ENTRY structure in the logon session.
- Enumerates the Cached MasterKeys list and extracts each key’s:
- GUID
- Timestamp
- SHA1 hash of the master key
- Prints the extracted key hashes and metadata to the console.
sekurlsa::credman
This command lists Credentials Manager.
- Calls kuhl_m_sekurlsa_acquireLSA to initialize access to the LSASS process and locate necessary memory structures for credential extraction.
- Acquires each part of information (Logon Id, Session, Username, Credentials, etc.) from the logon session list and displays that information.
- If the
lsasrv.dll
module exists in the LSASS memory, locates the internal KIWI_CREDMAN_SET_LIST_ENTRY structure. - Extracts credentials such as username, domain, and password by reading memory at calculated offsets within the structure, depending on Windows version.
kerberos::ptt
This command performs Pass-The-Ticket.
- If the user specifies the directory path as command line arguments, find a Kerberos ticket file (
.kirbi
) from that directory.
- For each Kerberos ticket file, reads the data and injects it into the current logon session by calling LsaCallAuthenticationPackage with the Kerberos authentication package.
kerberos::list
This command lists Kerberos tickets.
- Requests Kerberos ticket cache using LsaCallAuthenticationPackage function.
- If the request is successful, display the information of the retrieved cached ticket.
kerberos::ask
This command asks or get TGT tickets.
- Checks if the user specifies the
target
option for the remote host. - Prepares the request data with the KERB_RETRIEVE_TKT_REQUEST structure.
- Retrieves encoded Kerberos ticket by calling LsaCallAuthenticationPackage with the request data.
- Extracts the response data including the following items:
- Service
- Domain
- Target domain
- Key
- Key type
- Ticket
- Ticket flags
- If the user specifies the
tkt
flag, write the encoded ticket to a file with the.tkt
extension. - If the user specifies the
export
flag, retrieves encoded Kerberos Credentials by calling LsaCallAuthenticationPackage again with the KERB_RETRIEVE_TICKET_AS_KERB_CRED option at this time. Then, write the encoded ticket to a file with the.kirbi
extension.
kerberos::tgt
This command retrieves current TGT.
- Retrieves current Kerberos ticket by calling LsaCallAuthenticationPackage.
- Extracts the response data including the following items:
- Service
- Domain
- Target domain
- Key
- Key type
- Ticket
- Ticket flags
kerberos::purge
This command purges Kerberos tickets.
It requests to purge tickets by calling LsaCallAuthenticationPackage with the KERB_PURGE_TKT_CACHE_REQUEST.
kerberos::golden
This command forges a Golden Ticket, a fake Ticket Granting Ticket (TGT), using the KRBTGT account hash. It allows persistent domain access as any user.
- Checks if the user specifies the
admin
option or theuser
option, and also checks if thedomain
option is specified. - Sets the key type depending on the specified key option such as
des
,rc4
,aes128
,aes256
.
- Gets the pointer to the KERB_ECRYPT structure by calling CDLocateCSystem.
- Sets the lifetime for the fake TGT from the local system time by calling GetSystemTimeAsAsFileTime.
- Prepares the information (SID, User Id, Groups Id, etc.) which is used for the fake TGT.
-
Issues the fake TGT by calling kuhl_m_kerberos_golden_data which processes as below:
- Prepares the ticket data with the KIWI_KERBEROS_TICKET structure.
- Converts the ticket data -> KERB_VALIDATION_INFO -> PACTYPE.
- Signs the PAC data by calling kuhl_m_pac_signature.
- Generates the EncTicketPart by calling kuhl_m_kerberos_ticket_createAppEncTicketPart.
- Encrypts the EncTicketPart by calling kuhl_m_kerberos_encrypt which uses the CSystem’s Encrypt function.
- Generates a KrbCred by calling kuhl_m_kerberos_ticket_createAppKrbCred.
-
After generating the fake TGT, if the user specifies the
ptt
option, the specified ticket is injected into the current logon session by calling LsaCallAuthenticationPackage to make it active and usable by the system, otherwise the ticket is saved to a file.
kerberos::hash
This command generates a password hash to keys.
- Gets the pointer to the KERB_ECRYPT structure by calling CDLocateCSystem.
- Calculates the NT hash by calling HashPassword_NT5 or HashPassword_NT6 depending on the system version.
- Prints the NT hash to the console.
kerberos::decrypt
This command decrypts encoded tickets.
- Sets the key type and the key length depending on the specified options including
rc4
,aes128
,aes256
, anddes
.
- Gets the pointer to the KERB_ECRYPT structure by calling CDLocateCSystem.
- Decrypt the specified key by calling pCSystem->Decrypt.
privilege::debug
This command asks debug privilege.
Calls RtlAdjustPrivilege with the SE_DEBUG flag.
privilege::driver
This commands asks load driver privilege.
Calls RtlAdjustPrivilege with the SE_LOAD_DRIVER flag.
privilege::security
This command asks security privilege.
Calls RtlAdjustPrivilege with the SE_SECURITY flag.
privilege::tcb
This command asks tcp privilege.
Calls RtlAdjustPrivilege with the SE_TCB flag.
privilege::backup
This command asks backup privilege.
Calls RslAdjustPrivilege with the SE_BACKUP flag.
privilege::restore
This command asks restore privilege.
Calls RtlAdjustPrivilege with the SE_RESTORE flag.
privilege::sysenv
This command asks system environment privilege.
Calls RtlAdjustPrivilege with the SE_SYSTEM_ENVIRONMENT
privilege::id
This command asks privilege by its ID.
It is the same as the above commands except that it takes the privilege flag ID as a command argument.
For example, run privilege::id 20
for asking debug privilege.
privilege::name
This command asks privilege by its name.
It is the same as the above commands except that it takes the privilege name as a command argument.
Looks up the privilege ID from the specified privilege name by calling LookupPrivilegeValue.
For example, run privilege::name SeDebugPrivilege
for asking debug privilege.
process::list
This command lists processes.
- Gets the current process information by calling NtQuerySystemInformation.
- For each process, display its PID and name with the pSystemProcessInformation->UniqueProcessId and the pSystemProcessInformation->ImageName.
- In addition, enumerate threads for each process and display the thread ID with the pSystemProcessInformation->Threads[i].ClientId.UniqueThread.
process::exports
This command lists exports.
- If the user specifies the
pid
option, get the handle to the process from the specified PID by calling OpenProcess.
- Gets the pointer to the PEB structure for the process and get the Dll base address and the size.
- For each module, parses the IMAGE_EXPORT_DIRECTORY structure to enumerate exported symbols.
- Extracts each function’s name, ordinal, and Relative Virtual Address (RVA). This allows users to resolve actual API addresses or detect function forwarding.
process::imports
This command lists imports.
It is almost the same as process::exports
, but it enumerates imported functions.
process::start
This command starts a process.
Creates a new process by calling CreateProcess with the specified command line.
status = CreateProcess(NULL, dupCommandLine, NULL, NULL, FALSE, iProcessFlags, NULL, NULL, &startupInfo, ptrProcessInfos);
process::stop
This command terminates a process.
- Opens the process for the specified PID by calling OpenProcess.
- Terminates the process by calling NtTerminateProcess.
hProcess = OpenProcess(access, FALSE, pid)
status = NtTerminateProcess(hProcess, STATUS_SUCCESS);
process::suspend
This command suspends a process.
It uses NtSuspendProcess internally.
- Opens the process for the specified PID by calling OpenProcess.
- Suspends the process by calling NtSuspendProcess.
hProcess = OpenProcess(access, FALSE, pid)
status = NtSuspendProcess(hProcess);
process::resume
This command resumes a process.
- Opens the process for the specified PID by calling OpenProcess.
- Resumes the process by calling NtResumeProcess.
hProcess = OpenProcess(access, FALSE, pid)
status = NtResumeProcess(hProcess);
process::run
This command starts a process with current token.
- Creates a pipe by calling CreatePipe and gets handles to the read and write.
- Sets the HANDLE_FLAG_INHERIT flag to the read handle by calling SetHandleInformation.
- Gets the pointer to the environment block by calling CreateEnvironmentBlock. As a result, the current process’ environment is herited.
- Creates a new process in the context of the current token by calling CreateProcessAsUser with the specified command line.
process::runp
This command starts a process with a token of a parent process.
- Checks if the user specifies the
ppid
orpid
option. If neither is specified, the LSASS is used as parent process by default. - Dynamic API resolution for InitializeProcThreadAttributeList, UpdateProcThreadAttribute, DeleteProcThreadAttributeList by calling *GetProcAddress with the
kernel32.dll
module. - Get the handle to the parent process by calling OpenProcess with the *PROCESS_CREATE_PROCESS for letting a new process to be created in the process.
- Locates the current process’s attribute list for the newly created process.
- Initializes the attribute list by calling InitializeProcThreadAttributeList.
- Updates the attribute list for inheriting the parent process by calling UpdateProcThreadAttribute with the PROC_THREAD_ATTRIBUTE_PARENT_PROCESS parameter.
- Creates a new process by calling CreateProcess with the specified command line and the attribute list.
- Displays the token information for the process.
service::start
This command starts a service.
- Gets the handle to the service control manager by calling OpenSCManager.
- Gets the handle to the specified service by calling OpenService.
- Starts the service by calling StartService.
service::remove
This command removes a service.
Its operation is almost the same as the service::start
but it calls DeleteService instead of StartService.
service::stop
This command stops a service.
Its operation is almost the same as service::start
but it calls ControlService with the SERVICE_CONTROL_STOP control code instead of StartServer.
service::suspend
This command suspends a service.
Its operation is almost the same as service::stop
but it specifies the SERVICE_CONTROL_PAUSE control code.
service::resume
This command resumes a service.
Its operation is almost the same as service::stop
but it specifies the SERVICE_CONTROL_CONTINUE control code.
service::preshutdown
This command preshutdowns a service.
Its operation is almost the same as service::stop
but it specifies the SERVICE_CONTROL_PRESHUTDOWN control code.
service::shutdown
This command shutdowns a service.
Its operation is almost the same as service::shutdown
but it specifies the SERVICE_CONTROL_SHUTDOWN control code.
service::list
This command lists services.
However, as far as I can see, the corresponding function just returns STATUS_SUCCESS…
lsadump::sam
This command gets the SysKey to decrypt SAM entries.
- If the user specifies the
system
option, opens the SYSTEM hive file by calling CreateFile.
- Maps the file into memory by calling CreateFileMapping and MapViewOfFile.
- Gets the computer name by retrieving the data from
HKLM\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName
. - Gets the SysKey by retrieving the data from
HKLM\SYSTEM\CurrentControlSet\Control\LSA
with concatenating the SysKey names including JD, Skew1, GBG, Data.
- If the user specifies the
sam
option, opens the SAM hive file by calling CreateFile. - Maps the file into memory by calling CreateFileMapping and MapViewOfFile.
- Gets the local SID from
HKLM\SAM\SAM\Domains\Account\V
and prints it to the console.
- Retrieves the SAM key from
HKLM\SAM\SAM\Domains\Account\F
and decrypts it with MD5 by calling RtlDecryptData2. - Enumerates the users under
HKLM\SAM\SAM\Domains\Account\Users
and gets the handle to the registry for each user. - Gets hashes (LM, NTLM, LM History, HTLM History) from
HKLM\SAM\SAM\Domains\Account\Users\[user]\V
. - Decrypts each hash depending on the key type (CryptAPI or CNG).
lsadump::secrets
This command gets the SysKey to decrypt SECRETS entries.
- The steps up to getting the SysKey are the same as the
lsadump::sam above
.
- Gets the handle to the registry for
HKLM\SECURITY\Policy
.
- Gets the data for
HKLM\SECURITY\Policy\PolRevision
. - If the pPolRevision->Minor is greater than 9, gets the data from
HKLM\SECURITY\Policy\PolEKList
, and decrypts PolEKList or PolSecretEncryptionKey using the SysKey to obtain the LSA encryption key, which is then used to decrypt the actual Secrets (CurrVal).
- If the pPolRevision->Minor is 9 or less, gets the data from
HKLM\SECURITY\Policy\PolSecretEncryptionKey
and decrypts the keys with the SysKey using MD5.
- Open the handle to the registry for
HKLM\SECURITY\Policy\Secrets
. - Enumerates the subkeys from the registry.
- For each subkey, gets the data for
HKLM\SECURITY\Policy\Secrets\[secret]\CurrVal
and decrypts it.
lsadump::cache
This command gets the SysKey to decrypt NL$KM then MSCache(v2).
-
If the user specifies the
user
option, enters the cache replace mode.- If the user specifies the
dcc
, the hash is stored to cacheData.dcc. - If the user specifies the
ntlm
, the hash is stored to cacheData.ntlm. - If the user specifies neither, the password is retrieved as a command line argument and calculates NTLM hash, then stores it to cacheData.ntlm.
- If the user specifies the
- If the user specifies the
subject
option, opens the cert store named “My” and finds the subject from the store. - Gets the corresponding private key from the certificate by calling CryptAcquireCertificatePrivateKey and stores phCryptProvOrNCryptKey to cacheData.hProv, and also stores pdwKeySpec to cacheData.keySpec.
lsadump::lsa
This command asks LSA Server to retrieve SAM/AD entries.
-
If the user specifies the
patch
option…- Gets the pointer to the service status information for the “SamSs” service.
- Gets the handle to the process for the PID stored in the status information.
- Gets the information of the
samsrv.dll
in the process. - Patches the module to apply PAGE_READWRITE or PAGE_EXECUTE_READWRITE protection.
-
Otherwise, if the user specifies the
inject
option…- Gets the pointer to the service status information for the “SamSs” service.
- Gets the handle to the process for the PID stored in the status information.
- Copies the address of kuhl_sekurlsa_samsrv_thread to the remote function.
- Gets the handle to the Policy object and the policy account domain information by calling LsaQueryInformationPolicy.
- Gets the handle to the SAM object by calling SamConnect.
- Gets the handle to the policy account domain by calling SamOpenDomain with the domain SID for the policy account domain information.
- If the user specifies the
id
option, looks up the specified ID by calling SamLookupIdsInDomain and gets the user credentials (LM and NTLM hashes) from SamQueryInformationUser. - If the user specifies the
name
option, looks up the name by calling SamLookupNamesInDomain and gets the user credentials (same as above) from SamQueryInformationUser. - If the user specifies neither, enumerates users by calling SamEnumerateUsersInDomain and gets credentials for each user.
lsadump::trust
This command asks LSA Server to retrieve Truth Auth Information.
- If the user specifies the
patch
option, applies to in-memory patch tolsasrv.dll
orlsadb.dll
to enable dumping trust information.
- Otherwise, enumerates domains trusted to authenticate logon credentials by calling LsaEnumerateTrustedDomains.
- For each domain, calls LsaQueryTrustedDomainInfoByName to retrieve the information and NT hashes the passwords and display them.
lsadump::backupkeys
This command dumps backup keys.
-
If the user specifies the
guid
option, retrieves the backup key name from the GUID. The key name is prefixed with “G$BCKUPKEY_” and is used for finding the secret in the following process:- If the user specifies the
secret
option, calls LsaQuerySecret to dump the LSA secret. - Otherwise, the LSA secret is dumped by calling LsaRetrievePrivateData.
- If the user specifies the
-
After dumping, it is decrypted and exported to a file with
.pfx
or.key
extension.
lsadump::rpdata
This command dumps a LSA secret from a specified key name.
Calls LsaRetrievePrivateData to dump the LSA secrets from the specified key name, and display them.
lsadump::dcsync
This command asks a DC to synchronize an object and dumps credentials.
- Gets the pointer to the DOMAIN_CONTROLLER_INFO structure for the specified domain.
- Gets the name of the domain controller from DomainControllerName in the structure.
-
Initializes the session with the LDAP server running on the domain controller by calling ldap_init.
-
Searches the LDAP directory by calling ldap_search_s with filtering by “(dn=RootDSE)”.
-
If the user specifies the
laps
option…- Gets the RootDN by calling ldap_get_values_len from the search result.
- Searches the LDAP directory by calling ldap_search_s with filtering by ”(&(objectclass=attributeSchema)(attributeID=” TEXT(szOID_ANSI_msMcsAdmPwd) L”))”.
- Gets the distinguished name and the identifier.
- Builds a RPC binding by calling RpcBindingFromStringBinding, RpcBindingSetAuthInfoEx, RpcBindingSetOption.
- Establishes the DRS (Directory Replication Service) binding by calling IDL_DRSBind.
- Gets the GUID for the NTDS DSA object by calling IDL_DRSDomainControllerInfo.
- Also establishes the DRS binding for the corresponding GUID by calling IDL_DRSBind.
- Asks updates from the NC replica on the server by calling IDL_DRSGetNCChanges.
- After retrieving the updates, enumerate the REPLNTINFLIST structure for the object.
- For each REPLINTINFLIST structure, extracts the corresponding value and decrypts it with MD5.
- Dumps the result with the standard format or the CSV format. It depends on the command line argument.
lsadump::dcshadow
This command injects a data to DC.
- If the user specifies the
stack
option, the specified data — including the object, attribute, and value — is queued for later use. - If the user specifies the
push
option, all previously queued changes are replicated to the domain controller.
-
Initializes the session with the LDAP server on the specified domain controller by calling ldap_init.
-
Sets the LDAP version to 3.0 and enables the LDAP signing, and establishes a connection with the LDAP server by calling ldap_connect then authenticates the client by calling ldap_bind_s.
-
Gets the domain information via the RootDSE by calling ldap_search_s to find it.
-
Gets the information for the fake computer account by calling ldap_search_s.
-
Gets the information for the account containing objectGUID, invocationId, msDS-ReplicationEpoch. Build the replication data.
-
If the user specifies the
addentry
option, calls IDL_DRSAddEntry to inject the replication data. -
If the server start option, once the replication data injected, the RPC server starts by calling the corresponding APIs such as RpcServerUseProtseqEp, RpcServerRegisterAuthInfo, RpcServerRegisterIf2, RpcServerInqBindings, RpcEpRegister, RpcServerListen.
-
If the user specifies neigher
addentry
norstartServer
, performs the following processing:- If the user specifies the
push
,manualregister
orkill
option, registers the specified object to Active Directory via LDAP by calling ldap_add_s, ldap_modify_s, IDL_DRSAddEntry. - Once it succeeds, if the user specifies the
push
ormanualpush
option, force sync by adding the replication data the target domain controller by calling IDL_DRSReplicaAdd, and immediately delete the link by calling IDL_DRSReplicaDel. - If the user specifies the
kill
option, triggers to remove the LingeringObject by calling ldap_modify_s. - If the user specifies the
manualunregister
option, unregister the fake DC from Active Directory by calling ldap_delete_s.
- If the user specifies the
lsadump::setntlm
This command asks a server to set a new password/ntlm for one user.
- Initializes the SAMPR_USER_INFO_BUFFER structure with NTLM and LM password hashes to prepare it for use in later.
- If the user specifies the
password
option, calls RtlCalculateNtOwfPassword to calculate NT hash from the password. - If the user specifies the
ntlm
option, converts the specified hash to Hex. - Gets the handle to the specified server by calling SamConnect.
- Enumerates domains in the Sam server by calling SamEnumerateDomainsInSamServer.
- For each domain, gets the handle to the domain by calling SamOpenDomain.
- If the user specifies the name, looks up the account name by calling SamLookupNamesInDomain to get the RID.
- Gets the handle to the user by calling SamOpenUser.
- Overwrites the password/ntlm with the new one by calling SamSetInformationUser against the user.
lsadump::changentlm
This command asks a server to change a password/ntlm for one user.
The processing here is similar to the lsadump::setntlm
, but the last function called is SamiChangePasswordUser instead of SamSetInformationUser.
lsadump::netsync
This command retrieves NTLM hashes by abusing the NETLOGON protocol.
- Gets the server challenge (the NETLOGON_CREDENTIAL structure) from the server by calling I_NetServerReqChallenge with the client challenge.
- Calculates MD5 hashes for the decimal 0, the client challenge data, and the server challenge data.
- Calculates the HMAC with MD5 by calling CryptAcquireContext, CryptCreateHash, CryptSetHashParam, CryptHashData, CryptGetHashParam to get the session key.
- Encrypts the client challenge and the server challenge data by calling RtlEncryptBlock to get the client credential and the candidate server credential.
- Authenticates the specified remote host by calling I_NetServerAuthenticate2 with the client credential to get the server credential.
-
If it succeeds, compare the candidate server credential and the server credential.
-
Enumerates secure channels including WorkstationSecureChannel, ServerSecureChannel, TrustedDnsDomainSecureChannel, CdcServerSecureChannel.
-
For each secure channel, the following processing is executed:
- Adds the timestamp and encrypted client credential for the Authenticator by calling RtlEncryptBlock.
- Gets the encrypted new and old passwords by calling I_NetServerTrustPasswordsGet for the specified account.
- Decrypts the passwords by calling RtlDecryptNtOwfPwdWithUserKey with the session key to get the NTLM hashes.
lsadump::packages
This command lists security packages.
- Calls EnumerateSecurityPackages to enumerate the security packages.
- Displays each package information including name, description, capabilities, version, etc.
lsadump::mbc
This command dumps the MachineBoundCertificate.
- Gets the data form the registry path
HKLM\System\CurrentControlSet\Lsa\Kerberos\Parameters\MachineBoundCertificate
. - Extracts data from that.
lsadump::zerologon
This command abuses the ZeroLogon vulnerability for the NETLOGON protocol.
-
Prepares the
NETLOGON_AUTHENTICATOR Authenticator = {{0}, 0}
for abusing the the ZeroLogon vulnerability. -
Creates the RPC binding by calling the corresponding APIs such as RpcStringBindingCompose, RpcBindingFromStringBinding, RpcBindingSetAuthInfoEx, RpcBindingSetOption.
-
The following processing will be attempted up to 2000 times:
- Gets the server challenge by calling NetrServerReqChallenge with the zero padding authenticator credential.
- Authenticates by calling NetrServerAuthenticate2.
- If it succeeds, reset the password of the domain controller by calling NetrServerPasswordSet2.
lsadump::postzerologon
This command sets a new password for one user after ZeroLogon.
- Enumerates accounts of the specified server by calling the corresponding APIs such as SamConnect, SamEnumerateDomainsInSamServer, SamLookupDomainInSamServer, SamOpenDomain.
- If the specified account is found, get the RID by calling SamLookupNamesInDomain.
- Gets the handle to the account by calling SamOpenUser and sets the new password by calling SamSetInformationUser.
- Once updated, set the new password for the LSA secret by calling LsaSetSecret.
ts::sessions
This command lists sessions on a terminal server.
- Gets the handle to the specified terminal server by calling WinStationOpenServerW.
- Enumerates sessions on the server by calling WinStationEnumerateW.
- Gets the information for each session by calling WinStationQueryInformationW.
- Prints the result to the console.
ts::remote
This command connects a remote terminal server.
It connects to the specified terminal server by calling WinStationConnectW.
event::clear
This command clear an Windows event log.
- Gets the handle to the specified log by calling OpenEventLog.
- Checks the number of the event logs by calling GetNumberOfEventLogRecords.
- Clears the event log by calling ClearEventLog.
- Checks again the number of the event logs by calling GetNumberOfEventLogRecords.
token::whoami
This command displays current identity.
- Gets the handle to the token for current process, and uses GetTokenInformation to get the information of the token then displays them. Also, calls LookupPrivilegeName to display the privileges.
- Get the handle to the token for current thread, and do the same processing as above.
- If the user specifies the
domainadmin
orenterpriseadmin
option, gets the domain information by calling LsaQueryInformationPolicy. - Gets the SID and the name by calling CreateWellKnownSid and LookupAccountSid.
vault::list
This command lists Windows Vaults.
- Enumerates vaults by calling VaultEnumerateVaults.
- For each vault, opens the handle to the vault by calling VaultOpenVault.
- Gets the information for the vault by calling VaultGetInformation and displays it.
- Enumerates the vault items by calling VaultEnumerateItems and displays each information for the item.
- Gets the Authenticator for the item by calling VaultGetItem7 and displays the information.
dpapi::blob
This command describes a DPAPI blob.
- If the user specifies the
in
option (file path), reads the data from the file path. - If the user specifies the
raw
option, converts the specified data to the Hex buffer. - Extracts the information from the specified blob such as the description, the version, the GUID of the provider, the HMAC key, the salt, etc. And display them.
- Gets the master key entry from the GUID.
- Decrypts the blob with the master key by calling CryptDecrypt. The cryptographic algorithm depends on that blob.
dpapi::masterkey
This command describes a MasterKey file and unprotect each MasterKey.
-
Reads buffer from the specified MasterKey file.
-
Extracts the master key, the backup key, the credential history, and the domain key from the offset for the buffer.
-
Displays the information for the master key such as version, GUID, flags.
-
If the credential history exists in the master key, find the corresponding credential entry from a global list.
-
Displays the information of the entry including SID, GUID, MD4 hash, SHA1 hash, MD4p hash.
-
Gets the derived key depending on the masterKeys->dwFlag.
-
Decrypts the master key with the derived key in the following method:
- Derives the decryption kay (session key) and IV with PBKDF2.
- Decrypts the master key by calling CryptDecrypt.
- Verifies the decrypted master key with HMAC.
- Displays the decrypted master key.
dpapi::cred
This command describes a Credentials file and unprotect it.
Its operation is almost the same as the dpapi::masterkey
, but it reads a Credentials file and decrypts the credentials information.
dpapi::chrome
- Initializes the SQLite library by calling sqlite3_initialize.
- Opens the specified database file by calling sqlite3_open.
- Checks if the “logins” table exists in the database by executing the “select count(*) from sqlite_master where type=‘table’ and name=logins” query.
- If it exists, execute the “select signon_realm, origin_url, username_value, password_value from logins” query to extract the information from the table.
- Enumerates the result and display the URL, username, and password which is decrypt by calling BCryptDecrypt.
- Checks if the “cookies” table exist in the database by executing the “select count(*) from sqlite_master where type=‘table’ and name=cookies” query.
- If it exists, execute the “select host_key, path, name, creation_utc, expires_utc, encrypted_value from cookies order by host_key, path, name” query to extract the information from the table.
- Enumerate the result and display the information. The encrypted cookie value is decrypted by calling BCryptDecrypt.
IOCs
Files
- mimikatz.exe:
61c0810a23580cf492a6ba4f7654566108331e7a4134c968c2d6a05261b2d8a1