Exemple #1
0
def deleteEvent(iUUID="", iEventID=""):
    try:
        mispDB = pm.ExpandedPyMISP(url=gv._MISP_URL,
                                   key=gv._MISP_KEY,
                                   ssl=gv._MISP_VERIFYCERT,
                                   debug=gv._DEBUG)
        event_id = ""

        if iUUID != "":
            kwargs = {"uuid": iUUID}
            result = mispDB.search(controller='events',
                                   return_format='json',
                                   limit=1,
                                   **kwargs)
            for val in result:
                event_id = val["Event"]["id"]
        elif iEventID != "":
            event_id = iEventID

        if event_id != "":
            if gv._DEBUG:
                print(
                    "f(x) deleteEvent: ATTEMPTING TO DELETE EVENT [IF EXISTS]: {}"
                    .format(event_id))
            mispDB.delete_event(event_id)

        else:
            print(
                "f(x) deleteEvent: EMPTY EVENT_ID FOUND. NO DELETION MADE\niUUID: {}\niEventID: {}\nRETURNED EVENT ID [IF APPLICABLE]: {}"
                .format(iUUID, iEventID, event_id))

    except Exception as e:
        print(e)
Exemple #2
0
    def run(self):
        api_key = secrets.get_secret(self.api_key_name)
        if not api_key:
            raise AnalyzerRunException(
                f"no MISP API key retrieved with name: {self.api_key_name}")

        if not self.url_name:
            raise AnalyzerRunException(
                f"no MISP URL retrieved, key value: {self.url_key_name}")

        misp_instance = pymisp.ExpandedPyMISP(self.url_name, api_key)
        # debug=True)

        # we check only for events not older than 90 days and max 50 results
        now = datetime.datetime.now()
        date_from = now - datetime.timedelta(days=90)
        params = {
            # even if docs say to use "values",...
            # .. at the moment it works correctly only with "value"
            "value": self.observable_name,
            "type_attribute": [self.observable_classification],
            "date_from": date_from.strftime("%Y-%m-%d %H:%M:%S"),
            "limit": 50,
            "enforce_warninglist": True,
        }
        if self.observable_classification == "hash":
            params["type_attribute"] = ["md5", "sha1", "sha256"]
        result_search = misp_instance.search(**params)
        if isinstance(result_search, dict):
            errors = result_search.get("errors", [])
            if errors:
                raise AnalyzerRunException(errors)

        return {"result_search": result_search, "instance_url": self.url_name}
Exemple #3
0
    def __init__(
        self,
        url: str,
        key: str,
        ssl: bool = True,
        tags: Optional[List[str]] = None,
        artifact_types: Optional[List[Type[Artifact]]] = None,
        filter_string: Optional[str] = None,
        allowed_sources: Optional[List[str]] = None,
        include_artifact_source_name: bool = True,
        include_event_id_in_info: bool = False,
    ):
        """MISP operator."""
        self.api = pymisp.ExpandedPyMISP(url, key, ssl)
        if tags:
            self.tags = tags
        else:
            self.tags = ["type:OSINT"]
        self.event_info = "{source_name}"
        self.url = url

        super().__init__(artifact_types, filter_string, allowed_sources)
        self.artifact_types = artifact_types or [Domain, Hash, IPAddress, URL]

        self.include_artifact_source_name = include_artifact_source_name
        self.include_event_id_in_info = include_event_id_in_info
Exemple #4
0
    def __init__(self,
                 url,
                 key,
                 ssl=True,
                 tags=None,
                 artifact_types=None,
                 filter_string=None,
                 allowed_sources=None):
        """MISP operator."""
        self.api = pymisp.ExpandedPyMISP(url, key, ssl)
        if tags:
            self.tags = tags
        else:
            self.tags = ['type:OSINT']
        self.event_info = 'ThreatIngestor Event: {source_name}'

        super(Plugin, self).__init__(artifact_types, filter_string,
                                     allowed_sources)
        self.artifact_types = artifact_types or [
            threatingestor.artifacts.Domain,
            threatingestor.artifacts.Hash,
            threatingestor.artifacts.IPAddress,
            threatingestor.artifacts.URL,
            threatingestor.artifacts.YARASignature,
        ]
Exemple #5
0
def pushToMISP(event,
               iUpdate=False,
               mURL="",
               mKey="",
               mVerifycert="",
               mDebug=""):
    try:
        mispDB = pm.ExpandedPyMISP(url=mURL,
                                   key=mKey,
                                   ssl=mVerifycert,
                                   debug=mDebug)
        if gv._DEBUG:
            print("f(x) pushToMISP(): PUSHING EVENT TO MISP: {}".format(event))

        # NEW EVENT
        if iUpdate == False:
            event.publish()
            event = mispDB.add_event(event, pythonify=True)
        else:
            event.publish()
            event = mispDB.update_event(event, pythonify=True)
    except Exception as e:
        if gv._DEBUG:
            print("f(x) pushToMISP() ERROR: {}".format(e))
        pass
    finally:
        print("f(x) pushToMISP: CREATED MISP EVENT: {}".format(event.info))
        return True
Exemple #6
0
def init():
    # If we have an old settings.py file then this variable won't exist
    global valid_attribute_distributions
    try:
        valid_attribute_distributions = valid_attribute_distribution_levels
    except Exception:
        valid_attribute_distributions = ['0', '1', '2', '3', '4', '5']
    return pymisp.ExpandedPyMISP(url, key, ssl)
