Ejemplo n.º 1
0
    def delegate_command(self, message_text):
        response = ""
        message_tokens = message_text.split()
        command = message_tokens[0]
        parameters = message_tokens[1:len(message_tokens)]

        if command == '!help':
            response = "\nHelp is on it's way...try these:\n"
            for command_name, plugin in self.plugins.iteritems():
                response += "\n{0} -- {1}".format(
                    command_name,
                    plugin['help_text']
                )
        else:
            if command not in self.plugins:
                response = "Unknown command: " + command + ". Try !help"
            else:
                plugin = self.plugins[command]
                logger.info("Sending to {0}".format(plugin['plugin_class'].__module__))
                try:
                    response = "\n" + plugin['plugin_class'].handle_command(parameters)
                except Exception as e:
                    response = "\nReceived an error when processing your request."
                    logger.exception(e)

        return response
Ejemplo n.º 2
0
def clearESCache():
    es = esConnect(None)
    indexes = es.get_open_indices()
    # assums index names  like events-YYYYMMDD etc.
    # used to avoid operating on current indexes
    dtNow = datetime.utcnow()
    indexSuffix = date.strftime(dtNow, '%Y%m%d')
    previousSuffix = date.strftime(dtNow - timedelta(days=1), '%Y%m%d')
    for targetindex in sorted(indexes):
        if indexSuffix not in targetindex and previousSuffix not in targetindex:
            url = '{0}/{1}/_stats'.format(random.choice(options.esservers), targetindex)
            r = requests.get(url)
            if r.status_code == 200:
                indexstats = json.loads(r.text)
                if indexstats['_all']['total']['search']['query_current'] == 0:
                    fielddata = indexstats['_all']['total']['fielddata']['memory_size_in_bytes']
                    if fielddata > 0:
                        logger.info('target: {0}: field data {1}'.format(targetindex, indexstats['_all']['total']['fielddata']['memory_size_in_bytes']))
                        clearurl = '{0}/{1}/_cache/clear'.format(random.choice(options.esservers), targetindex)
                        clearRequest = requests.post(clearurl)
                        logger.info(clearRequest.text)
                        # stop at one?
                        if options.conservative:
                            return
                else:
                    logger.debug('{0}: <ignoring due to current search > field data {1}'.format(targetindex, indexstats['_all']['total']['fielddata']['memory_size_in_bytes']))
            else:
                logger.error('{0} returned {1}'.format(url, r.status_code))
Ejemplo n.º 3
0
    def run(self):
        self.taskQueue.set_message_class(RawMessage)

        while True:
            try:
                records = self.taskQueue.get_messages(self.options.prefetch)
                for msg in records:
                    msg_body = msg.get_body()
                    try:
                        # get_body() should be json
                        message_json = json.loads(msg_body)
                        self.on_message(message_json)
                        # delete message from queue
                        self.taskQueue.delete_message(msg)
                    except ValueError:
                        logger.error('Invalid message, not JSON <dropping message and continuing>: %r' % msg_body)
                        self.taskQueue.delete_message(msg)
                        continue
                time.sleep(.1)
            except (SSLEOFError, SSLError, socket.error):
                logger.info('Received network related error...reconnecting')
                time.sleep(5)
                self.connection, self.taskQueue = connect_sqs(
                    options.region,
                    options.accesskey,
                    options.secretkey,
                    options.taskexchange
                )
                self.taskQueue.set_message_class(RawMessage)
Ejemplo n.º 4
0
def main():
    # connect and declare the message queue/kombu objects.
    # only py-amqp supports ssl and doesn't recognize amqps
    # so fix up the connection string accordingly
    connString = 'amqp://{0}:{1}@{2}:{3}/{4}'.format(options.mquser, options.mqpassword, options.mqserver, options.mqport, options.mqvhost)
    if options.mqprotocol == 'amqps':
        mqSSL = True
    else:
        mqSSL = False
    mqConn = Connection(connString, ssl=mqSSL)
    # Task Exchange for events sent via http for us to normalize and post to elastic search
    if options.mqack:
        # conservative, store msgs to disk, ack each message
        eventTaskExchange = Exchange(name=options.taskexchange, type='direct', durable=True, delivery_mode=2)
    else:
        # fast, transient delivery, store in memory only, auto-ack messages
        eventTaskExchange = Exchange(name=options.taskexchange, type='direct', durable=True, delivery_mode=1)
    eventTaskExchange(mqConn).declare()
    # Queue for the exchange
    if options.mqack:
        eventTaskQueue = Queue(options.taskexchange, exchange=eventTaskExchange, routing_key=options.taskexchange, durable=True, no_ack=False)
    else:
        eventTaskQueue = Queue(options.taskexchange, exchange=eventTaskExchange, routing_key=options.taskexchange, durable=True, no_ack=True)
    eventTaskQueue(mqConn).declare()

    # topic exchange for anyone who wants to queue and listen for mozdef.event
    eventTopicExchange = Exchange(name=options.eventexchange, type='topic', durable=False, delivery_mode=1)
    eventTopicExchange(mqConn).declare()

    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info('started without uwsgi')
    # consume our queue and publish on the topic exchange
    taskConsumer(mqConn, eventTaskQueue, eventTopicExchange, es).run()
Ejemplo n.º 5
0
def registerPlugins():
    pluginList = list()  # tuple of module,registration dict,priority
    if os.path.exists('plugins'):
        modules = pynsive.list_modules('plugins')
        for mname in modules:
            module = pynsive.import_module(mname)
            importlib.reload(module)
            if not module:
                raise ImportError('Unable to load module {}'.format(mname))
            else:
                if 'message' in dir(module):
                    mclass = module.message()
                    mreg = mclass.registration
                    if type(mreg) != list:
                        raise ImportError(
                            'Plugin {0} registration needs to be a list'.
                            format(mname))
                    if 'priority' in dir(mclass):
                        mpriority = mclass.priority
                    else:
                        mpriority = 100
                    if isinstance(mreg, list):
                        logger.info(
                            '[*] plugin {0} registered to receive messages with {1}'
                            .format(mname, mreg))
                        pluginList.append((mclass, mreg, mpriority))
    return pluginList
