Beispiel #1
0
def handle_campaign(config: Dict[Text, Any], incident: Dict[Text, Any],
                    incident_id: Text) -> None:
    """
    Create incident -attributedTo-> campaign facts
    If we have a mapping from campaign (UUID) to name, a campaign -name-> will also be created
    """

    campaign = ("{}-{}".format(config["veris_prefix"], incident["campaign_id"])
                if incident.get("campaign_id") else None)

    if not campaign:
        return

    handle_fact(
        config["actapi"].fact("attributedTo").source("incident",
                                                     incident_id).destination(
                                                         "campaign", campaign),
        output_format=config["output_format"],
    )

    name = config["campaign_map"].get(format(campaign))

    if name:
        handle_fact(
            config["actapi"].fact("name", name).source("campaign", campaign),
            output_format=config["output_format"],
        )

    else:
        warning(
            "No name found for campaign {}. Make sure veris-campaign is provided and the ID is included in csv field (without prefix)"
            .format(campaign))
Beispiel #2
0
def handle_organizations(
    config: Dict[Text, Any], incident: Dict[Text, Any], incident_id: Text
) -> None:
    """
    Create facts:
        * incident -targets-> organization
        * organization -locatedIn-> country
    """
    victim = incident.get("victim", {}).get("victim_id")

    if not victim:
        return

    handle_fact(
        config["actapi"]
        .fact("targets")
        .source("incident", incident_id)
        .destination("organization", victim),
        output_format=config["output_format"],
    )

    for country_code in incident.get("victim", {}).get("country", []):
        country = config["cn_map"].get(country_code)

        if country:
            handle_fact(
                config["actapi"]
                .fact("locatedIn")
                .source("organization", victim)
                .destination("country", country),
                output_format=config["output_format"],
            )
Beispiel #3
0
def process(
    actapi: act.api.Act,
    country_list: List[Dict[str, str]],
    output_format: Text = "json",
) -> None:
    """
    Loop over all ISO-3166 countries and construct facts for
    county -memberOf-> subRegion and subRegion -memberOf-> region.
    """

    for c_map in country_list:
        country_name = c_map["name"]
        sub_region = c_map["sub-region"]
        region = c_map["region"]

        if country_name and sub_region:
            handle_fact(
                actapi.fact("memberOf")
                .source("country", country_name)
                .destination("subRegion", sub_region),
                output_format=output_format,
            )
        else:
            warning("Missing name or sub-region: {}".format(c_map))

        if sub_region and region:
            handle_fact(
                actapi.fact("memberOf")
                .source("subRegion", sub_region)
                .destination("region", region),
                output_format=output_format,
            )
        else:
            warning("Missing sub-region or region: {}".format(c_map))
Beispiel #4
0
def add_sectors(client: act.api.Act,
                ta_cards: List,
                vocab: List,
                output_format: Text = "json") -> None:
    """
    Only submit sectors if in STIX vocabulary
    """
    for actor in ta_cards:
        if "observed-sectors" in actor:
            for sector in actor["observed-sectors"]:
                if sector.lower(
                ) in vocab["definitions"]["industry-sector-ov"]["enum"]:
                    for ta in actor["actor"].split(","):
                        chain = act.api.fact.fact_chain(
                            client.fact("memberOf").source(
                                "organization",
                                "*").destination("sector", sector.lower()),
                            client.fact("targets").source("incident",
                                                          "*").destination(
                                                              "organization",
                                                              "*"),
                            client.fact("attributedTo").source(
                                "incident",
                                "*").destination("threatActor", ta),
                        )

                    for fact in chain:
                        handle_fact(fact, output_format=output_format)
Beispiel #5
0
def handle_reports(
    config: Dict[Text, Any], incident: Dict[Text, Any], incident_id: Text
) -> None:
    """
    Extract all references in incident. For each (URL-)reference, check whether we should
    download the content and creaa a sha256 hash digest of it (must match config["hash_url_matching"]).
    The sha256 hash is also cached locally.
    """

    # Split references by ";"
    references = [
        ref.strip() for ref in incident.get("reference", "").split(";") if ref.strip()
    ]

    if references:
        for ref in references:
            if not re.search(config["hash_url_matching"], ref):
                continue

            report_hash = config["db_cache"].query_download_update(ref)

            if report_hash:
                handle_fact(
                    config["actapi"]
                    .fact("mentions")
                    .source("report", report_hash)
                    .destination("incident", incident_id),
                    output_format=config["output_format"],
                )