Exemple #7
0
def run(
    config: Subview,
    logging: Subview,
    inq: JoinableQueue,
    subscribe_callback: Callable,
    unsubscribe_callback: Callable,
):
    global logger, filter_config, workers
    logger = threatbus.logger.setup(logging, __name__)
    config = config[plugin_name]
    try:
        validate_config(config)
    except Exception as e:
        logger.fatal("Invalid config for plugin {}: {}".format(
            plugin_name, str(e)))

    filter_config = config["filter"].get(list)

    # start Attribute-update receiver
    if config["zmq"].get():
        workers.append(ZmqReceiver(config["zmq"], inq))
    elif config["kafka"].get():
        workers.append(KafkaReceiver(config["kafka"], inq))

    # bind to MISP
    if config["api"].get(dict):
        # TODO: MISP instances shall subscribe themselves to threatbus and each
        # subscription shall have an individual outq and receiving thread for intel
        # updates.
        host, key, ssl = (
            config["api"]["host"].get(),
            config["api"]["key"].get(),
            config["api"]["ssl"].get(),
        )
        try:
            global misp, lock
            lock.acquire()
            misp = pymisp.ExpandedPyMISP(url=host, key=key, ssl=ssl)
            lock.release()
        except Exception:
            # TODO: log individual error per MISP subscriber
            logger.error(
                f"Cannot subscribe to MISP at {host}, using SSL: {ssl}")
            lock.release()
        if not misp:
            logger.error("Failed to start MISP plugin")
            return
    else:
        logger.warning(
            "Starting MISP plugin without API connection, cannot report back sightings or request snapshots."
        )

    outq = JoinableQueue()
    subscribe_callback("stix2/sighting", outq)
    workers.append(SightingsPublisher(outq))
    for w in workers:
        w.start()
    logger.info("MISP plugin started")
Exemple #8
0
    def __init__(self):
        self.misp_backend = pymisp.ExpandedPyMISP(
            OCD_DTL_MISP_HOST,
            OCD_DTL_MISP_API_KEY,
            ssl=OCD_DTL_MISP_USE_SSL,
            timeout=60,
        )

        # Init a common thread pool to run sync operation in background
        self.thread_pool = concurrent.futures.ThreadPoolExecutor(max_workers=OCD_DTL_MISP_WORKER)
Exemple #9
0
def getOrgEvents(iOrgID):
    try:
        misp = pm.ExpandedPyMISP(gv._MISP_URL, gv._MISP_KEY,
                                 gv._MISP_VERIFYCERT)
        kwargs = {"org_id": iOrgID}
        # result = misp.search('events', published=0, **kwargs)
        result = misp.search('events', published=1, **kwargs)
        return result

    except Exception as e:
        print(e)
Exemple #10
0
def connect_misp(host: str, key: str, ssl: bool):
    """
    Connects to a MISP instance. Returns the pymisp.MISP object.
    @param host The MISP URL to connect to
    @param key The MISP API key
    @param ssl Boolean flag to use SSL
    """
    try:
        return pymisp.ExpandedPyMISP(url=host, key=key, ssl=ssl)
    except Exception:
        logger.critical(
            f"Cannot connect to MISP at '{host}', using SSL '{ssl}'")
Exemple #11
0
def run(
    config: DynaBox,
    logging: DynaBox,
    inq: JoinableQueue,
    subscribe_callback: Callable,
    unsubscribe_callback: Callable,
):
    global logger, filter_config, workers
    logger = threatbus.logger.setup(logging, __name__)
    assert plugin_name in config, f"Cannot find configuration for {plugin_name} plugin"
    config = config[plugin_name]

    filter_config = config.filter if "filter" in config else {}

    # start Attribute-update receiver
    if "zmq" in config:
        workers.append(ZmqReceiver(config.zmq, inq))
    elif "kafka" in config:
        workers.append(KafkaReceiver(config.kafka, inq))

    # bind to MISP
    if "api" in config:
        # TODO: MISP instances shall subscribe themselves to threatbus and each
        # subscription shall have an individual outq and receiving thread for intel
        # updates.
        try:
            global misp, lock
            lock.acquire()
            misp = pymisp.ExpandedPyMISP(
                url=config.api.host, key=config.api.key, ssl=config.api.ssl
            )
            lock.release()
        except Exception:
            # TODO: log individual error per MISP subscriber
            logger.error(
                f"Cannot subscribe to MISP at {config.api.host}, using SSL: {config.api.ssl}"
            )
            lock.release()
        if not misp:
            logger.error("Failed to start MISP plugin")
            return
    else:
        logger.warning(
            "Starting MISP plugin without API connection, cannot report back sightings or request snapshots."
        )

    outq = JoinableQueue()
    subscribe_callback("stix2/sighting", outq)
    workers.append(SightingsPublisher(outq))
    for w in workers:
        w.start()
    logger.info("MISP plugin started")
    def __init__(self, url, key, ssl=True, name='Unnamed', proxies=None):
        self.misp_connections = []
        if type(url) is list:
            for idx, server in enumerate(url):
                verify = True

                # Given ssl parameter is a list
                if isinstance(ssl, list):
                    if isinstance(ssl[idx], str) and os.path.isfile(ssl[idx]):
                        verify = ssl[idx]
                    elif isinstance(ssl[idx], str) and not os.path.isfile(ssl[idx]) and ssl[idx] != "":
                        raise CertificateNotFoundError('Certificate not found under {}.'.format(ssl[idx]))
                    elif isinstance(ssl[idx], bool):
                        verify = ssl[idx]

                # Do the same checks again, for the non-list type
                elif isinstance(ssl, str) and os.path.isfile(ssl):
                    verify = ssl
                elif isinstance(ssl, str) and not os.path.isfile(ssl) and ssl != "":
                    raise CertificateNotFoundError('Certificate not found under {}.'.format(ssl))
                elif isinstance(ssl, bool):
                    verify = ssl
                self.misp_connections.append(pymisp.ExpandedPyMISP(url=server,
                                                                   key=key[idx],
                                                                   ssl=verify,
                                                                   proxies=proxies))
        else:
            verify = True
            if isinstance(ssl, str) and os.path.isfile(ssl):
                verify = ssl
            elif isinstance(ssl, str) and not os.path.isfile(ssl) and ssl != "":
                raise CertificateNotFoundError('Certificate not found under {}.'.format(ssl))
            elif isinstance(ssl, bool):
                verify = ssl
            self.misp_connections.append(pymisp.ExpandedPyMISP(url=url,
                                                               key=key,
                                                               ssl=verify,
                                                               proxies=proxies))
        self.misp_name = name
