Panther high experimental python

GTI/VirusTotal Threat Intelligence Indicator Match

Detects when an IP address, domain, or file hash in any log event matches a known malicious indicator from Google Threat Intelligence (GTI) / VirusTotal enrichment. Severity is elevated based on GTI's threat severity verdict and the number of vendors flagging the indicator as malicious.

View Source

Detection Logic

from panther_gti_helpers import (
    get_gti_object,
    gti_alert_context,
    gti_severity,
    severity_greater_than,
)

INDICATOR_FIELDS = (
    "p_any_ip_addresses",
    "p_any_domain_names",
    "p_any_md5_hashes",
    "p_any_sha1_hashes",
    "p_any_sha256_hashes",
)

MATCHED_INDICATORS = {}  # {indicator: indicator_type}


def _first(value):
    """Collapse a possibly list-shaped lookup value (multiple LUT hits) to a single value."""
    if isinstance(value, list):
        return next((entry for entry in value if entry), None)
    return value


def rule(event):
    global MATCHED_INDICATORS  # pylint: disable=global-statement
    MATCHED_INDICATORS = {}

    gti = get_gti_object(event)
    if not gti:
        return False

    for field in INDICATOR_FIELDS:
        for value in event.get(field, []) or []:
            if value in MATCHED_INDICATORS:
                continue
            indicator_type = _first(gti.indicator_type(value))
            if not indicator_type:
                continue
            if not gti.is_malicious(value):
                continue
            MATCHED_INDICATORS[value] = indicator_type

    return bool(MATCHED_INDICATORS)


def title(event):
    log_type = event.get("p_log_type", "Unknown")
    if len(MATCHED_INDICATORS) == 1:
        indicator, ioc_type = next(iter(MATCHED_INDICATORS.items()))
        return f"GTI: Known malicious {ioc_type} [{indicator}] detected in {log_type}"
    return f"GTI: {len(MATCHED_INDICATORS)} threat indicators detected in {log_type}"


def severity(event):
    highest = None
    for indicator in MATCHED_INDICATORS:
        sev = gti_severity(event, indicator)
        if highest is None or severity_greater_than(sev, highest):
            highest = sev
    return highest or "DEFAULT"


def alert_context(event):
    if not MATCHED_INDICATORS:
        return {}
    ctx = {}
    for indicator, indicator_type in MATCHED_INDICATORS.items():
        indicator_ctx = gti_alert_context(event, indicator)
        indicator_ctx["MatchedIndicatorType"] = indicator_type
        ctx[indicator] = indicator_ctx
    return ctx

Field Validations

Loading…

Comments (0)

Loading comments...