SSH honeypotları ve üretim jump hostlerini yıllardır çalıştırıyorum ve /var/log/auth.log'daki gürültü asla durmuyor. Brute-force tarayıcıları, kimlik bilgisi doldurma botları ve zaman zaman bir şansla doğru tahmin yapanlar sürekli geliyor. fail2ban gibi geleneksel kural tabanlı araçlar yardımcı oluyor, ancak bunlar reaktif ve eşik sınırlarının altında kalıp duran düşük-hızlı saldırıları kaçırıyor. Son zamanlarda, sadece bilinen kötü kalıplar için değil, normal yönetici erişimimin temeline uymayan anormal davranışları da tespit etmek için log akışlarını analiz etmek üzere büyük dil modelleri (LLM'ler) ile deneyler yapmaya başladım.
LLM'ler Log Anomali Tespiti İçin Neden Kullanılır?
Çoğu log analizörü imzalar veya basit eşikler üzerinden çalışır: 10 dakikada bir IP'den 5'ten fazla başarısız giriş denemesi varsa, onu engelle. Bu, gürültülü botnetler için işe yarar, ancak saldırganlar uyarlanmıştır. Yavaşlar, proxy ağları arasında döner veya sızıntılardan elde edilen, kullanıcı veritabanınızda gerçekten mevcut olan kimlik bilgilerini kullanır. Bir LLM, sabit bir sayıya takılmaz; ortamınız için "normal" nasıl göründüğünü öğrenir—gün içinde saat, tipik kullanıcılar, standart kaynak ağları, hatta sudo günlüklerinde tuş vuruş ritmi—and sapmaları işaretler.
Kurulumumda, sshd'den gelen journalctl çıktısını her 30 saniyede bir küçük yerel bir LLM'ye (Ollama üzerinden Llama 3 8B kullanıyorum) besliyorum. Prompt şu şekilde: "Son 5 dakikadaki aşağıdaki SSH oturum açma olaylarına bakın, tipik yönetici erişim desenleriyle karşılaştırıldığında anything unusual görüyor musunuz? Şüpheli IP'ler, kullanıcılar veya zaman anomali'lerini listeleyin." Model, risk puanları ve açıklamalar içeren kısa bir JSON blob'u döndürür.
Pipeline Oluşturulması
İlk olarak, rsyslog'u kimlik doğrulama günlüklerini adlandırılmış bir pipe'a kopyalayacak şekilde yapılandırdım, böylece yerellik kaybetmeden akışını sağlayabilirim:
# /etc/rsyslog.d/ssh-llm.conf
if $programname == 'sshd' then ^/var/run/ssh-llm.pipe
& stop
Ardından, basit bir Python betiği bu pipe'ı okur, son 5 dakikalık olayları pencere alır ve yerel Ollama API'sini çağırır:
import json, subprocess, time, collections
from datetime import datetime, timedelta
def window_events(pipe_path, minutes=5):
events = []
cutoff = datetime.now() - timedelta(minutes=minutes)
with open(pipe_path, 'r') as p:
for line in p:
if 'Failed password' in line or 'Accepted password' in line:
# parse timestamp, ip, user etc. (simplified)
events.append(line.strip())
return [e for e in events if datetime.now() - parse_time(e) < timedelta(minutes=minutes)]
while True:
try:
events = window_events('/var/run/ssh-llm.pipe')
if not events:
time.sleep(10)
continue
prompt = f"""Analyze these SSH log entries for anomalies:
{chr(10).join(events[-20:])}
Return JSON: {{"anomalous": true/false, "reason": "short explanation", "risk_score": 0-100}}
"""
result = subprocess.run(['ollama', 'run', 'llama3'], input=prompt.encode(), capture_output=True)
analysis = json.loads(result.stdout.decode().strip())
if analysis.get('risk_score', 0) > 70:
trigger_alert(analysis, events)
except Exception as e:
log_error(e)
time.sleep(30)
Ayarlama ve Yanlış Pozitifler
Birinci hafta gürültülüydü. LLM, yeni bir kahve dükkanı Wi-Fi'sinden kendi sabah girişimi ASN'yi tanımadığı için anormal olarak işaretledi. Bilinen mobil ASN'lerin beyaz listesini ekledim ve modelin sadece ani artışlar yerine trendleri görmesi için bağlam penceresine bir önceki saatki logu dahil ettim. Ayrıca, promptu "genel olarak anormal" yerine "bu spesifik sunucu için anormal" şeklinde ayarladım; bu da internet taramalarının arka plan radyasyonunu görmezden gelmemize yardımcı oldu.
Faydalı bir ipucu: LLM'nin ham çıktısını ayrı bir dosyaya logluyorum ve haftalık olarak yanlış pozitifleri inceleyerek promptu iyileştiriyorum. Zamanla sinyal-gürültü oranı önemli ölçüde iyileştirdi. Şimdi günde bir kez uygulanabilir bir uyarı alıyorum; genellikle, fail2ban'ın 10 dakikada 3 denemeden aşağı kalması nedeniyle kaçırdığı bir konak IP'sinden gelen yavaş brute-force saldırısıdır.
Uyarı ve Yanıt
Risk skoru 70'yi aşınca, betik log parçacığını, LLM'nin gerekçesini ve iptables -I INPUT -s <ip> -j DROP komutunu tek tıkla çalıştıracak bir düğmeyi Mattermost kanalım üzerinden gönderir. Yüksek güvenilirlikli durumlar (skor >90) için IP'yi 4 saat sonra süresi dolacak şekilde geçici bir engelleme listesine otomatik olarak eklerim (manuel olarak uzatmadığım sürece). Bu, yanıtı orantılı tutar—kendi yazım hatalı sabahlarımı kilitlemiyorum, ama kimlik bilgisi doldurma saldırılarını şansına bırakmadan önce durduruyorum.
Sınırlamalar ve Sonraki Adımlar
Bu bir mükemmel çözüm değil. Yüksek hacimli log akışı yaparken LLM'ler yavaş olabilir ve zaman zaman hallüsinasyon yaparak yanlış nedenler üretebilir. Gecikme ve gizlilik için modeli yerel olarak tutuyorum; kimlik doğrulama loglarını üçüncü parti bir API'ye göndermek bir seçenek değil. Şu an için LLM'yi, mevcut uyarı ardışık sistemimi değiştirmek yerine onu besleyen gelişmiş bir anomali puanlayıcı olarak görüyorum.
Eğer internetten erişilebilir SSH çalıştırıyorsanız ve saldırganları sadece engellemek yerine önceden önlemek istiyorsanız, bunu deneyin. Küçük başlayın: birkaç saatlik logu yerel bir modele aktarın ve neyin garip olduğunu görün. Ortamınızda "normal" gerçekte nasıl görünür, şaşırabilirsiniz.
AI CLI araçları hakkında önceki yazımda da belirttiğim gibi, hedefim sysadmin kararını değiştirmek değil, grep ve awk ile kolayca yapılamayacak ölçekte desen tanıma ile onu desteklemek.
Hızlı Kontrol Listesi
- Rsyslog üzerinden kimlik doğrulama günlüklerini adlandırılmış bir boruya akışa al
- Bağlam için pencere olayları (5-15 dakika)
- Anomali skoru ve gerekçesi için LLM'e sor
- Eylem yapılabilir eşikleri ayarla (örnek: >70 uyarı için, >90 otomatik blok için)
- Haftalık olarak yanlış pozitifleri inceleyerek promptu ve beyaz listeyi ayarla
- Yanıtın orantılı ve tersine çevrilebilir olduğundan emin ol