Fail2ban'ı yıllardır açık SSH uç noktalarında kullanıyorum. Temel brute force saldırıları için iyi çalışıyor — bir IP’den çok fazla başarısız deneme olduğunda o IP tutuklanıyor. Ancak saldırganlar uyarlamış. Artık denemeleri düzine IP’ye dağıtıyor, hızını yavaşlatıyor veya sıktırılmış konut proxy’leri üzerinden credential stuffing yapıyor. Fail2ban’ın regex tabanlı filtreleri bu düşük ve yavaş desenleri yakalamıyor çünkü sıkı zaman pencerelerindeki tekrarlamayı arıyor. İşte burada log bağlamını analiz edip kural tabanlı sistemlerin gözden kaçırdığı anormal davranışları işaretlemek için LLM’lerle denemeler yapmaya başladım.
Amacım Fail2ban’ı değiştirmek değil, onu desteklemek. Yerel bir LLM (Ollama üzerinden Mistral 7B kullanıyorum) ile birleştirilmiş auth loglarını besliyorum ve giriş denemelerini anomaly açısından puanlıyorum: zaman kümelemesi, kullanıcı adı kalıpları, coğrafi imkansızlık veya oturum anomalları. Puan eşiği aşarsa LLM aday bir iptables kuralı üretir. Daha sonra bu kuralı doğruluyorum ve cron tetiklenmiş bir betik üzerinden uyguluyorum — inceleme olmadan otomatik uygulama yapmuyorum.
Ortamımda bu iş akışı şöyle çalışıyor.
Log Verilerini Toplama ve Hazırlama
Fail2ban zaten /var/log/auth.log dosyasını izliyor. Ben bunu genişleterek her beş dakikada bir ilgili satırları bir hazırlık dosyasına kopyalıyorum via cron. SSH daemon loglarına odaklanıyorum: başarısız şifreler, geçersiz kullanıcılar ve kimlik doğrulamasından önce kesilen bağlantılar.
Son 20 dakikalık ilgili girişleri şu komutla çıkarıyorum:
journalctl -u sshd --since "20 minutes ago" | \
grep -E "Failed password|Invalid user|disconnected" > /var/log/ssh-anomaly-staging.log
Bu şekilde girişin LLM tarafından hızlıca işlenebileceği kadar küçük tutuluyor. Tam logları beslemiyorum — sadece potansiyel risk gösteren ham satırları alıyorum.
LLM ile Anomaly Puanlama
Staging logunu okuyan ve Ollama’ya odaklı bir prompt göndererek çalışan basit bir Python sarmaçası geliştirdim. Prompt modelden şu şeyleri yapmasını istiyor:
- Anormal giriş davranışı gösteren IP’leri belirle
- Zaman kümelemesi, kullanıcı adı yeniden kullanımı ve başarısız kalıpları değerlendir
- Engellemeye değer olan IP’leri sadece tek satırda birer çıktı ver
- Hiçbiri yoksa tam olarak "none" çıktısı ver
Scriptin çekirdeği şu şekilde:
import subprocess
import ollama
def analyze_ssh_log(log_path):
with open(log_path, 'r') as f:
log_content = f.read()
prompt = f"""Analyze the following SSH daemon log entries for signs of brute force or credential stuffing.
Look for:
- Multiple failed attempts from the same IP over time
- Attempts with non-existent users (e.g., 'admin', 'test', 'oracle')
- Patterns suggesting credential stuffing (e.g., common passwords across users)
- Geographic or timing impossibility (if implied by username/time)
Output only the IP addresses that should be blocked, one per line.
If no IPs meet the threshold, output exactly: none
LOG:
{log_content}
"""
response = ollama.generate(model='mistral', prompt=prompt)
return response['response'].strip()
ips = analyze_ssh_log('/var/log/ssh-anomaly-staging.log')
if ips and ips.lower() != 'none':
with open('/var/log/ssh-block-candidates.txt', 'w') as f:
f.write(ips)
Model mükemmel değil — bazen paylaşılan NAT IP’lerini flagler veya çok yavaş tıkanmaları kaçırır — ama Fail2ban’ın kaçırdığı desenleri yakalar, örneğin aynı IP’den 2 saat içinde 10 deneme ancak dönüşen kullanıcı adlarıyla.
Blokları Doğrulama ve Uygulama
LLM çıktısını doğrudan asla uygulamıyorum. Ayrı bir doğrulama betiği aday IP’leri şunlarla karşılaştırır:
- Mevcut Fail2ban tutuklamaları (tekrarlamamak için)
- Beyaz listedeki ağlar (ofisim, izleme sistemim)
- ASN itibarı (yerel önbellek üzerinden kötü bilinen ASN’ler)
IP geçerse, 2 saatlik zaman aşımıyla geçici bir iptables kuralı ekliyorum:
while read ip; do
if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then
iptables -I INPUT -s $ip -j DROP -m comment --comment "LLM-SSH-Anomaly-$(date +%s)"
echo "$(date): Blocked $ip via LLM analysis" >> /var/log/ssh-llm-block.log
fi
done < /var/log/ssh-block-candidates.txt
Kaynak ve zaman damgası izlemek için yorum kullanıyorum. 2 saatten eski kuralları temizleyen bir cron işiyle birikmesini önlüyorum.
Ayarlama ve Yanlış Pozitifler
Başlangıçta LLM iç izleme sondağımızın IP’lerini flagledi çünkü SSH banner’larını test ediyordu. Bu ağları beyaz listeye ekledim. Başka bir kez, geliştiricilerin kullandığı bir cloud NAT’ini engelledi — sonra fark ettik ki bir geçiş sırasında kimlik bilgilerini döndürüyordu. Şimdi anomaly skoru çok yüksek olmadıkça bilinen dev/cloud aralıklarını hariç tutuyorum.
Ayrıca prompt’u tek başarısız denemeleri görmezden gelecek şekilde ayarladım — model şimdi desenleri arıyor, izole hataları değil. Bu gürültüyü yaklaşık %70 azaltti.
Neden Fail2ban’ın Eşiğini Sadece Düşürmüyorum?
Belki şöyle düşünürsün: neden Fail2ban’ın maxretry veya findtime değerlerini sadece düşürmüyorum? Denedim. Eşiği düşürmek, hatalı bağlantıları olan veya PAM modülleriyle (Duo gibi) giriş yapıp bir girişimde birden fazla başarısızlık loglayan正当な kullanıcıların kilitlemesine yol açtı. LLM yaklaşımı sadece saymakle kalmaz, yorumlar — bu da insan değerlendirmesini ölçeklenebilir desen tanıma ile destekler.
AI tarafından üretilen iptables kurallarını loglardan oluşturmak konulu önceki yazımda da bahsettiğim gibi, değer tam otomasyonda değil, insan değerlendirmesini ölçeklenebilir desen algılamayla zenginleştirmede.
Sonuç
Bu bir mükemmel çözüm değil. LLM gecikme getirir, bakım gerektirir ve ayarlama ihtiyacı duyuyor. Ancak açık SSH’ye karşı sürekli evrim gösteren saldırganlar için faydalı bir ek katman sağlıyor. Fail2ban’ın radarı altında günlerce kalabilen düşük seviyeli credential stuffing kampanyalarını yakaladığını gördüm.
İnternete açık SSH çalıştırıyorsan ve gürültüyü azaltıp ince saldırıları yakalamak istiyorsan, Fail2ban’ı LLM log analizleriyle birleştirmeyi dene. Elle incelemeden başla, çıktıları doğrula ve zamanla prompt’u sıklaştır. Hedef kuralları değiştirmek değil, onları daha akıllı hale getirmek.
Kapak görseli: Jefferson Lab · PDM (Openverse / kamu malı) · https://www.flickr.com/photos/53950384@N02/55166403733
