Example #1
0
    def __init__(self, work_dir, config, key='server.key', cert='server.crt', **kwargs):
        """
            Main class which runs Beeswarm in Honeypot mode.

        :param work_dir: Working directory (usually the current working directory)
        :param config: Beeswarm configuration dictionary, None if no configuration was supplied.
        :param key: Key file used for SSL enabled capabilities
        :param cert: Cert file used for SSL enabled capabilities
        """
        if config is None or not os.path.isdir(os.path.join(work_dir, 'data')):
            Honeypot.prepare_environment(work_dir)

        self.work_dir = work_dir
        self.config = config
        self.key = os.path.join(work_dir, key)
        self.cert = os.path.join(work_dir, cert)
        self._servers = []
        self._server_greenlets = []

        self.honeypot_id = self.config['general']['id']
        Session.honeypot_id = self.honeypot_id

        # write ZMQ keys to files - as expected by pyzmq
        extract_keys(work_dir, config)
        if not (os.path.isfile(os.path.join(work_dir, 'server.key'))):
            cert_info = config['certificate_info']
            if cert_info['common_name']:
                cert_info['common_name'] = cert_info['common_name']
            else:
                cert_info['common_name'] = get_most_likely_ip()

            cert, priv_key = create_self_signed_cert(cert_info['country'], cert_info['state'],
                                                     cert_info['organization'], cert_info['locality'],
                                                     cert_info['organization_unit'], cert_info['common_name'])

            cert_path = os.path.join(work_dir, 'server.crt')
            key_path = os.path.join(work_dir, 'server.key')
            with open(cert_path, 'w') as certfile:
                certfile.write(cert)
            with open(key_path, 'w') as keyfile:
                keyfile.write(priv_key)
            send_zmq_push(SocketNames.SERVER_RELAY.value,
                          '{0} {1} {2}'.format(Messages.KEY.value, self.honeypot_id, priv_key))
            send_zmq_push(SocketNames.SERVER_RELAY.value,
                          '{0} {1} {2}'.format(Messages.CERT.value, self.honeypot_id, cert))

        if self.config['general']['fetch_ip']:
            try:
                url = 'http://api.externalip.net/ip'
                req = requests.get(url)
                self.honeypot_ip = req.text
                logger.info('Fetched {0} as external ip for Honeypot.'.format(self.honeypot_ip))
            except (Timeout, ConnectionError) as e:
                logger.warning('Could not fetch public ip: {0}'.format(e))
        else:
            self.honeypot_ip = ''

        # spawning time checker
        if self.config['timecheck']['enabled']:
            Greenlet.spawn(self.check_time)
Example #2
0
    def incoming_server_comms(self, server_public, client_public, client_secret):
        context = beeswarm.shared.zmq_context
        # data (commands) received from server
        receiving_socket = context.socket(zmq.SUB)

        # setup receiving tcp socket
        receiving_socket.curve_secretkey = client_secret
        receiving_socket.curve_publickey = client_public
        receiving_socket.curve_serverkey = server_public
        receiving_socket.setsockopt(zmq.RECONNECT_IVL, 2000)
        # messages to this specific drone
        receiving_socket.setsockopt(zmq.SUBSCRIBE, self.id)
        # broadcasts to all drones
        receiving_socket.setsockopt(zmq.SUBSCRIBE, Messages.IP)

        logger.debug(
            'Trying to connect receiving socket to server on {0}'.format(self.config['beeswarm_server']['zmq_command_url']))

        receiving_socket.connect(self.config['beeswarm_server']['zmq_command_url'])
        gevent.spawn(self.monitor_worker, receiving_socket.get_monitor_socket(), 'incomming socket ({0}).'
                     .format(self.config['beeswarm_server']['zmq_url']))

        poller = zmq.Poller()
        poller.register(receiving_socket, zmq.POLLIN)

        while True:
            # .recv() gives no context switch - why not? using poller with timeout instead
            socks = dict(poller.poll(1))
            # hmm, do we need to sleep here (0.1) works, gevnet.sleep() does not work
            gevent.sleep(0.1)

            if receiving_socket in socks and socks[receiving_socket] == zmq.POLLIN:
                message = receiving_socket.recv()
                # expected format for drone commands are:
                # DRONE_ID COMMAND OPTIONAL_DATA
                # DRONE_ID and COMMAND must not contain spaces
                drone_id, command, data = message.split(' ', 2)
                logger.debug('Received {0} command.'.format(command))
                assert (drone_id == self.id)
                # if we receive a configuration we restart the drone
                if command == Messages.CONFIG:
                    send_zmq_push('inproc://serverRelay', '{0}'.format(Messages.PING))
                    self.config_received.set()
                    config = json.loads(data)
                    with open('beeswarmcfg.json', 'w') as local_config:
                        local_config.write(json.dumps(config, indent=4))
                    self.stop()
                    self._start_drone()
                elif command == Messages.DRONE_DELETE:
                    self._handle_delete()
                else:
                    self.internal_server_relay.send('{0} {1}'.format(command, data))
        logger.warn('Command listener exiting.')
