teknikbakis

219 bin VPN denemesi IP'siz kaldı, “engellenen” iki adres 46 dakika denemeyi sürdürdü

FortiGate'in SSL-VPN olaylarında saldırganın adresi srcip'te değil remip'te duruyor. Kara listeyi SSL-VPN ayarına bağlamak ise bağlantıyı düşürmüyor, yalnız girişi reddediyor. Pano ikisinde de yeşil gösteriyordu.

DOSYA TB-2026-010
SİSTEM FortiGate-60E · FortiOS 6.2
KATMAN Log ayrıştırma / SSL-VPN erişimi
SÜRE 26–27 Eyl 2026 · ölçüm 46 dk
DURUM AÇIK
KANIT 3 ek

Semptom

Bir kurumun FortiGate-60E'si (FortiOS 6.2) SSL-VPN portalını internete açıyordu ve portal, internete açık her giriş ekranı gibi, gün boyu kaba kuvvet denemesi alıyordu. Duvarın syslog akışını kendi yazdığım bir boru hattında işliyordum: satır ayrıştırılıyor, kaynak IP'ye göre zenginleştiriliyor, sonra kara listeye, canlı akışa, alarma ve bir itibar servisine giden kötüye kullanım raporuna dağıtılıyordu.

Panoda iki tuhaflık vardı ve ikisi de yeşil görünüyordu.

Birincisi bir sayıydı. Pano "24 saatte 2.977 VPN denemesi" diyordu (27 Eyl 2026). Ama saldırgan listesinde, alarmlarda, canlı akışta ve dışa giden raporda tek bir VPN saldırganı yoktu. Sistem denemeleri sayabiliyor, kimin yaptığını söyleyemiyordu.

İkincisi bir rozetti. Bir gün önce (26 Eyl 2026) en ısrarcı iki adresi bir kara liste grubuna koyup grubu SSL-VPN ayarına bağlamıştım. Pano durumu "Engellendi" olarak gösterdi. Duvarın ham loglarında ise aynı iki adres aynı ritimle, aynı hata satırını üretmeye devam ediyordu.

Yanlış yollar

İki semptomun arkasında aynı türden bir varsayım vardı: bir sinyalin varlığını, işin yapıldığının kanıtı saymak.

  • "Sayaç çalışıyorsa ayrıştırıcı da çalışıyordur." Sayaç action alanına bakıyordu; bir satırı IP'si olmadan da sayabiliyordu. Sayı doğruydu. IP'ye bağlı her şey ise — zenginleştirme, kara liste, alarm, rapor — aynı satırı hiç görmüyordu. Eksik hata üretmediği için sessizce birikti.
  • "FortiGate satırında kaynak srcip'tedir." Trafik kayıtları için doğru, olay kayıtları için değil. Ayrıştırıcı bu varsayımla yazılmıştı ve VPN satırlarında IP alanını boş bırakıyordu.
  • "Grup bir kurala bağlandıysa IP engellenmiştir." Pano rozeti grubun başvuru sayısından türetiyordu: REST API'nin döndürdüğü q_ref 0 iken boşta, 1 olunca "Engellendi". Bu, yapılandırmanın durumunu söyler; trafiğe ne olduğunu söylemez.

Bir de bilerek almadığım kolay yol vardı: iki adresin /24 bloğunu topluca kapatmak. Hedefim saldıran adresti, blok değil. Bu karar sonradan ölçümün kendisine yaradı — engellenmeyen komşular kontrol grubu oldu.

Doğru test

İki soruyu birbirinden ayırdım ve ikisini de ölçerek sordum.

Birinci soru: VPN satırında saldırganın adresi var mı, varsa hangi alanda? Ham satırları yan yana koymak yetti.

EK-1 Trafik kaydı ile SSL-VPN olay kaydı yan yana
# Trafik kaydı: kaynak srcip alanında
date=2026-09-27 time=03:12:44 … type="traffic" subtype="local" …
  srcip=198.51.100.23 srcintf="wan1" dstip=192.0.2.1 dstport=23 … action="deny" …

# SSL-VPN olay kaydı: srcip YOK, karşı taraf remip alanında
date=2026-09-27 time=03:14:07 devname="FGT-ORNEK" logid="0101039426"
  type="event" subtype="vpn" level="alert" vd="root" …
  logdesc="SSL VPN login fail" action="ssl-login-fail" tunneltype="ssl-web"
  tunnelid=0 remip=203.0.113.47 user="admin" group="N/A" dst_host="N/A"
  reason="sslvpn_login_permission_denied" msg="SSL user failed to logged in"

Satırlar okunabilirlik için bölündü, alanlar kısaltıldı (…). IP, kullanıcı ve cihaz adı örnektir. Olay kaydında srcip diye bir alan hiç yok.

