Skip to content

About

NTCIP 1202 traffic-signal attack lab: emulated controller + SUMO intersection. snmpset commands drive a live SUMO-GUI window.

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

NTCIP 1202 Traffic Signal Attack Lab

A self-contained, software-only offensive-security lab that pairs an emulated NTCIP 1202 traffic-signal controller with an Eclipse SUMO intersection simulation. Real snmpset commands drive a real SUMO-GUI window, so every attack is visible end-to-end without ever touching a physical device.

Companion write-up (Turkish): mucahic.com/dossier-08.html

Lab cover

What this is

A pure-software workbench for studying how a modern traffic-signal controller can be manipulated over its native management protocol. The lab exposes a realistic NTCIP 1202 / SNMPv2c attack surface and renders the consequences in a SUMO simulation, so the operator can see queues build, gridlock spread and adaptive logic fall for spoofed sensor data.

It is not a production controller and not intended for any device on a public network. Use it to learn, to demo, and to design defenses.

Why this exists

There is no shortage of NTCIP material on GitHub, but every project takes one small slice:

Project What it does What it is not
mnit-rtmc/ntcip Rust library, focused on DMS Not 1202, not a server
markashook/SharpNTCIP C# protocol library Client only, no emulator
usdot-fhwa-OPS/V2X-Hub NTCIP 1202 SPAT plugin Talks to a real controller
mmitss/mmitss-az Arizona MMITSS V2I Needs real signal hardware
sumoITScontrol SUMO signal-control framework TraCI/TCP only, no SNMP
Fortiphyd/GRFICSv3 OT security lab Chemical process, not traffic

This lab fills the gap between them: an emulated controller that speaks NTCIP 1202 on the wire and a visual SUMO target that lets you see what happens after the SET request lands. The whole thing is one pip install and one python command away from a working offensive playground.

Architecture

NTCIP attack chain

   ┌──────────────┐    UDP/1161 (SNMP v2c)    ┌────────────────────────────────┐
   │  attacker    │ ────────────────────────> │  controller.py                 │
   │  snmpset     │                           │  ┌─────────────────────────┐   │
   └──────────────┘                           │  │  pysnmp agent thread    │   │
                                              │  │  - public  (read)       │   │
                                              │  │  - private (write)      │   │
                                              │  └────────────┬────────────┘   │
                                              │               │                 │
                                              │  ┌────────────▼────────────┐   │
                                              │  │  ControllerState        │   │
                                              │  │  (thread-safe dict)     │   │
                                              │  └────────────┬────────────┘   │
                                              │               │                 │
                                              │  ┌────────────▼────────────┐   │
                                              │  │  TraCI bridge (main)    │   │
                                              │  │  every step:            │   │
                                              │  │  state -> SUMO TLS      │   │
                                              │  └────────────┬────────────┘   │
                                              └───────────────┼────────────────┘
                                                              │ TCP / TraCI
                                                              ▼
                                                       ┌────────────┐
                                                       │  SUMO-GUI  │
                                                       │ (intersect)│
                                                       └────────────┘

A single Python process exposes two doors. One door takes SNMP packets from the attacker; the other door drives the SUMO simulation through TraCI. The two threads share a small in-memory state object protected by a lock. That is literally the only bridge between the SNMP world and the simulation world.

MIB

Vendor branch 1.3.6.1.4.1.1206 (NTCIP organization). The lab exposes a deliberately small subset that captures the attacks in the write-up.

