def start(cls, addr, iface=None, config=None): daemons = [] for proto in ("tcp", "tls", "udp"): ports = config.get("%s_ports" % proto) if ports is None: continue for port in ports: daemon = SipSession(proto=proto, config=config) daemon.bind(addr, port, iface=iface) daemon.listen() daemons.append(daemon) if len(daemons) > 0: global g_timer_cleanup if g_timer_cleanup is None: logger.warning("Starting cleanup loop") g_timer_cleanup = Timer( 60, cleanup, repeat=True, ) g_timer_cleanup.start() else: logger.debug("Cleanup loop already started!") return daemons
class hpfeedihandler(ihandler): default_reconnect_timeout = 10.0 default_port = 10000 def __init__(self, path, config=None): logger.debug('hpfeedhandler init') reconnect_timeout = config.get("reconnect_timeout") if reconnect_timeout is None: reconnect_timeout = self.default_reconnect_timeout try: reconnect_timeout = float(reconnect_timeout) except (TypeError, ValueError) as e: logger.warn( "Unable to convert value '%s' for reconnect timeout to float" % reconnect_timeout) reconnect_timeout = self.default_reconnect_timeout port = config.get("port") if port is None: port = self.default_port try: port = int(port) except (TypeError, ValueError) as e: logger.warn("Unable to convert value '%s' for port to int" % port) port = self.default_port self.client = hpclient(config['server'], port, config['ident'], config['secret'], reconnect_timeout=reconnect_timeout) ihandler.__init__(self, path) self.dynip_resolve = config.get('dynip_resolve', '') self.dynip_timer = None self.ownip = None if isinstance(self.dynip_resolve, str) and self.dynip_resolve.startswith("http"): logger.debug('hpfeedihandler will use dynamic IP resolving!') self.dynip_timer = Timer( 300, self._dynip_resolve, delay=2, repeat=True, ) self.dynip_timer.start() def stop(self): if self.dynip_timer: self.dynip_timer.stop() self.dynip_timer = None def _ownip(self, icd): if self.dynip_resolve and 'http' in self.dynip_resolve: if self.ownip: return self.ownip else: raise Exception('Own IP not yet resolved!') return icd.con.local.host def __del__(self): # self.client.close() pass def connection_publish(self, icd, con_type): try: con = icd.con self.client.publish(CONNCHAN, connection_type=con_type, connection_transport=con.transport, connection_protocol=con.protocol, remote_host=con.remote.host, remote_port=con.remote.port, remote_hostname=con.remote.hostname, local_host=self._ownip(icd), local_port=con.local.port) except Exception as e: logger.warn('exception when publishing: {0}'.format(e)) def handle_incident(self, i): pass def handle_incident_dionaea_connection_tcp_listen(self, icd): self.connection_publish(icd, 'listen') con = icd.con logger.info("listen connection on %s:%i" % (con.remote.host, con.remote.port)) def handle_incident_dionaea_connection_tls_listen(self, icd): self.connection_publish(icd, 'listen') con = icd.con logger.info("listen connection on %s:%i" % (con.remote.host, con.remote.port)) def handle_incident_dionaea_connection_tcp_connect(self, icd): self.connection_publish(icd, 'connect') con = icd.con logger.info("connect connection to %s/%s:%i from %s:%i" % (con.remote.host, con.remote.hostname, con.remote.port, self._ownip(icd), con.local.port)) def handle_incident_dionaea_connection_tls_connect(self, icd): self.connection_publish(icd, 'connect') con = icd.con logger.info("connect connection to %s/%s:%i from %s:%i" % (con.remote.host, con.remote.hostname, con.remote.port, self._ownip(icd), con.local.port)) def handle_incident_dionaea_connection_udp_connect(self, icd): self.connection_publish(icd, 'connect') con = icd.con logger.info("connect connection to %s/%s:%i from %s:%i" % (con.remote.host, con.remote.hostname, con.remote.port, self._ownip(icd), con.local.port)) def handle_incident_dionaea_connection_tcp_accept(self, icd): self.connection_publish(icd, 'accept') con = icd.con logger.info("accepted connection from %s:%i to %s:%i" % (con.remote.host, con.remote.port, self._ownip(icd), con.local.port)) def handle_incident_dionaea_connection_tls_accept(self, icd): self.connection_publish(icd, 'accept') con = icd.con logger.info("accepted connection from %s:%i to %s:%i" % (con.remote.host, con.remote.port, self._ownip(icd), con.local.port)) def handle_incident_dionaea_connection_tcp_reject(self, icd): self.connection_publish(icd, 'reject') con = icd.con logger.info("reject connection from %s:%i to %s:%i" % (con.remote.host, con.remote.port, self._ownip(icd), con.local.port)) def handle_incident_dionaea_connection_tcp_pending(self, icd): self.connection_publish(icd, 'pending') con = icd.con logger.info("pending connection from %s:%i to %s:%i" % (con.remote.host, con.remote.port, self._ownip(icd), con.local.port)) def handle_incident_dionaea_download_complete_unique(self, i): self.handle_incident_dionaea_download_complete_again(i) if not hasattr(i, 'con') or not self.client.connected: return logger.debug('unique complete, publishing md5 {0}, path {1}'.format( i.md5hash, i.file)) try: self.client.sendfile(i.file) except Exception as e: logger.warn('exception when publishing: {0}'.format(e)) def handle_incident_dionaea_download_complete_again(self, i): if not hasattr(i, 'con') or not self.client.connected: return logger.debug('hash complete, publishing md5 {0}, path {1}'.format( i.md5hash, i.file)) try: tstamp = timestr() sha512 = sha512file(i.file) self.client.publish(CAPTURECHAN, time=tstamp, saddr=i.con.remote.host, sport=str(i.con.remote.port), daddr=self._ownip(i), dport=str(i.con.local.port), md5=i.md5hash, sha512=sha512, url=i.url) except Exception as e: logger.warn('exception when publishing: {0}'.format(e)) def handle_incident_dionaea_modules_python_smb_dcerpc_request(self, i): if not hasattr(i, 'con') or not self.client.connected: return logger.debug('dcerpc request, publishing uuid {0}, opnum {1}'.format( i.uuid, i.opnum)) try: self.client.publish(DCECHAN, uuid=i.uuid, opnum=i.opnum, saddr=i.con.remote.host, sport=str(i.con.remote.port), daddr=self._ownip(i), dport=str(i.con.local.port)) except Exception as e: logger.warn('exception when publishing: {0}'.format(e)) def handle_incident_dionaea_module_emu_profile(self, icd): if not hasattr(icd, 'con') or not self.client.connected: return logger.debug('emu profile, publishing length {0}'.format( len(icd.profile))) try: self.client.publish(SCPROFCHAN, profile=icd.profile) except Exception as e: logger.warn('exception when publishing: {0}'.format(e)) def _dynip_resolve(self, events, data): i = incident("dionaea.upload.request") i._url = self.dynip_resolve i._callback = "dionaea.modules.python.hpfeeds.dynipresult" i.report() def handle_incident_dionaea_modules_python_hpfeeds_dynipresult(self, icd): fh = open(icd.path, mode="rb") self.ownip = fh.read().strip().decode('latin1') logger.debug('resolved own IP to: {0}'.format(self.ownip)) fh.close()
class virustotalhandler(ihandler): def __init__(self, path, config=None): logger.debug("%s ready!" % (self.__class__.__name__)) ihandler.__init__(self, path) self.apikey = config.get("apikey") comment = config.get("comment") if comment is None: comment = "This sample was captured in the wild and uploaded by the dionaea honeypot.\n#honeypot #malware #networkworm" self.comment = comment self.cookies = {} self.backlog_timer = Timer( interval=20, delay=0, function=self.__handle_backlog_timeout, repeat=True, ) self.backlog_timer.start() p = config.get("file") self.dbh = sqlite3.connect(p) self.cursor = self.dbh.cursor() self.cursor.execute(""" CREATE TABLE IF NOT EXISTS backlogfiles ( backlogfile INTEGER PRIMARY KEY, status TEXT NOT NULL, -- new, submit, query, comment md5_hash TEXT NOT NULL, path TEXT NOT NULL, timestamp INTEGER NOT NULL, scan_id TEXT, lastcheck_time INTEGER, submit_time INTEGER );""") def __handle_backlog_timeout(self, watcher, event): logger.debug("backlog_timeout") # try to comment on files # comment on files which were submitted at least 60 seconds ago sfs = self.cursor.execute( """SELECT backlogfile, md5_hash, path FROM backlogfiles WHERE status = 'comment' AND submit_time < strftime("%s",'now')-1*60 LIMIT 1""" ) for sf in sfs: self.cursor.execute( """UPDATE backlogfiles SET status = 'comment-' WHERE backlogfile = ?""", (sf[0], )) self.dbh.commit() self.make_comment(sf[0], sf[1], sf[2], 'comment') return # try to receive reports for files we submitted sfs = self.cursor.execute( """SELECT backlogfile, md5_hash, path FROM backlogfiles WHERE status = 'query' AND submit_time < strftime("%s",'now')-15*60 AND lastcheck_time < strftime("%s",'now')-15*60 LIMIT 1""" ) for sf in sfs: self.cursor.execute( """UPDATE backlogfiles SET status = 'query-' WHERE backlogfile = ?""", (sf[0], )) self.dbh.commit() self.get_file_report(sf[0], sf[1], sf[2], 'query') return # submit files not known to virustotal sfs = self.cursor.execute( """SELECT backlogfile, md5_hash, path FROM backlogfiles WHERE status = 'submit' LIMIT 1""" ) for sf in sfs: self.cursor.execute( """UPDATE backlogfiles SET status = 'submit-' WHERE backlogfile = ?""", (sf[0], )) self.dbh.commit() self.scan_file(sf[0], sf[1], sf[2], 'submit') return # query new files sfs = self.cursor.execute( """SELECT backlogfile, md5_hash, path FROM backlogfiles WHERE status = 'new' ORDER BY timestamp DESC LIMIT 1""" ) for sf in sfs: self.cursor.execute( """UPDATE backlogfiles SET status = 'new-' WHERE backlogfile = ?""", (sf[0], )) self.dbh.commit() self.get_file_report(sf[0], sf[1], sf[2], 'new') return def stop(self): self.backlog_timer.stop() self.backlog_timer = None def handle_incident(self, icd): pass def handle_incident_dionaea_download_complete_unique(self, icd): self.cursor.execute( """INSERT INTO backlogfiles (md5_hash, path, status, timestamp) VALUES (?,?,?,strftime("%s",'now')) """, (icd.md5hash, icd.file, 'new')) def get_file_report(self, backlogfile, md5_hash, path, status): cookie = str(uuid.uuid4()) self.cookies[cookie] = vtreport(backlogfile, md5_hash, path, status) i = incident("dionaea.upload.request") i._url = "https://www.virustotal.com/vtapi/v2/file/report" i.resource = md5_hash i.apikey = self.apikey i._callback = "dionaea.modules.python.virustotal.get_file_report" i._userdata = cookie i.report() def handle_incident_dionaea_modules_python_virustotal_get_file_report( self, icd): f = open(icd.path, mode='r') j = json.load(f) cookie = icd._userdata vtr = self.cookies[cookie] if j['response_code'] == -2: logger.warn("api throttle") self.cursor.execute( """UPDATE backlogfiles SET status = ? WHERE backlogfile = ?""", (vtr.status, vtr.backlogfile)) self.dbh.commit() elif j['response_code'] == -1: logger.warn("something is wrong with your virustotal api key") elif j['response_code'] == 0: # file unknown # mark for submit if vtr.status == 'new': self.cursor.execute( """UPDATE backlogfiles SET status = 'submit', lastcheck_time = strftime("%s",'now') WHERE backlogfile = ?""", (vtr.backlogfile, )) elif vtr.status == 'query': self.cursor.execute( """UPDATE backlogfiles SET lastcheck_time = strftime("%s",'now') WHERE backlogfile = ?""", (vtr.backlogfile, )) self.dbh.commit() elif j['response_code'] == 1: # file known # self.cursor.execute("""UPDATE backlogfiles SET status = 'comment', lastcheck_time = strftime("%s",'now') WHERE backlogfile = ?""", (vtr.backlogfile,)) self.cursor.execute( """DELETE FROM backlogfiles WHERE backlogfile = ?""", (vtr.backlogfile, )) self.dbh.commit() logger.debug("report {}".format(j)) i = incident("dionaea.modules.python.virustotal.report") i.md5hash = vtr.md5hash i.path = icd.path i.report() else: logger.warn("virustotal reported {}".format(j)) del self.cookies[cookie] def scan_file(self, backlogfile, md5_hash, path, status): cookie = str(uuid.uuid4()) self.cookies[cookie] = vtreport(backlogfile, md5_hash, path, status) i = incident("dionaea.upload.request") i._url = "https://www.virustotal.com/vtapi/v2/file/scan" i.apikey = self.apikey i.set('file://file', path) i._callback = "dionaea.modules.python.virustotal_scan_file" i._userdata = cookie i.report() def handle_incident_dionaea_modules_python_virustotal_scan_file(self, icd): f = open(icd.path, mode='r') j = json.load(f) logger.debug("scan_file {}".format(j)) cookie = icd._userdata vtr = self.cookies[cookie] if j['response_code'] == -2: logger.warn("api throttle") self.cursor.execute( """UPDATE backlogfiles SET status = ? WHERE backlogfile = ?""", (vtr.status, vtr.backlogfile)) self.dbh.commit() elif j['response_code'] == -1: logger.warn("something is wrong with your virustotal api key") elif j['response_code'] == 1: scan_id = j['scan_id'] # recycle this entry for the query self.cursor.execute( """UPDATE backlogfiles SET scan_id = ?, status = 'comment', submit_time = strftime("%s",'now') WHERE backlogfile = ?""", ( scan_id, vtr.backlogfile, )) self.dbh.commit() del self.cookies[cookie] def make_comment(self, backlogfile, md5_hash, path, status): cookie = str(uuid.uuid4()) self.cookies[cookie] = vtreport(backlogfile, md5_hash, path, status) i = incident("dionaea.upload.request") i._url = "https://www.virustotal.com/vtapi/v2/comments/put" i.apikey = self.apikey i.comment = self.comment i.resource = md5_hash i._callback = "dionaea.modules.python.virustotal_make_comment" i._userdata = cookie i.report() def handle_incident_dionaea_modules_python_virustotal_make_comment( self, icd): cookie = icd._userdata vtr = self.cookies[cookie] f = open(icd.path, mode='r') try: j = json.load(f) if j['response_code'] == -2: logger.warn("api throttle") self.cursor.execute( """UPDATE backlogfiles SET status = ? WHERE backlogfile = ?""", (vtr.status, vtr.backlogfile)) self.dbh.commit() elif j['response_code'] == -1: logger.warn("something is wrong with your virustotal api key") elif j['response_code'] == 1: self.cursor.execute( """UPDATE backlogfiles SET status = 'query' WHERE backlogfile = ? """, (vtr.backlogfile, )) self.dbh.commit() except Exception as e: pass del self.cookies[cookie]