Example #3
0
 def monitor_worker(self, monitor_socket, log_name):
     monitor_socket.linger = 0
     poller = zmq.Poller()
     poller.register(monitor_socket, zmq.POLLIN)
     while True:
         socks = poller.poll(0)
         if len(socks) > 0:
             data = recv_monitor_message(monitor_socket)
             event = data['event']
             value = data['value']
             if event == zmq.EVENT_CONNECTED:
                 logger.info('Connected to {0}'.format(log_name))
                 send_zmq_push('ipc://serverRelay', '{0} {1}'.format(Messages.PING, self.id))
             elif event == zmq.EVENT_DISCONNECTED:
                 logger.warning('Disconnected from {0}, will reconnect in {1} seconds.'.format(log_name, 5))
         gevent.sleep()
Example #4
0
 def monitor_worker(self, monitor_socket, log_name):
     monitor_socket.linger = 0
     poller = zmq.Poller()
     poller.register(monitor_socket, zmq.POLLIN)
     while True:
         socks = poller.poll(1)
         gevent.sleep(0.1)
         if len(socks) > 0:
             data = recv_monitor_message(monitor_socket)
             event = data['event']
             value = data['value']
             if event == zmq.EVENT_CONNECTED:
                 logger.info('Connected to {0}'.format(log_name))
                 if 'outgoing' in log_name:
                     send_zmq_push('inproc://serverRelay', '{0}'.format(Messages.PING))
                     own_ip = gevent.socket.gethostbyname(socket.gethostname())
                     send_zmq_push('inproc://serverRelay', '{0} {1}'.format(Messages.IP,
                                                                         own_ip))
                     send_zmq_push('inproc://serverRelay', '{0}'.format(Messages.DRONE_CONFIG))
                 elif 'incomming':
                     pass
                 else:
                     assert False
             elif event == zmq.EVENT_DISCONNECTED:
                 logger.warning('Disconnected from {0}, will reconnect in {1} seconds.'.format(log_name, 5))
         gevent.sleep()
Example #5
0
 def monitor_worker(self, monitor_socket, log_name):
     monitor_socket.linger = 0
     poller = zmq.Poller()
     poller.register(monitor_socket, zmq.POLLIN)
     while True:
         socks = poller.poll(1)
         gevent.sleep(0.1)
         if len(socks) > 0:
             data = recv_monitor_message(monitor_socket)
             event = data['event']
             if event == zmq.EVENT_CONNECTED:
                 logger.info('Connected to {0}'.format(log_name))
                 # always ask for config to avoid race condition.
                 send_zmq_push(SocketNames.SERVER_RELAY.value, '{0}'.format(Messages.DRONE_WANT_CONFIG.value))
                 if 'outgoing' in log_name:
                     send_zmq_push(SocketNames.SERVER_RELAY.value, '{0}'.format(Messages.PING.value))
                     own_ip = get_most_likely_ip()
                     send_zmq_push(SocketNames.SERVER_RELAY.value, '{0} {1}'.format(Messages.IP.value, own_ip))
                 elif 'incomming':
                     pass
                 else:
                     assert False
             elif event == zmq.EVENT_DISCONNECTED:
                 logger.warning('Disconnected from {0}, will reconnect in {1} seconds.'.format(log_name, 5))
         gevent.sleep()