Ejemplo n.º 6
0
def main():
    if options.checkjvmmemory:
        if isJVMMemoryHigh():
            logger.info('initiating cache clearing')
            clearESCache()
    else:
        clearESCache()
Ejemplo n.º 7
0
 def run(self):
     while True:
         try:
             records = self.sqs_queue.receive_messages(
                 MaxNumberOfMessages=options.prefetch)
             for msg in records:
                 msg_body = msg.body
                 try:
                     # get_body() should be json
                     message_json = json.loads(msg_body)
                     self.on_message(message_json)
                     # delete message from queue
                     msg.delete()
                 except ValueError:
                     logger.error(
                         'Invalid message, not JSON <dropping message and continuing>: %r'
                         % msg_body)
                     msg.delete()
                     continue
             time.sleep(options.sleep_time)
         except (SSLEOFError, SSLError, socket.error):
             logger.info('Received network related error...reconnecting')
             time.sleep(5)
             self.sqs_queue = connect_sqs(options.region, options.accesskey,
                                          options.secretkey,
                                          options.taskexchange)
Ejemplo n.º 8
0
    def delegate_command(self, message_text):
        response = ""
        message_tokens = message_text.split()
        command = message_tokens[0]
        parameters = message_tokens[1:len(message_tokens)]

        if command == '!help':
            response = "\nHelp is on it's way...try these:\n"
            for command_name, plugin in self.plugins.iteritems():
                response += "\n{0} -- {1}".format(command_name,
                                                  plugin['help_text'])
        else:
            if command not in self.plugins:
                response = "Unknown command: " + command + ". Try !help"
            else:
                plugin = self.plugins[command]
                logger.info("Sending to {0}".format(
                    plugin['plugin_class'].__module__))
                try:
                    response = "\n" + plugin['plugin_class'].handle_command(
                        parameters)
                except Exception as e:
                    response = "\nReceived an error when processing your request."
                    logger.exception(e)

        return response
    def identify_plugins(self, enabled_plugins):
        if not os.path.exists(self.plugin_location):
            return []

        module_name = os.path.basename(self.plugin_location)
        root_plugin_directory = self.plugin_location

        plugin_manager = pynsive.PluginManager()
        plugin_manager.plug_into(root_plugin_directory)

        plugins = []

        found_modules = pynsive.list_modules(module_name)
        for found_module in found_modules:
            module_filename, module_name = found_module.split('.')
            if enabled_plugins is not None and module_name not in enabled_plugins:
                # Skip this plugin since it's not listed as enabled plugins
                # as long as we have specified some enabled plugins though
                # this allows us to specify no specific plugins and get all of them
                continue

            module_obj = pynsive.import_module(found_module)
            reload(module_obj)
            plugin_class_obj = module_obj.Command()
            logger.info('Plugin {0} registered to receive command with {1}'.format(module_name, plugin_class_obj.command_name))
            plugins.append(
                {
                    'plugin_class': plugin_class_obj,
                    'command_name': plugin_class_obj.command_name,
                    'help_text': plugin_class_obj.help_text
                }
            )
        return plugins
Ejemplo n.º 10
0
def main():
    # connect and declare the message queue/kombu objects.
    # only py-amqp supports ssl and doesn't recognize amqps
    # so fix up the connection string accordingly
    connString = "amqp://{0}:{1}@{2}:{3}/{4}".format(options.mquser,
                                                     options.mqpassword,
                                                     options.mqserver,
                                                     options.mqport,
                                                     options.mqvhost)
    if options.mqprotocol == "amqps":
        mqSSL = True
    else:
        mqSSL = False
    mqConn = Connection(connString, ssl=mqSSL)
    # Task Exchange for events sent via http for us to normalize and post to elastic search
    if options.mqack:
        # conservative, store msgs to disk, ack each message
        eventTaskExchange = Exchange(name=options.taskexchange,
                                     type="direct",
                                     durable=True,
                                     delivery_mode=2)
    else:
        # fast, transient delivery, store in memory only, auto-ack messages
        eventTaskExchange = Exchange(name=options.taskexchange,
                                     type="direct",
                                     durable=True,
                                     delivery_mode=1)
    eventTaskExchange(mqConn).declare()
    # Queue for the exchange
    if options.mqack:
        eventTaskQueue = Queue(
            options.taskexchange,
            exchange=eventTaskExchange,
            routing_key=options.taskexchange,
            durable=True,
            no_ack=False,
        )
    else:
        eventTaskQueue = Queue(
            options.taskexchange,
            exchange=eventTaskExchange,
            routing_key=options.taskexchange,
            durable=True,
            no_ack=True,
        )
    eventTaskQueue(mqConn).declare()

    # topic exchange for anyone who wants to queue and listen for mozdef.event
    eventTopicExchange = Exchange(name=options.eventexchange,
                                  type="topic",
                                  durable=False,
                                  delivery_mode=1)
    eventTopicExchange(mqConn).declare()

    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info("started without uwsgi")
    # consume our queue and publish on the topic exchange
    taskConsumer(mqConn, eventTaskQueue, eventTopicExchange, es).run()
Ejemplo n.º 11
0
def isJVMMemoryHigh():
    url = "{0}/_nodes/stats?pretty=true".format(
        random.choice(options.esservers))
    r = requests.get(url)
    logger.debug(r)
    if r.status_code == 200:
        nodestats = r.json()

        for node in nodestats['nodes']:
            loadaverage = nodestats['nodes'][node]['os']['cpu']['load_average']
            cpuusage = nodestats['nodes'][node]['os']['cpu']['percent']
            nodename = nodestats['nodes'][node]['name']
            jvmused = nodestats['nodes'][node]['jvm']['mem'][
                'heap_used_percent']
            logger.debug('{0}: cpu {1}%  jvm {2}% load average: {3}'.format(
                nodename, cpuusage, jvmused, loadaverage))
            if jvmused > options.jvmlimit:
                logger.info(
                    '{0}: cpu {1}%  jvm {2}% load average: {3} recommending cache clear'
                    .format(nodename, cpuusage, jvmused, loadaverage))
                return True
        return False
    else:
        logger.error(r)
        return False
