Azure Sentinel Adım Adım Bulut SIEM Kullanımı – Bölüm5 – Windows Server Loglarının Kusto İle İncelenmesi
Makalemin bu bölümünde bir önceki bölümde topladığımız loglar ile nasıl Kusto Query Language (KQL) ile takip edebileceğimizi anlatacağım.
Makalemin bundan önceki bölümlerine aşağıdaki linkler üzerinden ulaşabilirsiniz.
https://www.hakanuzuner.com/azure-sentinel-adim-adim-bulut-siem-kullanimi-bolum1/
https://www.hakanuzuner.com/azure-sentinel-adim-adim-bulut-siem-kullanimi-bolum2-office-365-audit/
Hatırlarsanız en son aşağıdaki gibi çok ciddi sayıda log toplamış durumdaydık.
Şimdi hızlı bir şekilde bir SIEM aracının ara yüz dışında aynı diğer SIEM ürünlerinde olduğu gibi nasıl sorgu çekiyoruz onu görelim.
Soru ekranında kullandığımız dil KUSTO’ dur.
Hızlıca basit örnekler ile başlayalım.
Örneğin benim güvenlik olay günlüklerini topladığım windows sunucuda çok sayıda başarısız olay var, örneğin kaç adet başarısız giriş olayı var? En çok hangi kullanıcı hesabı için bu yanlış şifre denemesi yapılmış? Bu hesaplar var olan hesaplar mı yoksa deneme yapılan hesaplar mı? Hangi RDP oturumları başarıyla gerçekleşti? Bu ve benzeri soruların cevapları için kusto dilini kullanacağız.
Son 24 saat içerisinde toplam kaç log kayıt edilmiş?
SecurityEvent | where TimeGenerated >= ago(1d) | count
67.663
Peki bu logları listelemek istersek sadece Count bölümünü kaldırabiliriz
Gördüğünüz gibi birileri sürekli kullanıcı denemesi yapıyor.
Öncelikle tabiki güvenlik olay günlüklerinin açıklamalarını biliyor olmalıyız.
Event ID 4625 – An account failed to log on
Bakalım hatalı giriş denemeleri için son 24 saatlik logları aşağıdaki komut seti ile listeliyoruz
SecurityEvent | where TimeGenerated >= ago(1d) | where EventID == 4625
Peki bu raporu daha anlamlı bir hale getirmek için tüm bu denemeleri ve makine raporunu aşağıdaki gibi görebiliriz
SecurityEvent | where TimeGenerated >= ago(1d) | where EventID == 4625 | summarize FailedLogins=count() by Account,Computer
Hayır her şeyi anladım de opet nedir arkadaş ? Bu canlı bir sistem ve bildiğiniz çatır çatır atak alıyor.
Peki bunu en çok failed login denemesine göre sıralamak istersek
SecurityEvent | where TimeGenerated >= ago(1d) | where EventID == 4625 | summarize FailedLogins=count() by Account,Computer | sort by FailedLogins desc
Evet Türklerin de atak yaptığını ali, hasan, depo gibi kullanıcı isimlerinden anlıyoruz.
Zaman, ip ve makine ismine göre sorgu çekmek istersek?
//Count number of failed authentication
let GetFailedAuth = (startTime: datetime, endTime:datetime, v_Vm:string, v_SourceIp:string){
SecurityEvent
| where TimeGenerated between (startTime .. endTime)
| where EventID == “4625”
| where AccountType == “User”
| extend _Account = trim(@'[^\w]+’, Account)
| where Computer contains v_Vm
| where v_SourceIp contains IpAddress
| count
};
GetFailedAuth(datetime(‘2020-06-21T10:00:00’), datetime(‘2020-06-21T17:00:00’), toupper(‘rds.cp.local’), (‘91.241.19.240’))
Gördüğünüz gibi sadece 7 saat içerisinde bir ip adresinden gelen şifre denemesi sayısı 2795. Gerçekten çılgınlar gibi atak yapıyorlar.
Aynı kod kümesi ile artık bir önceki sorgularda olduğu gibi kullanıcı bazlı rapor çekmek çok kolay.
//Get top accounts that were failed to sign in
let GetFailedAuth = (startTime: datetime, endTime:datetime, v_Vm:string, v_SourceIp:string){
SecurityEvent
| where TimeGenerated between (startTime .. endTime)
| where EventID == “4625”
| where AccountType == “User”
| extend _Account = trim(@'[^\w]+’, Account)
| where Computer contains v_Vm
| where v_SourceIp contains IpAddress
| summarize count() by _Account
| sort by count_ desc
};
GetFailedAuth(datetime(‘2020-06-01T10:00:00’), datetime(‘2020-06-21T17:00:00’), toupper(‘rds.cp.local’), (‘91.241.19.240’))
Aslında burada yapmak istediğim aynı Onprem bir siem aracında olduğu gibi aslında istediğiniz gibi logların içerisinde sonuç çıkarabiliyoruz.
Burada daha önemli bir konu var, yukarıda gördüğünüz gibi zaten hep olmayan kullanıcıları denemişler, evet doğru görüyorsunuz Administrator hesabı da bizde yok ? rename yani, bunu nasıl anlıyoruz, aşağıdaki sorgu ile gerçekten var olan bir hesap üzerinden şifre denemesi olmuş mu?
//Get account that may exist in the indicated host
let GetFailedAuth = (startTime: datetime, endTime:datetime, v_Vm:string, v_SourceIp:string){
SecurityEvent
| where TimeGenerated between (startTime .. endTime)
| where EventID == “4625”
| where AccountType == “User”
| extend _Account = trim(@'[^\w]+’, Account)
| where Computer contains v_Vm
| where v_SourceIp contains IpAddress
| where SubStatus =~ “0xc000006A”
| project TimeGenerated,
Computer,
_Account,
LogonType,
LogonProcessName,
SubStatus,
Activity
};
GetFailedAuth(datetime(‘2020-06-01T10:00:00’), datetime(‘2020-06-21T17:00:00’), toupper(‘rds.cp.local’), (‘91.241.19.240’))
Sıfır, peki bunu nereden anlıyoruz?
SIEM veya log toplama sistemleriniz için “0xc000006A” kodunu kullanırsanız bu kod “user name is correct but the password is wrong” kullanıcı adı doğru fakat şifresi yanlış anlamına gelir. Bu sorguyu kayıt edip düzenli rapor veya alert tanımı yaptırabilirsiniz, daha fazla bilgi için
https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4625
Bu güzel bir şey yani bizim kullanıcı isimlerimizi en azından bu tarih aralığı ve ip adresi için deneyen olmamış.
Peki bir sonraki merak konusu başarılı RDP oturumları.
Burada da logon type ve Event ID bilgisi önemli.
//Get succeeded logon with RDP
let GetFailedAuth = (startTime: datetime, endTime:datetime, v_Vm:string){
SecurityEvent
| where TimeGenerated between (startTime .. endTime)
| where EventID == “4624”
| extend _Account = trim(@'[^\w]+’, Account)
| where Computer contains v_Vm
| where LogonType == 3 or
LogonType == 10
| project TimeGenerated,
Computer,
LogonType,
LogonProcessName,
SubStatus,
Activity
};
GetFailedAuth(datetime(‘2020-06-01T10:00:00’), datetime(‘2020-06-21T17:00:00’), toupper(‘rds.cp.local’))
Bu ve benzeri örnekler için Sentinel ile beraber sunulan Hunting bölümünü incelemenizi tavsiye ederim.
Hunting bölümüne geldikten sonra burada Microsoft tarafından hazır sunulan sorguları görebilirsiniz. Örneğin arama bölümüne failed yazdığınızda karşınıza aşağıdaki gibi sonuçlar çıkacaktır.
İstediğinizin üzerine tıklayın ve sağ bölümde sorguyu çalıştırıp sonuçları görün
Bu bölümde aslında kusto dilini öğrenmek için çok yararlıdır. Ama tavsiyem İngilizceniz var ise aşağıdaki eğitimi almanız.
https://www.pluralsight.com/courses/kusto-query-language-kql-from-scratch
Kaynak
https://github.com/microsoft/Microsoft-threat-protection-Hunting-Queries