Microsoft Sentinel, farklı kaynaklardan gelen güvenlik telemetrisini Kusto Query Language (KQL) ile aramayı ve sorguları sürekli çalışan tespit kurallarına dönüştürmeyi sağlar. İyi bir kural yalnız “şüpheli” bir olayı bulmaz; doğru zaman penceresini seçer, normal davranışı hesaba katar, kullanıcı-cihaz-IP varlıklarını eşler ve analistin karar verebileceği bağlamı üretir.

Bu rehber, savunma ve yetkili izleme amacıyla hazırlanmıştır. Hedef; ham Windows ve ağ günlüklerinden başlayıp okunabilir KQL sorguları, ASIM normalizasyonu, UEBA bağlamı ve yönetilebilir analytics rule yaşam döngüsü kurmaktır.

1. KQL tespit mühendisliği yaklaşımı

Bir avcılık sorgusu ile üretim tespit kuralı aynı kalite eşiğine sahip değildir. Avcılık sorgusu analistin etkileşimli incelemesine dayanabilir; üretim kuralı ise her çalışmada öngörülebilir sonuç, düşük maliyet, sınırlı gürültü ve kararlı varlık eşleme üretmelidir.

KatmanAmaçBaşarı ölçütü
VeriKaynakların eksiksiz ve zamanında gelmesiBeklenen tablo ve alanlar dolu
NormalizasyonFarklı üreticileri ortak şemaya taşımakASIM alanları tutarlı
AnalitikŞüpheli davranışı ölçmekAçıklanabilir KQL mantığı
BağlamKullanıcı, cihaz ve IP riskini eklemekUEBA ve varlık eşleme
OperasyonAlarmı yönetilebilir olaya çevirmekDüşük gürültü, net triage
Yaşam döngüsüKuralı sürümlemek ve iyileştirmekTest, geri alma, sahiplik


2. Önce veri sağlığını doğrulayın

KQL yazmadan önce bağlantıların çalıştığı varsayılmamalı. SecurityEvent, SigninLogs, DeviceProcessEvents, CommonSecurityLog, Syslog veya özel tablolar için son veri zamanı ve hacim trendi ölçülmelidir. Sessiz bir tablo, “tehdit yok” değil, bağlantı kesintisi anlamına gelebilir.

CODE TERMINAL
union withsource=SourceTable isfuzzy=true
    SecurityEvent,
    SigninLogs,
    CommonSecurityLog,
    Syslog
| summarize LastEvent=max(TimeGenerated), Events=count() by SourceTable
| extend MinutesSinceLastEvent=datetime_diff('minute', now(), LastEvent)
| order by MinutesSinceLastEvent desc


Bu sorgu başlangıç kontrolüdür. Kaynakların doğal hacimleri farklıdır; her tablo için beklenen gecikme eşiği ayrı belirlenmelidir. Örneğin kimlik doğrulama verisi için 15 dakika kritik olabilirken, günlük aktarılan envanter tablosu için aynı eşik anlamsızdır.

3. Zaman filtresini en başa taşıyın

KQL performansında en etkili alışkanlıklardan biri taranan zamanı ve tabloyu erken daraltmaktır. Gereksiz sütunları taşımamak için project, pahalı hesaplardan önce basit where koşulları ve tekrar kullanılan küçük veri kümeleri için uygun let blokları kullanılabilir.

CODE TERMINAL
let Lookback = 1h;
SigninLogs
| where TimeGenerated >= ago(Lookback)
| where ResultType != 0
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName,
          ResultType, ResultDescription, LocationDetails
| summarize Failures=count(), Apps=dcount(AppDisplayName)
    by UserPrincipalName, IPAddress, bin(TimeGenerated, 10m)
| where Failures >= 12 and Apps >= 3


Sabit eşikler kopyalanıp bırakılmamalı. Kurumun kullanıcı sayısı, kimlik sağlayıcı davranışı, VPN çıkış IP'leri ve servis hesapları için temel çizgi çıkarılmalı; eşik bu dağılıma göre ayarlanmalıdır.