Ejemplo n.º 12
0
def main():
    if options.checkjvmmemory:
        if isJVMMemoryHigh():
            logger.info('initiating cache clearing')
            clearESCache()
    else:
        clearESCache()
Ejemplo n.º 13
0
def clearESCache():
    es = esConnect(None)
    indexes = es.get_indices()
    # assums index names  like events-YYYYMMDD etc.
    # used to avoid operating on current indexes
    dtNow = datetime.utcnow()
    indexSuffix = date.strftime(dtNow, '%Y%m%d')
    previousSuffix = date.strftime(dtNow - timedelta(days=1), '%Y%m%d')
    for targetindex in sorted(indexes):
        if indexSuffix not in targetindex and previousSuffix not in targetindex:
            url = '{0}/{1}/_stats'.format(random.choice(options.esservers), targetindex)
            r = requests.get(url)
            if r.status_code == 200:
                indexstats = json.loads(r.text)
                if indexstats['_all']['total']['search']['query_current'] == 0:
                    fielddata = indexstats['_all']['total']['fielddata']['memory_size_in_bytes']
                    if fielddata > 0:
                        logger.info('target: {0}: field data {1}'.format(targetindex, indexstats['_all']['total']['fielddata']['memory_size_in_bytes']))
                        clearurl = '{0}/{1}/_cache/clear'.format(random.choice(options.esservers), targetindex)
                        clearRequest = requests.post(clearurl)
                        logger.info(clearRequest.text)
                        # stop at one?
                        if options.conservative:
                            return
                else:
                    logger.debug('{0}: <ignoring due to current search > field data {1}'.format(targetindex, indexstats['_all']['total']['fielddata']['memory_size_in_bytes']))
            else:
                logger.error('{0} returned {1}'.format(url, r.status_code))
Ejemplo n.º 14
0
 def run(self):
     if self.slack_client.rtm_connect():
         logger.info("Bot connected to slack")
         self.post_welcome_message(random.choice(greetings))
         self.listen_for_messages()
     else:
         logger.error("Unable to connect to slack")
         sys.exit(1)
Ejemplo n.º 15
0
 def run(self):
     if self.slack_client.rtm_connect():
         logger.info("Bot connected to slack")
         self.post_welcome_message(random.choice(greetings))
         self.listen_for_messages()
     else:
         logger.error("Unable to connect to slack")
         sys.exit(1)
Ejemplo n.º 16
0
    def send_message_to_plugin(self, plugin_class, message, metadata=None):
        if 'utctimestamp' in message and 'summary' in message:
            message_log_str = '{0} received message: ({1}) {2}'.format(
                plugin_class.__module__, message['utctimestamp'],
                message['summary'])
            logger.info(message_log_str)

        return plugin_class.onMessage(message), metadata
Ejemplo n.º 17
0
 def listen_for_messages(self):
     while True:
         for slack_message in self.slack_client.rtm_read():
             message_type = slack_message.get('type')
             if message_type == 'desktop_notification':
                 logger.info("Received message: {0}".format(slack_message['content']))
                 self.handle_message(slack_message)
         time.sleep(1)
Ejemplo n.º 18
0
 def listen_for_messages(self):
     while True:
         for slack_message in self.slack_client.rtm_read():
             message_type = slack_message.get('type')
             if message_type == 'desktop_notification':
                 logger.info("Received message: {0}".format(
                     slack_message['content']))
                 self.handle_message(slack_message)
         time.sleep(1)
Ejemplo n.º 19
0
    def run(self):
        while True:
            try:
                records = self.sqs_queue.receive_messages(
                    MaxNumberOfMessages=options.prefetch)
                for msg in records:
                    # msg.id is the id,
                    # get_body() should be json

                    # pre process the message a bit
                    tmp = msg.body
                    try:
                        msgbody = json.loads(tmp)
                    except ValueError:
                        # If Boto wrote to the queue, it might be base64 encoded, so let's decode that
                        try:
                            tmp = base64.b64decode(tmp)
                            msgbody = json.loads(tmp)
                        except Exception as e:
                            logger.error(
                                "Invalid message, not JSON <dropping message and continuing>: %r"
                                % msg.get_body())
                            msg.delete()
                            continue

                    # If this is still not a dict,
                    # let's just drop the message and move on
                    if type(msgbody) is not dict:
                        logger.debug(
                            "Message is not a dictionary, dropping message.")
                        msg.delete()
                        continue

                    event = dict()
                    event = msgbody

                    if "tags" in event:
                        event["tags"].extend([options.taskexchange])
                    else:
                        event["tags"] = [options.taskexchange]

                    # process message
                    self.on_message(event, msg)

                    # delete message from queue
                    msg.delete()
                time.sleep(options.sleep_time)

            except ValueError as e:
                logger.exception("Exception while handling message: %r" % e)
                msg.delete()
            except (SSLEOFError, SSLError, socket.error):
                logger.info("Received network related error...reconnecting")
                time.sleep(5)
                self.sqs_queue = connect_sqs(options.region, options.accesskey,
                                             options.secretkey,
                                             options.taskexchange)
Ejemplo n.º 20
0
def main():
    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info('started without uwsgi')

    # establish api interface with papertrail
    ptRequestor = PTRequestor(options.ptapikey, evmax=options.ptquerymax)

    # consume our queue
    taskConsumer(ptRequestor, es).run()
Ejemplo n.º 21
0
def main():
    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info('started without uwsgi')

    # establish api interface with papertrail
    ptRequestor = PTRequestor(options.ptapikey, evmax=options.ptquerymax)

    # consume our queue
    taskConsumer(ptRequestor, es).run()
Ejemplo n.º 22
0
def main():
    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info("started without uwsgi")

    if options.mqprotocol not in ("pubsub"):
        logger.error("Can only process pubsub queues, terminating")
        sys.exit(1)

    # connect to GCP and consume our queue
    PubSubtaskConsumer(es, options).run()
Ejemplo n.º 23
0
 def listen_for_messages(self):
     while True:
         try:
             for slack_message in self.slack_client.rtm_read():
                 message_type = slack_message.get('type')
                 if message_type == 'desktop_notification':
                     logger.info("Received message: {0}".format(slack_message['content']))
                     self.handle_message(slack_message)
         except websocket.WebSocketConnectionClosedException:
             logger.info("Received WebSocketConnectionClosedException exception...reconnecting")
             time.sleep(3)
             self.slack_client.rtm_connect()
         time.sleep(1)
