def activate(self): logger.debug('Activating %s' % self.__class__.__name__) self.service = ThreatConnect(settings.THREATCONNECT_ACCESS_ID, settings.THREATCONNECT_SECRET_KEY, settings.THREATCONNECT_DEFAULT_ORG, settings.THREATCONNECT_BASE_URL) self.service.set_api_result_limit(100)
def get_client(): params = demisto.params() access = params['accessId'] secret = params['secretKey'] default_org = params.get('defaultOrg') url = params['baseUrl'] proxy_ip = params['proxyIp'] proxy_port = params['proxyPort'] tc = ThreatConnect(access, secret, default_org, url) if proxy_ip and proxy_port and len(proxy_ip) > 0 and len(proxy_port) > 0: tc.set_proxies(proxy_ip, int(proxy_port)) return tc
def test_ip_get_indicators_multiple_owners(mocker): mocker.patch('ThreatConnect_v2.get_xindapi', side_effect=[GET_XINDAPI_OWNER1, GET_XINDAPI_OWNER2]) mocker.patch('ThreatConnect_v2.get_client', return_value=ThreatConnect()) indicators = get_indicators('127.0.0.1', 'Address', 'Demisto Inc.,PhishTank', -1, -1) assert indicators == EXPECTED_INDOCATORS_OUTPUT
def test_associate_indicator_request(indicator_type, indicator, expected_url, mocker): mocker.patch.object(Response, 'json', return_value={}) api_request = mocker.patch.object(ThreatConnect, 'api_request', return_value=Response()) mocker.patch('ThreatConnect_v2.get_client', return_value=ThreatConnect()) associate_indicator_request(indicator_type, indicator, 'test', '0') url = f'/v2/indicators/{expected_url}/groups/test/0' assert api_request.call_args[0][0].request_uri == url
def activate(self): logger.debug('Activating %s' % self.__class__.__name__) self.service = ThreatConnect( settings.THREATCONNECT_ACCESS_ID, settings.THREATCONNECT_SECRET_KEY, settings.THREATCONNECT_DEFAULT_ORG, settings.THREATCONNECT_BASE_URL) self.service.set_api_result_limit(100)
# retrieve configuration file config = ConfigParser.RawConfigParser() config.read(config_file) try: api_access_id = config.get('threatconnect', 'api_access_id') api_secret_key = config.get('threatconnect', 'api_secret_key') api_default_org = config.get('threatconnect', 'api_default_org') api_base_url = config.get('threatconnect', 'api_base_url') api_result_limit = int(config.get('threatconnect', 'api_result_limit')) except ConfigParser.NoOptionError: print('Could not retrieve configuration file.') sys.exit(1) tc = ThreatConnect(api_access_id, api_secret_key, api_default_org, api_base_url) tc.set_api_result_limit(api_result_limit) tc.report_enable() # # CHANGE FOR YOUR TESTING ENVIRONMENT # - These victims must be created before running this script # owner = 'Example Community' # org or community lu_id = 1 # adversary id for loop update mu_id = 4 # adversary id for manual update # dl_id = 999999 # adversary id to delete email_id = 17 # email resource id to associate with adversary email_address = '*****@*****.**' # email address to associate to adversary rn = randint(1, 1000) # random number generator for testing
# retrieve configuration file config = ConfigParser.RawConfigParser() config.read(config_file) try: api_access_id = config.get('threatconnect', 'api_access_id') api_secret_key = config.get('threatconnect', 'api_secret_key') api_default_org = config.get('threatconnect', 'api_default_org') api_base_url = config.get('threatconnect', 'api_base_url') api_result_limit = int(config.get('threatconnect', 'api_result_limit')) except ConfigParser.NoOptionError: print('Could not retrieve configuration file.') sys.exit(1) tc = ThreatConnect(api_access_id, api_secret_key, api_default_org, api_base_url) tc.set_api_result_limit(api_result_limit) tc.report_enable() # # CHANGE FOR YOUR TESTING ENVIRONMENT # - These adversaries must be created before running this script # lu_id = 22 # task id for loop update mu_id = 23 # task id for manual update # dl_id = 999999 # adversary id to delete email_id = 27 # email resource id to associate with adversary victim_id = 2 # victim resource id to associate with adversary ip_address = '10.121.82.247' # ip address to associate to adversary rn = randint(1, 1000) # random number generator for testing
import sys from threatconnect import ThreatConnect config = ConfigParser.RawConfigParser() config.read('./tc.conf') try: api_access_id = config.get('threatconnect', 'api_access_id') api_secret_key = config.get('threatconnect', 'api_secret_key') api_default_org = config.get('threatconnect', 'api_default_org') api_base_url = config.get('threatconnect', 'api_base_url') except ConfigParser.NoOptionError: print('Could not read configuration file.') sys.exit(1) tc = ThreatConnect(api_access_id, api_secret_key, api_default_org, api_base_url) owners = tc.owners() try: # retrieve the Owners owners.retrieve() except RuntimeError as e: print('Error: {0}'.format(e)) sys.exit(1) def getOwnerNames(): namelist = [] for owner in owners: namelist.append(owner.name) return namelist
def __init__(self, access_id="", secret_key="", default_org="", base_url="", out_file="tc.json", sources="", ioc_types="", custom_ioc_key="", feed_url="", cb_server_token="", cb_server_url="https://127.0.0.1", cb_server_ssl_verify=False, ioc_min=None, niceness=None, debug=False, log_file=None, max_iocs=5000): logger.info("ThreatConnect Base URL: {0}".format(base_url)) self.tcapi = ThreatConnect(api_aid=access_id, api_sec=secret_key, api_url=base_url, api_org=default_org) self.sources = sources self.ioc_min = ioc_min self.ioc_types = ioc_types logger.info("Configured IOC Types are : {0}".format(self.ioc_types)) logger.info("Configured IOC Min is : {0}".format(self.ioc_min)) self.custom_ioc_key = custom_ioc_key self.max_iocs = max_iocs if self.sources[0] == "*": owners = self.tcapi.owners() try: # retrieve the Owners owners.retrieve() except RuntimeError as e: logger.error(traceback.format_exc()) sys.exit(1) # iterate through the Owners self.sources = [owner.name for owner in owners] logger.info("Sources = {0}".format(self.sources)) self.niceness = niceness if self.niceness is not None: os.nice(self.niceness) self.debug = debug if self.debug: logger.setLevel(logging.DEBUG) self.log_file = log_file self.out_file = out_file self.feed = None self.cb = CbResponseAPI(url=cb_server_url, token=cb_server_token, ssl_verify=cb_server_ssl_verify) self.feed_url = feed_url
class CbThreatConnectConnector(object): def __init__(self, access_id="", secret_key="", default_org="", base_url="", out_file="tc.json", sources="", ioc_types="", custom_ioc_key="", feed_url="", cb_server_token="", cb_server_url="https://127.0.0.1", cb_server_ssl_verify=False, ioc_min=None, niceness=None, debug=False, log_file=None, max_iocs=5000): logger.info("ThreatConnect Base URL: {0}".format(base_url)) self.tcapi = ThreatConnect(api_aid=access_id, api_sec=secret_key, api_url=base_url, api_org=default_org) self.sources = sources self.ioc_min = ioc_min self.ioc_types = ioc_types logger.info("Configured IOC Types are : {0}".format(self.ioc_types)) logger.info("Configured IOC Min is : {0}".format(self.ioc_min)) self.custom_ioc_key = custom_ioc_key self.max_iocs = max_iocs if self.sources[0] == "*": owners = self.tcapi.owners() try: # retrieve the Owners owners.retrieve() except RuntimeError as e: logger.error(traceback.format_exc()) sys.exit(1) # iterate through the Owners self.sources = [owner.name for owner in owners] logger.info("Sources = {0}".format(self.sources)) self.niceness = niceness if self.niceness is not None: os.nice(self.niceness) self.debug = debug if self.debug: logger.setLevel(logging.DEBUG) self.log_file = log_file self.out_file = out_file self.feed = None self.cb = CbResponseAPI(url=cb_server_url, token=cb_server_token, ssl_verify=cb_server_ssl_verify) self.feed_url = feed_url def stop(self): self.stopEvent.set() def getDebugMode(self): return self._debug def setDebugMode(self, debugOn): self._debug = debugOn if self._debug == True: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) debug = property(getDebugMode, setDebugMode) def _PollThreatConnect(self): self.generate_feed_from_threatconnect() self.createFeed() last = None while (True): if self.stopEvent.isSet(): logger.info( "Threatconnect Connector was signalled to stop...stopping") return else: #poll threat connect if the time delta has passed since the last time we did now = datetime.now() delta = now - last if last is not None else self.interval last = now if delta >= self.interval: self.generate_feed_from_threatconnect() else: time.sleep(self.interval.seconds + 1) logger.debug("Done sleeping...") def RunForever(self): logger.info("ThreatConnect agent starting...") threading.Thread(target=self._PollThreatConnect).start() def createFeed(self): if self.feed is not None: self.feed.upload(self.cb, self.feed_url) def generate_feed_from_threatconnect(self): first = True reports = [] feedinfo = { 'name': 'threatconnect', 'display_name': "ThreatConnect", 'provider_url': "http://www.threatconnect.com", 'summary': "Sends threat intelligence from Threatconnect platform to Carbon Black Response", 'tech_data': "There are no requirements to share any data with Carbon Black to use this feed.", 'icon': 'threatconnect-logo.png', 'category': "Connectors", } feedinfo = CbFeedInfo(**feedinfo) self.feed = CbFeed(feedinfo, reports) created_feed = self.feed.dump(validate=False, indent=0) with open(self.out_file, 'w') as fp: fp.write(created_feed) fp.seek(0) offset = len(created_feed) - 1 # create an Indicators object for source in self.sources: for t in self.ioc_types: indicators = self.tcapi.indicators() filter1 = indicators.add_filter() # filter1.add_owner(source) filter1.add_pf_type(t, FilterOperator.EQ) if self.ioc_min is not None: filter1.add_pf_rating(self.ioc_min, FilterOperator.GE) try: # retrieve Indicators indicators.retrieve() except RuntimeError as e: print('Error: {0}'.format(e)) logger.info("Number of indicators:{0}".format( len(indicators))) for index, indicator in enumerate(indicators): if index > self.max_iocs: logger.info("Max number of IOCs reached") break # print (indicator.type) score = indicator.rating * 20 if indicator.rating is not None else 0 # int(row.get('rating', 0)) * 20 # Many entries are missing a description so I placed this here to default them # to the IOC value in the absence of a description. title = indicator.description if indicator.description is not None else "{0}-{1}".format( source, indicator.id) # row.get('description', None) # if not title: # title = row.get('summary') fields = { 'iocs': {}, 'id': str(indicator.id), 'link': indicator.weblink, 'title': title, 'score': int(score), 'timestamp': int( datetime.strptime( indicator.date_added, "%Y-%m-%dT%H:%M:%SZ").timestamp()), } # The next few lines are designed to insert the Cb supported IOCs into the record. logger.debug("Indacator is {0}".format(indicator)) if indicator.type == "File": fields['iocs'] = { k: [indicator.indicator[k]] for k in indicator.indicator if indicator.indicator[k] is not None } elif indicator.type == "Address": fields['iocs']['ipv4'] = [indicator.indicator] elif indicator.type == "Host": fields['iocs']['dns'] = [indicator.indicator] else: squery = urllib.parse.urlencode({ "cb.urlver": "1", "q": indicator.indicator[self.custom_ioc_key] }) fields['iocs']['query'] = [{ 'index_type': 'modules', 'search_query': squery }] report = CbReport(**fields) try: report.dump(validate=True) except: logger.info("This query is not valid: {0}".format( indicator.indicator[self.custom_ioc_key])) continue # APPEND EACH NEW REPORT ONTO THE LIST IN THE JSON FEED # THIS METHOD IS VERY LONG LIVED # THIS METHOD CALL WILL LAST FOR # HOURS -> DAYS IN LARGE ORGS reports.append(report) self.feed = CbFeed(feedinfo, reports) fp.write(self.feed.dump(validate=False, indent=0))
import ConfigParser from threatconnect import ThreatConnect config = ConfigParser.RawConfigParser() config.read(config_file) try: api_access_id = config.get('threatconnect', 'api_access_id') api_secret_key = config.get('threatconnect', 'api_secret_key') api_default_org = config.get('threatconnect', 'api_default_org') api_base_url = config.get('threatconnect', 'api_base_url') except ConfigParser.NoOptionError: print('Could not read configuration file.') sys.exit(1) tc = ThreatConnect(api_access_id, api_secret_key, api_default_org, api_base_url) owners = tc.owners() try: owners.retrieve() except RunTimeErrors as e: print('Error: {0}'.format(e)) sys.exit(1) for owner in owners: print(owner.id) print(owner.name) print(owner.type)
class ThreatConnectPlugin(Plugin): @property def enabled(self): return settings.THREATCONNECT_ACCESS_ID is not None and \ settings.THREATCONNECT_SECRET_KEY is not None def activate(self): logger.debug('Activating %s' % self.__class__.__name__) self.service = ThreatConnect(settings.THREATCONNECT_ACCESS_ID, settings.THREATCONNECT_SECRET_KEY, settings.THREATCONNECT_DEFAULT_ORG, settings.THREATCONNECT_BASE_URL) self.service.set_api_result_limit(100) def retrieve_indicator(self, indicator, indicator_type=None): indicators = self.service.indicators() if indicator_type: f = indicators.add_filter(indicator_type) else: f = indicators.add_filter() f.add_owner(['Common Community']) f.add_indicator(indicator) results = sorted(indicators.retrieve(), key=lambda x: x.rating) return results[-1] if results else None def threshold_met(self, report): return hasattr(report, 'rating') and report.rating >= 1 and \ hasattr(report, 'confidence') and report.confidence >= 50 def react(self): if not any(self.reports.values()): return rating = max([0] + [ r.rating for r in self.reports.values() if r and hasattr(r, 'rating') and r.rating ]) return self.reaction(rating) def reaction(self, score): if score == 0: return 'sunny' elif 0 <= score < 0.5: return 'mostly_sunny' elif 0.5 <= score < 1: return 'partly_sunny' elif 1 <= score < 2: return 'barely_sunny' elif 2 <= score < 2.5: return 'cloud' elif 2.5 <= score < 3: return 'rain_cloud' elif 3 <= score < 3.5: return 'thunder_cloud_and_rain' elif 3.5 <= score < 4: return 'lightning' elif score >= 4: return 'tornado' def risk_level(self, score): try: score = float(score) except TypeError: return 'UNKNOWN' if score == 0: return 'UNKNOWN' elif 0 < score < 1: return 'VERY LOW' elif 1 <= score < 2: return 'LOW' elif 2 <= score < 3: return 'MODERATE' elif 3 <= score < 4: return 'HIGH' elif score >= 4: return 'VERY HIGH'
class ThreatConnectPlugin(Plugin): @property def enabled(self): return settings.THREATCONNECT_ACCESS_ID is not None and \ settings.THREATCONNECT_SECRET_KEY is not None def activate(self): logger.debug('Activating %s' % self.__class__.__name__) self.service = ThreatConnect( settings.THREATCONNECT_ACCESS_ID, settings.THREATCONNECT_SECRET_KEY, settings.THREATCONNECT_DEFAULT_ORG, settings.THREATCONNECT_BASE_URL) self.service.set_api_result_limit(100) def retrieve_indicator(self, indicator, indicator_type=None): indicators = self.service.indicators() if indicator_type: f = indicators.add_filter(indicator_type) else: f = indicators.add_filter() f.add_owner(['Common Community']) f.add_indicator(indicator) results = sorted(indicators.retrieve(), key=lambda x: x.rating) return results[-1] if results else None def threshold_met(self, report): return hasattr(report, 'rating') and report.rating >= 1 and \ hasattr(report, 'confidence') and report.confidence >= 50 def react(self): if not any(self.reports.values()): return rating = max([0] + [r.rating for r in self.reports.values() if r and hasattr(r, 'rating') and r.rating]) return self.reaction(rating) def reaction(self, score): if score == 0: return 'sunny' elif 0 <= score < 0.5: return 'mostly_sunny' elif 0.5 <= score < 1: return 'partly_sunny' elif 1 <= score < 2: return 'barely_sunny' elif 2 <= score < 2.5: return 'cloud' elif 2.5 <= score < 3: return 'rain_cloud' elif 3 <= score < 3.5: return 'thunder_cloud_and_rain' elif 3.5 <= score < 4: return 'lightning' elif score >= 4: return 'tornado' def risk_level(self, score): try: score = float(score) except TypeError: return 'UNKNOWN' if score == 0: return 'UNKNOWN' elif 0 < score < 1: return 'VERY LOW' elif 1 <= score < 2: return 'LOW' elif 2 <= score < 3: return 'MODERATE' elif 3 <= score < 4: return 'HIGH' elif score >= 4: return 'VERY HIGH'
config_file = "tc.conf" config = ConfigParser.RawConfigParser() config.read(config_file) try: api_access_id = config.get('threatconnect', 'api_access_id') api_secret_key = config.get('threatconnect', 'api_secret_key') api_default_org = config.get('threatconnect', 'api_default_org') api_base_url = config.get('threatconnect', 'api_base_url') api_result_limit = int(config.get('threatconnect', 'api_result_limit')) api_export_days = int(config.get('threatconnect', 'api_export_days')) except ConfigParser.NoOptionError: print('Could not retrieve configuration file.') sys.exit(1) tc = ThreatConnect(api_access_id, api_secret_key, api_default_org, api_base_url) tc.set_api_result_limit(api_result_limit) # initializing stuff csv = tocsv.csv() # directory configurations // idea: set it in config file # if you are running this in the linux server with ML, change r"\csv" to r"\mhscript" f_name_directory = os.getcwd() + r"\csv" n_files = len(os.listdir(f_name_directory)) if n_files > 0: print("CSV file already exists in {}".format(f_name_directory)) print("Deleting csv file") if not bool((input("Press ENTER to continue...\n"))): os.remove(path=f_name_directory + r"\0.csv") else:
# https://docs.threatconnect.com/en/latest/python/quick_start.html#standard-script-heading config = ConfigParser.RawConfigParser() config.read('./tc.conf') try: api_access_id = config.get('threatconnect', 'api_access_id') api_secret_key = config.get('threatconnect', 'api_secret_key') api_default_org = config.get('threatconnect', 'api_default_org') api_base_url = config.get('threatconnect', 'api_base_url') api_result_limit = config.get('threatconnect', 'api_result_limit') except ConfigParser.NoOptionError: print('Could not read configuration file.') sys.exit(1) tc = ThreatConnect(api_access_id, api_secret_key, api_default_org, api_base_url) tc.set_api_result_limit(1000) # instantiate Owners object #owners = tc.owners() owners = ['ThreatConnect Intelligence', 'Common Community'] groups = tc.groups() filter1 = groups.add_filter() # only retrieve Groups from the given owner(s) filter1.add_owner(owners) try: groups.retrieve() except RuntimeError as e: