The internet’s routing infrastructure — the system that determines how packets travel from one network to another — was not designed with security as a primary consideration. BGP (Border Gateway Protocol), the protocol that glues together the approximately 75,000 Autonomous Systems (ASes) that constitute the global internet, operates fundamentally on trust. When an AS announces that it is the best path to a given IP prefix, neighboring ASes generally believe it. This design decision, reasonable in 1989, enables a class of attacks with global impact.

BGP Fundamentals

Autonomous Systems and Prefix Announcements

The internet is organized into Autonomous Systems — independently operated networks identified by a unique Autonomous System Number (ASN). Each AS operates under a single administrative domain and routing policy. Examples: AS15169 (Google), AS8075 (Microsoft), AS16509 (Amazon AWS), AS13335 (Cloudflare).

ASes announce reachability to IP address blocks (prefixes) via BGP. An announcement says: “To reach these IP addresses, send traffic to me.” Neighboring ASes propagate these announcements, building a distributed map of how to reach every prefix on the internet.

BGP Route Selection Priority (simplified):

  1. Highest LOCAL_PREF (internal preference)
  2. Shortest AS_PATH (fewest hops)
  3. Lowest MED (Multi-Exit Discriminator)
  4. Prefer eBGP over iBGP routes
  5. Longest prefix match wins — a /25 beats a /24 for overlapping space

This last rule is the foundation of most BGP hijacking attacks.

A Normal BGP Session

# View BGP routing table on a Linux router running BIRD or FRR
# FRR (FRRouting) — show BGP table
vtysh -c "show ip bgp"

# Show specific prefix
vtysh -c "show ip bgp 8.8.8.0/24"

# Show BGP neighbors
vtysh -c "show ip bgp neighbors"

# Show BGP summary
vtysh -c "show ip bgp summary"

How BGP Hijacking Works

Attack Flow — More-Specific Prefix Hijack

Legitimate state:

  • AS64500 (Victim Corp) announces 203.0.113.0/24 to the internet
  • All traffic destined for 203.0.113.0/24 routes through AS64500

Attack state:

  1. Attacker (AS64999) announces 203.0.113.0/25 and 203.0.113.128/25
  2. These /25 announcements are more specific than the victim’s /24
  3. BGP route selection on internet routers prefers the /25 (longer prefix match)
  4. Traffic destined for 203.0.113.0–255 now routes to AS64999
  5. Attacker can blackhole (drop), inspect, or selectively forward traffic

Sub-prefix hijack (stealth variant): An attacker who wants to avoid complete traffic loss at the target (which would alert defenders quickly) can announce only one of the two /25s. Traffic to that half of the /24 goes to the attacker; traffic to the other half reaches the legitimate destination. This makes the attack less obvious and harder to detect from inside the victim organization.

Attack Flow — BGP Session Compromise

If an attacker can compromise a BGP-speaking router (via remote code execution, BGP session hijacking, or insider access), they can inject arbitrary route announcements with a legitimate ASN. This is harder to detect because the announcements appear to come from a trusted AS with an established peering relationship.

Real Incidents

Pakistan Telecom / YouTube — February 2008

The first widely publicized BGP hijacking incident demonstrated the global impact possible from a single misconfigured announcement.

Pakistan Telecom (PTCL, AS17557) was ordered to block YouTube within Pakistan. Their intended implementation: announce a more-specific route for YouTube’s prefix that pointed to a null route, affecting only Pakistani customers. Their actual implementation: announce 208.65.153.0/24 (a /24 within YouTube’s 208.65.152.0/22) to their upstream provider PCCW (AS3491).

PCCW propagated the announcement to their full peering mesh. Within minutes, the more-specific /24 announcement spread globally. Approximately 2/3 of global internet traffic destined for YouTube routed to Pakistan Telecom, which dropped it. YouTube was largely unreachable worldwide for ~2 hours until PCCW filtered the announcement.

Why this matters: A single upstream provider failing to filter a customer’s BGP announcements caused a global internet outage for a major platform. No attack intent was required — misconfiguration was sufficient.

AWS Route 53 BGP Hijack — April 24, 2018

At approximately 11:00 UTC on April 24, 2018, eNet (AS10297), a small Ohio-based ISP, began advertising Amazon’s Route 53 DNS IP prefixes (205.251.200.0/24 and others) with more-specific /24 announcements. These routes propagated to Amazon’s upstream providers and spread globally.

For approximately 2 hours, DNS queries from numerous networks worldwide were answered by an attacker-controlled server. The primary target was MyEtherWallet (MEW), an Ethereum wallet service. The attacker’s server:

  1. Presented a phishing site with a valid HTTPS certificate (from a different CA — the certificate was for a Russian hosting provider, and browsers showed a warning for MEW’s domain, which some users ignored)
  2. Captured Ethereum private keys and wallet credentials entered by users
  3. Stole approximately $152,000 in Ethereum (ETH) before the attack was mitigated

Key lesson: BGP hijacking does not require compromising the target organization. It intercepts traffic before it reaches the target. Even organizations with impeccable internal security are vulnerable to routing-layer attacks.

Rostelecom — April 2020

On April 1, 2020, Rostelecom (AS12389, Russia’s state-owned telecommunications operator) originated BGP routes for approximately 8,800 IP prefixes belonging to companies including Google, Amazon Web Services, Microsoft Azure, Akamai, Cloudflare, and others. The hijack lasted approximately 1 hour.

Affected prefixes included:

  • Google: 8.8.8.0/24 (Google Public DNS)
  • Cloudflare: 1.1.1.0/24
  • Amazon: Multiple AWS regions
  • Approximately 200 major internet companies total

Network analysis by BGPMon and others suggested the routes propagated to Rostelecom’s customers and several upstream transit providers before being withdrawn. Whether this was intentional espionage or misconfiguration remains disputed.

Indosat (Indonesia) — April 2014

Indosat (AS4761) leaked over 417,000 routes it had received from its customers and peers to its upstream provider Level 3 (now Lumen). Level 3 accepted and propagated these routes globally. For approximately 15 minutes, significant portions of internet traffic were rerouted through Indonesia. This incident affected networks including CloudFlare, Tata Communications, and numerous others.

Detection

Real-Time BGP Monitoring with BGPStream

BGPStream (CAIDA/Route Views) provides live and historical BGP data from multiple collectors worldwide.

 1#!/usr/bin/env python3
 2"""
 3bgp_monitor.py — Monitor BGP for prefix hijacking of owned prefixes
 4Uses pybgpstream to consume live BGP data from Route Views collectors
 5"""
 6from datetime import datetime
 7import pybgpstream
 8
 9# Your organization's legitimate ASN and prefixes
10MY_ASN = 64500
11MY_PREFIXES = ["203.0.113.0/24", "198.51.100.0/24"]
12
13def is_subprefix(candidate, parent):
14    """Check if candidate is a more-specific prefix of parent."""
15    from ipaddress import ip_network
16    try:
17        c = ip_network(candidate, strict=False)
18        p = ip_network(parent, strict=False)
19        return c.subnet_of(p) and c.prefixlen > p.prefixlen
20    except ValueError:
21        return False
22
23def check_origin_as(as_path, expected_asn):
24    """Verify the origin AS (rightmost in AS_PATH) matches expected."""
25    if not as_path:
26        return False
27    path_parts = as_path.strip().split()
28    return path_parts and path_parts[-1] != str(expected_asn)
29
30stream = pybgpstream.BGPStream(
31    project="ris-live",
32    record_type="updates",
33)
34
35print(f"[{datetime.utcnow().isoformat()}] Monitoring BGP for hijacks of AS{MY_ASN} prefixes")
36
37for elem in stream:
38    if elem.type not in ("A", "R"):  # Announcements and RIB entries
39        continue
40
41    prefix = elem.fields.get("prefix", "")
42    as_path = elem.fields.get("as-path", "")
43    next_hop = elem.fields.get("next-hop", "")
44
45    for my_prefix in MY_PREFIXES:
46        # Alert on unexpected origin AS for our prefixes
47        if prefix == my_prefix and check_origin_as(as_path, MY_ASN):
48            print(f"[ALERT] Unexpected origin for {prefix}: AS_PATH={as_path} next_hop={next_hop}")
49
50        # Alert on more-specific prefix announcement (sub-prefix hijack)
51        if is_subprefix(prefix, my_prefix) and check_origin_as(as_path, MY_ASN):
52            print(f"[ALERT] Sub-prefix hijack: {prefix} (part of {my_prefix}) "
53                  f"originated by non-{MY_ASN}: AS_PATH={as_path}")

RPKI Validation with Routinator

RPKI allows you to validate BGP announcements against cryptographically signed Route Origin Authorizations.

 1# Install Routinator (NLnet Labs RPKI validator)
 2cargo install routinator
 3
 4# Initialize and run Routinator
 5routinator init
 6routinator server --rtr 127.0.0.1:3323
 7
 8# Validate a specific route announcement
 9# Usage: routinator validate --asn <ASN> --prefix <prefix>