4. ASIM ile üretici bağımlılığını azaltma

Advanced Security Information Model (ASIM), farklı günlük kaynaklarını ortak alan adları ve anlamlarla sorgulamaya yardım eder. Örneğin ağ oturumu, DNS, kimlik doğrulama ve süreç olayları farklı üreticilerden gelse bile aynı normalleştirilmiş şema üzerinden avlanabilir.

ASIM kullanmanın avantajı yalnız daha kısa sorgu değildir. Bir güvenlik duvarı değiştiğinde bütün kuralları yeniden yazmak yerine parser katmanı güncellenebilir. Bunun karşılığında parser kapsamı, alan eşlemesi ve performans düzenli test edilmelidir.

CODE TERMINAL
_Im_Authentication(starttime=ago(1h))
| where EventResult == "Failure"
| summarize Failures=count(), Targets=dcount(TargetUsername)
    by SrcIpAddr, bin(TimeGenerated, 10m)
| where Failures > 20 and Targets > 5


Çalışma alanındaki ASIM parser adı ve parametreleri sürüme göre doğrulanmalıdır. Üretime almadan önce normalize edilen SrcIpAddr, TargetUsername, EventResult ve EventProduct alanlarının kaynak kayıtla aynı anlamı taşıdığı örnek olaylarla test edilmelidir.

5. UEBA bağlamını doğru kullanma

User and Entity Behavior Analytics, kullanıcı ve cihaz davranışındaki sapmaları ve risk bağlamını incelemeye yardımcı olur. UEBA skoru tek başına “kötü niyet” kanıtı değildir; tespitin önceliğini ve araştırma sırasını iyileştiren bir sinyaldir.

Bir kural; olağandışı ülke, yeni cihaz, yüksek riskli kullanıcı ve kısa aralıkta ayrı kaynaklardan erişim gibi bağlamları birleştirebilir. Ancak kullanıcıya ait hassas veya seyrek aktivite, vardiya değişimi ve kurumsal VPN gibi meşru açıklamalar için istisna modeli kurulmalıdır.

6. join kullanımında patlamayı önleyin

İki büyük tabloyu ham biçimde join etmek hem maliyeti hem yanlış pozitifleri artırabilir. Önce her tarafı zaman, alan ve olay türüyle daraltın; mümkünse bir tarafı summarize ile küçültün. Join anahtarının gerçekten tekil veya beklenen kardinalitede olup olmadığını ölçün.

CODE TERMINAL
let FailedUsers = SigninLogs
| where TimeGenerated > ago(30m) and ResultType != 0
| summarize Failures=count(), FailureIPs=make_set(IPAddress, 20)
    by UserPrincipalName
| where Failures >= 15;
AuditLogs
| where TimeGenerated > ago(30m)
| where OperationName has_any ("Add member", "Update user")
| extend UserPrincipalName=tostring(TargetResources[0].userPrincipalName)
| join kind=innerunique FailedUsers on UserPrincipalName
| project TimeGenerated, OperationName, UserPrincipalName, Failures, FailureIPs


Bu örnek, başarısız oturum açma yoğunluğuyla kısa süre sonra görülen hesap değişikliğini ilişkilendirir. Alan yolları tenant ve olay türüne göre değişebilir; TargetResources dizisi örnek kayıtlar üzerinden doğrulanmalıdır.

7. Eşik yerine davranış oranı

Sadece “10 hata oldu” gibi eşikler büyük ve küçük hesaplar için aynı anlamı taşımaz. Başarısız/başarılı oranı, önceki döneme göre sapma veya aynı IP'nin hedeflediği benzersiz hesap sayısı daha dayanıklı sinyaller üretebilir.

CODE TERMINAL
SigninLogs
| where TimeGenerated > ago(24h)
| summarize Total=count(), Failures=countif(ResultType != 0),
            Successes=countif(ResultType == 0), Users=dcount(UserPrincipalName)
    by IPAddress, bin(TimeGenerated, 15m)
