One of the most pressing internal network security issues is limiting the ability of an attacker to perform privilege escalation. In my experience, once administrative level access is obtained to a Windows system it is trivial for an attacker to dump user credentials and pivot throughout the network, eventually gaining the most privileged accounts without detection.
While preventative controls such as hardening Windows group policy configurations, LAPS, MFA, and segmentation can be implemented to slow an attacker down, the ability to detect remains the most readily available method. In order to detect the password extraction stage of the attack, we need to identify processes that hook into LSASS. For my testing, I used the popular Mimikatz toolset for extracting passwords / password hashes and Sysmon, Microsoft’s free event extension to research the DLLs. Based on my research, using a basic (and free) endpoint tool, Sysmon, I believe we have the capability to detect Mimikatz in all flavors: in-memory, on-disk, and packed on-disk. Once identified in Sysmon, the Windows logs still need to be forwarded on to your SIEM to trigger an alert. In my analysis, this detection method results in very few false positives. This method can also be extended to Endpoint Detection and Response (EDR) tools that capture processes.
*** Full caveat: I have only tested this in a few environments, so your mileage may vary. Further testing should be performed prior to rollout. In addition, the SIEM will need to correlate the events that happen in succession. ***
Uncovering Mimikatz Activity
To detect Mimikatz activity, I went to the core of what Mimikatz needs to run, namely its loading of Windows DLLs. This is important as this will always occur no matter what process Mimikatz is injected into and cannot be obfuscated via in-memory execution or a packed exe. Using Sysmon with the -l flag to identify DLL image loading, I extracted the DLLs of both in-memory execution via a beacon (spawned in the context of rundll32.exe via Cobalt Strike) and Mimikatz executing on disk via command prompt.
As some of these libraries may differ between methods, I wanted to identify only libraries that were persistent across both methods and came up with the following list, highlighting similarities:
From this list of shared DLLs, I then started to build out my DLLs for detection. Searches with a subset of these DLLs against a Carbon Black instance showed a small number of false positives using the following DLL list:
Querying for these unique DLLs in the EDR solution Carbon Black resulted in only 17 processes. This is great news as it appears that the fingerprint for Mimikatz is unique from other processes, resulting in very few false positives. This Carbon Black instance has over 2 months of process information for 9,000,000+ processes across workstations and servers, so a pretty significant sample size. Further opportunities exist for strengthening this search by decreasing the time window for ensuring all DLLs are loading in conjunction, but that was outside the scope of this exercise. Using this detection method, either in Sysmon or an EDR tool, we should be able to key off of all instances of Mimikatz.
Due to changes in reflective DLL loading that are used by Mimikatz in-memory (Powersploit, Cobalt Strike, Powershell Empire), the method to detect Mimikatz in memory has changed. Previously, when Mimikatz loaded in memory via DLL injection, Sysmon would show both the requested DLL, as well as dependencies when they were loaded by the process. However, with the changes to DLL injection, only the requested libraries, not the dependencies are shown in Sysmon.
Therefore, rather than a list of ~10 DLLs, we now see two DLLs in sysmon when mimikatz is run in memory: vaultcli.dll and wlanapi.dll. These two API’s then load a set of dependencies (1,2) that are not populated in sysmon when Mimikatz runs in memory. We do still see these dependencies loaded in sysmon when Mimikatz is run on disk. Therefore, detection alerts should still use the previous rule, as well as key off of vaultcli.dll and wlanapi.dll.
Given this smaller list, they'll be some more false positives, but this can be resolved. In my test environment with 10m+ processes, we're at roughly 500 false positives vs 20 previously when searching for these two DLLs. However, removing two known applications, I was able to remove the false positives and set up a rule that will properly trigger when Mimikatz is used in-memory. As each environment is unique, these applications will vary on environment and can be identified and whitelisted after enabling the query.
In addition, as more companies move to newer Windows Operating Systems, LSA Protection should be enabled. Doing so will require Mimikatz to load mimidrv.sys, which can be logged as well. Either loading of the driver or the DLL loading listed above will detect Mimikatz usage in-memory and on disk. This was out of scope for this review, but I will discuss in a future blog post about detection when LSA protection is enabled.