How to Code Your Own BotNet. DumBotNet
Today, somebody asked in the forums about this topic, and I wondered how easy/difficult could be to build a very minimal BotNet system, simple enough to be followed by somebody with little experience on the topic, but complete enough to actually demonstrate the concept.
So I tried, and DumBotNet was born. The name is pretty appropriate: A Network of Dumb Bots. The Bot code is 92 LoC (according to sloccount) so it should be easy to assimilate.
Let's start with a definition. A BotNet is a quite simple and standard distributed system composed of an application running in one machine (generically known as Master, call it command & control application if you prefer), that commands many other applications running on remote machines (generically known as Slaves... call them bots if you prefer). Each Slave can be commanded individually or together will all other Slaves in the network.
This is a pretty general distributed computing scenario and the so-called BotNet is just one use case among many others. In other scenarios those Bots are called agents, sensor nodes, ...
The tricky part about BotNets, is not the networking itself. The tricky part is getting they installed on the target machine and keep them invisible to the monitoring tools in that machines (AV, firewall, etc...). We are just going to talk about the networking. The easy part.
So, let's go. I had uploaded the code in github (bot.c). I will be referencing that code during the tutorial.
One last thing. The tutorial just covers the Slave/Bot part. For the Master (or Command and Control application if you prefer) I will just be using NetKitty (yes again :). It's source code is available on-line if you want to see how the Master should look like. Just keep in mind that NetKitty is not a BotNet master. It's a generic tool, so just consider it for reference.
So a very minimal Bot for DumBotNet has to do the following:
- Initialize itself
- Connect to the C&C server at start up so the master knows it is alive
- Go into an infinite loop:
- Wait for a message from the master
- Parse the message and then do whatever that message is suppose to do.
Let's see those steps in more detail
Look for the main function in the code, it is towards the end of the file (line 119).
The DumBotNet initialisation is pretty basic. It just takes the first parameter passed on the command line and stores it in a variable. That will be the Bot's name used to identify the messages from/to this specific Bot.
In real life, the Bot should generate an unique number, for instance using the computer MAC address, a time stamp, some random number, the HD serial number... Whatever is unique to the machine it is going to run.
Next thing to do is to connect to the master and let it know the Bot is alive. This is done by the function bot_connect_cc. Go and look for it in the code (line 98).
Actually, there is nothing special in there. Just fill the sockaddr_in structure with the server data (in this case we have IP and port hardcoded... you know?, this is DumBotNet), create a TCP socket, connect to the server and there you go.
Once connected the Bot will send a message prefixed with its name and a colon, so the server can know who is reporting. To send a message to the server you just have to write to the socket, the same way you do with a normal file.
Back to the main function, just after the connection to the master, you can see the infinite loop (while(1) line 129). Within the loop, the Bot executes forever two functions:
The first one reads a message from the server and stores it in a buffer, and the second one parses the message from the server and executes the associated command. I had separated this two functions because, in a real application, neither reading the data nor parsing it is that simple... In other words, you will have to rework these functions in order to do something useful.
In this minimal example, the bot_read function (line 44) just tries to read 1Kb from the socket. This is the a naive implementation that will fail in many different ways. It will never work in the real world. That's the price to have a very small working example.
For instance, it will fail miserably if you paste a bunch of commands in the master. The master will sent all of them in a single packet and the command sequence will be completely messed up...
For those of you that want to go further, you have to define a command delimiter (for instance the \n) or a message format to properly separete commands within the received data. Doing that, usually implies keeping a buffer and copying pieces of data in and out. Otherwise you can read characters 1 by 1 in a loop, and return a command when you find your delimiter.
The parsing of the commands coming from the Master in the bot_parse function (line 72). For DumBotNet we had chose a pretty simple commanding schema:
The TARGET at the beginning of the command is the name of the Bot that has to execute the command. Alternatively the Master can use ALL as a TARGET to address all connected clients at once.
We need this target parameter because of NetKitty. When executed in server mode (as we have to do in this case), the server can send data to all the connected clients, but it cannot send data to a specific one. So, the Master is always sending the commands to all Bots (even if you are specifying one), and then, each bot has to decide to run or not to run the command.
This is not how a master shall work, but the trade off between sending duplicated commands and adding code for a bit better master was clear. This tutorial is already being quite long.
Back to the code, the bot_parser function parses each command from the server and extracts the target. If the target matches its name or the string ALL, then the bot will proceed to execute the command after the colon, otherwise it just silently ignores the message.
This is done by the function bot_run_cmd (line 53). This code should be familiar to you if you have been following this site this week (good post dtm). It is a standard popen loop that sends back the output of the command to the Master, through our socket.
For each line returned by popen, the Bot adds its name followed by a colon as prefix, so you can know who is the originator of the message. Note that the server already knows who has sent the message because each client uses its own connection. For us, humans, is a lot easier to just read the name of the originator.
So now we can try the DumBotNet. This is what we have to do.
First compile the bot. A simple make bot will do the trick. Copy the executable bot into /tmp. This step is just convenient. Not necessary at all. Alternatively install it in your system... Otherwise use the full path to the binary to run your bots. Whatever better suits you.
Then, in one terminal launch your C&C application. In this case this will just be NetKitty in server mode nk -s T,9999
Now we can launch your bots. Let's open two terminals, and change each one to a different directory. The different directories are just to issue an ls command and verify that the replies coming back from each Bot are different. Now, in one of the terminals run /tmp/bot Bot1 and in the other /tmp/bot Bot2.
Now, the terminal running NetKitty (the C&C Master) should had shown something like this:
Bot1: This is 'Bot1' Up and Running
Bot2: This is 'Bot2' Up and Running
OK. Our BotNet has 2 bots up and running. Now let's try some commands:
(... lists contents on the directory where Bot1 was launched)
(... same for Bot 2)
(... reports some system info for each machine. Will be the same in this case)
There you go.
If you plan to try it between multiple machines in your network (or from differents VMs), do not forgot to update the mater IP address in the source code... or you can start updating the code to get that IP from the command line...
I think this is the simplest BotNet you can build. At least, the simplest I could figure out. The Bot itself is very small and very simple, but I think it is enough to catch the main idea and to give a starting point for those of you who want to go deeper into network programming.