Skip to content

I. Conceptual Overview

Gabriel Ryan edited this page Aug 24, 2020 · 2 revisions

DropEngine is built around the principal of identifying discrete payload components and turning them into modules. The tool also provides built-in obfuscation, encryption, and symbolic substitution capabilities for evading signature-based detections.

Anatomy of a Basic Payload

At their core, initial access payloads are relatively simple, and involve two major operations:

  1. Load shellcode into memory
  2. Execute the shellcode
  • Terminology - Throughout the rest of this document, we'll refer to the subroutine responsible for performing these two actions as the Executor.

Due to the widespread use of application whitelisting technologies such as AppLocker, the Executor function that loads and runs our shellcode needs to be wrapped in a script or file that can be called by a LOLBAS / LOLBIN (for more information about LOLBAS / LOLBINs, see: https://github.com/LOLBAS-Project/LOLBAS).

This means that our initial access payload requires three basic components in order to run:

  • Shellcode Runner - the outer wrapper that can be executed using a LOLBAS / LOLBIN.
  • Executor - loads our shellcode into memory and executes it
  • Payload main - application entrypoint that calls our Executor function

This structure is illustrated in the following diagram:

Most modern initial access payloads either follow this pattern, or are structured in such a way that they can be modified to use it. The next example, which is an MSBuild payload template from MoveKit, does a good job of illustrating this concept.

Adding Payload Encryption

It's typically a good idea to protect your payloads with some sort of encryption. This prevents signature-based detections from flagging the most important parts of your payload, and makes it more difficult for human analysts to reverse engineer your dropper. Recall the basic payload execution process that we discussed in the previous section. If we update this process to include support for encrypted payloads, we have the following four steps:

  1. Derive the payload's encryption key
  2. Load encrypted payload into memory
  3. Decrypt payload using encryption key to obtain plaintext shellcode
  4. Load plaintext shellcode into memory and execute it

We won't go over the specifics of payload decryption / encryption for now (although if you're curious, feel free to check out IV.-Payload-Encryption-Modules). Just be aware that in order to add encryption and key derivation capabilities to our payload, we need to give it the following two additional components:

  • Decryption key function - Obtains, derives, or returns the payload's decryption key
  • Decrypter - Uses the decryption key to decrypt the shellcode into plaintext
Clone this wiki locally