Beispiel #6
0
def handle_threat_actor(
    config: Dict[Text, Any], incident: Dict[Text, Any], incident_id: Text
) -> None:
    """
    Creat facts from actor->external, where the variety includes at least on variety specified in config["threat_actor_variety"]

    """

    external_actor = incident.get("actor", {}).get("external", {})

    if not external_actor:
        return  # No threat actors

    # Varieties are "tags" on actors and we do not want to include all type of actors
    # Make sure at least one of the varieties are in the list of the configured varieties to include
    if any(
        [
            variety in config["threat_actor_variety"]
            for variety in external_actor.get("variety", [])
        ]
    ):
        threat_actors = [
            ta.strip()
            for ta in incident.get("actor", {}).get("external", {}).get("name", [])
        ]

        for ta in threat_actors:
            handle_fact(
                config["actapi"]
                .fact("attributedTo")
                .source("incident", incident_id)
                .destination("threatActor", ta),
                output_format=config["output_format"],
            )
Beispiel #7
0
def add_to_act(actapi: act.api.Act,
               doc: Dict,
               output_format: Text = "json") -> None:
    """Add a report to the ACT platform"""

    report_id: Text = doc["hexdigest"]
    title: Text = doc.get("title", "No title")
    indicators: Dict = doc.get("indicators", {})

    try:
        # Report title
        handle_fact(
            actapi.fact("name", title).source("report", report_id),
            output_format)
    except act.api.base.ResponseError as e:
        error("Unable to create fact: %s" % e)

    # Loop over all items under indicators in report
    for scio_indicator_type in EXTRACT_INDICATORS:
        # Get object type from ACT (default to object type in SCIO)
        act_indicator_type = SCIO_INDICATOR_ACT_MAP.get(
            scio_indicator_type, scio_indicator_type)
        report_mentions_fact(actapi, act_indicator_type,
                             indicators.get(scio_indicator_type, []),
                             report_id, output_format)

    # For SHA256, create content object
    for sha256 in list(set(indicators.get("sha256", []))):
        handle_fact(
            actapi.fact("represents").source("hash", sha256).destination(
                "content", sha256), output_format)

    # Add all URI components
    for uri in list(set(indicators.get("uri", []))):
        try:
            handle_uri(actapi, uri, output_format=output_format)
        except act.api.schema.MissingField:
            error("Unable to create facts from uri: {}".format(uri))

    # Locations (countries, regions, sub regions)
    for location_type in EXTRACT_GEONAMES:
        locations = doc.get("geonames", {}).get(location_type, [])

        report_mentions_fact(actapi, SCIO_GEONAMES_ACT_MAP[location_type],
                             locations, report_id, output_format)

    # Threat actor
    report_mentions_fact(actapi, "threatActor",
                         doc.get("threat-actor", {}).get("names", []),
                         report_id, output_format)

    # Tools
    report_mentions_fact(
        actapi, "tool",
        [tool.lower() for tool in doc.get("tools", {}).get("names", [])],
        report_id, output_format)

    # Sector
    report_mentions_fact(actapi, "sector", doc.get("sectors", []), report_id,
                         output_format)
Beispiel #8
0
def handle_tool(config: Dict[Text, Any], incident: Dict[Text, Any],
                incident_id: Text) -> None:
    "Create content -classifiedAs-> tool, and fact chain from content to incident. "

    # Both "," and ";" are used to separate tools :(

    tools = [
        malware.strip().lower() for malware in re.split(
            r';|,',
            incident.get("action", {}).get("malware", {}).get("name", ""))
        if malware
    ]

    for tool in tools:
        chain = act.api.fact.fact_chain(
            config["actapi"].fact("classifiedAs").source("content",
                                                         "*").destination(
                                                             "tool", tool),
            config["actapi"].fact("observedIn").source("content",
                                                       "*").destination(
                                                           "event", "*"),
            config["actapi"].fact("attributedTo").source(
                "event", "*").destination("incident", incident_id),
        )

        for fact in chain:
            handle_fact(fact, output_format=config["output_format"])
