예제 #1
0
class MISPCollectorBot(CollectorBot):

    def init(self):
        if PyMISP is None:
            self.logger.error('Could not import pymisp. Please install it.')
            self.stop()

        # Initialise MISP connection
        self.misp = PyMISP(self.parameters.misp_url,
                           self.parameters.misp_key,
                           self.parameters.misp_verify)

        # URLs used for deleting and adding MISP event tags
        self.misp_add_tag_url = urljoin(self.parameters.misp_url,
                                        'events/addTag')
        self.misp_del_tag_url = urljoin(self.parameters.misp_url,
                                        'events/removeTag')

    def process(self):
        # Grab the events from MISP
        misp_result = self.misp.search(
            tags=self.parameters.misp_tag_to_process
        )

        # Process the response and events
        if 'response' in misp_result:

            # Extract the MISP event details
            for e in misp_result['response']:
                misp_event = e['Event']

                # Send the results to the parser
                report = self.new_report()
                report.add('raw', json.dumps(misp_event, sort_keys=True))
                report.add('feed.url', self.parameters.misp_url)
                self.send_message(report)

            # Finally, update the tags on the MISP events.
            # Note PyMISP does not currently support this so we use
            # the API URLs directly with the requests module.

            for misp_event in misp_result['response']:
                # Remove the 'to be processed' tag
                self.misp.remove_tag(misp_event,
                                     self.parameters.misp_tag_to_process)

                # Add a 'processed' tag to the event
                self.misp.add_tag(misp_event,
                                  self.parameters.misp_tag_processed)
예제 #2
0
class MISPCollectorBot(CollectorBot):
    def init(self):
        if PyMISP is None:
            self.logger.error('Could not import pymisp. Please install it.')
            self.stop()

        # Initialise MISP connection
        self.misp = PyMISP(self.parameters.misp_url, self.parameters.misp_key,
                           self.parameters.misp_verify)

        # URLs used for deleting and adding MISP event tags
        self.misp_add_tag_url = urljoin(self.parameters.misp_url,
                                        'events/addTag')
        self.misp_del_tag_url = urljoin(self.parameters.misp_url,
                                        'events/removeTag')

    def process(self):
        # Grab the events from MISP
        misp_result = self.misp.search(
            tags=self.parameters.misp_tag_to_process)

        # Process the response and events
        if 'response' in misp_result:

            # Extract the MISP event details
            for e in misp_result['response']:
                misp_event = e['Event']

                # Send the results to the parser
                report = self.new_report()
                report.add('raw', json.dumps(misp_event, sort_keys=True))
                report.add('feed.url', self.parameters.misp_url)
                self.send_message(report)

            # Finally, update the tags on the MISP events.
            # Note PyMISP does not currently support this so we use
            # the API URLs directly with the requests module.

            for misp_event in misp_result['response']:
                # Remove the 'to be processed' tag
                self.misp.remove_tag(misp_event,
                                     self.parameters.misp_tag_to_process)

                # Add a 'processed' tag to the event
                self.misp.add_tag(misp_event,
                                  self.parameters.misp_tag_processed)