Example #6
0
 def monitor_worker(self, monitor_socket, log_name):
     monitor_socket.linger = 0
     poller = zmq.Poller()
     poller.register(monitor_socket, zmq.POLLIN)
     while True:
         socks = poller.poll(1)
         gevent.sleep(0.1)
         if len(socks) > 0:
             data = recv_monitor_message(monitor_socket)
             event = data['event']
             value = data['value']
             if event == zmq.EVENT_CONNECTED:
                 logger.info('Connected to {0}'.format(log_name))
                 if 'outgoing' in log_name:
                     send_zmq_push('inproc://serverRelay',
                                   '{0}'.format(Messages.PING))
                     own_ip = gevent.socket.gethostbyname(
                         socket.gethostname())
                     send_zmq_push('inproc://serverRelay',
                                   '{0} {1}'.format(Messages.IP, own_ip))
                     send_zmq_push('inproc://serverRelay',
                                   '{0}'.format(Messages.DRONE_CONFIG))
                 elif 'incomming':
                     pass
                 else:
                     assert False
             elif event == zmq.EVENT_DISCONNECTED:
                 logger.warning(
                     'Disconnected from {0}, will reconnect in {1} seconds.'
                     .format(log_name, 5))
         gevent.sleep()
Example #7
0
    def __init__(self,
                 work_dir,
                 config,
                 key='server.key',
                 cert='server.crt',
                 **kwargs):
        """
            Main class which runs Beeswarm in Honeypot mode.

        :param work_dir: Working directory (usually the current working directory)
        :param config: Beeswarm configuration dictionary, None if no configuration was supplied.
        :param key: Key file used for SSL enabled capabilities
        :param cert: Cert file used for SSL enabled capabilities
        """

        if fs.__version__ != '0.5.4':
            os.exit('the python fs package must be verison 0.5.4')

        if config is None or not os.path.isdir(os.path.join(work_dir, 'data')):
            Honeypot.prepare_environment(work_dir)

        self.work_dir = work_dir
        self.config = config
        self.key = os.path.join(work_dir, key)
        self.cert = os.path.join(work_dir, cert)
        self._servers = []
        self._server_greenlets = []

        self.honeypot_id = self.config['general']['id']
        Session.honeypot_id = self.honeypot_id

        # write ZMQ keys to files - as expected by pyzmq
        extract_keys(work_dir, config)
        if not (os.path.isfile(os.path.join(work_dir, 'server.key'))):
            cert_info = config['certificate_info']
            if cert_info['common_name']:
                cert_info['common_name'] = cert_info['common_name']
            else:
                cert_info['common_name'] = get_most_likely_ip()

            cert, priv_key = create_self_signed_cert(
                cert_info['country'], cert_info['state'],
                cert_info['organization'], cert_info['locality'],
                cert_info['organization_unit'], cert_info['common_name'])

            cert_path = os.path.join(work_dir, 'server.crt')
            key_path = os.path.join(work_dir, 'server.key')
            with open(cert_path, 'w') as certfile:
                certfile.write(cert)
            with open(key_path, 'w') as keyfile:
                keyfile.write(priv_key)
            send_zmq_push(
                SocketNames.SERVER_RELAY.value,
                '{0} {1} {2}'.format(Messages.KEY.value, self.honeypot_id,
                                     priv_key))
            send_zmq_push(
                SocketNames.SERVER_RELAY.value,
                '{0} {1} {2}'.format(Messages.CERT.value, self.honeypot_id,
                                     cert))

        if self.config['general']['fetch_ip']:
            try:
                url = 'http://api.externalip.net/ip'
                req = requests.get(url)
                self.honeypot_ip = req.text
                logger.info('Fetched {0} as external ip for Honeypot.'.format(
                    self.honeypot_ip))
            except (Timeout, ConnectionError) as e:
                logger.warning('Could not fetch public ip: {0}'.format(e))
        else:
            self.honeypot_ip = ''

        # spawning time checker
        if self.config['timecheck']['enabled']:
            Greenlet.spawn(self.check_time)
