SafetyKatz over .net

GhostPack was recently released by Will Shroeder.  This is a great package of C# offensive tools.  C# is a relatively untapped part of the offensive toolkit with some unique opportunities and challenges.  It is great because it gives you a great API that you can live off of, it is sometimes a challenge as different versions aren’t always consistently installed across different organizations.  In this post we are going to talk about applying a concept that I developed to one of these tools to reduce detection surface as much as possible.  The tool we are going to look at is SafetyKatz which wraps normal mimikatz in C# which in turn wraps some unmanaged code using a PELoader technique created by Casey Smith.  Essentially what this post boils down to is shrinking the on-disk footprint of SafetyKatz from about ~700KB to about 5KB and loading the rest over http or https using a technique I call .Net over .net.

So initially when you compile SafetyKatz you end up with a relatively large payload of 700+KB.  So how can we minimize this?

The way that we are going to accomplish this is that we are going to turn the SafetyKatz.exe binary into a library to be used by the executable that is actually going to land on the system.  We have to make some modifications to the SafetyKatz source code:

Essentially we are making the C# classes “public” so they can be accessed by our other binary.  It is unusual (and probably not optimal) to make Main public, but alas it works.

Let’s create a new C# project based on the PoCs from my original .Net over .net post.  As you can see I have stripped out the IronPython used in the Poc from the code and the references as we don’t need them for this example.

We need to set the executable to be x64 bit so that mimikatz can function.  This is done in the project properties, in the “Build” tab.

We then take a copy of SafetyKatz.exe to the source directory of our new application and add it as a reference. Not everyone realizes that .Net executables are actually just assemblies that can be referenced like .dlls, but under the right conditions this is possible.


We also want to set copy local to ‘False’:

We then add in the rest of our code to reference and call Main from SafetyKatz(the namespace is actually SharpDump).

The cool thing about the way this works is that we are hooking the C# assembly resolve system.  When the cmd.exe binary that this program compiles down to doesn’t find SafetyKatz.exe, that is referenced, in the various filesystem locations that it is designed to look for it in, it uses the OnResolveAssembly event to handle the missing assembly.  This handler finds and loads it over http and continues executing:

So what does the final payload look like? 4KB:

And as long as it can download SafetyKatz.exe from the location baked into the executable it runs just like regular SafetyKatz.exe:

I hope you found this helpful and it helps demonstrate the power of loading .Net assemblies into memory over HTTP(s).  If enough people are interested, I can upload the source code to GitHub.

Leave a Reply