예제 #3
0
class generateEvents():
    # generates a seperate event for every paste with more than 1 parsed IOC, after initialising a connection with the MISP instance.

    def __init__(self, paste):
        self.paste = paste
        self.url = MISP_URL
        self.key = MISP_KEY

    def initMISP(self):
        self.misp = PyMISP(self.url, self.key, False, 'json', debug=True)

    def addEvents(self):
        for i in range(len(self.paste)):
            if len(self.paste[i].iocs) != 0:
                logging.debug(
                    "Paste: {}, # of IOCs: {}. Creating an event.".format(
                        self.paste[i].title, len(self.paste[i].iocs)))
                event = self.misp.new_event(distribution=2,
                                            analysis=2,
                                            info=self.paste[i].title)
                self.misp.add_internal_link(event,
                                            self.paste[i].URI,
                                            category="External analysis")
                self.misp.add_tag(event, "Type:OSINT")
                self.misp.add_tag(event, 'osint:source-type="pastie-website"')
                self.misp.add_tag(event, 'OSINT')
                self.misp.add_tag(event, 'tlp:white')

                for j in range(len(self.paste[i].iocs)):
                    if self.paste[i].iocs[j].kind == "IP":
                        self.misp.add_ipsrc(event, self.paste[i].iocs[j].value)
                    elif self.paste[i].iocs[j].kind == "uri":
                        self.misp.add_url(event, self.paste[i].iocs[j].value)
                    elif self.paste[i].iocs[j].kind == "md5":
                        self.misp.add_hashes(event,
                                             md5=self.paste[i].iocs[j].value)
                    elif self.paste[i].iocs[j].kind == "sha1":
                        self.misp.add_hashes(event,
                                             sha1=self.paste[i].iocs[j].value)
                    elif self.paste[i].iocs[j].kind == "sha256":
                        self.misp.add_hashes(
                            event, sha256=self.paste[i].iocs[j].value)
                    elif self.paste[i].iocs[j].kind == "CVE":
                        #self.misp.add_object(event, 63, self.paste[i].iocs[j].value)
                        pass
                    if self.paste[i].iocs[j].kind == "email":
                        self.misp.add_email_src(event,
                                                self.paste[i].iocs[j].value)
                    if self.paste[i].iocs[j].kind == "filename":
                        self.misp.add_filename(event,
                                               self.paste[i].iocs[j].value)
                if PUBLISH_EVENTS:
                    self.misp.publish(event, alert=EMAIL_ALERTS)