Example #8
0
    def __init__(self, work_dir, config, key='server.key', cert='server.crt',
                 curses_screen=None, **kwargs):
        """
            Main class which runs Beeswarm in Honeypot mode.

        :param work_dir: Working directory (usually the current working directory)
        :param config: Beeswarm configuration dictionary, None if no configuration was supplied.
        :param key: Key file used for SSL enabled capabilities
        :param cert: Cert file used for SSL enabled capabilities
        :param curses_screen: Contains a curses screen object, if UI is enabled. Default is None.
        """
        if config is None or not os.path.isdir(os.path.join(work_dir, 'data')):
            Honeypot.prepare_environment(work_dir)
            with open('beeswarmcfg.json', 'r') as config_file:
                config = json.load(config_file, object_hook=asciify)
        self.work_dir = work_dir
        self.config = config
        self.key = key
        self.cert = cert
        self.curses_screen = curses_screen

        # TODO: pass honeypot otherwise
        Session.honeypot_id = self.config['general']['id']
        self.id = self.config['general']['id']

        # write ZMQ keys to files - as expected by pyzmq
        extract_keys(work_dir, config)
        if not (os.path.isfile(os.path.join(work_dir, 'server.key'))):
            cert_info = config['certificate_info']
            #TODO: IF NOT COMMON_NAME: Use own ip address...
            cert, priv_key = create_self_signed_cert(cert_info['country'], cert_info['state'],
                                                     cert_info['organization'], cert_info['locality'],
                                                     cert_info['organization_unit'], cert_info['common_name'])
            cert_path = os.path.join(work_dir, 'server.crt')
            key_path = os.path.join(work_dir, 'server.key')
            with open(cert_path, 'w') as certfile:
                certfile.write(cert)
            with open(key_path, 'w') as keyfile:
                keyfile.write(priv_key)
            send_zmq_push('ipc://serverRelay', '{0} {1} {2}'.format(Messages.KEY, self.id, keyfile))
            send_zmq_push('ipc://serverRelay', '{0} {1} {2}'.format(Messages.CERT, self.id, cert))

        if self.config['general']['fetch_ip']:
            try:
                url = 'http://api.externalip.net/ip'
                req = requests.get(url)
                self.honeypot_ip = req.text
                logger.info('Fetched {0} as external ip for Honeypot.'.format(self.honeypot_ip))
            except (Timeout, ConnectionError) as e:
                logger.warning('Could not fetch public ip: {0}'.format(e))
        else:
            self.honeypot_ip = ''

        self.status = {
            'mode': 'Honeypot',
            'ip_address': self.honeypot_ip,
            'honeypot_id': self.config['general']['id'],
            'total_sessions': 0,
            'active_sessions': 0,
            'enabled_capabilities': [],
            'managment_url': ''
        }

        # will contain BaitUser objects
        self.users = self.create_users()

        # inject authentication mechanism
        Session.authenticator = Authenticator(self.users)

        # spawning time checker
        if self.config['timecheck']['enabled']:
            Greenlet.spawn(self.checktime)

        # show curses UI
        if self.curses_screen is not None:
            self.uihandler = HoneypotUIHandler(self.status, self.curses_screen)
            Greenlet.spawn(self.show_status_ui)