Beispiel #9
0
def process(client: act.api.Act,
            ta_cards: List,
            output_format: Text = "json") -> None:
    "Extract threat actor cards from ThaiCERT"

    # Keep list of names with an alias points to
    # There should only be one to have a meaningfull alias
    ta_alias_names = defaultdict(set)
    ta_aliases = {}

    for actor in ta_cards:
        ta_name = actor["names"][0]["name"]

        ta_aliases[ta_name] = []

        for alias in actor["names"][1:]:
            alias_name = alias["name"]

            # names might be identical after format/normalization
            if ta_name == alias_name:
                continue

            ta_alias_names[alias_name].add(ta_name)
            ta_aliases[ta_name].append(alias_name)

    for ta_name in ta_aliases:
        for alias_name in ta_aliases[ta_name]:

            # This alias is mentioned for multiple main threat
            # actors so we skip this alias
            if len(ta_alias_names[alias_name]) > 1:
                warning(
                    f"Skipping TA alias {alias_name} <-> {ta_name} since {alias_name} is alias for multiple names: {ta_alias_names[alias_name]}"
                )
                continue

            handle_fact(
                client.fact("alias").bidirectional("threatActor", ta_name,
                                                   "threatActor", alias_name),
                output_format=output_format,
            )

    for actor in ta_cards:
        if "operations" in actor:
            for operation in actor["operations"]:
                if len(operation["activity"].split("\n")[0].split()) < 4:
                    for ta in actor["actor"].split(","):
                        handle_facts(
                            act.api.fact.fact_chain(
                                client.fact("attributedTo").source(
                                    "incident", "*").destination(
                                        "campaign",
                                        operation["activity"].split("\n")[0]),
                                client.fact("attributedTo").source(
                                    "incident",
                                    "*").destination("threatActor", ta),
                            ),
                            output_format=output_format,
                        )
Beispiel #10
0
def add_groups(client: Act,
               matrice: AttckMatrice,
               output_format: Text = "json") -> List:
    """
        extract objects/facts related to ATT&CK Threat Actors

    Args:
        attack (AttckMatrice):       Attack matrice
        output_format (Text):        "json" or "str" output format

    """

    notify: List = []

    for actor in matrice.actors:
        if deprecated_or_revoked(actor):
            # Object is revoked, add to notification list but do not add to facts that should be added to the platform
            notify.append(actor)
            continue

        for alias in actor.alias:
            if actor.name != alias:
                handle_fact(
                    client.fact("alias").bidirectional(
                        "threatActor",
                        actor.name,
                        "threatActor",
                        alias,
                    ),
                    output_format=output_format,
                )

        for tool in actor.known_tools:

            handle_facts(act.api.fact.fact_chain(
                client.fact("classifiedAs").source("content", "*").destination(
                    "tool", tool),
                client.fact("observedIn").source("content", "*").destination(
                    "incident", "*"),
                client.fact("attributedTo").source(
                    "incident", "*").destination("threatActor", actor.name),
            ),
                         output_format=output_format)

        for technique in actor.techniques:
            handle_facts(act.api.fact.fact_chain(
                client.fact("observedIn").source("technique",
                                                 technique.id).destination(
                                                     "incident", "*"),
                client.fact("attributedTo").source(
                    "incident", "*").destination("threatActor", actor.name),
            ),
                         output_format=output_format)

    return notify
Beispiel #11
0
def add_ta_campaign(client: Act, output_format: Text, threat_actor: Text,
                    campaign: Text) -> None:
    """ Threat Actor Campaign """
    chain = act.api.fact.fact_chain(
        client.fact("attributedTo").source("incident", "*").destination(
            "campaign", campaign),
        client.fact("attributedTo").source("incident", "*").destination(
            "threatActor", threat_actor))

    for fact in chain:
        handle_fact(fact, output_format=output_format)