예제 #4
0
class MISPHandler:

    def __init__(self, config: dict):
        self.url = config['misp_url']
        self.key = config['misp_auth_key']
        self.misp = PyMISP(self.url, self.key)
        self.tag_list = self.create_tag_list()

        self.logger = logging.getLogger('misp_handler')
        self.logger.debug("URLhausHandler init done")

    def create_tag_list(self) -> list:
        tags = []
        for item in self.misp.tags(pythonify=True):
            tags.append(item.name)
        return tags

    def make_sure_tag_exists(self, tag: str) -> bool:
        if tag in self.tag_list:
            return True
        else:
            self.misp.add_tag({"name": tag}, pythonify=True)
            self.tag_list = self.create_tag_list()
            if tag in self.tag_list:
                return True
            else:
                return False

    def add_tag_to_attribute(self, attr: MISPAttribute, tag: str) -> MISPAttribute:
        if self.make_sure_tag_exists(tag):
            attr.add_tag(tag)
        return attr

    def create_attr(self, raw_attr: dict) -> MISPAttribute:
        # Create attribute and assign simple values
        attr = MISPAttribute()
        attr.type = 'url'
        attr.value = raw_attr['url']
        attr.disable_correlation = False
        attr.__setattr__('first_seen', datetime.strptime(raw_attr['dateadded'], '%Y-%m-%d %H:%M:%S'))
        # Add URLhaus tag
        self.add_tag_to_attribute(attr, 'URLhaus')
        # Add other tags
        if raw_attr['tags']:
            for tag in raw_attr['tags'].split(','):
                self.add_tag_to_attribute(attr, tag.strip())

        # Add online/offline tag
        if not pandas.isna(raw_attr['url_status']):
            if raw_attr['url_status'] == 'online':
                attr.to_ids = True
            else:
                attr.to_ids = False
            self.add_tag_to_attribute(attr, raw_attr['url_status'])

        # Add reporter tag
        if not pandas.isna(raw_attr['reporter']):
            self.add_tag_to_attribute(attr, raw_attr['reporter'])

        attr.comment = raw_attr['urlhaus_link']
        return attr

    def create_attr_feodo(self, raw_attr: dict) -> MISPAttribute:
        attr = MISPAttribute()
        attr.type = 'ip-dst|port'
        attr.value = f"{raw_attr['DstIP']}|{raw_attr['DstPort']}"
        self.add_tag_to_attribute(attr, 'FeodoTracker')
        self.add_tag_to_attribute(attr, raw_attr['Malware'])
        attr.comment = 'Feodo tracker DST IP/port'
        attr.__setattr__('first_seen', datetime.strptime(raw_attr['Firstseen'], '%Y-%m-%d %H:%M:%S'))
        if not pandas.isna(raw_attr['LastOnline']):
            last_seen_time = datetime.strptime(str(raw_attr['LastOnline']), '%Y-%m-%d').replace(tzinfo=pytz.utc)
            first_seen_time = datetime.strptime(str(raw_attr["Firstseen"]), '%Y-%m-%d %H:%M:%S').replace(tzinfo=pytz.utc)
            if first_seen_time > last_seen_time:
                last_seen_time = first_seen_time + timedelta(seconds=1)
            attr.__setattr__('last_seen', last_seen_time)
        else:
            last_seen_time = datetime.strptime(str(raw_attr['Firstseen']), '%Y-%m-%d %H:%M:%S').replace(tzinfo=pytz.utc)
            attr.__setattr__('last_seen', last_seen_time)
        attr.to_ids = False
        attr.disable_correlation = False
        return attr

    def create_attr_azorult(self, raw_attr: dict) -> MISPAttribute:
        attr_list = []
        for type in [{'json': 'domain', 'misp': 'domain'},
                     {'json': 'ip', 'misp': 'ip-dst'},
                     {'json': 'panel_index', 'misp': 'url'}]:
            if type['json'] in raw_attr:
                attr = MISPAttribute()
                self.add_tag_to_attribute(attr, 'AzorultTracker')
                self.add_tag_to_attribute(attr, raw_attr['panel_version'])
                self.add_tag_to_attribute(attr, raw_attr['feeder'])
                self.add_tag_to_attribute(attr, raw_attr['status'])
                attr.comment = f'Azorult panel {type["misp"]}'
                attr.__setattr__('first_seen', datetime.fromtimestamp(raw_attr['first_seen']))
                attr.to_ids = False
                attr.disable_correlation = False
                attr.type = type['misp']
                attr.value = f"{raw_attr[type['json']]}"
                attr_list.append(attr)
        return attr_list

    @staticmethod
    def get_attribute_tag_list(self, tag_list: list) -> list:
        tags = []
        for item in tag_list:
            tags.append(item['name'])
        return tags

    @staticmethod
    def create_event(title: str, date_added: datetime) -> MISPEvent:
        misp_event = MISPEvent()
        misp_event.info = title
        if date_added != '':
            misp_event.date = date_added
        return misp_event

    def get_event(self, event_id):
        return self.misp.get_event(event_id, pythonify=True)

    def add_attr_to_event(self, event: MISPEvent, attribute: MISPAttribute):
        event.attributes.append(attribute)
        return event

    def update_event(self, event: MISPEvent):
        return self.misp.update_event(event, pythonify=True)

    def get_day_event(self, day: str, source: str, date: str):
        if source in ['URLHaus', 'FeodoTracker']:
            misp_event = self.misp.search('events', 'json', org=1, eventinfo=f'{source} import day {day}',
                                          pythonify=True)
        elif source in ['AzorultTracker']:
            misp_event = self.misp.search('events', 'json', org=1, eventinfo=f'{source} import panel {day}',
                                          pythonify=True)
        if len(misp_event) >= 1:
            return misp_event[0]
        else:
            if source in ['URLHaus', 'FeodoTracker']:
                misp_event = self.create_event(f"{source} import day {day}",
                                               date_added=datetime.timestamp(
                                                   datetime.strptime(date, '%Y-%m-%d %H:%M:%S')))
            elif source in ['AzorultTracker']:
                misp_event = self.create_event(f"{source} import panel {day}",
                                               date_added=datetime.fromtimestamp(date))
            event_id = self.misp.add_event(misp_event)
            self.misp.publish(event_id)
            return self.get_event(event_id)

    @staticmethod
    def delete_attribute_by_value(search_value: str, event: MISPEvent):
        found = False
        for a in event.attributes:
            if (hasattr(a, 'value') and a.value == search_value):
                a.deleted = True
        return event