Ejemplo n.º 24
0
 def listen_for_messages(self):
     while True:
         try:
             for slack_message in self.slack_client.rtm_read():
                 message_type = slack_message.get('type')
                 if message_type == 'desktop_notification':
                     logger.info("Received message: {0}".format(slack_message['content']))
                     self.handle_message(slack_message)
         except websocket.WebSocketConnectionClosedException:
             logger.info("Received WebSocketConnectionClosedException exception...reconnecting")
             time.sleep(3)
             self.slack_client.rtm_connect()
         time.sleep(1)
Ejemplo n.º 25
0
    def on_message(self, body, message):
        try:
            # just to be safe..check what we were sent.
            if isinstance(body, dict):
                full_body = body
            elif isinstance(body, str):
                try:
                    full_body = json.loads(body)
                except ValueError:
                    # not json..ack but log the message
                    logger.exception(
                        "mozdefbot_slack exception: unknown body type received %r"
                        % body)
                    return
            else:
                logger.exception(
                    "mozdefbot_slack exception: unknown body type received %r"
                    % body)
                return

            body_dict = full_body
            # Handle messages that have full ES dict
            if '_source' in full_body:
                body_dict = full_body['_source']

            if 'notify_mozdefbot' in body_dict and body_dict[
                    'notify_mozdefbot'] is False:
                # If the alert tells us to not notify, then don't post message
                message.ack()
                return

            # process valid message
            # see where we send this alert
            channel = options.default_alert_channel
            if 'ircchannel' in body_dict:
                if body_dict['ircchannel'] in options.channels:
                    channel = body_dict['ircchannel']

            # see if we need to delay a bit before sending the alert, to avoid
            # flooding the channel
            if self.lastalert is not None:
                delta = toUTC(datetime.now()) - self.lastalert
                logger.info(
                    'new alert, delta since last is {}\n'.format(delta))
                if delta.seconds < 2:
                    logger.info('throttling before writing next alert\n')
                    time.sleep(1)
            self.lastalert = toUTC(datetime.now())
            if len(body_dict['summary']) > 450:
                logger.info('alert is more than 450 bytes, truncating\n')
                body_dict[
                    'summary'] = body_dict['summary'][:450] + ' truncated...'

            logger.info("Posting alert: {0}".format(body_dict['summary']))
            self.bot.post_alert_message(body_dict, channel)
            message.ack()
        except ValueError as e:
            logger.exception(
                "mozdefbot_slack exception while processing events queue %r" %
                e)
Ejemplo n.º 26
0
    def run(self):
        while True:
            try:
                records = self.sqs_queue.receive_messages(
                    MaxNumberOfMessages=options.prefetch)
                for msg in records:
                    body_message = msg.body
                    event = json.loads(body_message)

                    if not event["Message"]:
                        logger.error(
                            "Invalid message format for cloudtrail SQS messages"
                        )
                        logger.error("Malformed Message: %r" % body_message)
                        continue

                    if event["Message"] == "CloudTrail validation message.":
                        # We don't care about these messages
                        continue

                    message_json = json.loads(event["Message"])

                    if "s3ObjectKey" not in message_json:
                        logger.error(
                            "Invalid message format, expecting an s3ObjectKey in Message"
                        )
                        logger.error("Malformed Message: %r" % body_message)
                        continue

                    s3_log_files = message_json["s3ObjectKey"]
                    for log_file in s3_log_files:
                        logger.debug("Downloading and parsing " + log_file)
                        s3_obj = self.s3_client.get_object(
                            Bucket=message_json["s3Bucket"], Key=log_file)
                        events = self.parse_s3_file(s3_obj)
                        for event in events:
                            self.on_message(event)

                    msg.delete()
            except (SSLEOFError, SSLError, socket.error):
                logger.info("Received network related error...reconnecting")
                time.sleep(5)
                self.sqs_queue = connect_sqs(
                    region_name=options.region,
                    aws_access_key_id=options.accesskey,
                    aws_secret_access_key=options.secretkey,
                    task_exchange=options.taskexchange,
                )
            time.sleep(options.sleep_time)
    def run(self):
        self.taskQueue.set_message_class(RawMessage)
        while True:
            try:
                records = self.taskQueue.get_messages(options.prefetch)
                for msg in records:
                    body_message = msg.get_body()
                    event = json.loads(body_message)

                    if not event['Message']:
                        logger.error(
                            'Invalid message format for cloudtrail SQS messages'
                        )
                        logger.error('Malformed Message: %r' % body_message)
                        continue

                    if event['Message'] == 'CloudTrail validation message.':
                        # We don't care about these messages
                        continue

                    message_json = json.loads(event['Message'])

                    if 's3ObjectKey' not in message_json:
                        logger.error(
                            'Invalid message format, expecting an s3ObjectKey in Message'
                        )
                        logger.error('Malformed Message: %r' % body_message)
                        continue

                    s3_log_files = message_json['s3ObjectKey']
                    for log_file in s3_log_files:
                        logger.debug('Downloading and parsing ' + log_file)
                        bucket = self.s3_connection.get_bucket(
                            message_json['s3Bucket'])

                        log_file_lookup = bucket.lookup(log_file)
                        events = self.process_file(log_file_lookup)
                        for event in events:
                            self.on_message(event)

                    self.taskQueue.delete_message(msg)
            except (SSLEOFError, SSLError, socket.error):
                logger.info('Received network related error...reconnecting')
                time.sleep(5)
                self.connection, self.taskQueue = connect_sqs(
                    task_exchange=options.taskexchange,
                    **get_aws_credentials(options.region, options.accesskey,
                                          options.secretkey))
                self.taskQueue.set_message_class(RawMessage)
Ejemplo n.º 28
0
def main():
    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info('started without uwsgi')

    if options.mqprotocol not in ('sqs'):
        logger.error('Can only process SQS queues, terminating')
        sys.exit(1)

    mqConn, eventTaskQueue = connect_sqs(options.region, options.accesskey,
                                         options.secretkey,
                                         options.taskexchange)

    # consume our queue
    taskConsumer(mqConn, eventTaskQueue, es, options).run()
