CreateYARARuleIndicators

python · Yara

Source

import demistomock as demisto  # noqa: F401
import plyara
import plyara.exceptions
import plyara.utils
from CommonServerPython import *  # noqa: F401

YARA_META_TO_XSOAR = {
    "descr": "description",
    "description": "description",
    "author": "author",
    "authour": "author",
    "id": "ruleid",
    "reference": "rulereference",
    "link": "rulereference",
}
# TODO - Add creation date as well

RELATIONSHIPS = ["Malware", "CVE", "Attack_Pattern"]


def parse_rules(rules: str, create_relationships: bool = False) -> CommandResults:
    """Parses a YARA rule in its string format into an XSOAR indicator

    Args:
        rules (list[str]): A string of one or more YARA rules

    Returns:
        CommandResults: Results in XSOAR format.
    """

    parser = plyara.Plyara()
    indicators: list[dict] = []
    successfully_created_indicators: int = 0
    relationships = []

    try:
        parsed_rules = parser.parse_string(rules)
        demisto.debug(f"Parsed {len(parsed_rules)} YARA Rules.")

    except plyara.exceptions.ParseError:
        demisto.debug(f"Failed to parse - {rules}")
        raise

    for parsed_rule in parsed_rules:
        indicators.append(build_indicator(parsed_rule))

    for indicator in indicators:
        execute_command("createNewIndicator", indicator)
        successfully_created_indicators += 1
        demisto.debug(f'Created new indicator {indicator["value"]} ({successfully_created_indicators}/len(parsed_rules))')

    if create_relationships:
        for indicator in indicators:
            relationships = build_relationships(indicator)

    readable_output = f'{tblToMd(f"{len(indicators)} new YARA rules created", indicators, ["value", "author", "description"])}'

    # Removing "type" from and MD blocks from context dict
    outputs = [{k: v.replace("```", "") if isinstance(v, str) else v for k, v in d.items() if k != "type"} for d in indicators]

    return CommandResults(
        outputs_prefix="ImportYARARule",
        outputs_key_field="Rule",
        outputs=outputs,
        readable_output=readable_output,
        relationships=relationships,
    )


def build_indicator(rule: dict[str, Any]) -> dict[str, Any]:
    """Builds the indicator in the correct XSOAR format to be created.

    Args:
        rule (dict[str, Any]): A given YARA rule.

    Returns:
        dict[str, Any]: An XSOAR indicator of type YARA Rule.
    """

    indicator = {
        "value": rule["rule_name"],
        "type": "YARA Rule",
        "rulestrings": [{"index": entry["name"][1:], "string": entry["value"]} for entry in rule["strings"]],
        "rulecondition": " ".join(rule["condition_terms"]),
        "rawrule": f"```\n{plyara.utils.rebuild_yara_rule(rule)}\n```",
    }

    if "tags" in rule:
        indicator["tags"] = rule["tags"]

    meta: list[Any] = rule.get("metadata", [])

    for key in YARA_META_TO_XSOAR:
        # populate metadata fields

        if value := parse_metadata(meta, key):
            indicator[YARA_META_TO_XSOAR[key]] = value

    return indicator


def parse_metadata(meta: list[dict], key: str) -> str:
    """
    Extracts the value of a YARA rule metadata key

    Args:
        meta (list[dict]): The YARA Rule metadata
        key (str): The metadata key to be extracted

    Returns:
        str: The value of the metadata key
    """

    for item in meta:
        lowered_dict = {key.lower(): value for key, value in item.items()}

        if key in lowered_dict:
            return lowered_dict[key]

    return ""


def build_relationships(indicator: dict) -> list[EntityRelationship]:
    relationships = []
    related_iocs: list[Any] = demisto.executeCommand("extractIndicators", args={"text": indicator["rawrule"]})
    related_iocs = json.loads(related_iocs[0].get("Contents", {}))

    demisto.debug(f"Found the following indicators in the YARA Rule {related_iocs}")

    for indicator_type in RELATIONSHIPS:
        demisto.debug(f"Handling {indicator_type} relationships")

        if indicator_type == "Malware":
            # Will extract only malware with APTXXX prefix.
            indicators = set(re.findall(r"(?i)apt[-_]?\d{1,2}", indicator["rawrule"]))

        else:
            indicators = related_iocs.get(indicator_type, [])

        for related_indicator in indicators:
            demisto.debug(f"Creating relationship object for {related_indicator}")

            relationships.append(
                EntityRelationship(
                    entity_a=indicator["value"],
                    entity_a_type="YARA Rule",
                    entity_b=related_indicator,
                    entity_b_type=indicator_type.replace("_", " "),
                    name=EntityRelationship.Relationships.RELATED_TO,
                )
            )

    return relationships


def main():  # pragma: no cover
    try:
        # TODO: replace the invoked command function with yours
        args = demisto.args()

        if args.get("yara_signatures", ""):
            yara_rules: str = args["yara_signatures"]

        elif args.get("entry_id", ""):
            file_path = demisto.getFilePath(args["entry_id"])["path"]
            with open(file_path) as f:
                yara_rules = f.read()

        else:
            raise Exception("Please provide exactly one input to the script yara_signatures or entry_id.")

        return_results(parse_rules(yara_rules, argToBoolean(args.get("create_relationships"))))

    except Exception as ex:
        demisto.error(traceback.format_exc())  # print the traceback
        return_error(f"Error: {ex!s}")


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()

README

Script Data


Name Description
Script Type python3
Tags Utility

Inputs


Argument Name Description
string One or more YARA signatures in string format.
entryID An entry ID for a file containing YARA signatures.

Outputs


Path Description Type
CreateYARARuleIndicators.value The YARA Rule name string
CreateYARARuleIndicators.description The YARA Rule description. string
CreateYARARuleIndicators.rawrule The raw YARA Rule in code block format. string
CreateYARARuleIndicators.rulecondition The YARA Rule condition. string
CreateYARARuleIndicators.strings The YARA Rule strings in grid format. string
CreateYARARuleIndicators.tags The YARA Rule tags. string