Playbook 2: ROA scope expansion and validation environment mapping

Why this phase exists

This is the pivot point where we transition from legitimate RPKI participant (phase 1) to control-plane attacker.

Phase 1 established our presence. Phase 2 manipulates the Guild Registry itself.

The critical insight: RPKI ROAs are not boolean (valid/invalid). They have scope. A ROA says “AS X is authorised to announce prefix Y with maximum length Z”. That maximum length is where the vulnerability lives.

If victim AS65001 has created a ROA for 203.0.113.0/24 with maxLength /24, they’ve protected themselves against exact-prefix hijacking. But they haven’t protected themselves against more-specific attacks (announcing 203.0.113.128/25).

Most organisations use maxLength conservatively because expanding it risks making mistakes (“I accidentally authorised too much”). We’re going to exploit that caution by creating a ROA that appears defensive but actually enables our attack.

From the BGP hijacking tree, this implements node 1.1.1 “Sub-prefix hijacking” but with control-plane preparation. We’re not just announcing a more-specific (that’s phase 3). We’re first ensuring that validators will mark our announcement as VALID.

Attack tree path

Primary: 1 → 1.1 → 1.1.1 “Sub-prefix hijacking” → 1.1.1.3 “Using forged origin AS to inject false routes”

But modified: instead of “forged origin AS” (which RPKI would catch), we’re creating authoritative ROAs that make our origin AS appear legitimate.

Supporting: 1.3.3.2 “Low-volume route manipulation” - our ROA changes are low-volume, gradual, and designed to avoid triggering change-rate alerts.

Phase 2 Actions

Action 2.1: Create ROA for our AS covering target prefix

Intent Create a ROA claiming that our AS64513 is authorised to originate 203.0.113.0/24 (the victim’s prefix), with maxLength /25 to enable more-specific hijacking in phase 3, whilst maintaining deniability through “operational error” cover story.

Preconditions

  • Phase 1 complete: our legitimate ROA (198.51.100.0/24) has been published for 7+ days

  • Target prefix 203.0.113.0/24 baseline documented

  • We have verified that victim either has no ROA, or has ROA with maxLength /24 only

  • If victim has ROA, it does not include our AS64513 (would create obvious conflict)

Execution method

This is the critical action. We are creating a ROA for address space we do not legitimately control.

Via RIR’s hosted RPKI portal (same interface as legitimate ROA creation):

ROA configuration:
{
  "asn": "AS64513",
  "prefix": "203.0.113.0/24", 
  "maxLength": 25,
  "ta": "arin"  # (or whichever RIR manages 203.0.113.0/24)
}

Submit this ROA creation request.

CRITICAL OPERATIONAL SECURITY ISSUE:

Most RIRs will reject this request because they verify that the submitting account controls the IP resources being authorised. This is the control mechanism that should prevent ROA poisoning.

However, there are paths to success:

Path A: Compromised RIR credentials If we have compromised credentials for an account that controls 203.0.113.0/24 (via phishing, credential stuffing, or insider access), the RIR will accept the ROA creation because it appears to come from the legitimate holder.

This is the most realistic attack path for actual malicious actors. It requires social engineering or account compromise first.

Path B: RIR validation bypass Some RIRs have had historical bugs in their validation logic. If current RIR software has validation weakness, fraudulent ROA might be accepted. This is rare and unlikely, but has happened historically (RPKI is complex, bugs exist).

Path C: Delegated RPKI If victim is using delegated RPKI (running their own CA rather than RIR-hosted), and we’ve compromised their CA infrastructure, we can create ROAs directly. This requires deeper compromise but provides more control.

For this playbook, we’re assuming Path A: compromised credentials.

Cover story if detected: “Operator error during bulk ROA update. We were creating ROAs for our own allocations and accidentally included incorrect prefix due to copy-paste error in spreadsheet.”

This cover story is plausible because these errors actually happen.

Expected technical effect

If ROA creation succeeds:

Within 60-90 minutes:

  • RIR repository contains fraudulent ROA authorising AS64513 for 203.0.113.0/24

  • Validators polling RIR will fetch new ROA

  • RPKI validation queries will now show:

    • AS65001 announcing 203.0.113.0/24: VALID (if they have ROA) or NOT_FOUND (if no ROA)

    • AS64513 announcing 203.0.113.0/24: VALID (newly created fraudulent ROA)

    • AS64513 announcing 203.0.113.128/25: VALID (covered by our maxLength /25)