Ejemplo n.º 29
0
def main():
    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info('started without uwsgi')

    if options.mqprotocol not in ('sqs'):
        logger.error('Can only process SQS queues, terminating')
        sys.exit(1)

    sqs_queue = connect_sqs(region_name=options.region,
                            aws_access_key_id=options.accesskey,
                            aws_secret_access_key=options.secretkey,
                            task_exchange=options.taskexchange)
    # consume our queue
    taskConsumer(sqs_queue, es, options).run()
Ejemplo n.º 30
0
    def run(self):
        while True:
            try:
                records = self.sqs_queue.receive_messages(
                    MaxNumberOfMessages=options.prefetch)
                for msg in records:
                    body_message = msg.body
                    event = json.loads(body_message)

                    if not event['Message']:
                        logger.error(
                            'Invalid message format for cloudtrail SQS messages'
                        )
                        logger.error('Malformed Message: %r' % body_message)
                        continue

                    if event['Message'] == 'CloudTrail validation message.':
                        # We don't care about these messages
                        continue

                    message_json = json.loads(event['Message'])

                    if 's3ObjectKey' not in message_json:
                        logger.error(
                            'Invalid message format, expecting an s3ObjectKey in Message'
                        )
                        logger.error('Malformed Message: %r' % body_message)
                        continue

                    s3_log_files = message_json['s3ObjectKey']
                    for log_file in s3_log_files:
                        logger.debug('Downloading and parsing ' + log_file)
                        s3_obj = self.s3_client.get_object(
                            Bucket=message_json['s3Bucket'], Key=log_file)
                        events = self.parse_s3_file(s3_obj)
                        for event in events:
                            self.on_message(event)

                    msg.delete()
            except (SSLEOFError, SSLError, socket.error):
                logger.info('Received network related error...reconnecting')
                time.sleep(5)
                self.sqs_queue = connect_sqs(
                    task_exchange=options.taskexchange,
                    **get_aws_credentials(options.region, options.accesskey,
                                          options.secretkey))
            time.sleep(options.sleep_time)
Ejemplo n.º 31
0
def registerPlugins():
    '''walk the plugins directory
       and register modules in pluginList
       as a tuple: (mfile, mname, mdescription, mreg, mpriority, mclass)
    '''

    plugin_location = os.path.join(os.path.dirname(__file__), "plugins")
    module_name = os.path.basename(plugin_location)
    root_plugin_directory = os.path.join(plugin_location, '..')

    plugin_manager = pynsive.PluginManager()
    plugin_manager.plug_into(root_plugin_directory)

    if os.path.exists(plugin_location):
        modules = pynsive.list_modules(module_name)
        for mfile in modules:
            module = pynsive.import_module(mfile)
            importlib.reload(module)
            if not module:
                raise ImportError('Unable to load module {}'.format(mfile))
            else:
                if 'message' in dir(module):
                    mclass = module.message()
                    mreg = mclass.registration
                    mclass.restoptions = options.__dict__

                    if 'priority' in dir(mclass):
                        mpriority = mclass.priority
                    else:
                        mpriority = 100
                    if 'name' in dir(mclass):
                        mname = mclass.name
                    else:
                        mname = mfile

                    if 'description' in dir(mclass):
                        mdescription = mclass.description
                    else:
                        mdescription = mfile

                    if isinstance(mreg, list):
                        logger.info(
                            '[*] plugin {0} registered to receive messages from /{1}'
                            .format(mfile, mreg))
                        pluginList.append((mfile, mname, mdescription, mreg,
                                           mpriority, mclass))
Ejemplo n.º 32
0
    def run(self):
        self.taskQueue.set_message_class(RawMessage)
        while True:
            try:
                records = self.taskQueue.get_messages(options.prefetch)
                for msg in records:
                    body_message = msg.get_body()
                    event = json.loads(body_message)

                    if not event['Message']:
                        logger.error('Invalid message format for cloudtrail SQS messages')
                        logger.error('Malformed Message: %r' % body_message)
                        continue

                    if event['Message'] == 'CloudTrail validation message.':
                        # We don't care about these messages
                        continue

                    message_json = json.loads(event['Message'])

                    if 's3ObjectKey' not in message_json:
                        logger.error('Invalid message format, expecting an s3ObjectKey in Message')
                        logger.error('Malformed Message: %r' % body_message)
                        continue

                    s3_log_files = message_json['s3ObjectKey']
                    for log_file in s3_log_files:
                        logger.debug('Downloading and parsing ' + log_file)
                        bucket = self.s3_connection.get_bucket(message_json['s3Bucket'])

                        log_file_lookup = bucket.lookup(log_file)
                        events = self.process_file(log_file_lookup)
                        for event in events:
                            self.on_message(event)

                    self.taskQueue.delete_message(msg)
            except (SSLEOFError, SSLError, socket.error):
                logger.info('Received network related error...reconnecting')
                time.sleep(5)
                self.connection, self.taskQueue = connect_sqs(
                    task_exchange=options.taskexchange,
                    **get_aws_credentials(
                        options.region,
                        options.accesskey,
                        options.secretkey))
                self.taskQueue.set_message_class(RawMessage)
Ejemplo n.º 33
0
def main():
    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info('started without uwsgi')

    if options.mqprotocol not in ('sqs'):
        logger.error('Can only process SQS queues, terminating')
        sys.exit(1)

    sqs_conn, eventTaskQueue = connect_sqs(
        task_exchange=options.taskexchange,
        **get_aws_credentials(
            options.region,
            options.accesskey,
            options.secretkey))
    # consume our queue
    taskConsumer(sqs_conn, eventTaskQueue, es, options).run()
def main():
    # meant only to talk to SQS using boto
    # and process events as json.

    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info('started without uwsgi')

    if options.mqprotocol not in ('sqs'):
        logger.error('Can only process SQS queues, terminating')
        sys.exit(1)

    sqs_conn, eventTaskQueue = connect_sqs(
        task_exchange=options.taskexchange,
        **get_aws_credentials(options.region, options.accesskey,
                              options.secretkey))
    # consume our queue
    taskConsumer(sqs_conn, eventTaskQueue, es).run()