Ayırt edici ölçü basitti: aynı zaman aralığındaki ssl-login-fail satırlarını iki kez saydım — bir kez eylem alanına göre, bir kez kaynak IP'si dolu olanlar. Son 24 saatte ilki 2.977, ikincisi sıfırdı. Pencereyi 30 güne açınca IP'siz kalan VPN hatalı girişi 219 bine çıktı.

İkinci soru: kısıt denemeleri durdurdu mu? Burada tek gruplu bir "önce/sonra" karşılaştırması yanıltır. Saldırganların ritmi düzensizdir; bir adresin on beş dakika susması engelin kanıtı değil, mola olabilir. Bu yüzden ölçüye bir kontrol grubu ekledim: aynı /24'ten deneyen ama listeye almadığım komşular. Kısıt çalışıyorsa deney grubu düşer, kontrol grubu aynı kalır. İkisi birlikte düşerse saldırgan mola vermiştir. İkisi birlikte sürerse kısıt etkisizdir.

EK-2 Kontrol gruplu ölçüm
T0        kara liste grubu SSL-VPN ayarına bağlandı (26 Eyl 2026)
Deney     gruptaki 2 adres            203.0.113.10, 203.0.113.11
Kontrol   aynı /24'teki, engellenmeyen komşular
Ölçü      adres başına ssl-login-fail satırı, T0 öncesi ve sonrası
Bekleme   46 dk   (ritim ≈ 4 deneme/saat/adres → en az 45 dk)

Sonuç     Deney ve kontrol, T0 sonrasında AYNI sıklıkta denemeye devam etti.
          Satır biçimi değişmedi: reason="sslvpn_login_permission_denied"
                                  tunneltype="ssl-web"

Engellenen adresler ile engellenmeyen komşuları arasında fark yok. Kısıt, trafiğe dokunmuyor.

Bekleme süresi ölçünün parçası. Bu adresler saatte yaklaşık dört kez deniyordu; on beş dakikalık bir pencerede hiç deneme görmemek olağandır. En az 45 dakika beklemeden sonuç okunmaz. 46 dakika boyunca iki grup da aynı sıklıkta denemeyi sürdürdü.

Kök neden

1 · Olay kaydının kendi şeması var

FortiOS'un iki log ailesi farklı şeyler anlatır. Trafik kayıtları (type=traffic) bir oturumu tarif eder; kaynak ve hedef srcip/dstip alanlarındadır. Olay kayıtları (type=event) bir alt sistemin ne yaptığını anlatır. SSL-VPN olaylarında (subtype=vpn: ssl-login-fail, ssl-new-con, ssl-alert, tunnel-up…) karşı tarafın adresi remip= alanındadır ve srcip hiç yoktur.

Ayrıştırıcı kaynağı yalnız srcip'ten okuyordu. Bulamayınca hata vermedi; satırı IP'siz yazdı, çünkü IP'siz satır geçerli bir satırdı. Sonraki her bileşenin anahtarı IP olduğu için VPN satırları veritabanında duruyor ama savunmanın hiçbir yerine ulaşmıyordu. Onları görebilen tek şey, eylem sayan sayaçtı.

ÇIKARIM

Boş gelen bir alan hata üretmiyorsa eksik veri "veri yok" gibi görünür. Sayılabilen ama bir kimliğe bağlanamayan satırların oranını ayrı bir metrik olarak izle. Bu vakada VPN olaylarında o oran yüzde yüzdü.

2 · source-address girişi reddediyor, bağlantıyı düşürmüyor

Uyguladığım kısıt şuydu:

config vpn ssl settings
    set source-address "KARA-LISTE"
    set source-address-negate enable
end

source-address, SSL-VPN'e hangi adreslerden giriş yapılabileceğini belirler; negate ile "bu gruptakiler hariç herkes" olur. Ölçümün gösterdiği şu: kısıt bağlantıyı düşürmüyor. TCP ve TLS kuruluyor, istek SSL-VPN sürecine (sslvpnd) ulaşıyor, giriş orada reddediliyor. Saldırganın gözünden hiçbir şey değişmiyor: önce de başarısızdı, şimdi de. Log satırı da değişmiyor: aynı reason="sslvpn_login_permission_denied", aynı tunneltype="ssl-web".

Kısıtın sağladığı şey, en iyi durumda, bu adreslerden başarılı bir girişin de reddedilmesi; bunu ayrıca sınamadım. Kesin olan, kaba kuvvet trafiğini durdurmadığı. Panonun "Engellendi" demesi ise bütünüyle yapılandırmadan türemişti: grup bir yere bağlanmıştı, o kadar.

Çözüm

1 · remip, yalnız saldırı eylemine

En kısa düzeltme "srcip yoksa remip'i al" olurdu. Tek satır — ve ikinci bir hata. Bu kural tunnel-up dahil her VPN olayına IP yazar. Kurumun meşru bir kullanıcısı tünelini cep telefonundan açıyor ve bir gün parolasını yanlış yazıyorsa o ssl-login-fail satırı onun adresini taşır. Kural ayrım yapmazsa kullanıcının cep telefonu IP'si kara listeye ve itibar servisine giden rapora düşer: kendi kullanıcını dünyaya saldırgan diye bildirmiş olursun.

