Simple Loader (Execution Guardrails)

This is a loader-agnostic stage that demonstrates execution guardrails using an environment-derived key.

Project Files

NOTES

This is something I really wanted to bring into Tradecraft Garden. I didn't get around to elegantly bringing Execution Guardrails into Cobalt Strike during my run, and that's partially because I felt they belonged in the loader, and I didn't have this kind of technology to do so in a maintainable way. But, I believe in Execution Guardrails as a FUNDAMENTAL GOOD in a safe and professional red team operation. The benefits include:

  • Positive control - If your agent lands somewhere it shouldn't, it's rendered inert.
  • Obfuscating client information - Red Team C2 payloads LEAK information about your red team operation and, sometimes, your client's environment. Execution Guardrails using environment-derived crpytographic keys are a layer of obfuscation to slow recovery of this information.
  • Evasion - Execution guardrails can frustrate sandboxing analysis, making it harder to examine your payload's behavior from a sample.

Execution Guardrails

This implementation of Execution Guardrails encrypts the output of a stage 2 loader with an environment-derived key. There are many possibilities to generate an environment-derived key.

guardrail.spec sets up our guardrail loader PIC. The loader is divided into two parts. gr_impl.c is the environment-key derivation logic and the decryption/verification routine. guardrail.c uses that logic. guardrail.c decrypts the code it is to run next. The two are combined with Crystal Palace's merge command.

free.c is our free and run PIC. This code frees our guardrail loader and passes execution to our stage 2 loader's output. All of this is setup in guardrail.spec too. After free.x64.o is loaded onto the program stack, run %STAGE2 is called. %STAGE2 is a user-specified variable for our follow-on specification file. linkfunc "go_stage2" appends run's result to our free and run PIC and links it to free and run's go_stage2 function.

The PIC for guardrail.c and free.c are both setup with the callable label initpic. Callable labels are Crystal Palace functions. The initpic label brings in PIC services from Simple PIC, merges LibTCG, and configures link-time optimization (and +gofirst) for our PIC programs.

The export command exports the free and run PIC + stage 2 package for further processing. prepsum prepends the Adler32 checksum of our PIC package to itself. rc4 $KEY encrypts this packaged with the passed-in key. preplen prepends the length of the ciphertext to itself.

Running this loader requires passing our environment-derived key, $ENVKEY, and our stage 2 .spec file, %STAGE2, to the ./link command. run.x86.exe and run.x64.exe both print an $ENVKEY that works with this example.

./link guardrail.spec demo/test.x64.dll out.bin \$ENVKEY=0302010003020100 -r %STAGE2="path/to/loader.spec"

For this demo, I recommend -r which tells Crystal Palace to immediately resolve %STAGE2's relative path(s) to the current working directory.

Security vs. Obfuscation

One of the questions I've sat with, is rc4 good enough here? RC4 is an encryption algorithm with known weaknesses. In this context, it's not security for the follow-on data its masking. That's why I've carefully chosen my words and described it as obfuscation--something in place to slow down the recovery of information a follow-on payload might leak. But, I don't see rc4 as the sole problem here. Even if I were to expose other encryption schemes (e.g., AES-CBC 128/256, ChaCha20, etc. are candidates), I believe one would need great care to select environment factors AND a key derivation scheme that yield enough bits of actual randomness before there's any measure of confidentiality in narrow threat model situations. I speculate that it's difficult to achieve a sound confidentiality guarantee with this technique and most attempts would fall short of truly achieving this.

Conversation

License

This project is licensed under the BSD License.