In a recent engagement I had to compromise a hardened desktop running CrowdStrike and Symantec Endpoint Protection. The initial code execution method was my reliable favorite MSBuild (C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe) which could be leveraged to execute C# code as an inline task. Initially I wrote a very basic loader that used a bruteforce decryption algorithm to run a Cobalt Strike beacon using VirtualAlloc and CreateThread. The shellcode was stored encrypted within the C# code and decrypted using a multibyte XOR key with the last 3 bytes removed. The while loop continuously increments the decryption key, performs XOR decryption and hashes the decrypted payload until the hash value of the decrypted shellcode matches its original hash value. This methods prevents antivirus or snooping eyes from easily reading the shellcode, and in fact no antivirus product would spend the amount of time required to decrypt the shellcode even if they knew how to run C# code in MSBuild project files. CrowdStrike detected and prevented the VirtualAlloc/CreateThread method and classified it as “Process Hollowing”. I'd never seen that technique detected before, but had been waiting for the day. I knew I’d have to take CrowdStrike seriously and wrote a new loader that used the same decryption routine but now executed code using the undocumented NtMapViewOfSection and NtQueueApcThread functions. The NtMapViewOfSection routine maps a view of a section object into the virtual address space of a subject process. The NtQueueApcThread routine adds a user-mode asynchronous procedure call (APC) object to the APC queue of the specified thread. These methods are far less common, and considered more stealthy. The majority of the loader code was taken from the Sharp-Suite UrbanBishop POC (https://github.com/FuzzySecurity/Sharp-Suite) which implemented exactly what I wanted. I updated the POC slightly to support inline shellcode and automatic process selection for the injection. The loader now successfully bypassed the CrowdStrike prevention rules. The use of MSBuild did trigger a detection alert in this particular configuration that was unfortunately unavoidable unless a different initial code execution method was used. The detection alert was not a prevention which meant the shell was allowed to live. The loader does create a suspended thread in the remote process to queue the APC. This can be avoided by selecting an already existing thread, however the thread needs to enter/be in an alertable state for the APC to execute and picking the wrong thread can impact the stability of the remote process. The trade-off for that extra bit of stealthiness did not seem worthwhile but I figured I'd mention it for anyone writing detections.
12 Comments
Sunny
6/30/2020 08:23:41 am
This is quite interesting. Would it possible for you to share the code you ran?
Reply
Dave
6/30/2020 09:25:48 am
Following...
Reply
VS
6/30/2020 11:18:15 am
would also love to get a sample, to test against other solutions
Reply
Pivot Point
6/30/2020 08:41:11 pm
incredible resources on finding to bypass. would it be possbile to share the code to reproduce.
Reply
FarCry
7/1/2020 05:39:53 am
"The use of MSBuild did trigger a detection alert in this particular configuration that was unfortunately unavoidable unless a different initial code execution method was used."
Reply
James
7/1/2020 05:19:15 pm
Dude! He got a shell out. I am pretty sure that is the definition of a bypass
Reply
FARCRY
7/16/2020 10:15:58 am
Obtaining a shell is not necessarily a complete "bypass" since EDR is designed to provide visibility and detections first and foremost. He may have been able to bypass a "prevention" pattern, but would still have alerted the SOC to his presence.
Michael
7/1/2020 05:45:48 pm
Hi, I wrote the blog post. The detection was only "unavoidable" with the usage of MSBuild. I actually did find a method to avoid the detection by backdooring a DLL file used by a Microsoft Word extension. However, that is very specific to the environment and not very universal but a good example of a different initial code execution method.
Reply
FARCRY
7/16/2020 10:17:56 am
It was not a complete bypass. People seem to forget that it wasn't that long ago it took on average 9 months for organizations to even figure out someone was in the network.
Reply
Jonathan
7/2/2020 02:04:42 am
Cool post! Would you be able to share the CrowdStrike prevention policy set-up? Was it the default one?
Reply
Gordon
7/2/2020 06:21:59 pm
We wont be releasing the code. Our client who is a CrowdStrike customer has the proof of concept and will pass it onto CrowdStrike.
Reply
Leave a Reply. |
AuthorRed Cursor ArchivesCategories |