def main(): args = parseargs() client = act.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, "mitre-attack") for url in (MITRE_ENTERPRISE_ATTACK_URL, MITRE_MOBILE_ATTACK_URL, MITRE_PRE_ATTACK_URL): cache = notify_cache(args.notifycache) # Get attack dataset as Stix Memory Store attack = get_attack(url, args.proxy_string, args.timeout) (techniques, techniques_notify) = get_techniques(attack) (groups, groups_notify) = get_groups(attack) (software, software_notify) = get_software(attack) # Add facts to platform facts = techniques + groups + software for (source_type, source_values, fact_type, destination_type, destination_values, link_type) in facts: add_fact(client, source_type, source_values, fact_type, destination_type, destination_values, link_type) # Get revoked objects, excluding those in cache notify = [ notify for notify in techniques_notify + groups_notify + software_notify if notify.id not in cache ] if notify: send_notification(notify, args.notifycache, args.smtphost, args.sender, args.recipient)
def test_get_object_by_type_value(): mock = get_mock_data("data/post_v1_object_facts_200.json") responses.add( responses.POST, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) obj = c.object(type="ipv4", value="127.0.0.1") facts = obj.facts() assert not facts.complete assert len(facts) == facts.size # We should have at least one fact assert len(facts) > 1 # All facts should be of type Fact assert all([isinstance(fact, act.fact.Fact) for fact in facts]) # All facts should have an UUID assert all([re.search(RE_UUID_MATCH, fact.id) for fact in facts])
def test_object_search(): mock = get_mock_data("data/post_v1_object_search_200.json") responses.add( responses.POST, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) objects = c.object_search( fact_type=["seenIn"], fact_value=["report"], limit=25) assert not objects.complete assert objects.size == 25 assert objects.count > 1000 obj = objects[0] # Objects should not have "object_type", since that property is stored in # "type" with pytest.raises(AttributeError): # pylint: disable=pointless-statement obj.object_type # Objects should not have "object_value", since that property is stored in # "value" with pytest.raises(AttributeError): # pylint: disable=pointless-statement obj.object_value # All facts should have an UUID assert all([re.search(RE_UUID_MATCH, obj.id) for obj in objects])
def setup(): cfg = cli.getConfStanza('act', 'config') app = cli.getConfStanza('app', 'launcher') api_url = cfg.get("api_url") user_id = cfg.get("act_userid") api_proxy = cfg.get("api_proxy") api_http_user = cfg.get("api_http_user") api_http_password = cfg.get("api_http_auth") requests_opt = { "headers": { # Include version string in user agent header "User-Agent": "act-splunk-{}".format(app.get("version")) } } if api_http_user or api_http_password: requests_opt["auth"] = (api_http_user, api_http_password) if api_proxy: requests_opt["proxies"] = { "http": api_proxy, "https": api_proxy, } return act.Act(api_url, user_id=user_id, log_level="warning", requests_common_kwargs=requests_opt)
def test_fact_acl(): mock = get_mock_data("data/get_v1_fact_uuid_access_200.json") responses.add(responses.GET, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) uuid = re.search(RE_UUID, mock["url"]).group("uuid") acl = c.fact(id=uuid).get_acl() assert acl == []
def test_get_fact_types(): mock = get_mock_data("data/get_v1_factType_200.json") responses.add(responses.GET, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) fact_types = c.get_fact_types() assert fact_types.size == len(fact_types)
def main(): """main function""" args = parse_args() actapi = act.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, "cyber-uio") in_data = sys.stdin.read().strip() if args.hexdigest: handle_hexdigest(actapi, in_data, args.proxy)
def test_fact_add_comment(): mock = get_mock_data("data/post_v1_fact_uuid_comments_201.json") responses.add(responses.POST, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) # Get comments uuid = re.search(RE_UUID, mock["url"]).group("uuid") c.fact(id=uuid).add_comment("Test comment")
def test_create_object_type(): mock = get_mock_data("data/post_v1_objectType_201.json") responses.add( responses.POST, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) object_type = c.object_type( name="threatActor", validator=".+").add() assert object_type.name == "threatActor" assert re.search(RE_UUID_MATCH, object_type.id)
def test_fact_get_comments(): mock = get_mock_data("data/get_v1_fact_uuid_comments_200.json") responses.add(responses.GET, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) # Get comments uuid = re.search(RE_UUID, mock["url"]).group("uuid") comments = c.fact(id=uuid).get_comments() assert comments # Should be non empty assert comments[0].comment == "Test comment" assert re.search(RE_TIMESTAMP, comments[0].timestamp) assert all([isinstance(comment, act.base.Comment) for comment in comments])
def test_add_fact(): mock = get_mock_data("data/post_v1_fact_201.json") responses.add(responses.POST, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) f = c.fact("seenIn", "report") \ .source("ipv4", "127.0.0.1") \ .destination("report", "xyz") assert f.type.name == "seenIn" assert f.value == "report" # We do not have id or timestamp yet assert f.id is None assert f.timestamp is None assert f.source_object is not None assert f.destination_object is not None assert f.bidirectional_binding is not None # Add fact f.add() fact_repr = repr(f) repr_f = eval(fact_repr) assert f == repr_f assert f.value == repr_f.value assert f.type.name == repr_f.type.name assert f.source_object == repr_f.source_object assert f.source_object.value == repr_f.source_object.value assert f.destination_object.type == repr_f.destination_object.type assert f.destination_object.value == repr_f.destination_object.value assert str(f) == str(repr_f) assert str(f) == \ "(ipv4/127.0.0.1) -[seenIn/report]-> (report/87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7)" # id, timestamp and organization should now be fetched from API assert re.search(RE_UUID_MATCH, f.id) assert re.search(RE_TIMESTAMP_MATCH, f.timestamp) assert re.search(RE_UUID_MATCH, f.organization.id)
def test_get_object_by_uuid(): mock = get_mock_data("data/post_v1_object_uuid_facts_200.json") responses.add( responses.POST, mock["url"], json=mock["json"], status=mock["status_code"]) uuid = re.search(RE_UUID, mock["url"]).group("uuid") c = act.Act("http://localhost:8080", 1) obj = c.object(id=uuid) facts = obj.facts() assert all([re.search(RE_UUID_MATCH, fact.id) for fact in facts])
def test_get_object_search(): mock = get_mock_data("data/post_v1_object_traverse_200.json") responses.add( responses.POST, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) obj = c.object(type="ipv4", value="127.0.0.1") path = obj.traverse('g.bothE("seenIn").bothV().path().unfold()') # Should contain both objects and facts assert any([isinstance(elem, act.obj.Object) for elem in path]) assert any([isinstance(elem, act.fact.Fact) for elem in path])
def test_get_object_types(): mock = get_mock_data("data/get_v1_objectType_200.json") responses.add( responses.GET, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) object_types = c.get_object_types() # We should have a fqdn object type assert "fqdn" in [object_t.name for object_t in object_types] # All object types should have a valid uuid assert all([re.search(RE_UUID_MATCH, object_t.id) for object_t in object_types])
def test_fact_search(): mock = get_mock_data("data/post_v1_fact_search_200.json") responses.add(responses.POST, mock["url"], json=mock["json"], status=mock["status_code"]) c = act.Act("http://localhost:8080", 1) facts = c.fact_search(fact_type=["seenIn"], fact_value=["report"], limit=25) assert not facts.complete assert facts.size == 25 assert facts.count > 1000 # All facts should have an UUID assert all([re.search(RE_UUID_MATCH, fact.id) for fact in facts])
def main(): """main function""" args = parse_args() actapi = act.Act(args.act_baseurl, args.user_id, args.loglevel, args.logfile, "vt-enrichment") in_data = sys.stdin.read().strip() proxies = {'http': args.proxy, 'https': args.proxy} if args.proxy else None vtapi = VirusTotalApi(args.apikey, proxies=proxies) if args.hexdigest: handle_hexdigest(actapi, vtapi, in_data) if args.ip: handle_ip(actapi, vtapi, in_data) if args.domain: handle_domain(actapi, vtapi, in_data)
def test_create_fact_type(): mock = get_mock_data("data/post_v1_factType_201.json") responses.add(responses.POST, mock["url"], json=mock["json"], status=mock["status_code"]) mock_data = mock["json"]["data"] threat_actor_id = mock_data["relevantObjectBindings"][0][ "destinationObjectType"]["id"] c = act.Act("http://localhost:8080", 1) fact_type = c.fact_type(name="threatActorAlias", validator=".+", relevant_object_bindings=[ act.fact.RelevantObjectBindings( act.obj.Object(id=threat_actor_id), act.obj.Object(id=threat_actor_id), True) ]).add() assert fact_type.name == "threatActorAlias" assert re.search(RE_UUID_MATCH, fact_type.id)
help="Loglevel (default = info)") return parser.parse_args() def process(actapi): """Process stdin, parse each separat line as a JSON structure and register a fact based on the structure. The form of input should be the on the form accepted by the ACT Rest API fact API.""" for line in sys.stdin: data = json.loads(line) fact = actapi.fact(**data) try: fact.add() except act.base.ResponseError as err: error("ResponseError while storing objects: %s" % err) if __name__ == '__main__': ARGS = parseargs() try: actapi = act.Act(ARGS.act_baseurl, ARGS.user_id, ARGS.loglevel, ARGS.logfile, "generic-uploader") process(actapi) except Exception as e: error("Unhandled exception: {}".format(traceback.format_exc())) raise
"uri", "*")) for fact in fact_chain(*chain): # Find content value (placeholder) handle_fact(fact) # Replace content with placeholder object if this was previously unknown if content == "*" and fact.destination_object.type.name == "content": content = fact.destination_object.value # Add port to uri placeholder if port and fact.destination_object.type.name == "uri": handle_fact( client.fact("port", str(port)).source( "uri", fact.destination_object.value)) if content != "*": handle_fact( client.fact("classifiedAs").source("content", content).destination( "tool", "carbanak")) if __name__ == '__main__': args = parseargs() carbanak_report( act.Act(args.act_baseurl, args.user_id, args.loglevel, args.log_file, "fireye-carbanak"), get_md5_lookup(args.md5_lookup), )
def create_api_agent(baseurl, userid): """creates an ACT API agent""" c = act.Act(baseurl, userid, log_level="info") return c
if location: client.fact("sourceGeography")\ .destination("location", location)\ .source("threatActor", name)\ .add() elif country: warning("country code not found in ISO, ISO3 or FIPS: %s\n" % country) # Loop over all items under indicators in report for alias in aliases: if alias == name: continue # Do not alias to ourself client.fact("threatActorAlias")\ .bidirectional("threatActor", alias, "threatActor", name)\ .add() if __name__ == '__main__': args = parseargs() client = act.Act(args.act_baseurl, args.user_id, args.log_level, args.log_file, "misp-threat-actors") # Get all reports from SCIO ta = get_misp_threat_actors() # Add IOCs from reports to the ACT platform add_to_act(client, ta)
if rrtype in RRTYPE_M: fact = actapi.fact(RRTYPE_M[rrtype]["fact_t"], RRTYPE_M[rrtype]["fact_v"]) fact = fact.source(RRTYPE_M[rrtype]["source_t"], query) fact = fact.destination(RRTYPE_M[rrtype]["dest_t"], answer) fact.add() elif rrtype == "ptr": pass # We do not insert ptr to act else: warning("Unsupported rrtype: %s: %s" % (rrtype, row)) class UnknownResult(Exception): """UnknownResult is used in API request (not 200 result)""" def __init__(self, *args, **kwargs): Exception.__init__(self, *args, **kwargs) if __name__ == '__main__': ARGS = parseargs() try: actapi = act.Act(ARGS.act_baseurl, ARGS.user_id, ARGS.loglevel, ARGS.logfile, "pdns-enrichment") process(actapi, ARGS.pdns_baseurl, ARGS.apikey, ARGS.timeout) except Exception as e: error("Unhandled exception: {}".format(traceback.format_exc())) raise
actapi, "threatActor", doc.get("threat-actor", {}).get("names", []), report_id) # Tools seen_in_report_fact( actapi, "tool", doc.get("tools", {}).get("names", []), report_id) # Sector seen_in_report_fact( actapi, "sector", doc.get("sectors", []), report_id) if __name__ == '__main__': ARGS = parseargs() try: actapi = act.Act(ARGS.act_baseurl, ARGS.act_user_id, ARGS.loglevel, ARGS.logfile, "scio") # Add IOCs from reports to the ACT platform add_to_act(actapi, get_scio_report()) except Exception as e: error("Unhandled exception: {}".format(traceback.format_exc())) raise
for location_type, location in c_map.items(): if not location: continue # Skip locations with empty values # Skip facts that are already added if location_type in LOCATION_TYPE_M and location not in facts_added: fact_type = LOCATION_TYPE_M[location_type] facts_added[location] = fact_type fact = actapi.fact(fact_type).source("location", location) if actapi.act_baseurl: fact.add() # Add fact to platform, if baseurl is specified else: print(fact.json( )) # Print fact to stdout, if baseurl is NOT specified if __name__ == '__main__': ARGS = parseargs() try: actapi = act.Act(ARGS.act_baseurl, ARGS.user_id, ARGS.loglevel, ARGS.logfile, "country-region") country_list = worker.fetch_json(ARGS.country_region_url, ARGS.proxy_string, ARGS.timeout) process(actapi, country_list) except Exception as e: error("Unhandled exception: {}".format(traceback.format_exc())) raise
meta_fact_types = json.loads(open(meta_fact_types_filename).read()) except json.decoder.JSONDecodeError: critical("Unable to parse file as json: %s" % meta_fact_types_filename) sys.exit(1) for meta_fact_type in meta_fact_types: name = meta_fact_type["name"] validator = meta_fact_type.get("validator", act.DEFAULT_VALIDATOR) fact_bindings = meta_fact_type.get("factBindings", []) if not fact_bindings: client.create_meta_fact_type_all_bindings(name, validator_parameter=validator) else: client.create_meta_fact_type(name, fact_bindings=fact_bindings, validator=validator) if __name__ == "__main__": args = parseargs() client = act.Act( args.act_baseurl, args.user_id, args.log_level, args.log_file, "act-types") create_object_types( client, object_types_filename=args.object_types_filename) create_fact_types(client, fact_types_filename=args.fact_types_filename) create_meta_fact_types(client, meta_fact_types_filename=args.meta_fact_types_filename)
try: fact.add() n += 1 except act.base.ResponseError as err: e += 1 log(str(err)) else: print(Style.BRIGHT, Fore.YELLOW, fact.json(), Style.RESET_ALL) log("Added {0} facts. {1} errors.".format(n, e)) for k, v in status.items(): log("{} {} sent to enrichment".format(v, k)) if __name__ == "__main__": ARGS = parseargs() CONF = configparser.ConfigParser() read = CONF.read(ARGS.config) if len(read) == 0: print("Could not read config file") sys.exit(1) try: actapi = act.Act(CONF['platform']['base_url'], ARGS.act_user_id, CONF['misp']['loglevel'], CONF['misp']['logfile'], "misp-import") main(actapi) except Exception as e: error("Unhandled exception: {}".format(traceback.format_exc())) raise
return filtered_result def out_result(filename, entries): with open(filename, "w") as f: f.write( json.dumps(entries, sort_keys=True, indent=4, separators=(',', ': '))) if __name__ == '__main__': args = parseargs() client = act.Act(args.act_baseurl, args.user_id, args.log_level, args.log_file, "mitre-attack") if args.models in ("all", "attack", "pre-attack"): attack_software_raw = mediawiki_ask(MITRE_ATTACK_URL, "[[Category:Software]]", MITRE_ALL_PROPERTIES) if args.models == "all" or args.models == "attack": attack_group_raw = mediawiki_ask(MITRE_ATTACK_URL, "[[Category:Group]]", MITRE_ALL_PROPERTIES) attack_technique_raw = mediawiki_ask(MITRE_ATTACK_URL, "[[Category:Technique]]", MITRE_ALL_PROPERTIES) attack_tactic_raw = mediawiki_ask(MITRE_ATTACK_URL, "[[Category:Tactic]]",