Example #9
0
    def incoming_server_comms(self, server_public, client_public, client_secret):
        context = beeswarm.shared.zmq_context
        # data (commands) received from server
        server_receiving_socket = context.socket(zmq.SUB)

        # setup receiving tcp socket
        server_receiving_socket.curve_secretkey = client_secret
        server_receiving_socket.curve_publickey = client_public
        server_receiving_socket.curve_serverkey = server_public
        server_receiving_socket.setsockopt(zmq.RECONNECT_IVL, 2000)
        # only subscribe to messages to this specific drone
        server_receiving_socket.setsockopt(zmq.SUBSCRIBE, str(self.id))

        # data from local socket
        local_receiving_socket = context.socket(zmq.PULL)
        if self.local_pull_socket:
            local_receiving_socket.bind('ipc://{0}'.format(self.local_pull_socket))

        logger.debug(
            'Trying to connect receiving socket to server on {0}'.format(
                self.config['beeswarm_server']['zmq_command_url']))

        outgoing_proxy = context.socket(zmq.PUSH)
        outgoing_proxy.connect(SocketNames.SERVER_RELAY.value)

        server_receiving_socket.connect(self.config['beeswarm_server']['zmq_command_url'])
        gevent.spawn(self.monitor_worker, server_receiving_socket.get_monitor_socket(), 'incomming socket ({0}).'
                     .format(self.config['beeswarm_server']['zmq_command_url']))

        poller = zmq.Poller()
        poller.register(server_receiving_socket, zmq.POLLIN)

        while True:
            # .recv() gives no context switch - why not? using poller with timeout instead
            socks = dict(poller.poll(1))
            # hmm, do we need to sleep here (0.1) works, gevnet.sleep() does not work
            gevent.sleep(0.1)

            if server_receiving_socket in socks and socks[server_receiving_socket] == zmq.POLLIN:
                message = server_receiving_socket.recv()
                # expected format for drone commands are:
                # DRONE_ID COMMAND OPTIONAL_DATA
                # DRONE_ID and COMMAND must not contain spaces
                drone_id, command, data = message.split(' ', 2)
                logger.debug('Received {0} command.'.format(command))
                assert (drone_id == str(self.id))
                # if we receive a configuration we restart the drone
                if command == Messages.CONFIG.value:
                    send_zmq_push(SocketNames.SERVER_RELAY.value, '{0}'.format(Messages.PING.value))
                    config = json.loads(data, object_hook=asciify)
                    if self.config != config or not self.config_received.isSet():
                        logger.debug('Setting config.')
                        self.config = config
                        with open(self.config_file, 'w') as local_config:
                            local_config.write(json.dumps(config, indent=4))
                        self.stop()
                        self._start_drone()
                        self.config_received.set()
                elif command == Messages.DRONE_DELETE.value:
                    self._handle_delete()
                else:
                    # Messages we cannot handles goes back to server (and pings).
                    send_zmq_push(SocketNames.SERVER_RELAY.value, '{0} {1}'.format(command, data))
            elif local_receiving_socket in socks and socks[local_receiving_socket] == zmq.POLLIN:
                data = local_receiving_socket.recv()
                outgoing_proxy.send('{0} {1}'.format(self.id, data))

        logger.warn('Command listener exiting.')
Example #10
0
    def incoming_server_comms(self, server_public, client_public,
                              client_secret):
        context = beeswarm.shared.zmq_context
        # data (commands) received from server
        receiving_socket = context.socket(zmq.SUB)

        # setup receiving tcp socket
        receiving_socket.curve_secretkey = client_secret
        receiving_socket.curve_publickey = client_public
        receiving_socket.curve_serverkey = server_public
        receiving_socket.setsockopt(zmq.RECONNECT_IVL, 2000)
        # messages to this specific drone
        receiving_socket.setsockopt(zmq.SUBSCRIBE, self.id)
        # broadcasts to all drones
        receiving_socket.setsockopt(zmq.SUBSCRIBE, Messages.IP)

        logger.debug(
            'Trying to connect receiving socket to server on {0}'.format(
                self.config['beeswarm_server']['zmq_command_url']))

        receiving_socket.connect(
            self.config['beeswarm_server']['zmq_command_url'])
        gevent.spawn(
            self.monitor_worker, receiving_socket.get_monitor_socket(),
            'incomming socket ({0}).'.format(
                self.config['beeswarm_server']['zmq_url']))

        poller = zmq.Poller()
        poller.register(receiving_socket, zmq.POLLIN)

        while True:
            # .recv() gives no context switch - why not? using poller with timeout instead
            socks = dict(poller.poll(1))
            # hmm, do we need to sleep here (0.1) works, gevnet.sleep() does not work
            gevent.sleep(0.1)

            if receiving_socket in socks and socks[
                    receiving_socket] == zmq.POLLIN:
                message = receiving_socket.recv()
                # expected format for drone commands are:
                # DRONE_ID COMMAND OPTIONAL_DATA
                # DRONE_ID and COMMAND must not contain spaces
                drone_id, command, data = message.split(' ', 2)
                logger.debug('Received {0} command.'.format(command))
                assert (drone_id == self.id)
                # if we receive a configuration we restart the drone
                if command == Messages.CONFIG:
                    send_zmq_push('inproc://serverRelay',
                                  '{0}'.format(Messages.PING))
                    self.config_received.set()
                    config = json.loads(data)
                    with open('beeswarmcfg.json', 'w') as local_config:
                        local_config.write(json.dumps(config, indent=4))
                    self.stop()
                    self._start_drone()
                elif command == Messages.DRONE_DELETE:
                    self._handle_delete()
                else:
                    self.internal_server_relay.send('{0} {1}'.format(
                        command, data))
        logger.warn('Command listener exiting.')