Exemple #13
0
    def __init__(self, configfile):
        self.load_config(configfile)
        if not self.config['verify_ssl']:
            import urllib3
            urllib3.disable_warnings()
#            logging.warning('InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings')
        try:
            self.misp = pymisp.ExpandedPyMISP(self.config['url'], self.config['key'], self.config['verify_ssl'])
#        except TimeoutError:
#            logging.error("Timeout error connecting to MISP instance")
#            sys.exit(1)
#        except OSError as e:
#            print(e)
        except pymisp.exceptions.PyMISPError as e:
            logging.error(e)
            sys.exit(1)
Exemple #14
0
def uuidSearch(iUUID):
    try:
        retVal = 0
        mispDB = pm.ExpandedPyMISP(url=gv._MISP_URL,
                                   key=gv._MISP_KEY,
                                   ssl=gv._MISP_VERIFYCERT,
                                   debug=gv._DEBUG)
        kwargs = {"uuid": iUUID}
        result = mispDB.search(controller='events',
                               return_format='json',
                               limit=1,
                               **kwargs)
        retVal = int(len(result))
        return retVal
    except Exception as e:
        print(e)
Exemple #15
0
def run(config, logging, inq, subscribe_callback, unsubscribe_callback):
    global logger
    logger = threatbus.logger.setup(logging, __name__)
    config = config[plugin_name]
    try:
        validate_config(config)
    except Exception as e:
        logger.fatal("Invalid config for plugin {}: {}".format(
            plugin_name, str(e)))
    if config["api"].get():
        host, key, ssl = (
            config["api"]["host"].get(),
            config["api"]["key"].get(),
            config["api"]["ssl"].get(),
        )
        try:
            global misp, lock
            lock.acquire()
            misp = pymisp.ExpandedPyMISP(url=host, key=key, ssl=ssl)
            lock.release()
        except Exception:
            # TODO: log individual error per MISP subscriber
            logger.error(
                f"Cannot subscribe to MISP at {host}, using SSL: {ssl}")
            lock.release()

    # TODO: MISP instances shall subscribe themselves to threatbus and each subscription shall have an individual outq and receiving thread for intel updates.
    outq = Queue()
    subscribe_callback("threatbus/sighting", outq)

    if misp:
        threading.Thread(target=publish_sightings, args=(outq, ),
                         daemon=True).start()
    if config["zmq"].get():
        threading.Thread(target=receive_zmq,
                         args=(config["zmq"], inq),
                         daemon=True).start()
    if config["kafka"].get():
        threading.Thread(target=receive_kafka,
                         args=(config["kafka"], inq),
                         daemon=True).start()
    logger.info("MISP plugin started")