The poisoning is complete: validators now believe our AS is legitimately authorised.

Expected observational footprint

This is where operational security becomes critical:

ROA creation footprint (HIGH RISK):

  • RIR audit logs show ROA creation for prefix not allocated to our account (ANOMALOUS)

  • If RIR has automated validation checks, this may trigger alert (LIKELY)

  • RPKI repository change logs show new ROA appeared (VISIBLE)

  • If victim monitors their prefix space for unexpected ROAs, they will see this (IF monitoring exists, which is rare)

Detection likelihood: Medium to High if RIR has automated validation

This is the highest-risk action in the entire attack chain. If caught here, abort immediately and execute cover story.

Manual steps

Before submission:

  1. Verify cover story documentation is prepared (spreadsheet with “error”, email chain showing routine RPKI work)

  2. Ensure fraudulent ROA request is submitted during business hours (appears routine, not suspicious 3am activity)

  3. Have monitoring ready to detect if RIR rejects request or raises alerts

After submission:

  1. Monitor RIR account for email notifications (rejection, approval, or “please confirm” messages)

  2. Check validators every 10 minutes for next 2 hours

  3. If ROA appears: document timestamp, proceed to action 2.2

  4. If ROA rejected: execute abort plan, do not retry

Timing uncertainty

This action has the highest timing uncertainty because we’re depending on:

  • RIR validation checks (might be instant, might take hours if manual review triggered)

  • Whether compromised account has recent successful ROA history (recent activity is less suspicious)

  • Whether ROA submission lands during routine business hours or weekend (weekends might delay human review)

Best case: 30 minutes (ROA accepted, published quickly) Typical case: 2-4 hours (ROA queued for publication) Worst case: Never (ROA rejected, account flagged)

Budget reality check

Most RIRs have automated validation but not comprehensive monitoring. A fraudulent ROA might get published simply because:

  • Validation checks ASN ownership, not necessarily prefix ownership

  • Historical data inconsistencies mean some allocations appear ambiguous

  • Bulk ROA updates are common, and manual review is not feasible for all submissions

The gap between “should be caught” and “actually gets caught” is substantial.


Action 2.2: Map global validation deployment

Intent Determine which regions and networks have RPKI validation deployed and enforced, so phase 3 can target regions where our fraudulent ROA will actually affect routing decisions.

Preconditions

  • Action 2.1 complete: fraudulent ROA is published in validators

  • At least 2 hours have passed (allow validator propagation)

  • We have test infrastructure in multiple geographic regions

Execution method

Use BGP test announcements from our legitimate prefix (198.51.100.0/24) to map validation deployment:

Test 1: Announce our prefix from WRONG AS (should be marked INVALID)

From test router in each region (AMER, EMEA, APAC):

# Temporarily announce 198.51.100.0/24 from AS64514 (not in our ROA)
router bgp 64514
 address-family ipv4 unicast
  network 198.51.100.0/24

Monitor for 30 minutes. If announcement is:

  • Accepted and propagated: Region does not enforce RPKI validation (or validates but doesn’t drop)

  • Rejected by peers: Region enforces RPKI validation (drops INVALID routes)

  • Accepted by some peers, rejected by others: Mixed deployment

Record results by region and peer.

Test 2: Verify our fraudulent ROA visibility

Query multiple independent validators:

# Check Cloudflare's validator
curl "https://rpki.cloudflare.com/api/v1/vrps?prefix=203.0.113.0/24"

# Check RIPE's validator  
curl "https://stat.ripe.net/data/rpki-validation/data.json?resource=203.0.113.0/24"

# Check our own Routinator
routinator vrps --output json | jq '.roas[] | select(.prefix == "203.0.113.0/24")'

Expected result: all validators should show BOTH the legitimate ROA (AS65001, if it exists) AND our fraudulent ROA (AS64513).

This is the control-plane attack succeeding: multiple conflicting ROAs exist, and validators accept both as valid.

Expected technical effect

Within 4 hours of testing:

