Skip to content
Forrest edited this page Jan 23, 2019 · 2 revisions

I've been working on a new .NET RAT to both escape security product detection and explore some .NET concepts I've been meaning to check out, in support of engagements. Meterpreter is too well-known/signatured to work during an engagement, in the presence of an advanced capability (like Crowdstrike). Combining advanced capabilities with AMSI has pretty much ruined PowerShell as a reliable and stealthy vector. The move to .NET was the rage over the last couple years (and well before), resulting in (and probably better described by) things like SpecterOps' SharpSploit and HarmJ0y's GhostPack.

These tools provide most of the functionality I would like in a RAT and they are familiar, so my goal became figuring out how I could remotely load and execute these capabilities. Well... my goal was really hijacked by a couple of things, as I wantonly developed, that I wanted to understand and try:

  • How do I .NET Reflection? (load and execute the goods)
  • Is there anything I can do to hide my activity from security products? (short-term hide the goods)
  • Can I/How do I unload modules when not in use? (long-term protect the goods)
  • How do I generalize these capabilities so I can load and call any method from any .NET DLL? (make it a tool)

.NET Reflection is well understood and documented. Loading additional .NET Assemblies from a file or byte-array and calling the methods within is easy.

Unloading .NET Assemblies after you're done with them? That's a bit more tricky. In general, once a DLL is loaded, it cannot be unloaded without destroying the current application... or what .NET knows as an AppDomain. Fortunately for us, we can create more AppDomains within our main AppDomain, which we can load Assemblies into, execute methods from said Assemblies, and then promptly unload the AppDomain and all Assemblies loaded in it. Unfortunately for us, doing this creates a whole track and field of Type hurdles and Serialization hoops that we must contort around. AppDomains bless us with many things: isolation, obscurity, the ability to unload, and paperclip-string solutions that I probably need to re-think. Oh, and did I mention my target was .NET 3.5/3.0?

What I'm doing here isn't too dissimilar from Luke Jennings' Countercept post on a Gargoyle-like solution for memory scanning evasion in .NET. Jennings' article makes for a good read and provides several detection strategies. I really haven't contributed anything more advanced or made progress on beating these detections (add it to the TODO's), but this is where I'm entering the loop.

Clone this wiki locally