Ana içeriğe geç
Kesit SQL
İleri · SQL Server Operasyon

Log tablosunda anomali avı: mesai dışı erişim, ardışık ID taraması, parola deneme

Erişim günlüğünden üç temel sinyali SQL ile çıkarmak, yanlış alarmı ayırmak, sinyali kanıta çevirmek.

Uygulamada aç, 9 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Sinyal kanıt değildir

Bir SQL sorgusu şüphe üretir, hüküm vermez. Her sinyal için üç soru sor: Normal hâli ne? Masum açıklaması var mı? Başka hangi kayıt bunu doğrular?

Veri kurgudurops_ tabloları hayali bir portal için tohumlu üreteçle kuruldu. Gerçek bir sistemden alınmadı; süre ve okuma değerleri ölçüm değildir. Motor SQLite olduğu için günlükteki SQL Server sorguları çalıştırılmaz, metin olarak incelenir. Tabloları sorgularsın, sistem yönetimi komutlarını yalnız okursun.

Sinyal 1: Mesai dışı erişim

Burada mesai hafta içi 08:00-18:00. Düz sorgu servis hesaplarıyla dolar: gece ETL'i zaten mesai dışında çalışır. Bu yüzden hesap listesiyle birleştir: off_hours_ok = 0 olanlar kim?

SELECT a.login_name, a.event_at, a.client_ip
FROM ops_access_log a
JOIN ops_logins l ON l.login_name = a.login_name
WHERE a.event_type = 'login_ok' AND l.off_hours_ok = 0
  AND (CAST(strftime('%H', a.event_at) AS INTEGER) NOT BETWEEN 8 AND 17 OR CAST(strftime('%w', a.event_at) AS INTEGER) IN (0, 6))
ORDER BY a.event_at;

Çıkan üç kaydı karşılaştır: biri akşam 18:22, biri cumartesi, biri salı sabaha karşı. Hepsi sorulur ama aciliyetleri aynı değildir. Aradaki fark adres sütunundadır.

Sinyal 2: Parola deneme

Başarısız girişi adrese göre say. İki desen vardır:

DesenGörünüşüHangi gruplama yakalar
Kaba kuvvet (brute force)Tek hesaba çok denemeHesap başına
Parola püskürtme (password spray)Çok hesaba az deneme, hesap kilidine takılmamak içinAdres başına farklı hesap sayısı
SELECT client_ip, COUNT(*) AS deneme, COUNT(DISTINCT login_name) AS hesap,
       MIN(event_at) AS ilk, MAX(event_at) AS son
FROM ops_access_log
WHERE event_type = 'login_fail'
GROUP BY client_ip
ORDER BY deneme DESC;

En çok denemeli adres saldırgan değil: svc_eski kapalı bir hesap, eski bir iş 30 dakikada bir bağlanmaya çalışıyor. İçeriden, tek hesaptan, düzenli aralıkla. Ama bu da bir bulgudur: işi kapatan yok ve gürültüsü gerçek saldırıyı gizler. En kritik soru sayı değil, başarısızlıklardan sonra başarı geldi mi?

Sinyal 3: Ardışık kayıt okuma

Gerçek kullanıcı müşterileri rastgele okur. Numarayı birer artırarak okuyan biri büyük olasılıkla listeyi çekiyordur (enumeration). LAG ile önceki kayıttan farkı al:

WITH o AS (
  SELECT login_name, client_ip, event_at, record_id,
         record_id - LAG(record_id) OVER (PARTITION BY login_name, client_ip ORDER BY event_at, event_id) AS fark
  FROM ops_access_log
  WHERE event_type = 'read'
)
SELECT login_name, client_ip, COUNT(*) AS ardisik, MIN(event_at) AS ilk, MAX(event_at) AS son
FROM o
WHERE fark = 1
GROUP BY login_name, client_ip
HAVING COUNT(*) >= 20
ORDER BY ardisik DESC;

İki sonuç çıkar. Biri haftalık ETL: planlı, içeriden, servis hesabı. Diğeri bir analist hesabı, dış adresten. Aynı sorgu, farklı anlam. Bağlam olmadan alarm kurarsan her pazar yanlış alarm gelir.

Sinyalleri zincirle

Tek başına zayıf sinyaller, aynı adres ve hesapta sırayla geliyorsa güçlü bir hikâye olur: çok deneme, sonra başarı, sonra toplu okuma. Bu sırayı tek bir zaman çizelgesine dök.

Kaynak nereden gelir?

Bu tablolar kurgu. Gerçek SQL Server'da karşılıkları (burada çalışmaz):

-- Sunucu denetimi: başarısız girişler (yalnız okumak için)
CREATE SERVER AUDIT denetim_giris TO FILE (FILEPATH = 'E:\Denetim\');
CREATE SERVER AUDIT SPECIFICATION giris_ozeti
    FOR SERVER AUDIT denetim_giris ADD (FAILED_LOGIN_GROUP) WITH (STATE = ON);
ALTER SERVER AUDIT denetim_giris WITH (STATE = ON);
Günlüğü de koruSaldırgan izini siler. Denetim kaydını ayrı konuma yaz, yazma yetkisini sınırla, saklama süresini belirle. Denetim hedefini ağ paylaşımına yazarken gecikmeye dikkat et: Belge, bunun sunucuyu yavaşlatabileceğini söyler.
Alıştırmalara geç (9)