Uyguladığım kural iki şart koyuyor: remip yalnız ssl-login-fail satırına yazılır ve tunnel-up ile tünel açtığı görülmüş hesapların hatalı girişleri saldırı sayılmaz. Tünel açmış hesaplar açılışta geçmiş kayıtlardan yüklenir, sonra olaylardan öğrenilir. Diğer VPN olayları IP'siz kalır.

EK-3 Düzeltilmiş kaynak IP kuralı (Python, sadeleştirildi)
IPV4 = re.compile(r"\d{1,3}(?:\.\d{1,3}){3}")
tunel_acmis = set()   # tunnel-up görülmüş hesaplar; açılışta geçmişten de yüklenir

def kaynak_ip(f):
    if f.get("srcip"):                          # trafik kayıtları
        return f["srcip"]
    if f.get("subtype") != "vpn":
        return None
    kullanici = f.get("user") or ""
    if f.get("action") == "tunnel-up" and kullanici:
        tunel_acmis.add(kullanici)              # meşru hesap: sahibi tünel açtı
    elif (f.get("action") == "ssl-login-fail"
          and kullanici not in tunel_acmis
          and IPV4.fullmatch(f.get("remip", ""))):
        return f["remip"]                       # yalnız saldırı eylemi
    return None                                 # diğer VPN olayları IP'siz

Bu kuraldan sonra VPN hatalı girişleri zenginleştirmeye, kara listeye, alarma ve rapora adresleriyle ulaşıyor; tünel açmış hesapların yazım hataları dışarıda kalıyor.

Bu kuralın bilinen bir bedeli var: saldırgan gerçek bir hesap adını denerse o denemeler IP'siz kalır. Meşru kullanıcıyı ihbar etmektense bu boşluğu kabul ettim.

Geri doldurma (backfill) ayrı bir dikkat ister. Geçmiş 30 günü yeniden işlemek 219 bin satırı bir anda IP'li hale getirir ve bu satırlar dışa giden raporlayıcıya da akar. Geri doldurmadan önce raporlayıcının ne göndereceğine bakmak gerekir: kapsam birden genişliyorsa önce onay, sonra doğru kategori. VPN'e kaba kuvvet denemesi "port taraması" olarak değil, kaba kuvvet olarak bildirilmeli.

2 · source-address: sıradaki aday, doğrulanmadı

Dosyanın açık kalma nedeni bu. Sıradaki aday, wan1 üzerinde kara liste grubunu kaynak alan bir deny local-in kuralı. Local-in kuralları duvarın kendisine gelen trafiğe uygulanır; beklentim, bağlantının SSL-VPN sürecine varmadan düşmesi.

# ADAY — FortiOS 6.2'de SSL-VPN'i kestiği henüz DOĞRULANMADI
config firewall local-in-policy
    edit 100
        set intf "wan1"
        set srcaddr "KARA-LISTE"
        set dstaddr "all"
        set action deny
        set service "ALL"
        set schedule "always"
    next
end

Altını çizerek yazıyorum: bu kuralın FortiOS 6.2'de SSL-VPN trafiğini gerçekten kestiğini henüz doğrulamadım. Uyguladığımda ölçü aynı olacak: deney ve kontrol grubu, T0 öncesi ve sonrası, en az 45 dakika. Local-in de tutmazsa son seçenek yüzeyi kapatmak: portalı internete hiç açmamak, örneğin duvarın önündeki modemde port yönlendirmesini kaldırmak.

Kalıcı ders

  • Yapılandırma durumu etki kanıtı değildir. "Kurala bağlı" ile "engellendi" arasındaki fark yalnız trafikte görünür. Pano rozeti yapılandırmadan değil, ölçümden türemeli.
  • Engellemeyi kontrol grubuyla ölç. Engellenen adresleri, engellenmeyen benzerleriyle T0 öncesi ve sonrası karşılaştır; bekleme süresini saldırganın ritmine göre seç. Tek gruplu önce/sonra karşılaştırması molayı başarı sanar.
  • Her log türünün kendi şeması var. srcip trafik kaydının alanıdır; olay kaydında karşı taraf başka bir adla gelir. Ayrıştırıcıya bir "IP bulunamadı" sayacı koy ve sıfırdan büyükse bak.
  • Sayım, kimlik değildir. "2.977 deneme" doğru bir sayıydı. Kimlik olmadan hiçbir savunma o sayının üzerine kurulamaz.
  • Saldırganı ararken kendi kullanıcını ihbar etme. Dışa rapor gönderen her kuralın bir "bu bizim kullanıcımız mı?" süzgeci olmalı; geri doldurma bu süzgeci en çok zorlayan andır.