First Seen Network Flow Exporter Followed by Suspicious Source Activity

edit
IMPORTANT: This documentation is no longer updated. Refer to Elastic's version policy and the latest documentation.

First Seen Network Flow Exporter Followed by Suspicious Source Activity

edit

Identifies a newly observed NetFlow, IPFIX, or sFlow exporter IP followed by another detection alert with medium-or-higher severity or an elevated risk score, where that exporter IP is the source of the detected activity in the same data stream namespace. This correlation adds behavioral evidence that can help distinguish routine exporter onboarding from a potentially unauthorized or compromised exporter introduced as part of defense evasion.

Rule type: esql

Rule indices: None

Severity: high

Risk score: 73

Runs every: 15m

Searches indices from: now-45m (Date Math format, see also Additional look-back time)

Maximum alerts per execution: 100

References:

Tags:

  • Domain: Network
  • Use Case: Network Security Monitoring
  • Use Case: Threat Detection
  • Tactic: Defense Evasion
  • Rule Type: Higher-Order Rule
  • Data Source: Elastic Security
  • Data Source: NetFlow
  • Data Source: GoFlow2
  • Resources: Investigation Guide

Version: 2

Rule authors:

  • Elastic

Rule license: Elastic License v2

Investigation guide

edit

Triage and analysis

Investigating First Seen Network Flow Exporter Followed by Suspicious Source Activity

This higher-order rule correlates the building-block alert "First Seen Network Flow Exporter" with a later detection alert that has medium-or-higher severity or an elevated risk score within 30 minutes. The new exporter’s observer.ip must equal the later alert’s source.ip, and both alerts must share the same data_stream.namespace.

This relationship provides stronger evidence than suspicious flows merely reported by the exporter. It indicates that the exporter address itself was subsequently identified as the source of separately detected activity. It does not by itself prove telemetry injection, exporter compromise, or the addition of a rogue collector. A rogue collector receives flow exports and generally requires network-device configuration or audit telemetry to detect directly.

Possible investigation steps

  • Review the observer.ip, source.ip, correlation timestamps, and suspicious rule names and IDs surfaced in the alert. Pivot to the contributing alerts to review their risk score, destination, host, and user context.
  • Confirm that observer.ip belongs to the newly observed exporter and that NAT, shared addressing, or stale asset records did not cause the correlation.
  • Examine the second alert’s rule name and determine what behavior associated the exporter address with source.ip.
  • Verify the exporter’s owner, device type, software version, management plane, recent configuration changes, and approved collector destinations.
  • Review authentication, process, network-device audit, and configuration telemetry for the exporter around the correlation window.
  • Compare observation domains, exporter version, uptime, sequence values, templates, sampling configuration, and flow volume with established exporters.
  • Search for additional alerts involving the exporter address and for malformed, implausible, or conflicting flow records received from it.

False positive analysis

  • Validate recent device onboarding, migrations, disaster-recovery activation, penetration tests, vulnerability scans, and monitoring validation.
  • Determine whether source.ip represents the exporter itself or a shared NAT, proxy, scanner, or management address.
  • Confirm that the correlated source alert is a meaningful behavioral detection rather than an expected administrative or discovery event.

Response and remediation

  • If the exporter is unauthorized or compromised, restrict it at the collector boundary and isolate its management plane as appropriate.
  • Preserve flow records, source alerts, configuration history, authentication events, and network evidence.
  • Remove unauthorized export configuration, restore trusted device configuration, rotate affected credentials, and review collector ACLs and authentication.

Setup

edit

Setup

Enable the building-block rule "First Seen Network Flow Exporter" and detection rules that can identify suspicious activity with source.ip populated. The building-block rule requires decoded NetFlow, IPFIX, or sFlow records from the Elastic NetFlow (netflow.log) or GoFlow2 (goflow2.sflow) integration.

