If you want to execute arbitrary code on an endpoint during a penetration test, chances are you’ll have to evade some kind of antivirus solution. AV engines use two detection methods to identify malicious code – signature-based and heuristic-based detection. Heuristic, or behavioral-based detection, involves analyzing what code does when it executes and determining if that behavior indicative of malicious behavior. Examples of a heuristic detection would be identifying the use of process hollowing or the use of `CreateRemoteThread` for DLL injection. Signature-based detection involves looking for static signatures that match known-bad code.
Examples of signature-based detection include matching the file hash to known malware and matching strings within the potential malware. Many an AV vendor has been known to mark a payload as malware simply because @harmj0y appeared somewhere within the file. In this blog, we’re going to evade Windows Defender by modifying the Mimikatz source code to evade signature-based detections
Signature-based detection is brittle because it relies on matching specific signatures – often text strings – within the object being scanned. As a result, if we modify our payload so the relevant signatures are no longer found, we can evade signature-based detection. A well-known example of this is changing Mimikatz to Mimidogz. I’ve encountered AV products that have alerted simply because Will Schroeder’s Twitter handle @harmj0y, appeared in a PowerShell script. So now that we know what a signature-based detection is, how do we go about identifying what specific signatures are causing Windows Defender to identify our payload as malicious? Matt Hand @matterpreter created DefenderCheck to help identify exactly what bytes in a payload cause Defender to mark the payload as malicious.
I downloaded the Mimikatz source code and compiled it with Microsoft’s Visual Studio 2019. (Note: There are a few modifications that are required in order to compile the source code with Visual Studio. That exercise is left to the reader.)
After compiling the source, I used DefenderCheck to see if the binary was detected as malicious. No surprises here, it was detected as `HackTool:Win64/Mikatz!dha.` DefenderCheck returns a hexdump of the bytes that caused Defender to alert on the payload. In the following screenshot, we can see that detection occurred in an error message string contained in the binary. The specific string appears to be `mimikatz_doLocal.`
Detection on mimikatz_doLocal
I took an educated guess that it was the presence of `mimikatz` in the string that caused the detection, so I performed a search and replace to replace all instances of `mimikatz` with `mimidogz` and recompiled the binary. I ran the new binary through DefenderCheck and found this time the offending signature appeared to be `wdigest.dll` as shown in the following screenshot:
Detection on wdigest.dll
I searched for `wdigest.dll` in the source code and found it appeared in two files:
Wdigest.dll in source code
It took a bit to find exactly what was needed to evade detection here. `Wdigest.dll` appears in a list of DLLs. I tried reordering that list, placing wdigest.dll in different places, but every attempt still resulted in detection. The next step to was to understand how that list of DLLs was being used. We can see here that the list of DLLs is part of an array, `version_libs`.
Version_libs array definition
Digging a little further, we can see that the DLLs in `version_libs` are passed to GetFileVersionInfoSize and GetFileVersionInfo. Looking at the details for GetFileVersionInfo, we see that if the full path for the file being queried is not specified, the search sequence specified by the LoadLibrary function is used.
Digging into the LoadLibrary function, we find that if the file extension is omitted, the function will append both `.dll` and `.exe` to the file name. In the end, all that was required to bypass this particular signature was to remove the `.dll` from `wdigest.dll`!
Getting the binary working against an up-to-date versino of Defender required many other changes. Some of these changes included changing instances of the following strings: `kull, kuhl, kiwi, sekurlsa, logonpasswords, credman. Perhaps the most interesting signatures were for the following functions: `I_NetServerAuthenticate2`, `I_NetServerReqChallenge`, and `I_NetServerTrustPasswordsGet`. These functions are part of `netapi32.dll`. A stripped down version of this library is included in the mimikatz/lib directory as `netapi32.min.lib`. After some searching, I found a blog that discussed getting around this particular detection. First, I needed to create a `.def` file that I would use to build a new libary module to be included during the Mimikatz build process. The contents of the file are shown below. Here’s what’s happening: a library (DLL) may export one or more functions that can be used by other programs. Those functions are usually called by name, such as `I_NetServerAuthenticate2` from `netapi32.dll.` It is possible, however, to also call the functions by their `ordinal` – a number which refers to the function.
I_NetServerAuthenticate2 @ 59
I_NetServerReqChallenge @ 65
I_NetServerTrustPasswordsGet @ 62
This `.def` file needed to be compiled into a module. This was accomplished using the Visual Studio developer console and the following command: `lib /DEF:netapi32.def /OUT:netapi32.min.lib` After building `netapi32.min.lib,` I placed the file in the lib\x64 directory, replacing the original file. After rebuilding, the resulting executable no longer contained the offending function names from `netapi32.dll.`
A final check with DefenderCheck shows the file is no longer being detected as malicious.
DefenderCheck – no detections
It was time to see if all this hard work would pay off. As you can see, I was able to execute Mimikatz and extract credentials without triggering Defender. Some of the modifications that were required can be seen in the screenshot, including `mimidogz,` `securelsa,` and `loginpasswords.`
Successfully executing Mimikatz
This same technique can be used with any payload you want to execute on a system running Defender. In fact, you can do it against any AV with just a little more work. PowerSploit’s Find-AVSignature.ps1 can help automate the process, but the basic method is a binary tree-style search. This process can be time consuming, and even if you get past signature-based detection, you may be caught by heuristics.
However, in many cases, your efforts will be rewarded with code execution. Just keep in mind that because AV vendors are constantly updating their signatures, what works on Friday afternoon might not work on Monday morning when you need it.
Subcribe now to join our email list and continue getting up to date information on all of the live events, discussions, educational webcasts and giveaways