Validation deployment map complete:

  • AMER region: [X%] of peers enforce validation

  • EMEA region: [Y%] of peers enforce validation

  • APAC region: [Z%] of peers enforce validation

Target selection for phase 3:

  • Regions with 0-20% enforcement: safe for hijacking (most peers won’t validate)

  • Regions with 20-50% enforcement: moderate risk (mixed deployment)

  • Regions with 50%+ enforcement: high risk (significant validation coverage)

Our fraudulent ROA visibility:

  • Visible in all major validators: SUCCESS

  • Visible in some validators: PARTIAL (must identify which validators phase 3 target uses)

  • Not visible in any validators: FAILURE (ROA did not propagate, abort phase 3)

Expected observational footprint

Test announcement footprint:

  • BGP updates from our test infrastructure to peers (VISIBLE but appears like testing)

  • Some peers will see INVALID announcement and may log it (EXPECTED, appears like misconfiguration)

  • If anyone investigates: “We were testing RPKI validation deployment, accidentally announced from wrong AS, corrected immediately”

Validation query footprint:

  • HTTPS queries to public validators (COMMON, not suspicious)

  • No unusual access patterns (thousands of networks query validators daily)

Detection likelihood: Low. Test announcements appear like routine network testing. Validator queries are indistinguishable from normal operations monitoring.

Manual steps

  1. Document which peers accepted INVALID announcement (they lack validation)

  2. Document which peers rejected INVALID announcement (they enforce validation)

  3. Cross-reference with phase 3 target selection: choose regions where most traffic goes through non-validating peers

  4. Verify our fraudulent ROA appears in validators that target networks actually use (different organisations use different validators)

Timing uncertainty

Testing requires:

  • 30-60 minutes per test announcement (allow BGP convergence, peer response)

  • 2-4 hours total for multi-region testing

  • Additional time if results are ambiguous (some peers slow to respond, unclear whether they’re validating or just filtering for other reasons)

Budget full day for Action 2.2 completion.

Budget reality check

Global RPKI validation deployment is ~40% as of 2024, but not evenly distributed:

  • Major transit providers: 60-80% deployment (high validation coverage)

  • Enterprise networks: 20-40% deployment (moderate coverage)

  • Smaller ISPs: 0-20% deployment (minimal coverage)

Phase 3 will target regions where smaller ISPs dominate traffic patterns, as they’re least likely to have validation deployed.


Action 2.3: Establish monitoring for ROA changes

Intent Deploy monitoring to detect if victim discovers our fraudulent ROA and attempts to revoke it or create conflicting ROAs, providing early warning before phase 3 execution.

Preconditions

  • Action 2.1 complete: fraudulent ROA is published

  • Action 2.2 complete: validation deployment mapped

  • We have automated monitoring infrastructure

Execution method

Deploy continuous monitoring via RIPE Stat API and Routinator:

#!/usr/bin/env python3
# Monitor ROA changes for target prefix

import requests
import time
import json
from datetime import datetime

TARGET_PREFIX = "203.0.113.0/24"
CHECK_INTERVAL = 300  # 5 minutes

def check_roas():
    url = f"https://stat.ripe.net/data/rpki-validation/data.json?resource={TARGET_PREFIX}"
    response = requests.get(url)
    data = response.json()
    
    roas = data.get('data', {}).get('validating_roas', [])
    
    # Check for our fraudulent ROA
    our_roa_present = any(roa.get('origin') == 'AS64513' for roa in roas)
    
    # Check for new ROAs from victim
    victim_roas = [roa for roa in roas if roa.get('origin') == 'AS65001']
    
    return {
        'timestamp': datetime.utcnow().isoformat(),
        'our_roa_present': our_roa_present,
        'victim_roas': victim_roas,
        'total_roas': len(roas)
    }

while True:
    status = check_roas()
    print(json.dumps(status))
    
    if not status['our_roa_present']:
        print("ALERT: Our fraudulent ROA has been removed!")
    
    if len(status['victim_roas']) > baseline_count:
        print("ALERT: Victim created new ROAs!")
    
    time.sleep(CHECK_INTERVAL)

Deploy this monitoring before phase 3. If our ROA disappears, abort phase 3 immediately.

Expected technical effect

