Task execution
Tasks are initially parsed by the command program and then dispatched to workers via the command channel.
The operator can specify any number of workers to set to work on a specific task. The syntax is straightforward:
!execute (<number of workers>) <command> <arguments>
Worker tasks are parsed by the worker bot and can accept any number of arbitrary arguments,
which are extracted by an operator-defined regex. Here's an example of how the "run" command looks (which executes a command on the host machine):
def get_task_patterns(self):
return (
('run (?P<program>.*)', self.run),
# ... any other command patterns ...
)
def run(self, program):
fh = os.popen(program)
return fh.read()
Dead simple! Tasks can return any arbitrary text which is then parsed by the worker's task runner and sent back to the command program. At any time,
the operator can request the data for a given task.
A note on security
The operator must authenticate with the command program to issue commands - the password is hardcoded in the BotnetBot. Likewise, workers will only accept commands from the command program.
Example session
Below is a sample session. First step is to authenticate with the bot:
<cleifer> !auth password
<boss1337> Success
<cleifer> !status
<boss1337> 2 workers available
<boss1337> 0 tasks have been scheduled
Execute a command on one of the workers:
<cleifer> !execute 1 run vmstat
<boss1337> Scheduled task: "run vmstat" with id 1 [1 workers]
<boss1337> Task 1 completed by 1 workers
Print the data returned by the last executed command:
<cleifer> !print
<boss1337> [workerbot:{alpha}] - run vmstat
<boss1337> procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
<boss1337> r b swpd free buff cache si so bi bo in cs us sy id wa
<boss1337> 0 0 0 352900 583696 1298868 0 0 16 31 133 172 4 2 94 0
Find open ports on the workers hosts:
<cleifer> !execute ports
<boss1337> Scheduled task: "ports" with id 2 [2 workers]
<boss1337> Task 2 completed by 2 workers
<cleifer> !print
<boss1337> [workerbot:{alpha}] - ports
<boss1337> [22, 80, 631]
<boss1337> [workerbot_346:{rho}] - ports
<boss1337> [22, 80]
Becoming a bot herder
If you'd like to try this out yourself, feel free to grab a checkout of the source, available on GitHub. The worker is programmed with the following commands:
run executes the given program
download will download the file at the given url and save it to the host machine
info returns information about the host machine's operating system
ports does a quick port-scan of the system ports 20-1025
send_file streams the file on the host computer to the given host:port
status returns the size of the worker's task queue
Adding your own commands is really easy, though -- just add them to the tuple returned by the get_task_patterns method, which looks like this:
def get_task_patterns(self):
return (
('download (?P<url>.*)', self.download),
('info', self.info),
('ports', self.ports),
('run (?P<program>.*)', self.run),
('send_file (?P<filename>[^\s]+) (?P<destination>[^\s]+)', self.send_file),
('status', self.status_report),
# adding another command - this will return the system time and optionally
# take a format parameter
('get_time(?: (?P<format>.+))?', self.get_time),
)
Now define your callback, which will perform whatever task you like and optionally return a string. The returned data will be sent to the command program and made available to the operator.
def get_time(self, format=None):
now = datetime.datetime.now() # remember to import datetime at the top of the module
if format:
return now.strftime(format)
return str(now)
Here's how you might call that command:
<cleifer> !execute get_time
<boss1337> Scheduled task: "get_time" with id 1 [1 workers]
<boss1337> Task 1 completed by 1 workers
<cleifer> !print 1
<boss1337> [workerbot:{alpha}] - get_time
<boss1337> 2011-04-21 10:41:16.251871
<cleifer> !execute get_time %H:%M
<boss1337> Scheduled task: "get_time %H:%M" with id 2 [1 workers]
<boss1337> Task 2 completed by 1 workers
<cleifer> !print
<boss1337> [workerbot:{alpha}] - get_time %H:%M
<boss1337> 10:42
The bots are extensible so you can write your own commands if you want to take up bot-herding -- this tool could be used to restart web nodes, update checkouts, report on status, anything really since it can be used to execute arbitrary commands.
Happy hacking!