Ejemplo n.º 35
0
def registerPlugins():
    '''walk the plugins directory
       and register modules in pluginList
       as a tuple: (mfile, mname, mdescription, mreg, mpriority, mclass)
    '''

    plugin_location = os.path.join(os.path.dirname(__file__), "plugins")
    module_name = os.path.basename(plugin_location)
    root_plugin_directory = os.path.join(plugin_location, '..')

    plugin_manager = pynsive.PluginManager()
    plugin_manager.plug_into(root_plugin_directory)

    if os.path.exists(plugin_location):
        modules = pynsive.list_modules(module_name)
        for mfile in modules:
            module = pynsive.import_module(mfile)
            reload(module)
            if not module:
                raise ImportError('Unable to load module {}'.format(mfile))
            else:
                if 'message' in dir(module):
                    mclass = module.message()
                    mreg = mclass.registration
                    mclass.restoptions = options.__dict__

                    if 'priority' in dir(mclass):
                        mpriority = mclass.priority
                    else:
                        mpriority = 100
                    if 'name' in dir(mclass):
                        mname = mclass.name
                    else:
                        mname = mfile

                    if 'description' in dir(mclass):
                        mdescription = mclass.description
                    else:
                        mdescription = mfile

                    if isinstance(mreg, list):
                        logger.info('[*] plugin {0} registered to receive messages from /{1}'.format(mfile, mreg))
                        pluginList.append((mfile, mname, mdescription, mreg, mpriority, mclass))
Ejemplo n.º 36
0
    def onMessage(self, alert):
        source = alert['_source']

        # Find the self.option that contains one of the message tags
        selected_option = self.identify_option(source['tags'])
        if selected_option is None:
            logger.error("Unable to find config option for alert tags: {0}".format(source['tags']))

        if 'summary' in source:
            headers = {
                'Content-type': 'application/json',
            }

            payload = hjson.dumpsJSON({
                "service_key": "{0}".format(selected_option['service_key']),
                "event_type": "trigger",
                "description": source['summary'],
                "client": "MozDef",
                "client_url": "{0}/alert/{1}".format(self.options['web_url'], alert['_id']),
                "contexts": [
                    {
                        "type": "link",
                        "href": "{0}".format(selected_option['doc']),
                        "text": "View runbook on mana"
                    }
                ]
            })

            headers = {
                'Content-type': 'application/json',
            }
            resp = requests.post(
                'https://events.pagerduty.com/generic/2010-04-15/create_event.json',
                headers=headers,
                data=payload,
            )
            if not resp.ok:
                logger.exception("Received invalid response from pagerduty: {0} - {1}".format(resp.status_code, resp.text))
            else:
                logger.info("Triggered pagerduty notification for alert - {0}".format(alert['_id']))

        return message
Ejemplo n.º 37
0
def isJVMMemoryHigh():
    url = "{0}/_nodes/stats?pretty=true".format(random.choice(options.esservers))
    r = requests.get(url)
    logger.debug(r)
    if r.status_code == 200:
        nodestats = r.json()

        for node in nodestats['nodes']:
            loadaverage = nodestats['nodes'][node]['os']['cpu']['load_average']
            cpuusage = nodestats['nodes'][node]['os']['cpu']['percent']
            nodename = nodestats['nodes'][node]['name']
            jvmused = nodestats['nodes'][node]['jvm']['mem']['heap_used_percent']
            logger.debug('{0}: cpu {1}%  jvm {2}% load average: {3}'.format(nodename, cpuusage, jvmused, loadaverage))
            if jvmused > options.jvmlimit:
                logger.info('{0}: cpu {1}%  jvm {2}% load average: {3} recommending cache clear'.format(nodename, cpuusage, jvmused, loadaverage))
                return True
        return False
    else:
        logger.error(r)
        return False
Ejemplo n.º 38
0
def registerPlugins():
    pluginList = list()   # tuple of module,registration dict,priority
    if os.path.exists('plugins'):
        modules = pynsive.list_modules('plugins')
        for mname in modules:
            module = pynsive.import_module(mname)
            reload(module)
            if not module:
                raise ImportError('Unable to load module {}'.format(mname))
            else:
                if 'message' in dir(module):
                    mclass = module.message()
                    mreg = mclass.registration
                    if 'priority' in dir(mclass):
                        mpriority = mclass.priority
                    else:
                        mpriority = 100
                    if isinstance(mreg, list):
                        logger.info('[*] plugin {0} registered to receive messages with {1}'.format(mname, mreg))
                        pluginList.append((mclass, mreg, mpriority))
    return pluginList
Ejemplo n.º 39
0
def main():
    # meant only to talk to SQS using boto
    # and process events as json.

    if hasUWSGI:
        logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
    else:
        logger.info("started without uwsgi")

    if options.mqprotocol not in ("sqs"):
        logger.error("Can only process SQS queues, terminating")
        sys.exit(1)

    sqs_queue = connect_sqs(
        region_name=options.region,
        aws_access_key_id=options.accesskey,
        aws_secret_access_key=options.secretkey,
        task_exchange=options.taskexchange,
    )
    # consume our queue
    taskConsumer(sqs_queue, es).run()
Ejemplo n.º 40
0
    def onMessage(self, request, response):
        '''
        request: http://bottlepy.org/docs/dev/api.html#the-request-object
        response: http://bottlepy.org/docs/dev/api.html#the-response-object

        '''
        # format/validate request.json:
        ipaddress = None
        sendToBHVPC = False

        # loop through the fields of the form
        # and fill in our values
        try:
            for field in request.json:
                # were we checked?
                if self.name in field:
                    sendToBHVPC = field[self.name]
                if 'ipaddress' in field:
                    ipaddress = field['ipaddress']
            # are we configured?
            if self.multioptions is None:
                logger.error(
                    "Customs server blockip requested but not configured\n")
                sendToBHVPC = False

            if sendToBHVPC and ipaddress is not None:
                # figure out the CIDR mask
                if isIPv4(ipaddress) or isIPv6(ipaddress):
                    ipcidr = netaddr.IPNetwork(ipaddress)
                    if not ipcidr.ip.is_loopback() \
                       and not ipcidr.ip.is_private() \
                       and not ipcidr.ip.is_reserved():
                        ipaddress = str(ipcidr.cidr)
                        self.addBlackholeEntry(ipaddress)
                        logger.info('Blackholed {0}\n'.format(ipaddress))
        except Exception as e:
            logger.error('Error handling request.json %r \n' % (e))

        return (request, response)