The higher-order rule searches Elastic Security alert indices. The correlated source alert must preserve the exporter address in source.ip and preserve data_stream.namespace; alerts without either field cannot contribute to this correlation. Building-block, higher-order, machine-learning, new-terms, threat-match, and deprecated-rule alerts are excluded as the second event.

Rule query

edit
FROM .alerts-security.*
| WHERE event.kind == "signal"
    AND data_stream.namespace IS NOT NULL
    AND (
      (kibana.alert.rule.rule_id == "dfe3f626-4224-417e-aff1-8ef9a72c3191" AND observer.ip IS NOT NULL)
      OR
      (source.ip IS NOT NULL
        AND kibana.alert.rule.name IS NOT NULL
        AND kibana.alert.rule.rule_id IS NOT NULL
        AND kibana.alert.rule.rule_id != "dfe3f626-4224-417e-aff1-8ef9a72c3191"
        AND (kibana.alert.risk_score >= 47 OR kibana.alert.severity IN ("medium", "high", "critical"))
        AND KQL("""NOT kibana.alert.building_block_type : *""")
        AND NOT kibana.alert.rule.type IN ("machine_learning", "new_terms", "threat_match")
        AND NOT kibana.alert.rule.name LIKE "Deprecated - *"
        AND NOT KQL("""kibana.alert.rule.tags : "Rule Type: Higher-Order Rule" """))
    )
| EVAL
    Esql.is_exporter_alert = kibana.alert.rule.rule_id == "dfe3f626-4224-417e-aff1-8ef9a72c3191",
    Esql.is_suspicious_source_alert = kibana.alert.rule.rule_id != "dfe3f626-4224-417e-aff1-8ef9a72c3191",
    Esql.correlation_ip = CASE(Esql.is_exporter_alert, observer.ip, source.ip),
    Esql.exporter_alert_timestamp = CASE(Esql.is_exporter_alert, @timestamp, null),
    Esql.suspicious_source_alert_timestamp = CASE(Esql.is_suspicious_source_alert, @timestamp, null),
    Esql.suspicious_rule_name = CASE(Esql.is_suspicious_source_alert, kibana.alert.rule.name, null),
    Esql.suspicious_rule_id = CASE(Esql.is_suspicious_source_alert, kibana.alert.rule.rule_id, null)
| WHERE Esql.correlation_ip IS NOT NULL
| STATS
    Esql.exporter_alert_count = SUM(CASE(Esql.is_exporter_alert, 1, 0)),
    Esql.suspicious_source_alert_count = SUM(CASE(Esql.is_suspicious_source_alert, 1, 0)),
    observer.ip = MAX(CASE(Esql.is_exporter_alert, Esql.correlation_ip, null)),
    source.ip = MAX(CASE(Esql.is_suspicious_source_alert, Esql.correlation_ip, null)),
    Esql.exporter_alert_timestamp = MIN(Esql.exporter_alert_timestamp),
    Esql.suspicious_source_alert_timestamp = MAX(Esql.suspicious_source_alert_timestamp),
    Esql.suspicious_rule_name_values = VALUES(Esql.suspicious_rule_name),
    Esql.suspicious_rule_id_values = VALUES(Esql.suspicious_rule_id)
  BY data_stream.namespace, Esql.correlation_ip
| EVAL Esql.time_diff_seconds = DATE_DIFF(
    "second", Esql.exporter_alert_timestamp, Esql.suspicious_source_alert_timestamp
  )
| WHERE Esql.exporter_alert_count > 0
    AND Esql.suspicious_source_alert_count > 0
    AND Esql.time_diff_seconds >= 0
    AND Esql.time_diff_seconds <= 1800
| KEEP
    data_stream.namespace,
    observer.ip,
    source.ip,
    Esql.correlation_ip,
    Esql.exporter_alert_count,
    Esql.suspicious_source_alert_count,
    Esql.exporter_alert_timestamp,
    Esql.suspicious_source_alert_timestamp,
    Esql.suspicious_rule_name_values,
    Esql.suspicious_rule_id_values,
    Esql.time_diff_seconds

Framework: MITRE ATT&CKTM