Beispiel #12
0
def report_mentions_fact(actapi: act.api.Act, object_type: Text,
                         object_values: List[Text], report_id: Text,
                         output_format: Text) -> None:
    """Add mentions fact to report"""
    for value in list(set(object_values)):
        try:
            handle_fact(
                actapi.fact("mentions", object_type).source(
                    "report", report_id).destination(object_type, value),
                output_format)
        except act.api.base.ResponseError as e:
            error("Unable to create linked fact: %s" % e)
Beispiel #13
0
def add_ta_located_in(client: Act, output_format: Text, threat_actor: Text,
                      located_in: Text) -> None:
    """ Threat actor located in """
    chain = act.api.fact.fact_chain(
        client.fact("locatedIn").source("organization", "*").destination(
            "country", located_in),
        client.fact("attributedTo").source("threatActor",
                                           threat_actor).destination(
                                               "organization", "*"))

    for fact in chain:
        handle_fact(fact, output_format=output_format)
Beispiel #14
0
def add_ta_sectors(client: Act, output_format: Text, threat_actor: Text,
                   sectors: List[Text]) -> None:
    """ Threat Actor Sectors """
    for sector in sectors:
        chain = act.api.fact.fact_chain(
            client.fact("targets").source("incident", "*").destination(
                "organization", "*"),
            client.fact("memberOf").source("organization",
                                           "*").destination("sector", sector),
            client.fact("attributedTo").source("incident", "*").destination(
                "threatActor", threat_actor))

        for fact in chain:
            handle_fact(fact, output_format=output_format)
Beispiel #15
0
def add_ta_target_country(client: Act, output_format: Text, threat_actor: Text,
                          target_countries: List[Text]) -> None:
    """ Threat actor target countries """
    for target_country in target_countries:
        chain = act.api.fact.fact_chain(
            client.fact("targets").source("incident", "*").destination(
                "organization", "*"),
            client.fact("locatedIn").source("organization", "*").destination(
                "country", target_country),
            client.fact("attributedTo").source("incident", "*").destination(
                "threatActor", threat_actor))

        for fact in chain:
            handle_fact(fact, output_format=output_format)
Beispiel #16
0
def report_mentions_fact(
    actapi: act.api.Act,
    object_type: Text,
    object_values: Set[Text],
    report_id: Text,
    output_format: Text,
) -> None:
    """Add mentions fact to report"""
    for value in set(object_values):
        handle_fact(
            actapi.fact("mentions").source("report", report_id).destination(
                object_type, value),
            output_format,
        )
Beispiel #17
0
def add_ta_techniques(client: Act, output_format: Text, threat_actor: Text,
                      techniques: List[Text]) -> None:
    """ Threat Actor Techniques """

    for technique in techniques:
        chain = act.api.fact.fact_chain(
            client.fact("attributedTo").source("incident", "*").destination(
                "threatActor", threat_actor),
            client.fact("attributedTo").source("event", "*").destination(
                "incident", "*"),
            client.fact("classifiedAs").source("event", "*").destination(
                "technique", technique))

        for fact in chain:
            handle_fact(fact, output_format=output_format)
Beispiel #18
0
def test_validate_same_object() -> None:
    api = act.api.Act(
        "",
        None,
        strict_validator=True,
        object_formatter=object_format,
        object_validator=object_validates,
    )

    act.api.helpers.handle_fact.cache_clear()

    with pytest.raises(ValidationError,
                       match=r"Source object can not be equal to.*"):
        handle_fact(
            api.fact("mentions").source("report",
                                        "xyz").destination("report", "xyz"))
Beispiel #19
0
def test_validator_strict() -> None:
    api = act.api.Act(
        "",
        None,
        strict_validator=True,
        object_formatter=object_format,
        object_validator=object_validates,
    )
    act.api.helpers.handle_fact.cache_clear()

    with pytest.raises(ValidationError,
                       match=r"Destination object does not validate.*"):

        handle_fact(
            api.fact("mentions").source("report", "xyz").destination(
                "uri", ".X7f://cve-2014-0224"))