Ejemplo n.º 41
0
def registerPlugins():
    '''walk the ./plugins directory
       and register modules in pluginList
       as a tuple: (mfile, mname, mdescription, mreg, mpriority, mclass)
    '''

    plugin_manager = pynsive.PluginManager()
    if os.path.exists('plugins'):
        modules = pynsive.list_modules('plugins')
        for mfile in modules:
            module = pynsive.import_module(mfile)
            reload(module)
            if not module:
                raise ImportError('Unable to load module {}'.format(mfile))
            else:
                if 'message' in dir(module):
                    mclass = module.message()
                    mreg = mclass.registration
                    mclass.restoptions = options

                    if 'priority' in dir(mclass):
                        mpriority = mclass.priority
                    else:
                        mpriority = 100
                    if 'name' in dir(mclass):
                        mname = mclass.name
                    else:
                        mname = mfile

                    if 'description' in dir(mclass):
                        mdescription = mclass.description
                    else:
                        mdescription = mfile

                    if isinstance(mreg, list):
                        logger.info('[*] plugin {0} registered to receive messages from /{1}'.format(mfile, mreg))
                        pluginList.append((mfile, mname, mdescription, mreg, mpriority, mclass))
Ejemplo n.º 42
0
    def on_message(self, body, message):
        try:
            # just to be safe..check what we were sent.
            if isinstance(body, dict):
                body_dict = body
            elif isinstance(body, str) or isinstance(body, unicode):
                try:
                    body_dict = json.loads(body)  # lets assume it's json
                except ValueError as e:
                    # not json..ack but log the message
                    logger.exception("mozdefbot_slack exception: unknown body type received %r" % body)
                    return
            else:
                logger.exception("mozdefbot_slack exception: unknown body type received %r" % body)
                return

            if 'notify_mozdefbot' in body_dict and body_dict['notify_mozdefbot'] is False:
                # If the alert tells us to not notify, then don't post message
                message.ack()
                return

            # process valid message
            # see where we send this alert
            channel = options.default_alert_channel
            if 'ircchannel' in body_dict:
                if body_dict['ircchannel'] in options.channels:
                    channel = body_dict['ircchannel']

            # see if we need to delay a bit before sending the alert, to avoid
            # flooding the channel
            if self.lastalert is not None:
                delta = toUTC(datetime.now()) - self.lastalert
                logger.info('new alert, delta since last is {}\n'.format(delta))
                if delta.seconds < 2:
                    logger.info('throttling before writing next alert\n')
                    time.sleep(1)
            self.lastalert = toUTC(datetime.now())
            if len(body_dict['summary']) > 450:
                logger.info('alert is more than 450 bytes, truncating\n')
                body_dict['summary'] = body_dict['summary'][:450] + ' truncated...'

            logger.info("Posting alert: {0}".format(body_dict['summary']))
            self.bot.post_alert_message(body_dict, channel)
            message.ack()
        except ValueError as e:
            logger.exception("mozdefbot_slack exception while processing events queue %r" % e)
Ejemplo n.º 43
0
    def onMessage(self, request, response):
        '''
        request: http://bottlepy.org/docs/dev/api.html#the-request-object
        response: http://bottlepy.org/docs/dev/api.html#the-response-object

        '''
        response.headers['X-PLUGIN'] = self.description

        # Refresh the ip network list each time we get a message
        self.options.ipwhitelist = self.parse_network_whitelist(
            self.options.network_whitelist_file)

        ipaddress = None
        comment = None
        duration = None
        referenceID = None
        userid = None
        blockip = False

        try:
            # loop through the fields of the form
            # and fill in our values
            for field in request.json:
                # were we checked?
                if self.name in field:
                    blockip = field[self.name]
                if 'ipaddress' in field:
                    ipaddress = field['ipaddress']
                if 'duration' in field:
                    duration = field['duration']
                if 'comment' in field:
                    comment = field['comment']
                if 'referenceid' in field:
                    referenceID = field['referenceid']
                if 'userid' in field:
                    userid = field['userid']

            if blockip and ipaddress is not None:
                # figure out the CIDR mask
                if isIPv4(ipaddress) or isIPv6(ipaddress):
                    ipcidr = netaddr.IPNetwork(ipaddress)
                    if not ipcidr.ip.is_loopback() \
                       and not ipcidr.ip.is_private() \
                       and not ipcidr.ip.is_reserved():

                        whitelisted = False
                        for whitelist_range in self.options.ipwhitelist:
                            whitelist_network = netaddr.IPNetwork(
                                whitelist_range)
                            if ipcidr in whitelist_network:
                                whitelisted = True
                                logger.debug(
                                    '{0} is whitelisted as part of {1}\n'.
                                    format(ipcidr, whitelist_network))

                        if not whitelisted:
                            self.blockIP(str(ipcidr), comment, duration,
                                         referenceID, userid)
                            logger.info(
                                'added {0} to blocklist\n'.format(ipaddress))
                        else:
                            logger.info(
                                'not adding {0} to blocklist, it was found in whitelist\n'
                                .format(ipaddress))
        except Exception as e:
            logger.error('Error handling request.json %r \n' % (e))

        return (request, response)
Ejemplo n.º 44
0
    def send_message_to_plugin(self, plugin_class, message, metadata=None):
        if 'utctimestamp' in message and 'summary' in message:
            message_log_str = u'{0} received message: ({1}) {2}'.format(plugin_class.__module__, message['utctimestamp'], message['summary'])
            logger.info(message_log_str)

        return plugin_class.onMessage(message), metadata
Ejemplo n.º 45
0
    def run(self):
        # Boto expects base64 encoded messages - but if the writer is not boto it's not necessarily base64 encoded
        # Thus we've to detect that and decode or not decode accordingly
        self.taskQueue.set_message_class(RawMessage)
        while True:
            try:
                records = self.taskQueue.get_messages(options.prefetch)
                for msg in records:
                    # msg.id is the id,
                    # get_body() should be json

                    # pre process the message a bit
                    tmp = msg.get_body()
                    try:
                        msgbody = json.loads(tmp)
                    except ValueError:
                        # If Boto wrote to the queue, it might be base64 encoded, so let's decode that
                        try:
                            tmp = base64.b64decode(tmp)
                            msgbody = json.loads(tmp)
                        except Exception as e:
                            logger.error('Invalid message, not JSON <dropping message and continuing>: %r' % msg.get_body())
                            self.taskQueue.delete_message(msg)
                            continue

                    # If this is still not a dict,
                    # let's just drop the message and move on
                    if type(msgbody) is not dict:
                        logger.debug("Message is not a dictionary, dropping message.")
                        self.taskQueue.delete_message(msg)
                        continue

                    event = dict()
                    event = msgbody

                    # Was this message sent by fluentd-sqs
                    fluentd_sqs_specific_fields = {
                        'az', 'instance_id', '__tag'}
                    if fluentd_sqs_specific_fields.issubset(
                            set(msgbody.keys())):
                        # Until we can influence fluentd-sqs to set the
                        # 'customendpoint' key before submitting to SQS, we'll
                        # need to do it here
                        # TODO : Change nubis fluentd output to include
                        # 'customendpoint'
                        event['customendpoint'] = True

                    if 'tags' in event:
                        event['tags'].extend([options.taskexchange])
                    else:
                        event['tags'] = [options.taskexchange]

                    # process message
                    self.on_message(event, msg)

                    # delete message from queue
                    self.taskQueue.delete_message(msg)
                time.sleep(.1)

            except ValueError as e:
                logger.exception('Exception while handling message: %r' % e)
                self.taskQueue.delete_message(msg)
            except (SSLEOFError, SSLError, socket.error):
                logger.info('Received network related error...reconnecting')
                time.sleep(5)
                self.connection, self.taskQueue = connect_sqs(
                    options.region,
                    options.accesskey,
                    options.secretkey,
                    options.taskexchange
                )
                self.taskQueue.set_message_class(RawMessage)
Ejemplo n.º 46
0
    options.region = getConfig('region', '', options.configfile)

    # How long to sleep between polling
    options.sleep_time = getConfig('sleep_time', 0.1, options.configfile)


if __name__ == '__main__':
    # configure ourselves
    parser = OptionParser()
    parser.add_option("-c",
                      dest='configfile',
                      default=sys.argv[0].replace('.py', '.conf'),
                      help="configuration file to use")
    (options, args) = parser.parse_args()
    initConfig()
    initLogger(options)

    # open ES connection globally so we don't waste time opening it per message
    es = esConnect()

    try:
        main()
    except KeyboardInterrupt as e:
        logger.info("Exiting worker")
        if options.esbulksize != 0:
            es.finish_bulk()
    except Exception as e:
        if options.esbulksize != 0:
            es.finish_bulk()
        raise
Ejemplo n.º 47
0
    def run(self):
        while True:
            try:
                records = self.sqs_queue.receive_messages(
                    MaxNumberOfMessages=options.prefetch)
                for msg in records:
                    # msg.id is the id,
                    # get_body() should be json

                    # pre process the message a bit
                    tmp = msg.body
                    try:
                        msgbody = json.loads(tmp)
                    except ValueError:
                        # If Boto wrote to the queue, it might be base64 encoded, so let's decode that
                        try:
                            tmp = base64.b64decode(tmp)
                            msgbody = json.loads(tmp)
                        except Exception as e:
                            logger.error(
                                'Invalid message, not JSON <dropping message and continuing>: %r'
                                % msg.get_body())
                            msg.delete()
                            continue

                    # If this is still not a dict,
                    # let's just drop the message and move on
                    if type(msgbody) is not dict:
                        logger.debug(
                            "Message is not a dictionary, dropping message.")
                        msg.delete()
                        continue

                    event = dict()
                    event = msgbody

                    # Was this message sent by fluentd-sqs
                    fluentd_sqs_specific_fields = {
                        'az', 'instance_id', '__tag'
                    }
                    if fluentd_sqs_specific_fields.issubset(set(
                            msgbody.keys())):
                        # Until we can influence fluentd-sqs to set the
                        # 'customendpoint' key before submitting to SQS, we'll
                        # need to do it here
                        # TODO : Change nubis fluentd output to include
                        # 'customendpoint'
                        event['customendpoint'] = True

                    if 'tags' in event:
                        event['tags'].extend([options.taskexchange])
                    else:
                        event['tags'] = [options.taskexchange]

                    # process message
                    self.on_message(event, msg)

                    # delete message from queue
                    msg.delete()
                time.sleep(.1)

            except ValueError as e:
                logger.exception('Exception while handling message: %r' % e)
                msg.delete()
            except (SSLEOFError, SSLError, socket.error):
                logger.info('Received network related error...reconnecting')
                time.sleep(5)
                self.sqs_queue = connect_sqs(options.region, options.accesskey,
                                             options.secretkey,
                                             options.taskexchange)
Ejemplo n.º 48
0
    # secs to pass before checking for new/updated plugins
    # seems to cause memory leaks..
    # regular updates are disabled for now,
    # though we set the frequency anyway.
    options.plugincheckfrequency = getConfig('plugincheckfrequency', 120, options.configfile)


if __name__ == '__main__':
    # configure ourselves
    parser = OptionParser()
    parser.add_option("-c", dest='configfile', default=sys.argv[0].replace('.py', '.conf'), help="configuration file to use")
    (options, args) = parser.parse_args()
    initConfig()
    initLogger(options)

    # open ES connection globally so we don't waste time opening it per message
    es = esConnect()

    pluginList = registerPlugins()

    try:
        main()
    except KeyboardInterrupt as e:
        logger.info("Exiting worker")
        if options.esbulksize != 0:
            es.finish_bulk()
    except Exception as e:
        if options.esbulksize != 0:
            es.finish_bulk()
        raise