10routinator validate --asn 15169 --prefix 8.8.8.0/24
11# Output: "valid" (ROA exists and matches), "invalid" (ROA exists but disagrees),
12#         or "not-found" (no ROA published)
13
14routinator validate --asn 12389 --prefix 8.8.8.0/24
15# Should return: invalid (Rostelecom is not authorized to originate Google's prefix)
16
17# Check RPKI status of a prefix using whois (Cloudflare's RPKI lookup)
18whois -h whois.cloudflare.com "8.8.8.0/24"
19
20# Query RIPE NCC's RPKI validator
21curl -s "https://rpki-validator.ripe.net/api/v1/validity/15169/8.8.8.0/24" | python3 -m json.tool

BGP Route Analysis Tools

 1# Query BGP routing data via BGPkit API (bgpkit.com)
 2# Get current routes for a prefix
 3curl -s "https://api.bgpkit.com/v3/pfx2as?prefix=203.0.113.0/24" | python3 -m json.tool
 4
 5# Get historical announcements for a prefix
 6curl -s "https://api.bgpkit.com/v3/pfx2as?prefix=203.0.113.0/24&date=2024-04-24" | \
 7  python3 -m json.tool
 8
 9# Use RIPE RIS REST API for route visibility
10curl -s "https://stat.ripe.net/data/routing-status/data.json?resource=203.0.113.0/24" | \
11  python3 -c "import json,sys; d=json.load(sys.stdin); print(json.dumps(d['data'], indent=2))"
12
13# Query BGP looking glass (multiple available)
14# Route Views looking glass
15curl -s "http://www.routeviews.org/routeviews/index.php" 2>/dev/null
16
17# Using traceroute to detect rerouting (before/after baseline)
18mtr --report --report-cycles 10 8.8.8.8
19# Compare AS path in output against expected path
20
21# Detect TTL anomalies indicating BGP hijack (unexpected geographic rerouting)
22traceroute -A 8.8.8.8  # -A shows AS number for each hop

Monitoring for Latency and Geographic Anomalies

BGP hijacking often causes latency increases or unexpected geographic routing:

 1# Baseline latency measurement (run regularly and compare)
 2#!/bin/bash
 3TARGETS=("8.8.8.8" "1.1.1.1" "9.9.9.9")
 4for TARGET in "${TARGETS[@]}"; do
 5    LATENCY=$(ping -c 10 $TARGET | tail -1 | awk '{print $4}' | cut -d'/' -f2)
 6    echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) $TARGET avg_ms=$LATENCY"
 7done
 8
 9# Run every 5 minutes via cron; alert if latency exceeds 2x baseline
10# Sudden spike to a well-known resolver often indicates BGP rerouting

Splunk/SIEM Correlation for Network Teams

# If you ingest NetFlow/IPFIX data and have BGP data:
# Alert on significant changes in AS distribution for egress traffic
index=netflow
| lookup bgp_asn dst_ip AS asn OUTPUT asn as destination_asn
| bucket _time span=5m
| stats count by _time destination_asn
| streamstats window=12 current=false avg(count) as baseline_count by destination_asn
| eval deviation = abs(count - baseline_count) / baseline_count
| where deviation > 0.5
| table _time destination_asn count baseline_count deviation

Defense

1. Publish ROAs (Route Origin Authorizations)

The most impactful single action an organization can take. ROAs cryptographically bind your IP prefixes to your ASN.

 1# ROA creation is done through your Regional Internet Registry (RIR):
 2# ARIN (North America): https://account.arin.net
 3# RIPE NCC (Europe/Middle East): https://my.ripe.net
 4# APNIC (Asia-Pacific): https://myapnic.net
 5
 6# After publishing ROAs, verify they are visible in the global RPKI repository:
 7# Using RIPE's RPKI validator
 8curl -s "https://rpki-validator.ripe.net/api/v1/validity/64500/203.0.113.0/24" | \
 9  python3 -c "import json,sys; d=json.load(sys.stdin); print(d['validated_route']['validity']['state'])"
10# Expected: "valid"
11
12# Test with routinator
13routinator validate --asn 64500 --prefix 203.0.113.0/24
14
15# ROA best practices:
16# - Create ROAs for all your prefixes, including less-specifics
17# - Set max-length to your advertised prefix length (not longer)
18#   This prevents sub-prefix hijacks while allowing your /24 to be originated
19# - Example: ROA for 203.0.113.0/24, max-length /24
20#   This makes any more-specific announcement (like /25, /26) RPKI-INVALID

2. Configure RPKI Origin Validation on Your Routers

# Cisco IOS-XR — Enable RPKI and configure cache server
router bgp 64500
 bgp bestpath origin-as allow invalid   # Default: allow (for monitoring mode)
 bgp bestpath origin-as use validity    # Use RPKI validity in route selection
!
rpki server 127.0.0.1                   # Routinator RTR server
  transport tcp port 3323
  refresh-time 300
  response-time 60
!

# BIRD 2 — RPKI configuration
roa4 table rpki4;
roa6 table rpki6;

protocol rpki {
  roa4 { table rpki4; };
  roa6 { table rpki6; };
  remote "127.0.0.1" port 3323;
  retry keep 90;
  refresh keep 900;
  expire keep 172800;
}

filter bgp_in_filter {
  if (roa_check(rpki4, net, bgp_path.last) = ROA_INVALID) then {
    print "RPKI invalid route rejected: ", net, " AS", bgp_path.last;
    reject;
  }
  accept;
}

# FRRouting (FRR) — RPKI with rpki-client or Routinator
router bgp 64500
  bgp bestpath prefix-validate allow-invalid  # Monitoring mode
  !
  address-family ipv4 unicast
    bgp dampening
    neighbor 192.0.2.1 route-map RPKI_VALIDATE in

3. IRR Filtering and Prefix Filters

Internet Routing Registry (IRR) databases (RADB, ARIN IRR, RIPE DB) contain routing policy records. Route filters based on IRR data limit which prefixes a peer can announce.

# BIRD 2 — Import filter accepting only prefixes in IRR
# (IRR data must be pre-compiled into prefix lists using bgpq4)

# Generate prefix list from IRR using bgpq4
bgpq4 -4 -l PEER64999_ALLOWED AS64999 > /etc/bird/peer64999_prefixes.conf

# Apply in BIRD config
protocol bgp peer64999 {
  neighbor 192.0.2.1 as 64999;
  import filter {
    if net ~ [prefix_list(peer64999_prefixes)] then accept;
    reject;
  };
  export filter {
    if net ~ MY_PREFIXES then accept;
    reject;
  };
}

# MANRS (Mutually Agreed Norms for Routing Security) compliance:
# 1. Prevent propagation of incorrect routing information
# 2. Prevent traffic with spoofed source IP addresses
# 3. Facilitate global operational communication and coordination
# 4. Facilitate validation of routing information

4. Peering Agreement Controls

Work with your upstream providers to:

  • Enforce strict prefix limits (reject sessions with unexpectedly large prefix counts)
  • Require RPKI validation on your upstreams (ask if they perform origin validation)
  • Set up BGP session authentication (TCP MD5 or TCP-AO to prevent session injection)
# FRR — Enable TCP MD5 for BGP session authentication
router bgp 64500
  neighbor 192.0.2.1 password "strong-random-session-password"
  neighbor 192.0.2.1 maximum-prefix 1000 80  # Alert at 80%, drop at 1000

# Cisco IOS-XE
router bgp 64500
  neighbor 192.0.2.1 password 7 <encrypted>
  neighbor 192.0.2.1 maximum-prefix 1000 80 warning-only

5. Subscribe to BGP Monitoring Services

  • BGPMon (now part of Cisco) — real-time prefix hijack detection with email/API alerts
  • RIPE RIS Routing Information Service — free, global BGP data from 25+ collectors
  • BGPStream — open-source framework (CAIDA) for processing BGP data
  • Cloudflare Radar — provides BGP routing insights via dashboard and API
  • Kentik — commercial BGP visibility and anomaly detection

MITRE ATT&CK Mapping

  • T1584.001 — Compromise Infrastructure: Botnet (BGP via compromised routers)
  • T1557 — Adversary-in-the-Middle (result of successful BGP hijack)
  • T1498 — Network Denial of Service (via blackholing hijacked prefixes)

Summary

BGP hijacking exploits the internet’s foundational routing protocol, which was designed for cooperative operation among trusted parties. A single AS announcing more-specific prefixes can divert global internet traffic from legitimate destinations within minutes, enabling traffic interception, denial of service, or cryptocurrency theft — as demonstrated in the 2018 AWS Route 53 incident. Effective defense requires both publishing ROAs to declare routing authorization and configuring routers to enforce RPKI origin validation. Neither alone is sufficient: ROAs without enforcement are advisory-only, and enforcement without comprehensive ROA coverage creates operational risk from incorrectly configured records. The routing security community has made significant RPKI progress since 2018, but substantial portions of the global routing table remain unprotected.


References