diff --git a/README.md b/README.md index d62ac50..76f7b62 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Usage ------------ To start the monitor head to hale/src/ and execute python main.py. If it fires up with errors then the django settings.py file is not correctly set or some libraries are missing. When the monitor is running type 'help' or '?' to get the available commands. Type help command to get more info about the specific command. Starting up a monitor bot is done by first editing the hale/src/conf/modules.conf file, for example using a irc configuration as follow: -**` + [ircConf] module = irc botnet = irc.freenode.net @@ -77,7 +77,6 @@ To start the monitor head to hale/src/ and execute python main.py. If it fires u currenttopic_grammar = 332 ping_grammar = PING pong_grammar = PONG -`** Edit or create a new config by specifying a new uniquely named section ([ircConf] part). At the top of the config file there is a section called uniqueKeys where all unique fields for a module are specified and used to generate the botnet hash, this should usually not be changed to preserve correct botnet tracking. When this is done run useconf section to load the configuration and then fire up the bot with exec modulename id where id is set by you to identify the botnet. @@ -90,38 +89,38 @@ How to add modules, the current module API work as follow: 1) Implement module, for example: -import moduleManager -from utils import moduleInterface - -@moduleManager.register("irc") -def module_setup(config, hash): - """ - Function to register modules, simply - implement this to pass along the config - and hash to the module object and return - the it back. - """ - - return IRC(config, hash) - -# must inherit from Module class -class IRC(moduleInterface.Module): - - def __init__(self, config, hash): - self.config = config - self.hash = hash - - # must be implemented - def stop(self): - # stop execution - - # must be implemented - def run(self): - # start execution - - # must be implemented - def getConfig(self): - return self.config + import moduleManager + from utils import moduleInterface + + @moduleManager.register("irc") + def module_setup(config, hash): + """ + Function to register modules, simply + implement this to pass along the config + and hash to the module object and return + the it back. + """ + + return IRC(config, hash) + + # must inherit from Module class + class IRC(moduleInterface.Module): + + def __init__(self, config, hash): + self.config = config + self.hash = hash + + # must be implemented + def stop(self): + # stop execution + + # must be implemented + def run(self): + # start execution + + # must be implemented + def getConfig(self): + return self.config Add decorator for the register function (in this case module_setup) which will be called with the current configuration as argument and the config hash made of the unique keys. This function can be named anything. Pass along the configurations to the module object, the configHandler catches KeyErrors so if wrong configurations are sent to this function configHandler will notify you about it. @@ -129,90 +128,90 @@ Also follow the naming convention nameModule.py and @moduleManager.register("nam The rest of the module code is omitted but should create a twisted factory object and start this with the reactor in the run method, see the existing modules for an example. For tutorials on programming with Twisted, please see http://twistedmatrix.com/trac/wiki/Documentation. There are also some utils to make use of when developing modules, this is done as following: -# import all utils -from utils import * - -Socksify: - -# in the constructor create a new proxy object -self.prox = proxySelector.ProxySelector() - -# in the run method add the following after having created the factory method. -proxyInfo = self.prox.getRandomProxy() - if proxyInfo == None: - self.connector = reactor.connectTCP(host, port, factory) - else: - proxyHost = proxyInfo['HOST'] - proxyPort = proxyInfo['PORT'] - proxyUser = proxyInfo['USER'] - proxyPass = proxyInfo['PASS'] - socksify = socks5.ProxyClientCreator(reactor, factory) - if len(proxyUser) == 0: - self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE") - else: - self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE", proxyUser, proxyPass) + # import all utils + from utils import * + + Socksify: + + # in the constructor create a new proxy object + self.prox = proxySelector.ProxySelector() + + # in the run method add the following after having created the factory method. + proxyInfo = self.prox.getRandomProxy() + if proxyInfo == None: + self.connector = reactor.connectTCP(host, port, factory) + else: + proxyHost = proxyInfo['HOST'] + proxyPort = proxyInfo['PORT'] + proxyUser = proxyInfo['USER'] + proxyPass = proxyInfo['PASS'] + socksify = socks5.ProxyClientCreator(reactor, factory) + if len(proxyUser) == 0: + self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE") + else: + self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE", proxyUser, proxyPass) Logging: -# in the factory create the following method to handle logs (note that the hash and config must be sent to the factory) -# and call it in the protocol class with: self.factory.putLog(data) -def putLog(self, log): - """ - Put log to the event handler - """ - - moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.LOG_EVENT, log, self.hash, self.config) - -# apply reg expression to look for URLs containing possible malware -# and call it in the protocol class with: self.factory.checkForURL(data) -def checkForURL(self, data): - """ - Check for URL in the event handler - """ + # in the factory create the following method to handle logs (note that the hash and config must be sent to the factory) + # and call it in the protocol class with: self.factory.putLog(data) + def putLog(self, log): + """ + Put log to the event handler + """ + + moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.LOG_EVENT, log, self.hash, self.config) - moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.URL_EVENT, data, self.hash) + # apply reg expression to look for URLs containing possible malware + # and call it in the protocol class with: self.factory.checkForURL(data) + def checkForURL(self, data): + """ + Check for URL in the event handler + """ + + moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.URL_EVENT, data, self.hash) -# if you module should detect IP numbers of other bots and herders implement the following method in the factory -def addRelIP(self, data): - """ - Put possible ip related to the botnet being monitored - in the event handler. - """ - - moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.RELIP_EVENT, data, self.hash) + # if you module should detect IP numbers of other bots and herders implement the following method in the factory + def addRelIP(self, data): + """ + Put possible ip related to the botnet being monitored + in the event handler. + """ + + moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.RELIP_EVENT, data, self.hash) handling related IPs is done by applying a regular expression to be used for the protocol that the module is going to support, in case of irc module, the code looks like this: -checkHost = data.split(':')[1].split(' ')[0].strip() -match = self.factory.expr.findall(checkHost) -if match: - self.factory.addRelIP(data.split('@')[1].split(' ')[0].strip()) + checkHost = data.split(':')[1].split(' ')[0].strip() + match = self.factory.expr.findall(checkHost) + if match: + self.factory.addRelIP(data.split('@')[1].split(' ')[0].strip()) where the regular expression is as follow: -self.expr = re.compile('!~.*?@') + self.expr = re.compile('!~.*?@') 2) Drag the file to the modules directory. The moduleManager will then automatically import it and check for errors. 3) In modules.conf edit the configuration, in this case: -# specify unique configs for module -# a * means that all configs contaning the strings equal to the one -# after the * will be treated as unique. -# in this example all pass_grammar, mode_grammar etc should be -# treated as unique keys -[uniqueKeys] -irc = botnet, *grammar, ... etc -# name a section, can be anything as long as its unique -# and add module regname (in this case irc) as module option -[myIrcConf] -module = irc -nick = SpyBot -channel = #irc -... -etc. + # specify unique configs for module + # a * means that all configs contaning the strings equal to the one + # after the * will be treated as unique. + # in this example all pass_grammar, mode_grammar etc should be + # treated as unique keys + [uniqueKeys] + irc = botnet, *grammar, ... etc + # name a section, can be anything as long as its unique + # and add module regname (in this case irc) as module option + [myIrcConf] + module = irc + nick = SpyBot + channel = #irc + ... + etc. 4) Upload the module to the web ui by setting the module name to for example irc, filename ircModule.py and then add a config example for this module. @@ -221,11 +220,11 @@ Feeder bot HOWTO: When sending a request for a botnet to track the request is made as follow to the groupchat coordination room -sensorLoadReq + sensorLoadReq where all sensors reply with their id and queue length (number of monitored botnets) -sensorLoadAck id=353f6650859547ed06597dbfa1dcfd88 queue=0 + sensorLoadAck id=353f6650859547ed06597dbfa1dcfd88 queue=0 The feeder then choose one sensor based on this info like lowest queue length and if these are equal for several sensors, then the sensor id sorted alphabetically @@ -233,23 +232,23 @@ with lowest value is chosen. When the feeder has chosen a sensor it sends a private chat message to the sensor -startTrackReq config + startTrackReq config where config is a string representation of the configuration, for example -module=irc botnet=irc.freenode.net etc.. + module=irc botnet=irc.freenode.net etc.. The sensor then replies with with an acknowledgement together with the config hash which can be used to distringuish the botnet logs from the other logs in the share channel Example of acknowledgment: -startTrackAck hash + startTrackAck hash if no one else is monitoring this botnet, otherwise a startTrackNack is received if the botnet is already monitored or the sensor does not have the module installed for this botnet. Malware share is done by sensors sending a message like: -FileCaptured hash=353f6650... file content + FileCaptured hash=353f6650... file content where the content is Base64 encoded and comes directly after the file hash value.