Example #11
0
def configure_drone(id):
    db_session = database_setup.get_session()
    drone = db_session.query(Drone).filter(Drone.id == id).one()
    if drone.discriminator == 'honeypot':
        if drone.configuration is not None:
            config_obj = DictWrapper(json.loads(drone.configuration))
        else:
            # virgin drone
            config_obj = None
        form = NewHoneypotConfigForm(obj=config_obj)
        if not form.validate_on_submit():
            return render_template('create-honeypot.html', form=form, mode_name='Honeypot', user=current_user)
        else:
            server_zmq_command_url = 'tcp://{0}:{1}'.format(config['network']['zmq_host'], config['network']['zmq_command_port'])
            server_zmq_url = 'tcp://{0}:{1}'.format(config['network']['zmq_host'], config['network']['zmq_port'])
            # TODO: Check if key pair exists
            result = send_zmq_request('ipc://configCommands', '{0} {1}'.format(Messages.GEN_ZMQ_KEYS, str(drone.id)))
            zmq_public = result['public_key']
            zmq_private = result['private_key']

            drone_config = {
            'general': {
                'name': form.general__name.data,
                'mode': 'honeypot',
                'id': drone.id,
                'ip': '192.168.1.1',
                'fetch_ip': False
            },
            'beeswarm_server': {
                'enabled': True,
                'zmq_url' : server_zmq_url,
                'zmq_server_public': config['network']['zmq_server_public_key'],
                'zmq_own_public': zmq_public,
                'zmq_own_private': zmq_private,
                'zmq_command_url': server_zmq_command_url,
            },
            'log_syslog': {
                'enabled': False,
                'socket': '/dev/log'
            },
            'certificate_info': {
                'common_name': form.certificate_info__common_name.data,
                'country': form.certificate_info__country.data,
                'state': form.certificate_info__state.data,
                'locality': form.certificate_info__locality.data,
                'organization': form.certificate_info__organization.data,
                'organization_unit': form.certificate_info__organization_unit.data
            },
            'capabilities': {
                'ftp': {
                    'enabled': form.capabilities__ftp__enabled.data,
                    'port': form.capabilities__ftp__port.data,
                    'max_attempts': form.capabilities__ftp__max_attempts.data,
                    'banner': form.capabilities__ftp__banner.data,
                    'syst_type': form.capabilities__ftp__syst_type.data
                },
                'telnet': {
                    'enabled': form.capabilities__telnet__enabled.data,
                    'port': form.capabilities__telnet__port.data,
                    'max_attempts': form.capabilities__telnet__max_attempts.data
                },
                'pop3': {
                    'enabled': form.capabilities__pop3__enabled.data,
                    'port': form.capabilities__pop3__port.data,
                    'max_attempts': form.capabilities__pop3__max_attempts.data,
                },
                'pop3s': {
                    'enabled': form.capabilities__pop3s__enabled.data,
                    'port': form.capabilities__pop3s__port.data,
                    'max_attempts': form.capabilities__pop3s__max_attempts.data,
                },
                'ssh': {
                    'enabled': form.capabilities__ssh__enabled.data,
                    'port': form.capabilities__ssh__port.data,
                },
                'http': {
                    'enabled': form.capabilities__http__enabled.data,
                    'port': form.capabilities__http__port.data,
                    'banner': form.capabilities__http__banner.data
                },
                'https': {
                    'enabled': form.capabilities__https__enabled.data,
                    'port': form.capabilities__https__port.data,
                    'banner': form.capabilities__https__banner.data
                },
                'smtp': {
                    'enabled': form.capabilities__smtp__enabled.data,
                    'port': form.capabilities__smtp__port.data,
                    'banner': form.capabilities__smtp__banner.data
                },
                'vnc': {
                    'enabled': form.capabilities__vnc__enabled.data,
                    'port': form.capabilities__vnc__port.data
                }
            },
            'users': {},
            'timecheck': {
                'enabled': True,
                'poll': 5,
                'ntp_pool': 'pool.ntp.org'
            },
        }
            config_json = json.dumps(drone_config, indent=4)
            drone.name = form.general__name.data
            drone.configuration = config_json
            db_session.add(drone)
            db_session.commit()

            # everything good, push config to drone if it is listening
            send_zmq_push('ipc://droneCommandReceiver', '{0} {1} {2}'.format(drone.id, Messages.CONFIG, config_json))
            return render_template('finish-config.html', drone_id=drone.id, user=current_user)
    elif drone.discriminator == 'client':
        form = NewClientConfigForm()
        if not form.validate_on_submit():
            return render_template('create-client.html', form=form, mode_name='Honeypot', user=current_user)
        else:
            server_zmq_url = 'tcp://{0}:{1}'.format(config['network']['zmq_host'], config['network']['zmq_port'])
            server_zmq_command_url = 'tcp://{0}:{1}'.format(config['network']['zmq_host'], config['network']['zmq_command_port'])
            # TODO: Check if key pair exists
            result = send_zmq_request('ipc://configCommands', '{0} {1}'.format(Messages.GEN_ZMQ_KEYS, str(drone.id)))
            zmq_public = result['public_key']
            zmq_private = result['private_key']

            drone_config = {
                'general': {
                    'mode': 'client',
                    'id': drone.id,
                    'honeypot_id': None
                },
                'public_ip': {
                    'fetch_ip': True
                },
                'bait_sessions': {
                    'http': {
                        'enabled': form.http_enabled.data,
                        'server': form.http_server.data,
                        'port': form.http_port.data,
                        'timing': {
                            'active_range': form.http_active_range.data,
                            'sleep_interval': form.http_sleep_interval.data,
                            'activation_probability': form.http_activation_probability.data
                        },
                        'username': form.http_login.data,
                        'password': form.http_password.data
                    },
                    'ftp': {
                        'enabled': form.ftp_enabled.data,
                        'server': form.ftp_server.data,
                        'port': form.ftp_port.data,
                        'timing': {
                            'active_range': form.ftp_active_range.data,
                            'sleep_interval': form.ftp_sleep_interval.data,
                            'activation_probability': form.ftp_activation_probability.data
                        },
                        'username': form.ftp_login.data,
                        'password': form.ftp_password.data
                    },
                    'https': {
                        'enabled': form.https_enabled.data,
                        'server': form.https_server.data,
                        'port': form.https_port.data,
                        'timing': {
                            'active_range': form.https_active_range.data,
                            'sleep_interval': form.https_sleep_interval.data,
                            'activation_probability': form.https_activation_probability.data
                        },
                        'username': form.https_login.data,
                        'password': form.https_password.data
                    },
                    'pop3': {
                        'enabled': form.pop3_enabled.data,
                        'server': form.pop3_server.data,
                        'port': form.pop3_port.data,
                        'timing': {
                            'active_range': form.pop3_active_range.data,
                            'sleep_interval': form.pop3_sleep_interval.data,
                            'activation_probability': form.pop3_activation_probability.data
                        },
                        'username': form.pop3_login.data,
                        'password': form.pop3_password.data
                    },
                    'ssh': {
                        'enabled': form.ssh_enabled.data,
                        'server': form.ssh_server.data,
                        'port': form.ssh_port.data,
                        'timing': {
                            'active_range': form.ssh_active_range.data,
                            'sleep_interval': form.ssh_sleep_interval.data,
                            'activation_probability': form.ssh_activation_probability.data
                        },
                        'username': form.ssh_login.data,
                        'password': form.ssh_password.data
                    },
                    'pop3s': {
                        'enabled': form.pop3s_enabled.data,
                        'server': form.pop3s_server.data,
                        'port': form.pop3s_port.data,
                        'timing': {
                            'active_range': form.pop3s_active_range.data,
                            'sleep_interval': form.pop3s_sleep_interval.data,
                            'activation_probability': form.pop3s_activation_probability.data
                        },
                        'username': form.pop3s_login.data,
                        'password': form.pop3s_password.data
                    },
                    'smtp': {
                        'enabled': form.smtp_enabled.data,
                        'server': form.smtp_server.data,
                        'port': form.smtp_port.data,
                        'timing': {
                            'active_range': form.smtp_active_range.data,
                            'sleep_interval': form.smtp_sleep_interval.data,
                            'activation_probability': form.smtp_activation_probability.data
                        },
                        'username': form.smtp_login.data,
                        'local_hostname': form.smtp_local_hostname.data,
                        'password': form.smtp_password.data
                    },
                    'vnc': {
                        'enabled': form.vnc_enabled.data,
                        'server': form.vnc_server.data,
                        'port': form.vnc_port.data,
                        'timing': {
                            'active_range': form.vnc_active_range.data,
                            'sleep_interval': form.vnc_sleep_interval.data,
                            'activation_probability': form.vnc_activation_probability.data
                        },
                        'username': form.vnc_login.data,
                        'password': form.vnc_password.data
                    },
                    'telnet': {
                        'enabled': form.telnet_enabled.data,
                        'server': form.telnet_server.data,
                        'port': form.telnet_port.data,
                        'timing': {
                            'active_range': form.telnet_active_range.data,
                            'sleep_interval': form.telnet_sleep_interval.data,
                            'activation_probability': form.telnet_activation_probability.data
                        },
                        'username': form.telnet_login.data,
                        'password': form.telnet_password.data
                    }
                },
                'beeswarm_server': {
                    'enabled': True,
                    'zmq_url' : server_zmq_url,
                    'zmq_server_public': config['network']['zmq_server_public_key'],
                    'zmq_own_public': zmq_public,
                    'zmq_own_private': zmq_private,
                    'zmq_command_url': server_zmq_command_url,
                },
            }

            config_json = json.dumps(drone_config, indent=4)

            drone.configuration = config_json
            db_session.add(drone)
            db_session.commit()

            # everything good, push config to drone if it is listening
            send_zmq_push('ipc://droneCommandReceiver', '{0} {1} {2}'.format(drone.id, Messages.CONFIG, config_json))
            return render_template('finish-config.html', drone_id=drone.id, user=current_user)
    elif drone.discriminator is None:
        return render_template('drone_mode.html', drone_id=drone.id, user=current_user)
    else:
        assert(drone is None)
        abort(404, 'Drone with that id could not be found.')
