def main(): """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) # gets all ta names from objects(as a set of strings) and facts(as a # set with tuples of two strings) in ACT. threatactors = get_all_ta_from_act(args.baseurl, args.userid) # gets all threat actor aliases from act platform ta_aliases = get_all_alias_facts_from_act(args.baseurl, args.userid) # save ta and ta_aliases to json test file if args.output_json: with open('test/objects.json', 'w') as outfile: outfile.write(json.dumps(list(threatactors))) with open('test/facts.json', 'w') as outfile: outfile.write(json.dumps(list(ta_aliases))) # adds all ta names from threatActor objects from ACT into ta_map ta_map = add_ta_to_map(threatactors) # adds all ta names from alias-facts in ACT to the ta_map ta_map_with_aliases = add_ta_alias_to_map(ta_aliases, ta_map) # creates a new .cfg-file including all the content from ta_map # and the existing cfg.-file from arguments. create_config(ta_map_with_aliases, args.aliasfile, args.newaliasfile)
def main() -> None: # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) process(actapi, args.pdns_baseurl, args.apikey, args.timeout, args.proxy_string, args.output_format)
def main() -> None: """Main function""" # Look for default ini file in "/etc/actworkers.ini" and # ~/config/actworkers/actworkers.ini (or replace .config with # $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) # setup logging act.api.utils.setup_logging(args.loglevel, prefix='act-alienvault-otx') # check necessary configuration items for errors for item in [ 'config_path', 'otx_baseurl', 'otx_apikey', 'otx_path_lastretrived' ]: if item not in args: raise ConfigurationError( 'Missing configuration item {}'.format(item)) # initialise act api actapi = worker.init_act(args) # initialise otx api otxapi = AlienvaultOTXAPI(args) # create facts for indicators in each event for event in otxapi.get_subscribed(): handle_facts(actapi, event)
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) if not args.apikey: worker.fatal("You must specify --apikey on command line or in config file") in_data = sys.stdin.read().strip() proxies = { 'http': args.proxy_string, 'https': args.proxy_string } if args.proxy_string else None vtapi = VirusTotalApi(args.apikey, proxies=proxies) if args.hexdigest: handle_hexdigest(actapi, vtapi, in_data, output_format=args.output_format) if args.ip: handle_ip(actapi, vtapi, in_data, output_format=args.output_format) if args.domain: handle_domain(actapi, vtapi, in_data, output_format=args.output_format)
def main_log_error() -> None: "Main function. Log all exceptions to error" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) if not (args.act_baseurl and args.user_id): sys.stderr.write("Must specify --baseurl and --user-id\n") sys.exit(1) if not os.path.isfile(args.search_jobs): sys.stderr.write("File not found: {}\n".format(args.search_jobs)) sys.exit(2) if not args.search_jobs: sys.stderr.write("Must specify config file with search jobs\n") sys.exit(2) try: for name, options in parse_search_jobs(args.search_jobs).items(): process(actapi, args.output_path, name, options, args.workers) except Exception: error("Unhandled exception", exc_info=True) raise
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) # if not args.apikey: # worker.fatal("You must specify --apikey on command line or in config file") proxies = { 'http': args.proxy_string, 'https': args.proxy_string } if args.proxy_string else None params = { 'actapi': actapi, 'user_agent': args.user_agent, 'proxies': proxies, 'verify_ssl': args.no_check_certificate, 'output_format': args.output_format } if args.feed: handle_feed(**params) else: params['apikey'] = args.apikey for line in sys.stdin: params['hashdigest'] = line.strip() handle_hash(**params)
def main() -> None: """program entry point""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) manifest_dir = args.manifest_dir actapi = worker.init_act(args) verify_manifest_dir(manifest_dir) misp_feeds_file = os.path.join(manifest_dir, "misp_feeds.txt") with open(misp_feeds_file) as f: for line in f: feed_data = handle_feed(manifest_dir, line.strip(), args.proxy_string, args.cert_file) for event in feed_data: n = 0 e = 0 act.api.helpers.handle_fact(actapi.fact("name", event.info).source( "report", str(event.uuid)), output_format=args.output_format) n += 1 try: act.api.helpers.handle_fact( actapi.fact("externalLink").source( "uri", "{0}/{1}.json".format(line.strip(), event.uuid)).destination( "report", str(event.uuid)), output_format=args.output_format) n += 1 except act.api.base.ResponseError as err: e += 1 error("Error adding fact to platform", exc_info=True) for attribute in event.attributes: if not attribute.act_type: continue try: act.api.helpers.handle_fact( actapi.fact("mentions").source( "report", str(event.uuid)).destination( attribute.act_type, attribute.value), output_format=args.output_format) n += 1 except act.api.base.ResponseError as err: e += 1 error("Error adding fact to platform", exc_info=True) info("{0} facts. {1} errors.".format(n, e))
def main() -> None: """Main function""" # Look for default ini file in "/etc/actworkers.ini" and # ~/config/actworkers/actworkers.ini (or replace .config with # $XDG_CONFIG_DIR if set) args = worker.handle_args(worker.parseargs(WORKER_NAME)) actapi = worker.init_act(args) process(actapi, args.output_format)
def main() -> None: """ Main function """ # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) auth = None if args.http_user: auth = (args.http_user, args.http_password) actapi = act.api.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, worker.worker_name(), requests_common_kwargs={'auth': auth}) if args.type: types = [args.type] else: types = list(MITRE_URLS.keys()) for mitre_type in types: url = MITRE_URLS.get(mitre_type.lower()) if not url: error("Unknown mitre type: {}. Valid types: {}".format( mitre_type, ",".join(MITRE_URLS.keys()))) sys.exit(2) cache = notify_cache(args.notifycache) # Get attack dataset as Stix Memory Store attack = get_attack(url, args.proxy_string, args.http_timeout) techniques_notify = add_techniques(actapi, attack, args.output_format) groups_notify = add_groups(actapi, attack, args.output_format) software_notify = add_software(actapi, attack, args.output_format) # filter revoked objects from those allready notified notify = [ notify for notify in techniques_notify + groups_notify + software_notify if notify.id not in cache ] if notify: notified = send_notification(notify, args.smtphost, args.sender, args.recipient, url) for object_id in notified: # Add object to cache, so we will not be notified on the same object on the next run add_to_cache(args.notifycache, object_id)
def main_log_error() -> None: "Call main() and log all exceptions as errors" try: # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(worker.parseargs("Generic uploader")) actapi = worker.init_act(args) main(actapi) except Exception: error("Unhandled exception: {}".format(traceback.format_exc())) raise
def main() -> None: # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) auth = None if args.http_user: auth = (args.http_user, args.http_password) actapi = act.api.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, worker.worker_name(), requests_common_kwargs={'auth': auth}) process(actapi, args.pdns_baseurl, args.apikey, args.timeout, args.proxy_string, args.output_format)
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) auth = None if args.http_user: auth = (args.http_user, args.http_password) actapi = act.api.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, worker.worker_name(), requests_common_kwargs={'auth': auth}) if not args.country_codes: sys.stderr.write( "You must specify --country-codes on command line or in config file\n" ) sys.exit(1) if not os.path.isfile(args.country_codes): sys.stderr.write( "Country/region file not found at specified location: {}\n".format( args.country_codes)) sys.exit(2) # Get map of CC -> Country Name cn_map = get_cn_map(args.country_codes) db_cache = get_db_cache(CACHE_DIR) # Read IPs from stdin if args.stdin: in_data = [ip for ip in sys.stdin.read().split("\n")] handle_ip(actapi, cn_map, in_data, db_cache, args.output_format) # Bulk lookup elif args.bulk: all_ips = [ip for ip in open(args.bulk, "r")] batch_size = 50 i = 0 while i < len(all_ips): handle_ip(actapi, cn_map, (all_ips[i:i + batch_size]), db_cache, args.output_format) i += batch_size time.sleep(1) db_cache.close()
def main() -> None: """Main function""" args = worker.handle_args(parseargs()) actapi = worker.init_act(args) if not (args.act_baseurl and args.user_id): error("Worker must be configured with --act-baseurl and --userid") sys.exit(1) tools = search_tools(actapi, args.exclude_tools) aliases = get_aliases(actapi, list(tools.keys())) for tool1, tool2 in process(tools, aliases, args.threshold): handle_alias(actapi, tool1, tool2, args.submit, args.output_format)
def main() -> None: " main function " # Look for default ini file in "/etc/actworkers.ini" and # ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) if not args.argus_apikey: worker.fatal( "You must specify --apikey on command line or in config file") actapi = worker.init_act(args) process(actapi, args)
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) # Add IOCs from reports to the ACT platform add_to_act( actapi, get_scio_report(), args.output_format, )
def main_log_error() -> None: "Main function. Log all exceptions to error" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) try: process( actapi, worker.fetch_json(args.country_region_url, args.proxy_string, args.http_timeout), args.output_format) except Exception: error("Unhandled exception: {}".format(traceback.format_exc())) raise
def parseargs() -> argparse.Namespace: parser = worker.parseargs("URL unshortener worker") parser.add_argument( "--url-shorteners", dest="url_shorteners", default= "adf.ly, bit.ly, bitly.com, cc.uz, evassmat.com, goo.gl, is.gd, lnkd.in, smarturl.it, www.t2m.io, tiny.cc, tinyurl.com, x.co", help="Comma separated list of shortener-domains") parser.add_argument( "--user-agent", dest="user_agent", default= "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", help="User-agent to present to the redirect services") return worker.handle_args(parser)
def test_args_origin_id(monkeypatch: _pytest.monkeypatch.MonkeyPatch) -> None: """ test argument origin-id """ origin_id = "00000000-0000-0000-0000-000000000001" monkeypatch.setattr(sys, "argv", ["./test-worker.py", "--origin-id", origin_id]) args = worker.handle_args(worker.parseargs("Test worker")) actapi = worker.init_act(args) assert actapi.config.origin_id == origin_id fact = actapi.fact("mentions") \ .source("report", "xyz")\ .destination("fqdn", "test.com") assert fact.origin.id == origin_id
def main() -> None: """Main function""" args = worker.handle_args(parseargs()) actapi = worker.init_act(args) ta_cards = worker.fetch_json(args.thaicert_url, args.proxy_string, args.http_timeout) process(actapi, ta_cards["values"]) vocab = worker.fetch_json(STIX_VOCAB, args.proxy_string, args.http_timeout) add_sectors(actapi, ta_cards["values"], vocab) countries = worker.fetch_json(COUNTRY_REGIONS, args.proxy_string, args.http_timeout) countries = [country["name"].lower() for country in countries] add_countries(actapi, ta_cards["values"], countries) tools = worker.fetch_json(THAICERT_TOOLS_URL, args.proxy_string, args.http_timeout) add_tools(actapi, ta_cards["values"], tools["values"])
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) if not args.apikey: sys.stderr.write( "You must specify --apikey on command line or in config file\n") sys.exit(1) auth = None if args.http_user: auth = (args.http_user, args.http_password) actapi = act.api.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, worker.worker_name(), requests_common_kwargs={'auth': auth}) in_data = sys.stdin.read().strip() proxies = { 'http': args.proxy_string, 'https': args.proxy_string } if args.proxy_string else None vtapi = VirusTotalApi(args.apikey, proxies=proxies) if args.hexdigest: handle_hexdigest(actapi, vtapi, in_data, output_format=args.output_format) if args.ip: handle_ip(actapi, vtapi, in_data, output_format=args.output_format) if args.domain: handle_domain(actapi, vtapi, in_data, output_format=args.output_format)
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) if not args.country_codes: worker.fatal( "You must specify --country-codes on command line or in config file" ) if not os.path.isfile(args.country_codes): worker.fatal( "Country/region file not found at specified location: {}".format( args.country_codes), 2) # Get map of CC -> Country Name cn_map = get_cn_map(args.country_codes) db_cache = get_db_cache(CACHE_DIR) # Read IPs from stdin if args.stdin: in_data = sys.stdin.read().split("\n") handle_ip(actapi, cn_map, in_data, db_cache, args.proxy_string, args.output_format) # Bulk lookup elif args.bulk: all_ips = open(args.bulk, "r").readlines() batch_size = 50 i = 0 while i < len(all_ips): handle_ip(actapi, cn_map, (all_ips[i:i + batch_size]), db_cache, args.proxy_string, args.output_format) i += batch_size time.sleep(1) db_cache.close()
def main() -> None: "main function" try: # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) if not (args.act_baseurl and args.user_id): fatal("--act-baseurl and --user-id must be specified") if not (args.list or args.add or args.delete): fatal("Specify either --list, --add or --delete") if (args.delete) and not (args.origin_id): fatal("Specify --origin-id to delete an origin") actapi = worker.init_act(args) origin_handler(actapi, args) except Exception: error("Unhandled exception: {}".format(traceback.format_exc())) raise
def main_log_error() -> None: "Main function. Log all exceptions to error" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) auth = None if args.http_user: auth = (args.http_user, args.http_password) actapi = act.api.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, worker.worker_name(), requests_common_kwargs={'auth': auth}) try: process( actapi, worker.fetch_json(args.country_region_url, args.proxy_string, args.http_timeout), args.output_format ) except Exception: error("Unhandled exception: {}".format(traceback.format_exc())) raise
def main_log_error() -> None: "Call main() and log all exceptions as errors" try: # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(worker.parseargs("Generic uploader")) auth = None if args.http_user: auth = (args.http_user, args.http_password) actapi = act.api.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, worker.worker_name(), requests_common_kwargs={'auth': auth}) main(actapi) except Exception: error("Unhandled exception: {}".format(traceback.format_exc())) raise
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) fact_type_definition_path = pathlib.Path( args.fact_type_definition).expanduser().resolve() if not fact_type_definition_path.is_file(): print(f"{fact_type_definition_path} is not a file.") sys.exit(1) with fact_type_definition_path.open() as typedef: graph = graph_from_type_def(typedef, args.avoid, args.include, args.avoid_cost) start_type, start_value = args.start end_type, end_value = args.end start, end = find_start_and_end_nodes(graph, start_type, end_type) if not start: print(f"{start_type} is not an object type") sys.exit(1) if not end: print(f"{end_type} is not an object type") sys.exit(1) res = dijkstra(graph, start, end) chain = fact_chain_from_path_result(actapi, res, start, end, start_value, end_value) for fact in chain: handle_fact(fact, output_format=args.output_format)
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) auth = None if args.http_user: auth = (args.http_user, args.http_password) actapi = act.api.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, worker.worker_name(), requests_common_kwargs={'auth': auth}) # Add IOCs from reports to the ACT platform add_to_act( actapi, get_scio_report(), args.output_format, )
def main() -> None: """Main function""" args = worker.handle_args(worker.parseargs("IP Filter")) worker.init_act(args) process()
def main() -> None: """ Main function """ # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) if not args.ta: sys.stderr.write( "You must specify Threat Actor with --ta <THREAT ACTOR>\n") sys.exit(1) # Normalize and lookup country/technique/sectors # Print error with suggested match if not found ok = True try: args.target_countries = [ country_lookup(args, country) for country in args.target_countries ] except (VocabularyException, FileNotFoundError, worker.UnsupportedScheme) as e: sys.stderr.write(str(e)) ok = False try: args.techniques = [technique_lookup(tech) for tech in args.techniques] except VocabularyException as e: sys.stderr.write(str(e)) ok = False try: if args.ta_located_in: args.ta_located_in = country_lookup(args, args.ta_located_in) except VocabularyException as e: sys.stderr.write(str(e)) ok = False try: args.sectors = [sector_lookup(args, sector) for sector in args.sectors] except VocabularyException as e: sys.stderr.write(str(e)) ok = False if not ok: sys.exit(1) if args.target_countries: add_ta_target_country(actapi, args.output_format, args.ta, args.target_countries) if args.campaign: add_ta_campaign(actapi, args.output_format, args.ta, args.campaign) if args.tools: add_ta_tools(actapi, args.output_format, args.ta, args.tools) if args.techniques: add_ta_techniques(actapi, args.output_format, args.ta, args.techniques) if args.sectors: add_ta_sectors(actapi, args.output_format, args.ta, args.sectors) if args.ta_located_in: add_ta_located_in(actapi, args.output_format, args.ta, args.ta_located_in)
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) if not (args.privatekey and args.publickey): worker.fatal("You must specify --privatekey and --publickey on command line or in config file") proxies = { 'http': args.proxy_string, 'https': args.proxy_string } if args.proxy_string else None iSightHandler = ISightAPIRequestHandler(args.root, args.privatekey, args.publickey) data = iSightHandler.indicators(days=args.days, proxies=proxies) if 'success' not in data or not data['success']: logging.error("Unable to download from isight API [%s]", data['message'] if 'message' in data else "NA") return timestamp = int(time.time()) ### DEBUG -- dump json to disc for each run if args.debugdir: with open(os.path.join(args.debugdir, "error-{0}.json".format(timestamp)), "w") as f: json.dump(data, f) for i, dp in enumerate(data['message']): ### --- Handle mentions facts # Create report ID from the url (same approach as for feeds) and title to this ID. reportID = hashlib.sha256(dp['webLink'].encode('utf8')).hexdigest() handle_fact(actapi.fact('name', dp['title']).source('report', reportID)) for obj in OBJECT_MAP: # run through all fields that we want to mention if obj in dp and dp[obj]: # if the report contains data in the field factType = OBJECT_MAP[obj](dp[obj]) # translate to ACT fact type handle_fact(actapi.fact('mentions') # and create fact from field .source('report', reportID) .destination(factType, dp[obj].lower())) if dp['url']: handle_fact(actapi.fact('mentions') .source('report', reportID) .destination('uri', dp['url'])) try: handle_uri(actapi, dp['url']) except act.api.base.ValidationError as err: logging.error("%s while storing url from mentions [%s]", err, dp['url']) ### --- IP -> malwareFamily if dp['malwareFamily'] and dp['ip']: chain = act.api.fact.fact_chain( actapi.fact('connectsTo') .source('content', '*') .destination('uri', '*'), actapi.fact('componentOf') .source('ipv4', dp['ip']) .destination('uri', '*'), actapi.fact('classifiedAs') .source('content', '*') .destination('tool', dp['malwareFamily'].lower())) for fact in chain: handle_fact(fact) ### --- URL -> malwareFamily elif dp['networkType'] == 'url' and dp['malwareFamily']: try: handle_uri(actapi, dp['url']) except act.api.base.ValidationError as err: logging.error("%s while storing url from mentions [%s]", err, dp['url']) chain = act.api.fact.fact_chain( actapi.fact('connectsTo') .source('content', '*') .destination('uri', dp['url']), actapi.fact('classifiedAs') .source('content', '*') .destination('tool', dp['malwareFamily'].lower())) for fact in chain: handle_fact(fact) ### --- FQDN -> malwareFamily elif dp['networkType'] == 'network' and dp['domain'] and dp['malwareFamily']: chain = act.api.fact.fact_chain( actapi.fact('connectsTo') .source('content', '*') .destination('uri', '*'), actapi.fact('componentOf') .source('fqdn', dp['domain']) .destination('uri', '*'), actapi.fact('classifiedAs') .source('content', '*') .destination('tool', dp['malwareFamily'].lower())) for fact in chain: handle_fact(fact) ### --- hash -> malwareFamily elif dp['fileType'] and dp['malwareFamily'] and (dp['sha1'] or dp['sha256'] or dp['md5']): for digest_type in ['md5', 'sha1', 'sha256']: ### In some cases the iSight api does not return a sha256 hashdigest ### so we need to make a chain through a placeholder content if not dp['sha256']: if dp[digest_type]: chain = act.api.fact.fact_chain( actapi.fact('represents') .source('hash', dp[digest_type]) .destination('content', '*'), actapi.fact('classifiedAs') .source('content', '*') .destination('tool', dp['malwareFamily'])) for fact in chain: handle_fact(fact) else: ## There is a sha256, so we do _not_ need a chain if dp[digest_type]: handle_fact(actapi.fact('classifiedAs') .source('content', dp['sha256']) .destination('tool', dp['malwareFamily'])) handle_fact(actapi.fact('represents') .source('hash', dp[digest_type]) .destination('content', dp['sha256'])) ### -- Hash --> actor elif dp['fileType'] and dp['actor'] and (dp['sha1'] or dp['sha256'] or dp['md5']): for digest_type in ['md5', 'sha1', 'sha256']: ### In some cases the iSight api does not return a sha256 hashdigest ### so we need to make a chain through a placeholder content if not dp['sha256']: if dp[digest_type]: chain = act.api.fact.fact_chain( actapi.fact('represents') .source('hash', dp[digest_type]) .destination('content', '*'), actapi.fact('observedIn') .source('content', '*') .destination('event', '*'), actapi.fact('attributedTo') .source('event', '*') .destination('incident', '*'), actapi.fact('attributedTo') .source('incident', '*') .destination('threatActor', dp['actor'])) for fact in chain: handle_fact(fact) else: ## There is a sha256, so we do _not_ need a chain between all the way from hexdigest if dp[digest_type]: handle_fact(actapi.fact('represents') .source('hash', dp[digest_type]) .destination('content', dp['sha256'])) chain = act.api.fact.fact_chain( actapi.fact('observedIn') .source('content', dp['sha256']) .destination('event', '*'), actapi.fact('attributedTo') .source('event', '*') .destination('incident', '*'), actapi.fact('attributedTo') .source('incident', '*') .destination('threatActor', dp['actor'])) for fact in chain: handle_fact(fact) ### We do have a sha256 of a file (but possibly nothing else). Add the content to hexdigest facts elif dp['fileType'] and dp['sha256']: for digest in ['sha1', 'md5', 'sha256']: if dp[digest]: handle_fact(actapi.fact('represents') .source('hash', dp[digest]) .destination('content', dp['sha256'])) if args.debugdir: fields = [k for k, v in dp.items() if v and k not in ['reportId', 'title', 'ThreatScape', 'audience', 'intelligenceType', 'publishDate', 'reportLink', 'webLink']] logging.error("[%s] Extra fields while handeling index[%s] '%s'", timestamp, i, ", ".join(fields)) ### -- DEBUG! else: if args.debugdir: fields = [k for k, v in dp.items() if v and k not in ['reportId', 'title', 'ThreatScape', 'audience', 'intelligenceType', 'publishDate', 'reportLink', 'webLink']] logging.error("[%s] Unable to handle index[%s] with fields '%s'", timestamp, i, ", ".join(fields))
def main() -> None: """main function""" # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini # (or replace .config with $XDG_CONFIG_DIR if set) args = worker.handle_args(parseargs()) actapi = worker.init_act(args) if not args.country_codes: worker.fatal( "You must specify --country-codes on command line or in config file" ) if not args.veris_prefix: worker.fatal("You must specify --veris-prefix") if not (args.veris_url or args.veris_file or args.stdin): worker.fatal("You must specify --veris-url, --veris-file or --stdin") args.veris_prefix = args.veris_prefix.upper() if not os.path.isfile(args.country_codes): worker.fatal( "Country/region file not found at specified location: {}".format( args.country_codes), 2) args.threat_actor_variety = [ variety.strip() for variety in args.threat_actor_variety.split(",") ] # Configuration object that will be passed around to functions config = { # act API "actapi": actapi, # Map of CC -> Country Name "cn_map": get_cn_map(args.country_codes), # Map of CC -> Country Name "campaign_map": get_campaigns(args.veris_prefix, args.veris_campaign) if args.veris_campaign else {}, # Cache of url > sha256 "db_cache": urlcache.URLCache( requests_common_kwargs={ "proxies": { 'http': args.proxy_string, 'https': args.proxy_string }, "timeout": args.http_timeout }), "proxies": { 'http': args.proxy_string, 'https': args.proxy_string } if args.proxy_string else None, } # Add all arguments from args to config config.update(vars(args)) process(config)