Exemple #16
0
def main(args):
    logging.info('Passing through misp_exporter')
    with open(args.fingerprint) as file:
        try:
            data = json.load(file)
        except Exception:
            logging.error('Fingerprint not compatible.')
            return
    misp = pymisp.ExpandedPyMISP(args.misp_url,
                                 args.misp_key,
                                 ssl=False,
                                 debug=True)
    event = pymisp.MISPEvent(strict_validation=True)
    event.info = args.event_info
    event.distribution = args.distribution
    event.threat_level_id = args.threat_level
    event.analysis = args.analysis_level
    event.add_tag(tag='validated')
    ddos = pymisp.MISPObject('ddos', strict=True)
    logging.info('Fingerprint processed: {}'.format(args.fingerprint))
    if 'attack_vector' in data:
        av = data['attack_vector'][0]
        snort = {
            'protocol': [],
            'src_ip': [],
            'src_port': [],
            'dst_port': [],
            'options': [],
        }
        df = find_ips(av)
        logging.info('IPs found: {}'.format(len(df['ip'])))
        subnets = utils.smart_aggregate(df)
        logging.info('The IPs were summarized in: {} subnets'.format(
            len(subnets)))
        if args.subnets:
            add_attributes(event, subnets, 'ip-src', 'attacker subnet')
            ddos.add_attributes('ip-src', *subnets)
            snort['src_ip'] += subnets
        else:
            add_attributes(event, df['ip'], 'ip-src', 'attacker ip')
            ddos.add_attributes('ip-src', *df['ip'])
            snort['src_ip'] += df['ip'].tolist()
        if 'srcport' in av:
            sport = find_attr(av['srcport'], 'srcport')
            add_attributes(event, sport['srcport'], 'port',
                           'source port of attack')
            ddos.add_attributes('src-port', *sport['srcport'])
            snort['src_port'] += sport['srcport'].tolist()
        if 'dstport' in av:
            dport = find_attr(av['dstport'], 'dstport')
            add_attributes(event, dport['dstport'], 'port',
                           'destination port of attack')
            ddos.add_attributes('dst-port', *sport['dstport'])
            snort['dst_port'] += sport['dstport']
        if 'ip_proto' in av:
            proto4 = find_attr(av['ip_proto'], 'ip_proto')
            add_attributes(event, proto4['ip_proto'], 'other',
                           '4 level protocol of attack')
            ddos.add_attributes('protocol', *proto4['ip_proto'])
            snort['protocol'] += proto4['ip_proto'].tolist()
        if 'dns_qry_name' in av:
            snort['options'] += snort_content(av['dns_qry_name'])
        if 'http_request' in av:
            snort['options'] += snort_content(av['http_request'])
        if 'http_response' in av:
            snort['options'] += snort_content(av['http_response'])
        if 'http_user_agent' in av:
            snort['options'] += snort_content(av['http_user_agent'])
        if 'icmp_type' in av:
            snort['options'] += snort_itype(av['icmp_type'])
        if 'icmp_code' in av:
            snort['options'] += snort_icode(av['icmp_code'])
        if 'ip_ttl' in av:
            snort['options'] += snort_ttl(av['ip_ttl'])
        if 'ntp_priv_reqcode' in av:
            snort['options'] += snort_content(av['ntp_priv_reqcode'])
        if 'tcp_flags' in av:
            snort['options'] += snort_flags(av['tcp_flags'])
        if 'tags' in av:
            for tag in av['tags']:
                event.add_tag(tag=tag)
        if 'duration_sec' in av:
            add_attribute_comment(event, 'duration_sec', av['duration_sec'])
        if 'total_dst_ports' in av:
            add_attribute_comment(event, 'total_dst_ports',
                                  av['total_dst_ports'])
        if 'total_ips' in av:
            add_attribute_comment(event, 'total_ips', av['total_ips'])
        if 'total_packets' in av:
            add_attribute_comment(event, 'total_packets', av['total_packets'])
        add_attribute_snort(event, snort)
        event.add_tag(tag='ddos attack')
    if 'amplifiers' in data:
        amp = data['amplifiers'][0]
        dfa = find_ips(amp)
        logging.info('Amplifier IPs found: {}'.format(len(dfa['ip'])))
        subnetsa = utils.smart_aggregate(dfa)
        logging.info('The IPs were summarized in: {} subnets'.format(
            len(subnetsa)))
        if args.subnets:
            add_attributes(event, subnetsa, 'ip-src', 'amplifier subnet')
            for elem in subnetsa:
                ddos.add_attribute('ip-src', elem, to_ids=0)
        else:
            add_attributes(event, dfa['ip'], 'ip-src', 'amplifier ip')
            for elem in dfa['ip']:
                ddos.add_attribute('ip-src', elem, to_ids=0)
        event.add_tag(tag='ddos amplification attack')
    p = pathlib.Path(args.fingerprint)
    comment = 'DDoS fingerprint json file generated by dissector'
    event.add_attribute(type='attachment',
                        value=p.name,
                        data=p,
                        comment=comment)
    event.add_object(ddos, pythonify=True)
    event = misp.add_event(event, pythonify=True)
Exemple #17
0
def run(
    analyzer_name,
    job_id,
    observable_name,
    observable_classification,
    additional_config_params,
):
    logger.info(
        "started analyzer {} job_id {} observable {}"
        "".format(analyzer_name, job_id, observable_name)
    )
    report = general.get_basic_report_template(analyzer_name)
    try:
        api_key_name = additional_config_params.get("api_key_name", "MISP_KEY")
        api_key = secrets.get_secret(api_key_name)
        if not api_key:
            raise AnalyzerRunException(
                "no MISP API key retrieved, key value: {}".format(api_key_name)
            )

        url_key_name = additional_config_params.get("url_key_name", "MISP_URL")
        url_name = secrets.get_secret(url_key_name)
        if not url_name:
            raise AnalyzerRunException(
                "no MISP URL retrieved, key value: {}".format(url_key_name)
            )

        misp_instance = pymisp.ExpandedPyMISP(url_name, api_key)  # debug=True)

        # we check only for events not older than 90 days and max 50 results
        now = datetime.datetime.now()
        date_from = now - datetime.timedelta(days=90)
        params = {
            # even if docs say to use "values",...
            # .. at the moment it works correctly only with "value"
            "value": observable_name,
            "type_attribute": [observable_classification],
            "date_from": date_from.strftime("%Y-%m-%d %H:%M:%S"),
            "limit": 50,
            "enforce_warninglist": True,
        }
        if observable_classification == "hash":
            params["type_attribute"] = ["md5", "sha1", "sha256"]
        result_search = misp_instance.search(**params)
        if isinstance(result_search, dict):
            errors = result_search.get("errors", [])
            if errors:
                raise AnalyzerRunException(errors)
        report_to_give = {"result_search": result_search, "instance_url": url_name}
        report["report"] = report_to_give
    except AnalyzerRunException as e:
        error_message = (
            "job_id:{} analyzer:{} observable_name:{} Analyzer error {}"
            "".format(job_id, analyzer_name, observable_name, e)
        )
        logger.error(error_message)
        report["errors"].append(error_message)
        report["success"] = False
    except Exception as e:
        traceback.print_exc()
        error_message = (
            "job_id:{} analyzer:{} observable_name:{} Unexpected error {}"
            "".format(job_id, analyzer_name, observable_name, e)
        )
        logger.exception(error_message)
        report["errors"].append(str(e))
        report["success"] = False
    else:
        report["success"] = True

    general.set_report_and_cleanup(job_id, report)
    # pprint.pprint(report)

    logger.info(
        "ended analyzer {} job_id {} observable {}"
        "".format(analyzer_name, job_id, observable_name)
    )

    return report
