コード例 #1
0
ファイル: __init__.py プロジェクト: jps3/dionaea
    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
コード例 #2
0
ファイル: virustotal.py プロジェクト: jps3/dionaea
    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
            );""")
コード例 #3
0
    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()
コード例 #4
0
ファイル: __init__.py プロジェクト: jps3/dionaea
    def handle_INVITE(self, msg):
        logger.debug("{!s} handle_INVITE".format(self))

        self.__state = SipCall.INVITE
        self._timers["invite_handler"] = Timer(
            0.1,
            self.__handle_invite,
        )
        # ToDo: the data isn't used in the callback at the moment
        # self._timers["invite_handler"].data = msg
        self._timers["invite_handler"].start()
        return True
コード例 #5
0
ファイル: __init__.py プロジェクト: jps3/dionaea
    def __init__(self, proto, call_id, session, invite_message):
        logger.debug("{!s} __init__".format(self))

        logger.debug("SipCall {} session {} ".format(self, session))
        connection.__init__(self, proto)
        # Store incoming information of the remote host

        self.__session = session
        self.__state = SipCall.SESSION_SETUP
        self.__msg = invite_message
        # list of messages
        self._msg_stack = []

        self.__call_id = invite_message.headers.get(b"call-id").value
        self._call_id = call_id
        self._rtp_streams = {}

        self.local.host = self.__session.local.host
        self.local.port = self.__session.local.port

        self.remote.host = self.__session.remote.host
        self.remote.port = self.__session.remote.port

        user = self.__msg.headers.get(b"to").get_raw().uri.user

        self._user = self.__session.config.get_user_by_username(
            self.__session.personality, user)

        # fake a connection entry
        i = incident("dionaea.connection.udp.connect")
        i.con = self
        i.report()

        # Global timers
        self._timers = {
            "idle": Timer(60.0, self.__handle_timeout_idle, repeat=True),
            "invite_handler": None,
        }

        self._timers["idle"].start()
コード例 #6
0
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()
コード例 #7
0
ファイル: __init__.py プロジェクト: jps3/dionaea
    def __handle_invite(self):
        logger.debug("{!s} __handle_invite".format(self))

        logger.info("Handle invite")
        if self.__state == SipCall.INVITE:
            logger.debug("Send TRYING")
            # ToDo: Check authentication
            #self.__authenticate(headers)

            if self._user is None:
                msg = self.__msg.create_response(rfc3261.NOT_FOUND)
                self.send(msg.dumps())
                self.close()
                return

            msg = self.__msg.create_response(rfc3261.TRYING)

            self.send(msg)

            self.__state = SipCall.INVITE_TRYING
            # Wait up to two seconds
            self._timers["invite_handler"] = Timer(
                random.random() * 2,
                self.__handle_invite,
            )
            self._timers["invite_handler"].start()
            return

        if self.__state == SipCall.INVITE_TRYING:
            # Send 180 Ringing to make honeypot appear more human-like
            logger.debug("Send RINGING")
            msg = self.__msg.create_response(rfc3261.RINGING)

            self.send(msg)

            delay = random.randint(self._user.pickup_delay_min,
                                   self._user.pickup_delay_max)
            logger.info(
                "Choosing ring delay between {} and {} seconds: {}".format(
                    self._user.pickup_delay_min, self._user.pickup_delay_max,
                    delay))
            self.__state = SipCall.INVITE_RINGING
            self._timers["invite_handler"] = Timer(
                delay,
                self.__handle_invite,
            )
            self._timers["invite_handler"].start()
            return

        if self.__state == SipCall.INVITE_RINGING:
            logger.debug("Send OK")

            # Create a stream dump file with date and time and random ID in case of
            # flooding attacks
            pcap = self.__session.config.get_pcap()

            # Create RTP stream instance and pass address and port of listening
            # remote RTP host

            sdp = self.__msg.sdp

            media_port_names = self.__session.config.get_sdp_media_port_names(
                self._user.sdp)

            media_ports = {}

            for name in media_port_names:
                media_ports[name] = None

            bistream_enabled = False
            if "bistream" in self.__session.config._rtp.get("modes", {}):
                bistream_enabled = True

            for name in media_port_names:
                for media in sdp.get(b"m"):
                    if media.media.lower() == bytes(name[:5], "utf-8"):
                        self._rtp_streams[name] = RtpUdpStream(
                            name,
                            self,
                            self.__session,
                            self.__session.local.host,
                            0,  # random port
                            self.__session.remote.host,
                            media.port,
                            pcap=pcap,
                            bistream_enabled=bistream_enabled)
                        media_ports[name] = self._rtp_streams[name].local.port
                        i = incident("dionaea.connection.link")
                        i.parent = self
                        i.child = self._rtp_streams[name]
                        i.report()

            # Send 200 OK and pick up the phone
            msg = self.__msg.create_response(rfc3261.OK)

            # ToDo: add IP6 support
            msg.sdp = rfc4566.SDP.froms(
                self.__session.config.get_sdp_by_name(
                    self._user.sdp,
                    unicast_address=self.local.host,
                    addrtype="IP4",
                    media_ports=media_ports))

            msg_stack = self._msg_stack
            msg_stack.append(("out", msg))

            pcap.open(msg_stack=msg_stack,
                      personality=self.__session.personality,
                      local_host=self.local.host,
                      local_port=self.local.port,
                      remote_host=self.remote.host,
                      remote_port=self.remote.port)

            self.send(msg)

            self.__state = SipCall.CALL

            # ToDo: Send rtp data?
            return
コード例 #8
0
ファイル: virustotal.py プロジェクト: jps3/dionaea
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]