Monitoring provides:

  • Confirmation that fraudulent ROA remains published (ongoing success)

  • Early warning if victim discovers and revokes our ROA (abort trigger)

  • Detection of victim creating additional ROAs (may require re-planning phase 3)

  • Audit trail for incident response analysis later

Expected observational footprint

Monitoring footprint:

  • Periodic HTTPS queries to RIPE Stat API every 5 minutes (COMMON pattern, shared with thousands of networks)

  • No direct queries to victim infrastructure (all queries to public APIs)

Detection likelihood: Effectively zero. API queries are indistinguishable from normal network monitoring.

Manual steps

  1. Verify monitoring script runs continuously without interruption

  2. Set up alerting (email, SMS, or monitoring dashboard) for ROA status changes

  3. Document baseline ROA count so increases are detectable

  4. Test alert mechanism (temporarily stop monitoring, verify alerts fire)

Timing uncertainty

Monitoring runs continuously. No specific timing uncertainty, but note:

  • API rate limits: RIPE Stat allows reasonable query frequency, but excessive queries (multiple per second) will be throttled

  • Validator propagation lag: if victim revokes our ROA, it may take 30-60 minutes to propagate to all validators

Use 5-minute check interval as balance between rapid detection and API politeness.

Budget reality check

Continuous monitoring is feasible because RPKI APIs are public and designed for exactly this use case. No special access required, no authentication needed, no cost.

Recording the mess honestly

The credential compromise prerequisite

Action 2.1 only works if we have compromised RIR account credentials. This playbook does not cover how to obtain those credentials. That’s a separate attack path involving:

  • Phishing campaigns against network operations staff

  • Credential stuffing attacks against RIR portals

  • Insider access (malicious employee or contractor)

  • Supply chain compromise (attack on systems with RIR access)

Obtaining these credentials is often the hardest part of the entire attack chain. This playbook assumes it’s already done. If you don’t have credentials, Action 2.1 will fail immediately.

RIR validation varies by region

ARIN, RIPE, APNIC, LACNIC, and AFRINIC have different RPKI implementations with different validation strictness:

  • RIPE: Generally stricter, better automated validation

  • ARIN: Mixed, some manual review processes

  • APNIC: Varies by member type

  • Smaller RIRs: Often less automated, more manual review

The playbook assumes victim’s prefix is managed by an RIR with automated (but imperfect) validation. If manual review is triggered, Action 2.1 timing becomes unpredictable (hours to days).

The conflicting ROAs problem

If both legitimate and fraudulent ROAs exist, validators may behave inconsistently:

  • Some validators accept multiple ROAs for same prefix (common)

  • Some validators flag conflicts and require resolution (less common)

  • Routers might use first ROA seen, last ROA seen, or most specific match

This inconsistency is actually beneficial for attack: it creates confusion rather than clear rejection.

Where best practice lost to budget reality

Best practice says: RIRs should have comprehensive validation preventing ROA creation for resources not controlled by submitter. They should have automated conflict detection. They should have monitoring alerting on unusual ROA patterns.

Budget reality says: RIR systems are complex legacy platforms. Validation exists but has edge cases. Automated conflict detection is limited. Monitoring is mostly reactive (humans review after complaints are filed).

The gap is what makes phase 2 viable.

Success criteria for phase 2

Phase 2 succeeds when:

  • Fraudulent ROA is published and visible in multiple validators

  • Validation deployment map is complete (know which regions to target)

  • Monitoring is deployed and functioning (early warning system active)

  • No alerts from victim or RIR (operational security maintained)

Phase 2 fails if:

  • ROA creation rejected by RIR (abort, cannot proceed)

  • Fraudulent ROA published but immediately revoked (detected too quickly)

  • Validation deployment shows >80% enforcement globally (hijack unlikely to succeed)

Transition to phase 3

Do not proceed to phase 3 until:

  1. Fraudulent ROA has been published for at least 48 hours without revocation (demonstrates it’s not being actively monitored)

  2. Validation deployment map shows viable target regions (at least one region with <50% validation enforcement)

  3. Monitoring confirms ROA stability (no unexpected changes)

  4. Cover story and abort plan are prepared (in case phase 3 detection occurs)

Phase 3 (actual prefix hijacking) is the visible part of the attack. Everything done in phases 1-2 was preparation to make phase 3 appear valid to validation systems.