Suricata kural anatomisi
- Suricata kuralını eylem, başlık ve seçenekler olarak sökmeyi, doğru tamponda aramayı, kuralı pcap ile sınamayı ve fast.log satırını okumayı öğren.
- Bir kuralı okumayı öğrenince benzer mantıkla yeni bir kural da yazabilirsin.
- Kaba bir SQL enjeksiyon kuralını adım adım iyileştirecek, ardından iki adımlı tespiti ve hazır kural setlerini göreceksin.
Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +50 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.
Bir IDS'in gücü kurallarından gelir. Aynı motor iyi yazılmış bir kuralla saldırıyı ilk pakette yakalar, kötü yazılmış bir kuralla bütün gün yanlış alarm üretir. Suricata kuralları düz metin dosyalarında durur ve her kural tek satırdır. Satırın yapısını bir kez çözdüğünde hazır kural setlerini okuyabilir, kendi kuralını da yazabilirsin.
Bu derste önce bir kuralı parçalarına ayıracaksın. Sonra başlık değişkenlerini, akış yönünü ve protokol tamponlarını kullanarak kaba bir kuralı isabetli hale getireceksin. Ardından kuralı kayıtlı trafikle sınayıp fast.log satırını okuyacaksın. Son bölümde boyut denetimini, iki adımlı tespiti ve hazır kural setlerini göreceksin.
Bir kuralın üç parçası
Suricata trafiği kurallarla karşılaştırır, bu kurallara imza da denir. Her kural üç parçadan oluşur. İlk parça eylemdir ve kural eşleşince ne olacağını söyler. alert eşleşmeyi kaydeder ve alarm üretir.
drop paketi düşürür ve alarm yazar, ama paketi yalnız IPS modunda gerçekten durdurabilir. reject buna ek olarak gönderene bağlantıyı kesen bir TCP RST ya da ICMP hata paketi yollar. pass paketin incelemesini durdurur, sonraki kurallar ona bakmaz. İkinci parça başlıktır: protokol, kaynak adres, kaynak port, yön oku, hedef adres ve hedef port buradan okunur.
Üçüncü parça parantez içindeki seçeneklerdir. Seçenekler paketin içinde ne aranacağını, kuralın adını, kimliğini ve sınıfını tanımlar. Üç parça birlikte kuralın tam anlamını taşır.
alert tcp any any -> 198.51.100.10 80 (msg:"Olası SQL enjeksiyon denemesi"; content:"UNION SELECT"; nocase; sid:1000001; rev:1; classtype:web-application-attack;)
Bu kuralı parça parça oku. alert eylemi eşleşmeyi kaydeder, paketi durdurmaz. tcp any any protokolü ve kaynağı belirtir, herhangi bir adres ve porttan gelen trafiği kapsar. Ok işareti yönü gösterir, trafiğin 198.51.100.10 adresinin 80 numaralı portuna gittiğini arar.
Parantez içinde msg alanı alarmda görünecek okunur metni taşır. content alanı paket içinde aranan dizgiyi verir, nocase büyük küçük harfi önemsiz kılar. sid kurala benzersiz bir kimlik verir, rev sürüm numarasıdır. classtype ise saldırı türünü sınıflandırır ve alarmın önem derecesini belirler.
Kural çalışır ama kabadır. Paketin ham yükünün her yerinde arar ve saldırgan boşluğu değiştirince eşleşme kaçar. Sonraki bölümde onu adım adım iyileştireceksin.
Seçeneklerin bir kısmı kuralın kimlik kartıdır. msg alarmda görünen metindir. sid kuralın benzersiz numarasıdır ve Suricata'da zorunlu olan tek meta alandır; sid taşımayan kural hiç yüklenmez.
rev kuralın sürümüdür. msg ile rev zorunlu değildir, ama her kuralda yazılması standart uygulamadır. Suricata varsayılan olarak gid 1 kullanır. sid numaraları rastgele seçilmez.
Topluluğun tuttuğu SID tahsis listesi 1000000 ile 1999999 arasını yerel kurallara ayırır. Hazır setlerin kendi aralıkları vardır; ET Open 2000000 civarından başlar. Kendi kuralını yerel aralıkta tutarsan bir güncellemeyle gelen kuralla çakışmazsın. Yazım düzeni de bir gelenektir: msg başta durur, tespit seçenekleri ortada gelir, classtype gibi sınıflandırma alanları ile sid ve rev sona toplanır.
Etkinlik 1 / 7
Kuralda paketin içinde hangi dizginin arandığını gösteren seçenek hangi satırda?
Etkinlik 2 / 7
Aşağıdaki seçenekleri Suricata kural yazım düzenine uygun sırada diz: mesaj en başta, kimlik bilgileri en sonda.
Parçalara tıklayarak komutu soldan sağa kur.
Başlık, akış yönü ve doğru tampon
Başlıkta IP adresini elle yazmak yerine değişken kullanırsın. suricata.yaml dosyasında $HOME_NET korunan ağları, $EXTERNAL_NET geri kalan her yeri tanımlar. Varsayılan yapılandırmada HOME_NET özel adres bloklarıdır, EXTERNAL_NET ise HOME_NET dışındaki her adrestir. Ağ değişince kurallara dokunmaz, yalnız değişkeni güncellersin.
Yön oku üç biçimde gelir. -> kaynaktan hedefe giden trafiği, <> iki yönü birden arar. Suricata 8 ile gelen => ise isteği ve cevabı aynı işlemde birlikte eşleyen kurallarda kullanılır. Ters yönü gösteren bir ok yoktur, kuralı çevirip -> ile yazarsın.
flow:established,to_server seçeneği yalnız kurulmuş bir bağlantının istemciden sunucuya giden tarafını inceler. flow yazmazsan kural el sıkışma paketlerine de bakar. Başlık any any -> any any gibi genişse sunucunun cevapları da kapsama girer; kural hem yavaşlar hem yanlış pozitif üretir.
İlk kuraldaki content paketin ham yükünde arama yapar. Suricata ise trafiği protokollere ayırır ve her alanı ayrı bir tampona (buffer) koyar. Yapışkan tampon (sticky buffer) adı verilen anahtar kelimeler, ardından gelen content'lerin hangi tamponda aranacağını seçer.
http.method istek yöntemini, http.uri normalleştirilmiş adresi, http.request_body istek gövdesini taşır. dns.query DNS sorgusundaki adı, tls.sni TLS el sıkışmasındaki sunucu adını taşır. Seçilen tampon, başka bir tampon yazılana kadar geçerli kalır.
Doğru tamponun iki kazancı vardır. Birincisi isabettir: adreste aranan dizgi, gövdede geçtiği için alarm üretmez. İkincisi hızdır: motor bütün yükü değil, kısa bir alanı tarar. http.uri adresi normalleştirir, örneğin baştaki çift eğik çizgiyi teke indirir; ham adres için http.uri.raw tamponu vardır.
content değiştiricileri aramanın nerede ve nasıl yapılacağını daraltır. content varsayılan olarak harfe duyarlıdır, nocase bu duyarlılığı kaldırır. depth aramanın tamponun ilk kaç baytında yapılacağını, offset kaçıncı bayttan başlayacağını söyler. startswith ve endswith dizginin tamponun tam başında ya da tam sonunda durmasını ister.
distance ve within iki content'i birbirine bağlar. distance ikinci dizginin, birincinin bitişinden kaç bayt sonra aranmaya başlanacağını söyler. within ise aramanın ne kadar uzağa gideceğini sınırlar. distance:0, ikinci dizginin birincinin ardından herhangi bir yerde gelmesi demektir.
fast_pattern motorun ön elemede kullanacağı dizgiyi seçer. pcre düzenli ifadedir ve pahalıdır, bu yüzden yanına bir content eklersin. Motor önce ucuz content'i arar, pcre'yi yalnız aday paketlerde çalıştırır.
alert http $EXTERNAL_NET any -> $HOME_NET any (msg:"Olası SQL enjeksiyon denemesi, URI"; flow:established,to_server; http.uri; content:"union"; nocase; content:"select"; nocase; distance:0; classtype:web-application-attack; sid:1000001; rev:2;) alert dns $HOME_NET any -> any any (msg:"Şüpheli alan adı sorgusu, kotu.example"; dns.query; content:"kotu.example"; nocase; endswith; classtype:bad-unknown; sid:1000010; rev:1;)
İlk kural eski SQL kuralının iyileştirilmiş halidir. Protokol http yazıldığı için Suricata trafiği hangi portta HTTP olarak çözümlerse kuralı orada dener. flow:established,to_server yalnız istemcinin isteğine bakar, http.uri aramayı adresle sınırlar. İki ayrı content vardır: önce union, sonra onun ardından herhangi bir yerde select aranır.
Eski kural UNION SELECT dizgisini boşlukla tek parça arıyordu. Saldırgan boşluk yerine artı işareti, %20 ya da bir yorum koyunca eşleşme kaçıyordu. İki parçalı arama ayırıcıdan bağımsızdır. Kural değiştiği için rev 2 olmuştur.
İkinci kural iç ağdaki istemcilerin kotu.example alanını sorgulamasını yakalar. dns.query tamponu sorgulanan adı sondaki nokta olmadan taşır. endswith adın bu dizgiyle bitmesini ister; veri.kotu.example gibi alt alanlar da yakalanır.
Derinleş:fast_pattern ve çoklu desen eşleme
Bir sensörde on binlerce kural yüklü olabilir. Her paketi her kuralla tek tek karşılaştırmak mümkün değildir. Suricata bu yüzden her kuraldan tek bir dizgi seçer ve bütün kuralların dizgilerini tek geçişte arar. Bu işe çoklu desen eşleme (multi-pattern matching) denir.
Varsayılan algoritma Aho-Corasick'tir; Suricata Hyperscan desteğiyle derlenmişse mpm-algo: auto ayarı Hyperscan'i seçer. Ön elemede dizgisi bulunmayan kural o paket için hiç değerlendirilmez. Kuralda fast_pattern yazılmamışsa Suricata seçimi kendisi yapar.
Önce en yüksek öncelikli tamponu seçer, uygulama katmanı tamponları genelde ham yükten önce gelir. Sonra bu tampondaki en uzun content'i alır. Uzunluk eşitse karakter çeşitliliği yüksek olanı seçer.
Kısa ve sık geçen bir dizgi ön elemeye düşerse motor gereksiz yere çok kural değerlendirir. fast_pattern ile daha ayırt edici bir dizgiyi elle seçebilirsin.
Etkinlik 3 / 7
Aşağıdaki kural, verilen dört HTTP isteğinden hangisinde alarm üretir?
Önce kodu oku, sonra çıktıyı seç.
alert http $EXTERNAL_NET any -> $HOME_NET any (msg:"Olası SQL enjeksiyon denemesi, URI"; flow:established,to_server; http.uri; content:"union"; nocase; content:"select"; nocase; distance:0; sid:1000001; rev:2;)
Kuralı sınamak: söz dizimi, pcap ve fast.log
Yeni yazdığın kuralı hemen üretime sürmek risklidir. Önce bir test trafiğiyle çalıştırır, alarmın beklediğin paketi yakalayıp yakalamadığını kontrol edersin. Döngü üç adımdır. İlk adım söz dizimi denetimidir.
-T seçeneği yapılandırmayı ve kuralları yükler, hata varsa söyler ve çıkar. -S seçeneği verdiğin kural dosyasını, yapılandırmadaki kuralların yerine tek başına yükler. İkinci adım kayıtlı trafikle denemedir. -r seçeneği bir pcap dosyasını canlı trafik gibi okur, -l çıktıların yazılacağı klasörü seçer.
Üçüncü adım sonucu okumaktır. fast.log her alarmı tek satıra yazar. Köşeli parantezdeki üç sayı gid, sid ve rev değerleridir. [1:1000010:1], birinci gruptaki 1000010 numaralı kuralın birinci sürümü demektir. Satırın sonunda protokol, kaynak ve hedef adres ile port yer alır.
$ sudo suricata -T -c /etc/suricata/suricata.yaml -S yerel.rules
i: suricata: Configuration provided was successfully loaded. Exiting.
$ suricata -r deneme.pcap -S yerel.rules -l ./cikti
$ cat cikti/fast.log
09/24/2026-01:22:41.508113 [**] [1:1000010:1] Şüpheli alan adı sorgusu, kotu.example [**] [Classification: Potentially Bad Traffic] [Priority: 2] {UDP} 192.168.1.20:53144 -> 192.168.1.53:53Etkinlik 4 / 7
Yeni bir kuralı canlı trafiğe sürmeden önce onu bir ____ ortamında dener, alarmın doğru paketi yakaladığını doğrularsın.
Etkinlik 5 / 7
yerel.rules dosyasının söz dizimini denetlemek istiyorsun. /etc/suricata/suricata.yaml yapılandırmasını kullanan ve yalnız bu kural dosyasını yükleyen komutu yaz.
Boyuta bakmak: dsize ve bsize
Bazı saldırıların imzası içerik değil boyuttur. Giriş formuna binlerce karakterlik bir parola göndermek, taşma arayan bir denemenin tipik izidir. dsize paketin yük boyutuna eşik koyar; dsize:>1000 yükü 1000 bayttan büyük paketleri seçer.
Hızlı bir ilk adımdır, ama iki sınırı vardır. Paket düzeyinde çalışır, istek birkaç pakete bölünmüşse parçalara tek tek bakar. Ayrıca http.uri gibi uygulama katmanı tamponlarıyla aynı kuralda kullanılamaz.
Daha isabetli yol bsize'dır, çünkü bir tamponun uzunluğunu ölçer. http.request_body; bsize:>1000; yazdığında yalnız istek gövdesinin boyutuna bakarsın. Önce dsize ile hızlı bir alarm kurar, trafiği tanıdıkça kuralı tampon üzerinden bsize ile daraltırsın.
alert tcp $EXTERNAL_NET any -> $HOME_NET 80 (msg:"Olası uzun giriş isteği, paket boyutu"; flow:established,to_server; dsize:>1000; classtype:attempted-user; sid:1000020; rev:1;) alert http $EXTERNAL_NET any -> $HOME_NET any (msg:"Olası uzun parola, istek gövdesi"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/giris"; startswith; http.request_body; bsize:>1000; classtype:attempted-user; sid:1000021; rev:1;)
İki kuralı yan yana oku. İlki tcp protokolüyle yazılmıştır, çünkü dsize uygulama katmanı tamponlarıyla birlikte çalışmaz. 80 numaralı porta giden ve yükü 1000 bayttan büyük her paketi yakalar; büyük bir dosya yüklemesi de bu kurala takılır.
İkincisi http protokolüyle yazılmıştır. Önce yöntemin POST olmasını, sonra adresin /giris ile başlamasını ister.
En son yalnız istek gövdesinin uzunluğunu ölçer. Aynı büyük dosya yüklemesi farklı bir adrese gittiği için bu kurala takılmaz. Uzunluk eşiğini de uygulamanın gerçek sınırına göre seçersin. Formun kabul ettiği en uzun parola 128 karakterse, 1000 baytlık bir gövde zaten olağan dışıdır.
Etkinlik 6 / 7
Giriş formuna anormal uzunlukta parola gönderen bir isteği yakalamak için hangi seçenek en uygun ilk adımdır?
İki adımlı tespit ve hazır kural setleri
Bazı saldırılar tek pakette değil, bir dizide görünür. flowbits iki adımlı tespit kurar. İlk kural bir koşulu gördüğünde akışa bir işaret koyar: flowbits:set,giris_denendi; yazılır, flowbits:noalert; ile de kural kendi alarmını üretmez.
İkinci kural aynı akışta flowbits:isset,giris_denendi; ile işaretin varlığını arar ve yalnız o zaman alarm üretir. Böylece önce giriş sayfasına istek, ardından şüpheli bir cevap gibi sıralı olayları yakalarsın. Sayıya dayalı tespitte iki anahtar kelime sık karışır.
threshold alarm sayısını denetler, örneğin belirli bir sürede en fazla bir alarm üretir. detection_filter ise ilk eşleşmeleri sessizce sayar ve eşik aşıldıktan sonraki her eşleşmede alarm üretir. Kaba kuvvet denemesinde ilk birkaç başarısız giriş normaldir, detection_filter eşik aşılınca konuşur.
Kuralların çoğunu sıfırdan yazmazsın. Emerging Threats Open (ET Open), Suricata için ücretsiz yayımlanan en bilinen kural setidir. suricata-update aracı hiçbir ayar yapılmadan çalıştırıldığında ET Open setini indirir ve kuralları tek bir suricata.rules dosyasında birleştirir.
Kendi kuralların ayrı bir dosyada ve yerel sid aralığında durur. Snort kurallarını Suricata'ya taşırken dikkat gerekir. Söz dizimi benzerdir ama tampon adları ve bazı anahtar kelimelerin davranışı farklıdır.
Suricata belgeleri bu farkları ayrı bir sayfada listeler. Sık yapılan üç hata da buraya kadar gördüklerinden çıkar. Birincisi content'i ham yüke yazıp kodlanmış karakterleri kaçırmaktır. İkincisi başlığı any any -> any any bırakmak, üçüncüsü çok kısa bir content seçmektir.
Derinleş:Dönüşümler: tamponu aramadan önce değiştirmek
Bazen dizgiyi aramadan önce tamponu biçimlendirmek gerekir. Suricata buna dönüşüm (transform) der. Dönüşüm, tampon anahtar kelimesinin hemen ardından yazılır ve sonraki content'ler dönüştürülmüş veride aranır. to_lowercase tamponu küçük harfe çevirir, böylece nocase yazmadan harf farkını ortadan kaldırırsın.
compress_whitespace art arda gelen boşlukları teke indirir. strip_whitespace bütün boşlukları siler. url_decode yüzde kodlamasını çözer ve artı işaretini boşluğa çevirir; %uZZZZ biçimindeki Unicode kodlamasını ise çözmez. to_sha256 gibi dönüşümler tamponun özetini çıkarır; kurala açık metin yerine bilinen bir değerin özetini yazmak için kullanılır.
Dönüşümler zincirlenebilir. Örneğin bir istek satırını önce boşluk sıkıştırmasından, sonra özet dönüşümünden geçirebilirsin. Kodlamayla oynayan saldırılara karşı dönüşüm, birden çok content varyantı yazmaktan daha temiz bir çözümdür.
Etkinlik 7 / 7
Her anahtar kelimeyi yaptığı işle eşleştir.
Okumayı istediğin sırayla sürdürebilirsin. Ders, bütün etkinlikleri cevapladığında tamamlanır.
- Etkinlik 1· Bir kuralın üç parçası
- Etkinlik 2· Bir kuralın üç parçası
- Etkinlik 3· Başlık, akış yönü ve doğru tampon
- Etkinlik 4· Kuralı sınamak: söz dizimi, pcap ve fast.log
- Etkinlik 5· Kuralı sınamak: söz dizimi, pcap ve fast.log
- Etkinlik 6· Boyuta bakmak: dsize ve bsize
- Etkinlik 7· İki adımlı tespit ve hazır kural setleri