Beispiel #20
0
def add_software(client: Act,
                 matrice: AttckMatrice,
                 output_format: Text = "json") -> List:
    """
        extract objects/facts related to ATT&CK Software
        Insert to ACT if client.baseurl is set, if not, print to stdout

    Args:
        attack (AttckMatrice):       Attack matrice
        output_format (Text):        "json" or "str" output format

    """

    notify: List = []

    # Enterprise matrice has malwares and tools, but preattack has none of them
    for software in getattr(matrice, "malwares", []) + getattr(
            matrice, "tools", []):
        if deprecated_or_revoked(software):
            # Object is revoked/deprecated, add to notification list but do not add to facts that should be added to the platform
            notify.append(software)
            continue

        tool_name = software.name

        # Tool category
        handle_fact(
            client.fact("category", software.type).source("tool", tool_name),
            output_format=output_format,
        )

        for alias in software.alias:
            alias_name = alias

            if tool_name != alias_name:
                # Tool category (alias)
                handle_fact(
                    client.fact("category",
                                software.type).source("tool", alias_name),
                    output_format=output_format,
                )
                handle_fact(
                    client.fact("alias").bidirectional("tool", tool_name,
                                                       "tool", alias_name),
                    output_format=output_format,
                )

        for technique in software.techniques:
            handle_fact(
                client.fact("implements").source("tool",
                                                 software.name).destination(
                                                     "technique",
                                                     technique.id),
                output_format=output_format,
            )

    return notify
Beispiel #21
0
def add_software(client,
                 attack: MemoryStore,
                 output_format: Text = "json") -> List[stix2.AttackPattern]:
    """
        extract objects/facts related to ATT&CK Software
        Insert to ACT if client.baseurl is set, if not, print to stdout

    Args:
        attack (stix2):       Stix attack instance

    """

    notify = []

    for software in attack.query([Filter("type", "in", ["tool", "malware"])]):
        tool_name = software.name.lower()

        # Tool category
        handle_fact(client.fact("category",
                                software.type).source("tool", tool_name),
                    output_format=output_format)

        if getattr(software, "revoked", None):
            # Object is revoked, add to notification list but do not add to facts that should be added to the platform
            notify.append(software)
            continue

        if getattr(software, "x_mitre_deprecated", None):
            # Object is revoked, add to notification list AND continue to add to facts that should be added to the platform
            notify.append(software)

        for alias in getattr(software, "x_mitre_aliases", []):
            if tool_name != alias.lower():
                # Tool category (alias)
                handle_fact(client.fact("category", software.type).source(
                    "tool", alias.lower()),
                            output_format=output_format)
                handle_fact(client.fact("alias").bidirectional(
                    "tool", tool_name, "tool", alias.lower()),
                            output_format=output_format)

        #   ATT&CK concept   STIX Properties
        #   ==========================================================================
        #   Technqiues       relationship where relationship_type == "uses", points to
        #                    a target object with type == "attack-pattern"

        for technique in attack.related_to(software, relationship_type="uses"):
            if technique.type != "attack-pattern":
                continue

            handle_fact(client.fact("implements").source(
                "tool",
                software.name.lower()).destination("technique",
                                                   technique.name),
                        output_format=output_format)

    return notify
Beispiel #22
0
def add_ta_tools(client: Act, output_format: Text, threat_actor: Text,
                 tools: List[Text]) -> None:
    """ Threat Actor Tools """

    for tool in tools:
        chain = act.api.fact.fact_chain(
            client.fact("classifiedAs").source("content", "*").destination(
                "tool", tool.lower()),
            client.fact("observedIn").source("content",
                                             "*").destination("event", "*"),
            client.fact("attributedTo").source("event", "*").destination(
                "incident", "*"),
            client.fact("attributedTo").source("incident", "*").destination(
                "threatActor", threat_actor))

        for fact in chain:
            handle_fact(fact, output_format=output_format)