OID Field Type Notes
.1.3.6.1.4.1.1206.4.2.1.1.1.0 currentPhase Integer32 1 = NS green, 2 = EW green
.1.3.6.1.4.1.1206.4.2.1.1.2.0 greenTime Integer32 seconds
.1.3.6.1.4.1.1206.4.2.1.1.3.0 forceAllRed Integer32 1 = all-red gridlock
.1.3.6.1.4.1.1206.4.2.1.1.4.0 greenLockPhase Integer32 0 / 1 / 2 (green-forever lock)
.1.3.6.1.4.1.1206.4.2.1.1.5.0 preemptionPhase Integer32 0 / 1 / 2 (fake emergency)
.1.3.6.1.4.1.1206.4.2.1.1.6.0 loopSpoofMask Integer32 4-bit (N=1, E=2, S=4, W=8)
.1.3.6.1.4.1.1206.4.2.1.1.99.0 sysBanner OctetString identification string
.1.3.6.1.4.1.1206.4.2.1.1.100.0 screenshotRequest OctetString write a filename to capture SUMO

Communities: public (RO) and private (RW). This mirrors NTCIP 1202 defaults that are still found in real deployments.

Repository layout

ntcip-1202-lab/
├── scenario/        SUMO network + routes (4-leg signalized intersection)
├── server/          NTCIP 1202 SNMP agent + TraCI bridge (single process)
├── attacks/         SNMP client, recon, attack CLI, demo orchestrator
├── diagrams/        Generators for the article diagrams (PIL/SVG)
├── README.md
├── LICENSE          MIT
└── requirements.txt

captures/ is created at runtime and is gitignored.

Requirements

python -m pip install -r requirements.txt

eclipse-sumo installs the SUMO binaries (sumo, sumo-gui, netconvert) into the active Python's Scripts/ directory. controller.py extends PATH automatically so they are reachable without a manual setup step.

Build the network (once)

netconvert \
  --node-files scenario/network.nod.xml \
  --edge-files scenario/network.edg.xml \
  --output-file scenario/network.net.xml \
  --tls.guess true --tls.default-type static

Run

Terminal 1 — SUMO-GUI + SNMP agent + TraCI bridge:

python server/controller.py --mode full

Terminal 2 — recon and individual attacks:

python attacks/recon.py
python attacks/attack.py eternal-red
python attacks/attack.py green-forever --phase 1
python attacks/attack.py preemption    --phase 2
python attacks/attack.py loop-spoof    --mask 5
python attacks/attack.py reset
python attacks/attack.py screenshot --name eternal_red.png

Or the orchestrator that runs every attack and captures one screenshot per scene:

python attacks/demo_all.py

With a real Net-SNMP client

The agent talks plain SNMPv2c, so anything that speaks SNMP works against it. The lab uses the same protocol shape as a field controller:

snmpwalk -v2c -c public  127.0.0.1:1161 .1.3.6.1.4.1.1206.4.2.1.1
snmpset  -v2c -c private 127.0.0.1:1161 .1.3.6.1.4.1.1206.4.2.1.1.3.0 i 1

Attacks

The four attacks reflect the categories in the companion write-up.

  1. Eternal Red — forceAllRed = 1 keeps all directions red.
  2. Green Forever — greenLockPhase = 1|2 pins one axis green.
  3. Preemption Spam — preemptionPhase = 1|2 mimics a stuck emergency-vehicle signal.
  4. Loop Spoofing — loopSpoofMask injects phantom vehicles on selected approaches.

Each of these is one snmpset and gets one SUMO scene in return.

Defenses (so the lab is useful for both sides)

  • Rotate the community strings off public/private.
  • Put SNMP traffic on a management VLAN with strict L3 ACLs.
  • Move to SNMPv3 (auth + priv). NTCIP 1218 already favors this.
  • Verify the hardware conflict monitor is calibrated and recently tested.
  • Treat vendor remote access as just-in-time, not always-on.
  • Lock physical access to detector pull boxes.

Disclaimer

Designed for the simulation it ships with. Pointing real snmpset traffic at production traffic signals without written authorization is illegal in every jurisdiction the author is aware of. Stay in your own lab.

Author

Mücahit İç (MUCAHIC) — mucahic.com · LinkedIn · GitHub

About

NTCIP 1202 traffic-signal attack lab: emulated controller + SUMO intersection. snmpset commands drive a live SUMO-GUI window.

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages