Home About Me Projects ⇢ python-botnet

My (Ghetto) Python Botnet Experiment

Foreword
This is a project of mine that spawned from a much more innocent endeavor. For the last couple of weeks, I have been learning about and exploring the world of distributive computing. I set out to create a simple network of EC2 instances that would split up large data sets and work in parallel to accomplish expensive parsing tasks. I wanted to see at what point a task would be completed more efficiently via distributive computing versus running on a single machine without the delays of network communication. However, after designing a network to accommodate such an experiment, I realized that I had already created the basic architecture of a botnet; I had a master machine (my computer) that would be delegating tasks to a network of slave nodes (several EC2 instances). Needless to say, this epiphany quickly changed my objective.

Concept and Terminology Review
Unfortunately, I cannot claim to be an authority on networking by any means. With this said, the concept of a botnet is very simple in its most fundamental form; A botnet is a collection of machines that are remotely controlled by a master machine. The master machine delegates commands to these slave nodes in order to accomplish a wide variety of (usually malicious) tasks such as distributed denial-of-service attacks and email spam campaigns, as well as spreading malware to infect and create more slave nodes for the botnet itself. While I realize that there can be contextual distinctions between the terms client, slave, and bot, I will be using them interchangeably in this post to denote a machine that is being controlled by the master machine. Sue me.

Network Architecture
The actual network setup for this project was pretty straight forward. Using Amazon Web Services, I configured and launched a t2.micro EC2 instance running Ubuntu. While I was originally using my own computer as the master node with EC2 instances as the bots, I opted instead to use the EC2 instance as the (remote) master node for the sake of its comparatively static IP address.
For this simple implementation, I used TCP as the network protocol for communication between the master and client nodes. (In retrospect, I probably should have opted for a higher level protocol such as HTTP for the sake of not having to reinvent the wheel in terms of parsing/prepping incoming and outgoing data.)

Client/Server Software
My next task was to write the client and server scripts to be hosted in these respective locations. Given that the relationship between master and clients is a one-to-many relationship, I knew that the client would have to be the one to initiate the connection to the central master server. After spending a good bit of time with the asyncore documentation, I found a superb example of a TCP asyncore chatroom example HERE

No really, sue me
After combing line-by-line through this code to understand how the Client, RemoteClient, and Host classes functioned together, I extracted the code for the Client class and put it in a new file dubbed client.py. However, the design of this code was geared towards a chatroom model, where the clients could broadcast messages that the host simply relayed to the other clients. To fit my planned architecture, I needed to change this methodology to instead allow for the direct broadcasting of messages from the server itself to the clients, as opposed to using the server as a means for clients to communicate with one another. I extracted the RemoteClient and Host classes and placed them in a separate file named server.py.

server.py
In order to change the architecture to only allow delegation from the server to clients, I needed to create a means of direct command-and-control from the master server to the bot nodes. For this purpose, I created a method to run a command & control loop that responded to several user commands. While I had a number of ambitions in regards to the tasks that I wanted the botnet to be able to accomplish, I decided to focus my energy towards creating a system where simple shell commands could be delegated from the master and executed on the slave nodes. My command & control method in server.py was written as follows:

command & control method for server.py
While the safety of this code leaves something to be desired (namely the input validation) my focus at this point was getting this system up and running as soon as possible. I also should note that in order to have a C&C loop running simultaneously with the server's asynchronous loop that listens for incoming connections, I did have to start each of these processes as separate threads in the initiation code for server.py.

client.py
In order for the client to be able to receive and execute commands from the master server, I needed to implement a way for the client to interpret the incoming commands and execute them in the local shell. I accomplished this through the use of the 'call' method of the 'subprocess' library.

Best one-liner since the 2016 election. What the hell is shell injection anyways?
With this simple method implemented as a member function of client.py's Client class, I had everything in place to take control of my own laptop from the remote computer that I pay Amazon to let me use (Mitnick level stuff, I know).

The Moment of Truth
At this point, all I had left to do was put my code to the test. I had server.py hosted on an EC2 instance and client.py ready to go on two separate Mac OS X machines. I SSH'd into my EC2 instance and ran server.py. I then ran client.py from both local machines and watched the server notify me of two new client connections. Now for the real test; prompting the command & control interface with a shell command to be executed by the slave nodes. I chose to enter the prompt 'cmdall ping www.google.com'. To my delight, I watched the Terminal windows on both OS X machines start to fill up with responses from pinging google's servers.

Proof of demonstration (and a 25 minute nightmare using Preview's annotate feature)
Conclusion
For me, this project was both rewarding and humbling. Creating a primitive botnet with my machines and controlling them from a remote server was a very enjoyable experience. However, the biggest takeaway for me was a new found appreciation for just how advanced, powerful, and daunting large botnets are in today's world. Looking forward, my next task will likely be an exploration into learning how malware (such as botnet clientware) is able to spread, install, and run discreetly. Needless to say, I will be spending much more time learning about the dark side of distributed computing. I may even have to face the music and start writing C++ again (sigh).

Sources