EXPLORE
← Back to Explore
elastichighTTP

First Seen Network Flow Exporter Followed by Suspicious Source Activity

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.

MITRE ATT&CK

defense-evasion

Detection Query

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

Author

Elastic

Created

2026/08/24

Data Sources

Elastic SecurityNetFlowGoFlow2

Tags

Domain: NetworkUse Case: Network Security MonitoringUse Case: Threat DetectionTactic: Defense EvasionRule Type: Higher-Order RuleData Source: Elastic SecurityData Source: NetFlowData Source: GoFlow2Resources: Investigation GuideRule Type: ES|QL
Raw Content
[metadata]
creation_date = "2026/08/24"
integration = ["netflow", "goflow2"]
maturity = "production"
updated_date = "2026/09/18"

[rule]
author = ["Elastic"]
description = """
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.
"""
false_positives = [
    """
    Newly deployed network devices may legitimately generate other detection alerts during commissioning, testing,
    vulnerability scanning, or monitoring validation. Shared addresses, network address translation, and incomplete
    asset attribution can also cause unrelated activity to correlate to the exporter IP.
    """,
]
from = "now-45m"
interval = "15m"
language = "esql"
license = "Elastic License v2"
name = "First Seen Network Flow Exporter Followed by Suspicious Source Activity"
note = """## 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.
"""
references = [
    "https://www.elastic.co/docs/solutions/security/detect-and-alert/about-building-block-rules",
    "https://www.elastic.co/docs/reference/integrations/netflow",
    "https://www.elastic.co/docs/reference/integrations/goflow2",
    "https://datatracker.ietf.org/doc/html/rfc7011",
    "https://sflow.org/sflow_version_5.txt",
]
risk_score = 73
rule_id = "882c8edc-1e39-4a60-80b2-485491b6c91c"
setup = """## 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.
"""
severity = "high"
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",
    "Rule Type: ES|QL",
]
timestamp_override = "event.ingested"
type = "esql"

query = '''
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
'''


[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1562"
name = "Impair Defenses"
reference = "https://attack.mitre.org/techniques/T1562/"


[rule.threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"

[rule.investigation_fields]
field_names = [
    "observer.ip",
    "source.ip",
    "data_stream.namespace",
    "Esql.exporter_alert_timestamp",
    "Esql.suspicious_source_alert_timestamp",
    "Esql.suspicious_rule_name_values",
    "Esql.suspicious_rule_id_values",
    "Esql.time_diff_seconds",
]