Panther high experimental python

GreyNoise V3 Malicious IP Activity

Detects when an IP address in any log event is classified as malicious or unknown by GreyNoise V3 internet scanner intelligence. Known business services and benign IPs are excluded.

View Source

Detection Logic

from panther_greynoise_helpers import (
    get_greynoise_v3_business_service_object,
    get_greynoise_v3_object,
    greynoise_severity_decode,
    greynoise_v3_alert_context,
    severity_greater_than,
)

CLASSIFICATIONS_TO_ALERT = {"malicious", "unknown"}

MATCHED_IPS = {}  # {ip: classification}


def _alerting_classification(classification):
    """Collapse a possibly list-shaped classification (multiple LUT hits) to the
    single alertable classification, preferring 'malicious' over 'unknown'."""
    values = classification if isinstance(classification, list) else [classification]
    matches = [value for value in values if value in CLASSIFICATIONS_TO_ALERT]
    if not matches:
        return None
    return "malicious" if "malicious" in matches else matches[0]


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

    scanner = get_greynoise_v3_object(event)
    if not scanner:
        return False

    bsi = get_greynoise_v3_business_service_object(event)

    for ip_addr in event.get("p_any_ip_addresses", []):
        if bsi and bsi.found(ip_addr):
            continue

        classification = _alerting_classification(scanner.classification(ip_addr))
        if classification:
            MATCHED_IPS[ip_addr] = classification

    return bool(MATCHED_IPS)


def title(event):
    log_type = event.get("p_log_type", "Unknown")
    if len(MATCHED_IPS) == 1:
        ip_addr, classification = next(iter(MATCHED_IPS.items()))
        return f"GreyNoise: {classification.title()} IP [{ip_addr}] detected in {log_type}"
    return f"GreyNoise: {len(MATCHED_IPS)} suspicious IPs detected in {log_type}"


def severity(event):  # pylint: disable=unused-argument
    highest = None
    for classification in MATCHED_IPS.values():
        sev = greynoise_severity_decode(classification, "DEFAULT")
        if highest is None or severity_greater_than(sev, highest):
            highest = sev
    return highest or "DEFAULT"


def alert_context(event):
    if not MATCHED_IPS:
        return {}
    ctx = {}
    for ip_addr, classification in MATCHED_IPS.items():
        ip_ctx = greynoise_v3_alert_context(event, ip_addr)
        ip_ctx["MatchedClassification"] = classification
        ctx[ip_addr] = ip_ctx
    return ctx

Field Validations

Loading…

Comments (0)

Loading comments...