Microsoft Azure

Azure Sentinel Adım Adım Bulut SIEM Kullanımı – Bölüm5 – Windows Server Loglarının Kusto İle İncelenmesi

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/

https://www.hakanuzuner.com/azure-sentinel-adim-adim-bulut-siem-kullanimi-bolum3-azure-activity-ve-azure-ad-audit/

https://www.hakanuzuner.com/azure-sentinel-adim-adim-bulut-siem-kullanimi-bolum4-windows-server-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

Hakan Uzuner

2002 yılından beri aktif olarak bilişim sektöründe çalışmaktayım. Bu süreç içerisinde özellikle profesyonel olarak Microsoft teknolojileri üzerinde çalıştım. Profesyonel kariyerim içerisinde eğitmenlik, danışmanlık ve yöneticilik yaptım. Özellikle danışmanlık ve eğitmenlik tecrübelerimden kaynaklı pek çok farklı firmanın alt yapısının kurulum, yönetimi ve bakımında bulundum. Aynı zamanda ÇözümPark Bilişim Portalı nın Kurucusu olarak portal üzerinde aktif olarak rol almaktayım. Profesyonel kariyerime ITSTACK Bilgi Sistemlerinde Profesyonel Hizmetler Direktörü olarak devam etmekteyim.

İlgili Makaleler

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Başa dön tuşu