Beispiel #23
0
def add_countries(client: act.api.Act,
                  ta_cards: List,
                  countries: List,
                  output_format: Text = "json") -> None:
    """
    Only submit country if ISO-3166 country
    """
    for actor in ta_cards:
        if "country" in actor:
            for country in actor["country"]:
                if country.lower() in countries:
                    chain = act.api.fact.fact_chain(
                        client.fact("locatedIn").source("organization",
                                                        "*").destination(
                                                            "country",
                                                            country),
                        client.fact("attributedTo").source(
                            "threatActor",
                            actor["actor"]).destination("organization", "*"),
                    )

                    for fact in chain:
                        handle_fact(fact, output_format=output_format)

        if "observed-countries" in actor:
            for country in actor["observed-countries"]:
                if country.lower() in countries:
                    for ta in actor["actor"].split(","):
                        chain = act.api.fact.fact_chain(
                            client.fact("locatedIn").source(
                                "organization",
                                "*").destination("country", country),
                            client.fact("targets").source("incident",
                                                          "*").destination(
                                                              "organization",
                                                              "*"),
                            client.fact("attributedTo").source(
                                "incident",
                                "*").destination("threatActor", ta),
                        )

                        for fact in chain:
                            handle_fact(fact, output_format=output_format)
Beispiel #24
0
def add_tools(client: act.api.Act,
              ta_cards: List,
              tools: List,
              output_format: Text = "json") -> None:
    """
    Submit tool aliases and actor tools
    """
    tool_vocab = [tool["tool"] for tool in tools]
    for actor in ta_cards:
        if "tools" in actor:
            for tool in actor["tools"]:
                if tool in tool_vocab:
                    for ta in actor["actor"].split(","):
                        chain = act.api.fact.fact_chain(
                            client.fact("classifiedAs").source(
                                "content",
                                "*").destination("tool", tool.lower()),
                            client.fact("observedIn").source("content",
                                                             "*").destination(
                                                                 "event", "*"),
                            client.fact("attributedTo").source(
                                "event", "*").destination("incident", "*"),
                            client.fact("attributedTo").source(
                                "incident",
                                "*").destination("threatActor", ta),
                        )

                    for fact in chain:
                        try:
                            handle_fact(fact, output_format=output_format)
                        except act.api.base.ValidationError as err:
                            error("ResponseError while storing objects: %s" %
                                  err)

    for values in tools:
        aliases = set([tool["name"].strip()
                       for tool in values["names"]] + [values["tool"]])
        for tool1, tool2 in combinations(aliases, 2):
            fact = client.fact("alias").bidirectional("tool", tool1, "tool",
                                                      tool2)
            handle_fact(fact)
Beispiel #25
0
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 = cli.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)
Beispiel #26
0
def add_techniques(client,
                   attack: MemoryStore,
                   output_format: Text = "json") -> List[stix2.AttackPattern]:
    """
        extract objects/facts related to ATT&CK techniques

    Args:
        attack (stix2):       Stix attack instance

    """

    notify = []

    # ATT&CK concept    STIX Object type        ACT object
    # =========================================================
    # Technique         attack-pattern          technique
    # Filter out ATT&CK techniques (attack-pattern) from bundle

    for technique in attack.query([Filter("type", "=", "attack-pattern")]):
        if getattr(technique, "revoked", None):
            # Object is revoked, add to notification list but do not add to facts that should be added to the platform
            notify.append(technique)
            continue

        if getattr(technique, "x_mitre_deprecated", None):
            # Object is revoked, add to notification list AND continue to add to facts that should be added to the platform
            notify.append(technique)

        # Mitre ATT&CK Tactics are implemented in STIX as kill chain phases with kill_chain_name "mitre-attack"
        for tactic in technique.kill_chain_phases:
            if tactic.kill_chain_name != "mitre-attack":
                continue

            handle_fact(client.fact("accomplishes").source(
                "technique",
                technique.name).destination("tactic", tactic.phase_name),
                        output_format=output_format)

    return notify