Example #12
0
    def __init__(self,
                 work_dir,
                 config,
                 key='server.key',
                 cert='server.crt',
                 **kwargs):
        """
            Main class which runs Beeswarm in Honeypot mode.

        :param work_dir: Working directory (usually the current working directory)
        :param config: Beeswarm configuration dictionary, None if no configuration was supplied.
        :param key: Key file used for SSL enabled capabilities
        :param cert: Cert file used for SSL enabled capabilities
        """
        if config is None or not os.path.isdir(os.path.join(work_dir, 'data')):
            Honeypot.prepare_environment(work_dir)
            with open('beeswarmcfg.json', 'r') as config_file:
                config = json.load(config_file, object_hook=asciify)
        self.work_dir = work_dir
        self.config = config
        self.key = key
        self.cert = cert
        self._servers = []
        self._server_greenlets = []
        # will contain Session objects
        self._sessions = {}
        self._session_consumer = None

        # TODO: pass honeypot otherwise
        Session.honeypot_id = self.config['general']['id']
        self.id = self.config['general']['id']

        # write ZMQ keys to files - as expected by pyzmq
        extract_keys(work_dir, config)
        if not (os.path.isfile(os.path.join(work_dir, 'server.key'))):
            cert_info = config['certificate_info']
            if cert_info['common_name']:
                cert_info['common_name'] = cert_info['common_name']
            else:
                cert_info['common_name'] = get_most_likely_ip()

            cert, priv_key = create_self_signed_cert(
                cert_info['country'], cert_info['state'],
                cert_info['organization'], cert_info['locality'],
                cert_info['organization_unit'], cert_info['common_name'])

            cert_path = os.path.join(work_dir, 'server.crt')
            key_path = os.path.join(work_dir, 'server.key')
            with open(cert_path, 'w') as certfile:
                certfile.write(cert)
            with open(key_path, 'w') as keyfile:
                keyfile.write(priv_key)
            send_zmq_push('inproc://serverRelay',
                          '{0} {1} {2}'.format(Messages.KEY, self.id, keyfile))
            send_zmq_push('inproc://serverRelay',
                          '{0} {1} {2}'.format(Messages.CERT, self.id, cert))

        if self.config['general']['fetch_ip']:
            try:
                url = 'http://api.externalip.net/ip'
                req = requests.get(url)
                self.honeypot_ip = req.text
                logger.info('Fetched {0} as external ip for Honeypot.'.format(
                    self.honeypot_ip))
            except (Timeout, ConnectionError) as e:
                logger.warning('Could not fetch public ip: {0}'.format(e))
        else:
            self.honeypot_ip = ''

        # spawning time checker
        if self.config['timecheck']['enabled']:
            Greenlet.spawn(self.checktime)