| extend FailureRate=round(100.0 * Failures / Total, 1)
| where Total >= 20 and FailureRate >= 80 and Users >= 5


NAT, proxy ve kimlik sağlayıcı çıkışları çok sayıda kullanıcıyı tek IP'de birleştirebilir. Kurumsal IP listeleri ayrı watchlist ile yönetilmeli; sorgu içine kalıcı, belgesiz IP dizileri gömülmemelidir.

8. Watchlist ve referans verisi

Watchlist; kritik hesaplar, onaylı tarayıcılar, güvenilir çıkış IP'leri veya geçici istisnalar için kullanılabilir. Her listenin sahibi, veri kaynağı, yenileme sıklığı ve son kullanma alanı bulunmalıdır. Süresi dolmuş istisna sessizce kalıcı güvenlik açığına dönüşmemeli.

CODE TERMINAL
let TrustedIPs = _GetWatchlist('trusted-egress')
| project IPAddress=tostring(SearchKey);
SigninLogs
| where TimeGenerated > ago(1h) and ResultType != 0
| join kind=leftanti TrustedIPs on IPAddress
| summarize Failures=count(), Users=dcount(UserPrincipalName) by IPAddress
| where Failures > 30 and Users > 5


9. Analytics rule tasarımı

Zamanlanmış bir kuralda query frequency ve lookup period birlikte düşünülmelidir. Beş dakikada bir çalışan ve son bir saati tarayan kural, aynı olayı birçok kez üretebilir. Olay gruplama, suppression veya sorgu içi deduplication planı kurulmalıdır.


  • Ad: Davranışı, veri kaynağını ve kapsamı açıkça belirtin.
  • Taktik/teknik: MITRE ATT&CK eşlemesini gerçek davranışa göre yapın.
  • Varlık eşleme: Account, Host ve IP alanlarını doğru türlere bağlayın.
  • Özel ayrıntılar: Analistin ilk bakışta kullanacağı sayaç ve zamanları ekleyin.
  • Gruplama: Aynı kampanyaya ait alarmları tek olayda toplama mantığını test edin.
  • Yanıt: Otomasyon kuralı veya playbook eylemini riskle orantılı seçin.



10. Varlık eşleme neden kritik?

Bir KQL sonucu alarm üretebilir; ancak UserPrincipalName, DeviceName veya IPAddress doğru eşlenmediyse olay grafiği ve araştırma deneyimi zayıflar. Hesap varlığında Name ve UPNSuffix ayrımı, cihazda HostName ve DnsDomain ayrımı, IP'de geçerli adres biçimi kontrol edilmelidir.

Birden fazla hesabı virgülle birleştirip tek alan olarak eşlemekten kaçının. Her sonuç satırı analistin inceleyebileceği anlamlı bir olay birimini temsil etmeli. Çok değerli alanlar için genişletme veya olay ayrıntıları kullanılabilir.

11. Gürültü azaltma ve istisna yönetimi

Yanlış pozitiflerin tamamını büyük bir NOT listesiyle susturmak kuralı görünmez hale getirir. Önce sinyalin hangi davranışı ölçtüğünü netleştirin, ardından meşru aktiviteyi neden-sonuç ilişkisiyle modelleyin. Servis hesapları için ayrı eşik, yönetim ağları için ayrı referans ve bakım penceresi için süreli kural kullanılabilir.

Gürültü kaynağıZayıf çözümDaha iyi yaklaşım
Kurumsal proxyIP'yi kalıcı dışlaProxy arkasındaki kullanıcı ve uygulamayı zenginleştir
Servis hesabıHesabı tamamen dışlaBeklenen kaynak, hedef ve zaman aralığını tanımla
Zafiyet tarayıcıBütün taramayı susturOnaylı tarayıcı kimliği ve planlı pencereyi eşleştir
SeyahatÜlkeyi güvenilir sayCihaz, MFA, ASN ve UEBA bağlamıyla değerlendir
BakımKuralı kapatSüreli ve kayıtlı otomasyon istisnası kullan


