LoFP LoFP / newly deployed legitimate site-to-site or client vpn gateways, or established gateways that were inactive for more than 5 days, will generate an alert when first observed. where these peers are expected, their external destination ip addresses can be excluded.

Techniques

Sample rules

Newly Observed IPSEC NAT Traversal Peer

Description

This rule identifies outbound IPSEC NAT Traversal (NAT-T) traffic to an external destination IP that was not observed during the previous 5 days. IPSEC is a VPN technology that allows one system to talk to another using encrypted tunnels. NAT Traversal encapsulates IPSEC ESP traffic in UDP and, once a NAT device is detected, both peers float to UDP port 4500 for the tunnel data channel. Newly observed external NAT-T peers may indicate unauthorized VPN use or an adversary tunneling command and control or exfiltration traffic over the Internet.

Detection logic

FROM packetbeat-*, auditbeat-*, filebeat-*, logs-network_traffic.flow-*, logs-panw.panos*, logs-pfsense.log-*, logs-zeek.connection-* METADATA _id
| WHERE (
    data_stream.dataset IN ("network_traffic.flow", "zeek.connection")
    OR MV_CONTAINS(event.category, "network")
    OR MV_CONTAINS(event.category, "network_traffic")
  )
  AND network.transport == "udp"
  AND source.port == 4500
  AND destination.port == 4500
  AND CIDR_MATCH(source.ip, "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16")
  AND NOT CIDR_MATCH(
    destination.ip,
    "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12",
    "192.0.0.0/24", "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32",
    "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24",
    "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24",
    "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24", "198.18.0.0/15",
    "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", "FE80::/10", "FF00::/8"
  )
  AND (
    data_stream.dataset IS NULL
    OR data_stream.dataset != "panw.panos"
    OR event.action IS NULL
    OR event.action NOT IN ("flow_dropped", "flow_denied")
  )
| EVAL Esql.dataset = COALESCE(data_stream.dataset, event.dataset)
| STATS
    Esql.first_seen = MIN(@timestamp),
    Esql.last_seen = MAX(@timestamp),
    Esql.event_count = COUNT(*),
    Esql.source_ip_count = COUNT_DISTINCT(source.ip),
    Esql.source_ip_values = MV_SLICE(VALUES(source.ip), 0, 100),
    Esql.event_action_values = VALUES(event.action),
    Esql.dataset_values = VALUES(Esql.dataset),
    Esql.observer_name_values = MV_SLICE(VALUES(observer.name), 0, 20)
  BY destination.ip
| EVAL Esql.recent = DATE_DIFF("minute", Esql.first_seen, NOW())
| WHERE Esql.recent >= 0 AND Esql.recent <= 10
| KEEP destination.ip, Esql.*