Beispiel #27
0
def process(client: act.api.Act,
            ta_cards: List,
            output_format: Text = "json") -> None:
    "Extract threat actor cards from ThaiCERT"

    for actor in ta_cards:
        if len(actor["names"]) > 1:
            for alias in actor["names"][1:]:
                handle_fact(
                    client.fact("alias").bidirectional(
                        "threatActor",
                        actor["names"][0]["name"].lower(),
                        "threatActor",
                        alias["name"].lower(),
                    ),
                    output_format=output_format,
                )

        if "operations" in actor:
            for operation in actor["operations"]:
                if len(operation["activity"].split("\n")[0].split()) < 4:
                    for ta in actor["actor"].split(","):
                        chain = act.api.fact.fact_chain(
                            client.fact("attributedTo").source(
                                "incident", "*").destination(
                                    "campaign",
                                    operation["activity"].split("\n")[0]),
                            client.fact("attributedTo").source(
                                "incident",
                                "*").destination("threatActor", ta),
                        )

                for fact in chain:
                    try:
                        handle_fact(fact, output_format=output_format)
                    except act.api.base.ValidationError as err:
                        warning("ValidationError while storing objects: %s" %
                                err)
Beispiel #28
0
def add_tools(client: act.api.Act,
              ta_cards: List,
              tools: List,
              output_format: Text = "json") -> None:
    """
    Submit tool aliases and actor tools
    """
    tool_vocab = [tool["tool"] for tool in tools]
    for actor in ta_cards:
        if "tools" in actor:
            for tool in actor["tools"]:
                if tool in tool_vocab:
                    for ta in actor["actor"].split(","):
                        handle_facts(
                            act.api.fact.fact_chain(
                                client.fact("classifiedAs").source(
                                    "content", "*").destination("tool", tool),
                                client.fact("observedIn").source(
                                    "content",
                                    "*").destination("incident", "*"),
                                client.fact("attributedTo").source(
                                    "incident",
                                    "*").destination("threatActor", ta),
                            ),
                            output_format=output_format,
                        )

    for values in tools:
        aliases = set([tool["name"].strip()
                       for tool in values["names"]] + [values["tool"]])
        for tool1, tool2 in combinations(aliases, 2):

            if tool1 == tool2:
                continue

            fact = client.fact("alias").bidirectional("tool", tool1, "tool",
                                                      tool2)
            handle_fact(fact)
Beispiel #29
0
def handle_techniques(
    client: Act,
    technique: "AttckTechnique",
    main_technique: Optional["AttckTechnique"],
    output_format: Text = "json",
) -> List:
    """
    Args:
    client:                Act Client
    technique (str):       Technique or subtechnique ID
    main_technique (str):  If set, technique is a sub technique
    output_format (str):   Fact output if sent to stdout (text | json)
    """

    if deprecated_or_revoked(technique):
        # Object is revoked/deprecated, add to notification list but do not add to facts that should be added to the platform
        return [technique]

    if main_technique:
        handle_fact(
            client.fact("subTechniqueOf").source("technique",
                                                 technique.id).destination(
                                                     "technique",
                                                     main_technique.id),
            output_format=output_format,
        )

    handle_fact(
        client.fact("name", technique.name).source("technique", technique.id),
        output_format=output_format,
    )

    # Mitre ATT&CK Tactics are implemented in STIX as kill chain phases with kill_chain_name "mitre-attack"
    for tactic in technique.tactics:
        handle_fact(
            client.fact("accomplishes").source("technique",
                                               technique.id).destination(
                                                   "tactic", tactic.id),
            output_format=output_format,
        )

        handle_fact(
            client.fact("name", tactic.name).source("tactic", tactic.id),
            output_format=output_format,
        )

    return []
Beispiel #30
0
def test_validator_no_validator(caplog) -> None:
    api = act.api.Act("", None)
    act.api.helpers.handle_fact.cache_clear()

    # Should return None if fact does not validate
    fact = handle_fact(
        api.fact("mentions").source("report",
                                    "xyz").destination("uri",
                                                       "X7f://cve-2014-0224"))

    # No validator is specified so the above should return a fact
    assert fact is not None

    # Should not log errors
    assert caplog.text == ""