12. Test veri seti ve geriye dönük doğrulama

Kural canlıya alınmadan önce en az üç veri kümesiyle sınanmalı: bilinen kötü veya simüle edilmiş pozitif, bilinen normal trafik ve uç durumlar. Son 7-30 gün üzerinde geriye dönük çalıştırma; günlük alarm sayısını, benzersiz varlıkları ve yoğun saatleri ortaya çıkarır.

Test sorgusuna geçici summarize count() by bin(TimeGenerated, 1d) eklemek hacim profilini görmeyi kolaylaştırır. Üretim kuralındaki zaman parametreleriyle test sorgusunun aynı olduğundan emin olun.

13. Maliyet ve performans kontrolü

Sorgu performansı yalnız kullanıcı deneyimi değil, operasyon maliyetidir. Geniş union, regex, parse_json, mv-expand ve büyük join işlemleri zorunlu değilse azaltılmalı. Önce filtreleyip sonra ayrıştırmak, ham JSON alanından her çalışmada onlarca değer çıkarmaktan daha verimlidir.


  • Taranan zaman ve tabloyu en başta daraltın.
  • Yalnız gerekli sütunları project edin.
  • contains yerine anlam uygunsa has veya has_any kullanın.
  • Büyük join öncesi iki tarafın satır sayısını ölçün.
  • Tekrarlanan pahalı dönüşümleri parser veya ingestion-time transformation katmanına taşıyın.
  • Kural çalışma süresini ve sonuç hacmini sürüm değişimlerinde karşılaştırın.



14. Kuralı kod olarak yönetme

Analytics rule; sorgu, zamanlama, eşik, varlık eşleme, ATT&CK tekniği ve olay gruplama ayarlarıyla birlikte sürümlenmelidir. Değişiklik için açıklama, test kanıtı, sahip ve geri alma planı bulunmalı. Üretim portalındaki el ile düzenlemeler kaynağa geri işlenmezse yapılandırma sapması oluşur.

Geliştirme, test ve üretim çalışma alanları arasında tablo adları, watchlist isimleri ve connector kapsamı değişebilir. Ortama özgü değerler parametreleştirilmeli; aynı sorgunun her ortamda aynı anlamı ürettiği doğrulanmalıdır.

15. Operasyon kontrol listesi


  1. Kuralın kullandığı tablolar için veri sağlığı alarmı var mı?
  2. Zaman penceresi ve çalışma sıklığı yinelenen alarm üretmeyecek biçimde ayarlı mı?
  3. KQL sorgusu örnek pozitif ve normal veriyle test edildi mi?
  4. Hesap, cihaz ve IP varlıkları doğru alanlara eşlendi mi?
  5. UEBA skoru tek başına karar değil, bağlam olarak mı kullanılıyor?
  6. Watchlist ve istisnaların sahibi ile son kullanma tarihi var mı?
  7. Günlük alarm hacmi SOC kapasitesiyle uyumlu mu?
  8. Kural sürüm kontrolünde ve geri alma planı hazır mı?
  9. Analiste beklenen triage adımları ve veri kaynakları verildi mi?



Sonuç

Microsoft Sentinel'de iyi tespit; uzun bir KQL sorgusundan değil, sağlıklı veri, açık davranış hipotezi, doğru normalizasyon, bağlam ve sürdürülebilir operasyonun birleşiminden doğar. ASIM üretici bağımlılığını azaltır, UEBA önceliklendirmeyi güçlendirir, analytics rule tasarımı ise sorguyu gerçek bir SOC iş akışına dönüştürür. Her kural ölçülmeli, sürümlenmeli ve tehdit ile ortam değiştikçe yeniden ayarlanmalıdır.

Kaynaklar

TR Siber Ekibi Yazar · X
Kaynak bağlantısı ← Ana sayfaya dön