Exemple #18
0
def create_events(pulse_or_list, author=False, server=False, key=False, misp=False, blacklist_file = None, distribution=0, threat_level=4,
                  analysis=2, publish=True, tlp=True, discover_tags=False, to_ids=False, author_tag=False,
                  bulk_tag=None, dedup_titles=False, stop_on_error=False):
    """
    Parse a Pulse or a list of Pulses and add it/them to MISP if server and key are present

    :param pulse_or_list: a Pulse or list of Pulses as returned by `get_pulses`
    :param author: Prepend the author to the Pulse name
    :type author: Boolean
    :param server: MISP server URL
    :param key: MISP API key
    :param misp: MISP connection object
    :type misp: :class:`pymisp.PyMISP`
    :param blacklist_file: The name of a file containing a list of pulse title regexes for pulses taht should be ignored
    :type blacklist_file: String
    :param distribution: distribution of the MISP event (0-4)
    :param threat_level: threat level of the MISP object (1-4)
    :param analysis: analysis stae of the MISP object (0-2)
    :param publish: Is the MISP event should be published?
    :type publish: Boolean
    :param tlp: Add TLP level tag to event
    :type tlp: Boolean
    :param discover_tags: discover MISP tags from Pulse tags
    :type discover_tags: Boolean
    :param to_ids: Flag pulse attributes as being sent to an IDS
    :type to_ids: Boolean
    :param author_tag: Add the pulse author as an event tag
    :type author_tag: Boolean
    :param bulk_tag: A tag that will be added to all events for categorization (e.g. OTX)
    :type bulk_tag: String
    :param dedup_titles: Search MISP for an existing event title and update it, rather than create a new one
    :type dedup_titles: Boolean
    :return: a dict or a list of dict with the selected attributes
    """
    if not misp and (server and key):
        log.debug("Connection to MISP instance: {}".format(server))
        try:
            misp = pymisp.ExpandedPyMISP(server, key, ssl=False)
        except pymisp.PyMISPError as ex:
            raise ImportException("Cannot connect to MISP instance: {}".format(ex.message))
        except Exception as ex:
            raise ImportException("Cannot connect to MISP instance, unknown exception: {}".format(ex.message))
          
    # Let's load the list of blacklisted pulse titles, if exists
    global _otx_blacklisted_titles
    if blacklist_file and not _otx_blacklisted_titles:
        if not os.path.isfile(blacklist_file):
            log.warn("The blacklisted pulse titles file that has been provided does not exist: {}".format(blacklist_file))
        else:
            with open(blacklist_file) as f:
                lines = f.read().splitlines()
            for line in lines:
                if line != "":
                    _otx_blacklisted_titles.append(re.compile(line))
                
    # Let's load in cache all MISP tags available on the instance
    global _otx_tags_cache
    if _otx_tags_cache is None:
        _otx_tags_cache = misp.tags()

    if discover_tags:
        def get_tag_name(complete):
            parts = complete.split('=')
            if not len(parts):
                return complete
            last = parts[-1]
            if not len(last):
                return complete
            if last[0] == '"':
                last = last[1:]
            if last[-1] == '"':
                last = last[:-1]
            return last.lower()
        tags = dict()
        for tag in _otx_tags_cache:
            tags[get_tag_name(tag['name'])] = tag['name']
        misp.discovered_tags = tags

    if isinstance(pulse_or_list, (list, tuple)) or inspect.isgenerator(pulse_or_list):
        misp_events = []
        for pulse in pulse_or_list:
            try:
                misp_event = create_events(pulse, author=author, server=server, key=key, misp=misp,
                                           distribution=distribution, threat_level=threat_level, analysis=analysis,
                                           publish=publish, tlp=tlp, to_ids=to_ids, author_tag=author_tag,
                                           bulk_tag=bulk_tag, dedup_titles=dedup_titles, stop_on_error=stop_on_error)
                if misp_event:
                    misp_events.append(misp_event)
            except Exception as ex:
                if stop_on_error:
                    raise
                name = ''
                if pulse and 'name' in pulse:
                    name = pulse['name']
                log.error("Cannot import pulse {}: {}".format(name, ex))
        return misp_events

    pulse = pulse_or_list
    if author:
        event_name = pulse['author_name'] + ' | ' + pulse['name']
    else:
        event_name = pulse['name']
    event_name = event_name.strip()
    try:
        dt = date_parser.parse(pulse['created'])
    except (ValueError, OverflowError):
        log.error("Cannot parse Pulse 'created' date.")
        dt = datetime.utcnow()
    event_date = dt.strftime('%Y-%m-%d')
    
    # Let's ignore the pulse if its title is blacklisted
    for regex in _otx_blacklisted_titles:
        if regex.match(pulse['name']):
                log.info("## *** IGNORED *** {name} - {date}".format(name=event_name, date=event_date))
                return None
    log.info("## {name} - {date}".format(name=event_name, date=event_date))
    result_event = {
        'name': event_name,
        'date': event_date,
        'tags': list(),
        'attributes': {
            'hashes': {
                'md5': list(),
                'sha1': list(),
                'sha256': list(),
                'imphash': list(),
                'pehash': list()
            },
            'hostnames': list(),
            'domains': list(),
            'urls': list(),
            'ips': list(),
            'emails': list(),
            'mutexes': list(),
            'references': list(),
            'cves': list(),
            'filenames': list(),
            'yara': list()
        },
    }

    if misp:
        if not dedup_titles:
            event = pymisp.MISPEvent()
            event.distribution = distribution
            event.threat_level_id = threat_level
            event.analysis = analysis
            event.info = event_name
            event.date = dt
            event = misp.add_event(event)['Event']
        else:
            event = ''
            # Search MISP for the title
            result = misp.search(eventinfo=event_name, metadata=True)
            if len(result) == 0:
                event = pymisp.MISPEvent()
                event.distribution = distribution
                event.threat_level = threat_level
                event.analysis = analysis
                event.info = event_name
                event.set_date(dt)
                event = misp.add_event(event)['Event']
            else:
                for evt in result:
                    # If it exists, set 'event' to the event
                    if evt['Event']['info'] == event_name:
                        if 'SharingGroup' in evt['Event']:
                            del evt['Event']['SharingGroup']  # This deletes the SharingGroup from the list, thx SparkyNZL
                        event = evt['Event']
                        break
                if event == '':
                    # Event not found, even though search results were returned
                    # Build new event
                    event = pymisp.MISPEvent()
                    event.distribution = distribution
                    event.threat_level = threat_level
                    event.analysis = analysis
                    event.info = event_name
                    event.set_date(dt)
                    misp.add_event(event)
        time.sleep(0.2)
        if tlp:
            tag = None
            if 'TLP' in pulse:
                tag = "tlp:{}".format(pulse['TLP'])
            elif 'tlp' in pulse:
                tag = "tlp:{}".format(pulse['tlp'])
            if tag is not None:
                log.info("\t - Adding tag: {}".format(tag))
                tag_event(misp, event, tag)
                result_event['tags'].append(tag)

        if author_tag:
            tag_event(misp, event, pulse['author_name'])

        if bulk_tag is not None:
            tag_event(misp, event, bulk_tag)

    if misp and hasattr(misp, 'discovered_tags') and 'tags' in pulse:
        for pulse_tag in pulse['tags']:
            if pulse_tag.lower() in misp.discovered_tags:
                tag = misp.discovered_tags[pulse_tag.lower()]
                log.info("\t - Adding tag: {}".format(tag))
                tag_event(misp, event, tag)
                result_event['tags'].append(tag)
                
    if 'references' in pulse:
        for reference in pulse['references']:
            if reference:
                log.info("\t - Adding external analysis link: {}".format(reference))
                if misp:
                    a = pymisp.MISPAttribute()
                    a.category = "External analysis"
                    a.type = 'link'
                    a.value = reference
                    add_attribute(misp, event, a)
                result_event['attributes']['references'].append(reference)

    if misp and 'description' in pulse and isinstance(pulse['description'], six.text_type) and pulse['description']:
        log.info("\t - Adding external analysis comment")
        a = pymisp.MISPAttribute()
        a.category = 'External analysis'
        a.type = 'comment'
        a.value = pulse['description']
        add_attribute(misp, event, a)

    for ind in pulse['indicators']:
        ind_type = ind['type']
        ind_val = ind['indicator']
        a = pymisp.MISPAttribute()        
        a.value = ind_val
        a.to_ids = to_ids

        if 'description' in ind and isinstance(ind['description'], six.text_type) and ind['description']:
            a.comment = ind['description']
            
        if ind_type == 'FileHash-SHA256':
            log.info("\t - Adding SHA256 hash: {}".format(ind_val))
            a.category = 'Artifacts dropped'            
            a.type = 'sha256'
            add_attribute(misp, event, a)                        
            result_event['attributes']['hashes']['sha256'].append(ind_val)

        elif ind_type == 'FileHash-SHA1':
            log.info("\t - Adding SHA1 hash: {}".format(ind_val))
            a.category = 'Artifacts dropped'                        
            a.type = 'sha1'
            add_attribute(misp, event, a)                        
            result_event['attributes']['hashes']['sha1'].append(ind_val)

        elif ind_type == 'FileHash-MD5':
            log.info("\t - Adding MD5 hash: {}".format(ind_val))
            a.category = 'Artifacts dropped'                        
            a.type = 'md5'
            add_attribute(misp, event, a)                        
            result_event['attributes']['hashes']['md5'].append(ind_val)

        elif ind_type == 'FileHash-IMPHASH':
            log.info("\t - Adding IMPHASH hash: {}".format(ind_val))
            a.category = 'Artifacts dropped'                        
            a.type = 'imphash'
            add_attribute(misp, event, a)                        
            result_event['attributes']['hashes']['imphash'].append(ind_val)

        elif ind_type == 'FileHash-PEHASH':
            log.info("\t - Adding PEHASH hash: {}".format(ind_val))
            a.category = 'Artifacts dropped'                                    
            a.type = 'pehash'
            add_attribute(misp, event, a)                        
            result_event['attributes']['hashes']['pehash'].append(ind_val)
            
        elif ind_type == 'YARA':
            ind_title = ind.get('title', ind_val)
            ind_desc = ind.get('description', '')
            if ind_title == '':
                ind_title = ind_val
                if not ind_desc == '':
                    a.comment = ind_desc
            else:
                a.comment = "{} {}".format(ind_title, ind_desc)
            ind_val = ind.get('content', None)
            if ind_val is None or ind_val == "":
                log.warning("YARA indicator is empty: %s" % ind_title)
                continue
            log.info("\t - Adding YARA rule: {}".format(ind_title))
            a.category = 'Artifacts dropped'                                    
            a.type = 'yara'
            a.value = ind_val
            add_attribute(misp, event, a)                        
            result_event['attributes']['yara'].append({'title': ind_title, 'content': ind_val})

        elif ind_type == 'Mutex':
            log.info("\t - Adding mutex: {}".format(ind_val))
            a.category = 'Artifacts dropped'                                    
            a.type = 'mutex'
            add_attribute(misp, event, a)                        
            result_event['attributes']['mutexes'].append(ind_val)

        elif ind_type == 'FilePath':
            log.info("\t - Adding filename: {}".format(ind_val))
            a.category = 'Artifacts dropped'                                    
            a.type = 'filename'
            add_attribute(misp, event, a)                        
            result_event['attributes']['filenames'].append(ind_val)
            
        elif ind_type == 'URI' or ind_type == 'URL':
            log.info("\t - Adding URL: {}".format(ind_val))
            a.category = 'Network activity'            
            a.type = 'url'
            add_attribute(misp, event, a)                        
            result_event['attributes']['urls'].append(ind_val)

        elif ind_type == 'domain':
            log.info("\t - Adding domain: {}".format(ind_val))
            a.category = 'Network activity'                        
            a.type = 'domain'
            add_attribute(misp, event, a)                        
            result_event['attributes']['domains'].append(ind_val)

        elif ind_type == 'hostname':
            log.info("\t - Adding hostname: {}".format(ind_val))
            a.category = 'Network activity'                        
            a.type = 'hostname'
            add_attribute(misp, event, a)                        
            result_event['attributes']['hostnames'].append(ind_val)

        elif ind_type == 'IPv4' or ind_type == 'IPv6':
            log.info("\t - Adding ip: {}".format(ind_val))
            a.category = 'Network activity'                        
            a.type = 'ip-dst'
            add_attribute(misp, event, a)                        
            result_event['attributes']['ips'].append(ind_val)

        elif ind_type == 'email':
            log.info("\t - Adding email: {}".format(ind_val))
            a.category = 'Network activity'                        
            a.type = 'email-dst'
            result_event['attributes']['emails'].append(ind_val)
            add_attribute(misp, event, a)                        

        elif ind_type == 'CVE':
            log.info("\t - Adding CVE: {}".format(ind_val))
            a.type = 'External analysis'
            a.type = 'vulnerability'
            add_attribute(misp, event, a)            
            result_event['attributes']['cves'].append(ind_val)
            
        else:
            log.warning("Unsupported indicator type: %s" % ind_type)

    if misp and publish:
        misp.publish(event)
    return result_event
Exemple #19
0
def pushToMISPWithAttachment(event,
                             iPath,
                             iUpdate=False,
                             mURL="",
                             mKey="",
                             mVerifycert="",
                             mDebug="",
                             fo=None,
                             peo=None,
                             seos=None):
    try:
        mispDB = pm.ExpandedPyMISP(url=mURL,
                                   key=mKey,
                                   ssl=mVerifycert,
                                   debug=mDebug)
        if gv._DEBUG:
            print("f(x) pushToMISPWithAttachment() EVENT: {}".format(event))
        # CREATE EVENT
        if iUpdate == False:
            event.publish()
            mispDB.add_event(event, pythonify=True)
        else:
            event.publish()
            mispDB.update_event(event, pythonify=True)

        # # ADD ATTACHMENT
        if iUpdate == False:
            #     myPath = iPath
            #     fo = None
            #     peo = None
            #     seos = None

            # for f in glob.glob(myPath):
            # try:
            #     fo , peo, seos = make_binary_objects(f)
            # except Exception as e:
            #     continue
            if seos:
                try:
                    for s in seos:
                        try:
                            mispDB.add_object(event.uuid, s)
                        except Exception as e:
                            continue
                except Exception as e:
                    pass
            if peo:
                try:
                    mispDB.add_object(event.uuid, peo, pythonify=True)
                    for ref in peo.ObjectReference:
                        try:
                            mispDB.add_object_reference(ref)
                        except Exception as e:
                            continue
                except Exception as e:
                    pass
            if fo:
                try:
                    mispDB.add_object(event.uuid, fo)
                    for ref in fo.ObjectReference:
                        try:
                            mispDB.add_object_reference(ref, pythonify=True)
                        except Exception as e:
                            continue
                except Exception as e:
                    pass

            # UPDATE EVENT AFTER ADDING ATTACHMENT
            try:
                event.publish()
                mispDB.publish(event)
                print("f(x) pushToMISPWithAttachment: CREATED MISP EVENT: {}".
                      format(event.info))
            except Exception as e:
                pass
    except Exception as e:
        if gv._DEBUG:
            print("f(x) pushToMISPWithAttachment() ERROR: {}".format(e))
        pass
        # gv._THREAD_LIST.append(uexecutor.submit(pushToMISPWithAttachment,event, iPath, iUpdate, mURL, mKey, mVerifycert, mDebug, fo, peo, seos))
    finally:
        return True
Exemple #20
0
    def run(self, results):
        """Run analysis.
        @return: MISP results dict.
        """

        url = self.options.get("url", "")
        apikey = self.options.get("apikey", "")

        if not url or not apikey:
            log.error("MISP URL or API key not configured.")
            return

        self.misp = pymisp.ExpandedPyMISP(url, apikey, False, "json")

        self.threads = self.options.get("threads", "")
        if not self.threads:
            self.threads = 5

        self.iocs = deque()
        self.misper = dict()

        try:
            if self.options.get("upload_iocs", False) and results.get(
                    "malscore", 0) >= self.options.get("min_malscore", 0):
                distribution = int(self.options.get("distribution", 0))
                threat_level_id = int(self.options.get("threat_level_id", 4))
                analysis = int(self.options.get("analysis", 0))
                tag = self.options.get("tag") or "CAPEv2"
                info = self.options.get("title", "")
                upload_sample = self.options.get("upload_sample")

                malfamily = ""
                if results.get("detections", ""):
                    malfamily = results["detections"]

                event = MISPEvent()
                response = self.misp.search(
                    "attributes",
                    value=results["target"]["file"]["sha256"],
                    return_format="json")
                if response.get("Attribute", []):
                    res = self.misp.get_event(
                        response["Attribute"][0]["event_id"])["Event"]
                    event.load(res)
                else:
                    event.distribution = distribution
                    event.threat_level_id = threat_level_id
                    event.analysis = analysis
                    event.info = "{} {} - {}".format(
                        info, malfamily,
                        results.get('info', {}).get('id'))
                    event = self.misp.add_event(event, pythonify=True)

                # Add a specific tag to flag Cuckoo's event
                if tag:
                    self.misp.tag(event["uuid"], tag)

                #ToDo?
                self.signature(results, event)

                self.sample_hashes(results, event)
                self.all_network(results, event)
                self.dropped_files(results, event)

                #DeprecationWarning: Call to deprecated method upload_samplelist. (Use MISPEvent.add_attribute with the expand='binary' key)
                if upload_sample:
                    target = results.get("target", {})
                    f = target.get("file", {})
                    if target.get("category") == "file" and f:
                        with open(f["path"], 'rb') as f:
                            event.add_attribute(
                                'malware-sample',
                                value=os.path.basename(f["path"]),
                                data=BytesIO(f.read()),
                                expand='binary',
                                comment="Sample run",
                            )

                if results.get("target", {}).get(
                        "url",
                        "") and results["target"]["url"] not in whitelist:
                    self.misp.add_named_attribute(event, 'url',
                                                  [results["target"]["url"]])

                # ToDo migth be outdated!
                #if self.options.get("ids_files", False) and "suricata" in results.keys():
                #    for surifile in results["suricata"]["files"]:
                #        if "file_info" in surifile.keys():
                #            self.misper["iocs"].append({"md5": surifile["file_info"]["md5"]})
                #            self.misper["iocs"].append({"sha1": surifile["file_info"]["sha1"]})
                #            self.misper["iocs"].append({"sha256": surifile["file_info"]["sha256"]})

                if self.options.get(
                        "mutexes", False
                ) and "behavior" in results and "summary" in results[
                        "behavior"]:
                    if "mutexes" in results.get("behavior",
                                                {}).get("summary", {}):
                        for mutex in results["behavior"]["summary"]["mutexes"]:
                            if mutex not in whitelist:
                                self.misp.add_mutex(event, mutex)

                if self.options.get(
                        "registry", False
                ) and "behavior" in results and "summary" in results[
                        "behavior"]:
                    if "read_keys" in results["behavior"].get("summary", {}):
                        for regkey in results["behavior"]["summary"][
                                "read_keys"]:
                            self.misp.add_regkey(event, regkey)

                #Make event public
                if self.options.get("published", True):
                    event.published = True
                    self.misp.publish(event)

        except Exception as e:
            log.error("Failed to generate JSON report: %s" % e, exc_info=True)
Exemple #21
0
 def __init__(self):
     self.misp = pymisp.ExpandedPyMISP(MISP_URL, MISP_KEY, False)