class MISPInstance():
    def __init__(self, misp_instance_dir: Path, secure_connection: bool):
        with (misp_instance_dir / 'config.json').open() as f:
            self.instance_config = json.load(f)

        print('Initialize', self.instance_config['admin_orgname'])
        self.secure_connection = secure_connection

        self.synchronisations = {}
        self.name = self.instance_config['admin_orgname']

        # NOTE: never use that user again after initial config.
        initial_user_connector = PyMISP(self.instance_config['baseurl'],
                                        self.instance_config['admin_key'],
                                        ssl=self.secure_connection,
                                        debug=False)
        # Set the default role (id 3 is normal user)
        initial_user_connector.set_default_role(3)
        initial_user_connector.toggle_global_pythonify()

        self.baseurl = self.instance_config['baseurl']
        self.external_baseurl = self.instance_config['external_baseurl']

        # Create organisation
        organisation = MISPOrganisation()
        organisation.name = self.instance_config['admin_orgname']
        self.host_org = initial_user_connector.add_organisation(organisation)
        if not isinstance(self.host_org, MISPOrganisation):
            # The organisation is probably already there
            organisations = initial_user_connector.organisations()
            for organisation in organisations:
                if organisation.name == self.instance_config['admin_orgname']:
                    self.host_org = organisation
                    break
            else:
                raise Exception('Unable to find admin organisation')

        # Create Site admin in new org
        user = MISPUser()
        user.email = self.instance_config['email_site_admin']
        user.org_id = self.host_org.id
        user.role_id = 1  # Site admin
        self.host_site_admin = initial_user_connector.add_user(user)
        if not isinstance(self.host_site_admin, MISPUser):
            users = initial_user_connector.users()
            for user in users:
                if user.email == self.instance_config['email_site_admin']:
                    self.host_site_admin = user
                    break
            else:
                raise Exception('Unable to find admin user')

        self.site_admin_connector = PyMISP(self.baseurl,
                                           self.host_site_admin.authkey,
                                           ssl=self.secure_connection,
                                           debug=False)
        self.site_admin_connector.toggle_global_pythonify()

        # Setup external_baseurl
        self.site_admin_connector.set_server_setting('MISP.external_baseurl',
                                                     self.external_baseurl,
                                                     force=True)
        # Setup baseurl
        self.site_admin_connector.set_server_setting('MISP.baseurl',
                                                     self.baseurl,
                                                     force=True)
        # Setup host org
        self.site_admin_connector.set_server_setting('MISP.host_org_id',
                                                     self.host_org.id)

        # create other useful users
        self.orgadmin = self.create_user(
            self.instance_config['email_orgadmin'], 2)
        self.user = self.create_user(self.instance_config['email_user'], 3)
        # And connectors
        self.org_admin_connector = PyMISP(self.baseurl,
                                          self.orgadmin.authkey,
                                          ssl=self.secure_connection,
                                          debug=False)
        self.org_admin_connector.toggle_global_pythonify()
        self.user_connector = PyMISP(self.baseurl,
                                     self.user.authkey,
                                     ssl=self.secure_connection,
                                     debug=False)
        self.user_connector.toggle_global_pythonify()

    def __repr__(self):
        return f'<{self.__class__.__name__}(external={self.baseurl})>'

    def create_user(self, email, role_id):
        user = MISPUser()
        user.email = email
        user.org_id = self.host_org.id
        user.role_id = role_id
        new_user = self.site_admin_connector.add_user(user)
        if not isinstance(new_user, MISPUser):
            users = self.site_admin_connector.users()
            for user in users:
                if user.email == email:
                    new_user = user
                    break
            else:
                raise Exception('Unable to find admin user')
        return new_user

    def create_sync_user(self, organisation: MISPOrganisation) -> MISPServer:
        sync_org = self.site_admin_connector.add_organisation(organisation)
        if not isinstance(sync_org, MISPOrganisation):
            # The organisation is probably already there
            organisations = self.site_admin_connector.organisations(
                scope='all')
            for org in organisations:
                if org.name == organisation.name:
                    if not org.local:
                        org.local = True
                        org = self.site_admin_connector.update_organisation(
                            org)
                    sync_org = org
                    break
            else:
                raise Exception('Unable to find sync organisation')

        short_org_name = sync_org.name.lower().replace(' ', '-')
        email = f"sync_user@{short_org_name}.local"
        user = MISPUser()
        user.email = email
        user.org_id = sync_org.id
        user.role_id = 5  # Sync user
        sync_user = self.site_admin_connector.add_user(user)
        if not isinstance(sync_user, MISPUser):
            users = self.site_admin_connector.users()
            for user in users:
                if user.email == email:
                    sync_user = user
                    break
            else:
                raise Exception('Unable to find sync user')

        sync_user_connector = PyMISP(self.site_admin_connector.root_url,
                                     sync_user.authkey,
                                     ssl=self.secure_connection,
                                     debug=False)
        return sync_user_connector.get_sync_config(pythonify=True)

    def configure_sync(self, server_sync_config: MISPServer):
        # Add sharing server
        for s in self.site_admin_connector.servers():
            if s.name == server_sync_config.name:
                server = s
                break
        else:
            server = self.site_admin_connector.import_server(
                server_sync_config)
        server.pull = True
        server.push = False
        server = self.site_admin_connector.update_server(server)
        r = self.site_admin_connector.test_server(server)
        if r['status'] != 1:
            raise Exception(f'Sync test failed: {r}')
        print(server)
        print(server.to_json(indent=2))
        # NOTE: this is dirty.
        self.synchronisations[server_sync_config.name.replace(
            'Sync with ', '')] = server

    def add_tag_filter_sync(self, server_sync: MISPServer, name: str):
        # Add tag to limit push
        tag = MISPTag()
        tag.name = name
        tag.exportable = False
        tag.org_id = self.host_org.id
        tag = self.site_admin_connector.add_tag(tag)
        if not isinstance(tag, MISPTag):
            for t in self.site_admin_connector.tags():
                if t.name == name:
                    tag = t
                    break
            else:
                raise Exception('Unable to find tag')

        # Set limit on sync config
        filter_tag_push = {
            "tags": {
                'OR': [tag.id],
                'NOT': []
            },
            'orgs': {
                'OR': [],
                'NOT': []
            }
        }
        # filter_tag_pull = {"tags": {'OR': [], 'NOT': []}, 'orgs': {'OR': [], 'NOT': []}}
        server_sync.push_rules = json.dumps(filter_tag_push)
        # server.pull_rules = json.dumps(filter_tag_pull)
        server_sync = self.site_admin_connector.update_server(server_sync)

    def add_sharing_group(self,
                          name: str,
                          releasibility: str = 'Whatever it is a test',
                          servers: List[MISPServer] = [],
                          organisations: List[MISPOrganisation] = []):

        # Add sharing group
        for sg in self.site_admin_connector.sharing_groups():
            if sg.name == name:
                self.sharing_group = sg
                break
        else:
            sharing_group = MISPSharingGroup()
            sharing_group.name = name
            sharing_group.releasability = releasibility
            self.sharing_group = self.site_admin_connector.add_sharing_group(
                sharing_group)
            for server in servers:
                self.site_admin_connector.add_server_to_sharing_group(
                    self.sharing_group, server)
            for organisation in organisations:
                self.site_admin_connector.add_org_to_sharing_group(
                    self.sharing_group, organisation)