Both failure and experimentation have been instrumental in developing my offensive tradecraft skills. While not a red teamer by trade (I am an intelligence tool builder), being able to recreate tradecraft has always been important, validating the signals being generated from the automation that I build. One facet of our cyber intelligence, or counter cyber intelligence (CCI) to be more specific, are the detailed mappings of social structures within the commoditized exploit tool ecosystem. These data structures have the ability to anticipate which exploit tools and tradecraft may be combined with another, possibly being disparate at a surface glance but connected within our dataset by way of social, developer or technical relationships. It is these possible tradecraft combinations that then fuel our experimentation to ground-truth how the signals would behave if combined together. This writeup has been fueled by just such a scenario as we explore building a dropper that can bypass UAC (User Account Control) and persist through WMI, turned into shellcode and injected into a remote process. Testing was conducted on a Windows 10 box and with MDE (Microsoft Defender for Endpoint) installed, BlockMode and Automated Investigations enabled. While the attack was fully executed, MDE automated investigations caught up with us and eventually killed our fun. This is the story.
Lately, we have been zeroing in on a part of the kill chain that transpires right after an initial access event (like malicious macro downloads payload) has taken place and then finishing right before lateral movement. It is within this scope that we will operate for this writeup and build a dropper that will automate all aspects of the attack. Three months ago, many of our signals related to UAC bypass ran FUD (fully undetected) when tested on endpoints protected by MDE. As of late, Microsoft has stepped up their detection game and getting a FUD UAC bypass on an MDE protected endpoint, is difficult. In an attempt to combat this newfound blue team’s strength, we decided to build our exploitation logic so that it could be turned into shellcode via donut.exe (“Generates position-independent shellcode that loads .NET Assemblies, PE files, and other Windows payloads from memory”) and injected into various processes. Ultimately, the injected offensive logic is able to download additional payloads, bypass UAC, install WMI persistence and callback to Covenant C2 as NT AUTHORITY\SYSTEM.
Slippery.exe’s primary purpose is to be turned into shellcode and injected into WmiPrvSE.exe, via process hollowing. It’s exploit logic is that of a dropper / UAC Bypass which executes an attack chain, culminating in SYSTEM level persistence. Let’s walk through some of its code.
Slippery.exe establishes HTTPS connections with ngrok and leverages the curl.exe binary found preinstalled in Windows 10, to download its payloads.
Slippery.exe has two defined download paths where it will drop files to disk:
The UAC Bypass:
Leveraging the native binary fodhelper.exe, Slippery.exe will bypass UAC by exploiting odd behaviors found within fodhelper.exe. This native binary is an "auto-elevated" binary and will look for additional process creation arguments, should certain registry keys exist. If those keys are created, fodhelper.exe will execute the command value which is contained within one of those keys (high-integrity context), thereby bypassing UAC. We wrote some very basic C# code to exploit this vulnerability which was based on trending vectors, articulated within our CCI dataset. The bypass code achieves the following:
Persistence & Hiding Execution Relationships:
So, this method was really about dismantling the forensic relationship between the initial execution and the persistence mechanism because we knew the UAC bypass method would get flagged. In the end, we were caught on the decision to write to a protected folder as an unprivileged user, coupled with the UAC bypass that indeed was flagged. None the less, we feel this strategy applied slightly differently could be highly effective and run FUD. The exploit logic for persistence will be discussed in two parts; the initial part that registers the persistence and then the second part which details what the persistence does.
Persistence Logic (ClipEvent.ps1):
To gain persistence on this endpoint ClipEvent.ps1 opted for an old favorite and that was a WMI event subscription. One difference here is that we decided not to use mofcomp.exe to register an event subscription as that vector is detected by MDE, now. Instead, we crafted a PowerShell approach which did the following:
Persistence Payload Logic (wscRGB.ps1):
wscRGB.ps1 is a tiny script that is meant to start the process injector (fontdrvx64.exe) which injects Covenant C2 implant shellcode as NT AUTHORITY\SYSTEM. Its secondary function is to delete the initial files that were dropped to Public\Downloads.
Execution Relationship Obfuscation:
Our idea was to download the first process injector (containing the UAC bypass) and the first ps1 script (responsible for WMI persistence) into Public\Downloads and the second injector (Covenant implant) and ps1 script (WMI payload for the CommandLineEventConsumer) into a user writable folder, within system32. The rationale was that if our UAC bypass was alerted on, investigators would have a harder time connecting the dots between it and the resulting process injection, stemming from a sub folder in system32 with no clear execution linkage. We broke up the execution relationship by not passing execution directly from the process responsible for bypassing UAC (Slippery.exe’s logic injected into WmiPrvSE.exe) and registering WMI persistence. Instead, Slippery.exe would initially kill process rdpclip.exe (in case it was already active) and then at the end of its logic, start rdpclip.exe which would then trigger the WMI permanent event subscription, therby firing the second injector connecting back to the C2 as SYSTEM. Remember, part of the WMI payload’s logic (wscRGB.ps1) was to delete ClipEvent.ps1 (registers the WMI event subscription) which would clearly articulate the directory of the WMI payload to be executed by the “CommandLineEventConsumer.” That being said, defenders could still see the resulting WMI payload location by inspecting tools such as ScriptBlock Logging or the AMSI content output in MDE (shown below). Additionally, due to the fact we got lit up for dropping a file to a protected folder which was user writeable, the automation was able to see the injected process (Dropper/UAC bypass) WmiPrvSE.exe now connected with the WMI payloads in system32 we were trying to obfuscate (also shown below).
Process Injector (Process Hollowing (fontdrvx64.exe & SM.exe))
For the injector we used a modified version of a payload discussed at Defcon 27, “Writing custom backdoor payloads with C#,” which can be found below. Both fontdrvx64.exe and SM.exe were identical injectors, except for the shellcode that they injected. SM.exe was responsible for injecting the initial dropper/UAC bypass and fontdrvx64.exe was the persistent injector hidden within “C:\Windows\System32\spool\drivers\color\, responsible for injecting the Covenant implant.”
(defcon27_csharp_workshop/2.cs at master · mvelazc0/defcon27_csharp_workshop · GitHub)
In this round of experimental testing, MDE really ate our lunch for us but we learned quite a bit. Some key takeaways are as follows: