Yazılara geri dön
Yazı

Fail2ban + LLM: SSH brute force saldırılarına akıllı müdahale

Fail2ban ile LLM entegrasyonu, SSH auth loglarını analiz ederek dinamik ban süreleri ve kalıcı engeller önerir. Yanlış pozitifleri azaltın.

Yapay ZekaFail2banLLMSSHintrusion prevention

Fail2ban'ı yıllardır públicos SSH sunucularımda kullanıyorum. Kutu içinden oldukça iyi çalışıyor, ancak statik ban süreleri ve statik ignore kuralları bazen hedefi kaçırır—ya kalıcı saldırganları çok uzun süre serbest bırakır ya da şifreyi yanlış tuşlayan kullanıcıları gereksiz yere kilitler. Son zamanlarda Fail2ban'ın log çıktısını yerel bir LLM'e besleyerek daha adaptif bir tepki alıp alamayacağımı deneyeyim dedim. Mantık basit: sadece regex eşleşme sayısına güvenmek yerine, her başarısız giriş denemesinin niyetini LLM'in değerlendirmesini isteyip, ona göre özel bir ban süresi hatta kalıcı engel önermesini istiyorum.

Ortamımda nasıl kurduğumu anlatayım.

Neden statik Fail2ban kuralları yetersiz kalıyor

Fail2ban, desen eşleştirmede çok iyi. Bir filter tanımlarsın, maxretry ayarlarsın, ve IP, belirli bir zaman penceresi içinde N kez başarısız olduğunda yasağını uygular. Bu, şifre deneme saldırısıyla uğraşan gürültülü botlar için çok etkili. Ancak hedefli saldırılar genellikle eşiğin altında kalmaya çalışır—örneğin her on dakikada üç başarısız deneme—yasağı tetiklememek için. Bir başka yandan, sistem yöneticisi şifreyi iki kez yanlış girerse, yorgunluk ve kötü niyet arasında ayrım yapmadığı için Fail2ban onu on dakika kilitler.

Auth loglarında bu deseni fark ettim: aynı IP'ten saatler veya günler boyunca düşük hacimli, tekrarlanan denemeler, bazen sistemde olmayan kullanıcı adlarıyla. Bu rastgele taramalar değil; bunlar keşif faaliyetleri. Fail2ban'ın varsayılan jollerı, kullanıcı adı geçerliliği veya zamanlama desenlerini değerlendirmez—sadece eşleşme sayısını sayar.

LLM'e logları beslemek ve bağlam elde etmek

Auth verilerini üçüncü partiyle paylaşmak istemediğim için yerel olarak barındırılan küçük bir LLM kullanıyorum (Ollama üzerinden Llama 3). Fail2ban her bir IP'yi yasağın zamanında, o IP için son 20 başarısız denemeyi /var/log/auth.log'tan çekip, şöyle bir prompt ile modele iletiyorum bir script çalıştırarak:

Bu SSH giriş başarısızlıklarını analiz et. Bu, muhtemelen brute force saldırısı mı, credential stuffing mi yoksa insan hatası mı? Öner: 1) ban süresi (dakika), 2) kalıcı engel için yükseltme gerekli mi, ve 3) güven seviyesi (düşük/orta/yüksek).

[LOG SATIRLARI BURADA]

Model, jq ile ayrıştırdığım JSON benzeri bir yanıt döndürüyor. Örneğin:

{
  "assessment": "brute force",
  "recommended_ban_minutes": 1440,
  "permanent_block": false,
  "confidence": "high"
}

Güven seviyesi orta veya yüksekse, fail2ban-client komutu ile Fail2ban jail'ini dinamik olarak ayarlıyorum.

Yanıtın otomatikleştirilmesi için bir yardımcı script

/usr/local/bin/fail2ban-llm-adjust.sh adında bir script oluşturdum ve çalıştırılabilir kılardım. Bu script, Fail2ban'ın action.d klasörü üzerinden actionstart veya actionban kancasıyla çağrılıyor.

Script'in temel kısmı şu şekilde:

#!/bin/bash
IP="$1"
JAIL="$2"

# Bu IP için son hataları al
LOG LINES=$(grep "$IP" /var/log/auth.log | grep "Failed password" | tail -20)

if [ -z "$LOG LINES" ]; then
  exit 0
fi

# Ollama üzerinden yerel LLM'i çağır
RESPONSE=$(ollama run llama3 "Bu SSH giriş başarısızlıklarını analiz et. Bu, muhtemelen brute force saldırısı mı, credential stuffing mi yoksa insan hatası mı? Öner: 1) ban süresi (dakika), 2) kalıcı engel için yükseltme gerekli mi, ve 3) güven seviyesi (düşük/orta/yüksek).\n\n$LOG LINES" | tail -1)

# Değerleri çıkar (basit ayrıştırma; üretimde geliştirilmeli)
BAN_MIN=$(echo "$RESPONSE" | grep -o '"recommended_ban_minutes":[0-9]*' | cut -d: -f2)
PERM=$(echo "$RESPONSE" | grep -o '"permanent_block":[true|false]' | cut -d: -f2 | tr -d ' ',)
CONF=$(echo "$RESPONSE" | grep -o '"confidence":[a-z]*' | cut -d: -f2 | tr -d ' "')

if [ "$CONF" = "medium" ] || [ "$CONF" = "high" ]; then
  if [ "$BAN_MIN" -gt 0 ]; then
    fail2ban-client set "$JAIL" banip "$IP" bantime "$BAN_MIN"
  fi
  if [ "$PERM" = "true" ]; then
    # Kalıcı engel listesine ekle (örn. ipset veya firewall)
    /usr/local/bin/add-to-permanent-block.sh "$IP"
  fi
fi

Bu script'i sshd jail'ine entegre etmek için /etc/fail2ban/action.d/ssh.conf dosyasına şunu ekliyorum:

actionban = /usr/local/bin/fail2ban-llm-adjust.sh <ip> sshd

Ayarlama ve güvenlik konuları

Bu kurulum, Fail2ban'ın yerleşik mantığının yerine geçen bir şey değil, bir tamamlayıcı. Hala açıkça belirtilen şeyleri yakalamak için regex filtrelerine güveniyorum. LLM sadece bir ban tetiklendikten sonra çalıştığı için ilk engelle gecikme getirmez, sadece bir overhead ekler.

Birkaç güvenlik önlemi ekledim:

  • LLM 10 saniye içinde yanıt vermezse scriptten çıkıyor (asıl sürümde timeout kullanıyorum).
  • Bilinen yönetici IP'lerini bey listesi alıyorum, bu IP'ler auth başarısız olsa bile modele gitmiyor.
  • Tüm loglar denetim amaçlı /var/log/fail2ban-llm.log'a yazılıyor.

Birinci haftada, LLM sistemde olmayan kullanıcı adlarıyla (‘admin’, ‘root’, ‘user’) düşük ve hızlı ardışık denemeler yapan iki IP için kalıcı engel önerdi—statik kuralların kaçırdığı bu düşük ve yavaş modeli yakaladı. Ayrıca, aynı alt ağdaki birkaç IP için, yazım hatası gibi görünen durumlar için ban süresini azöttü.

Bu yaklaşımın ilerideki gelişimi

LLM'e ek bağlam sunarak deney yapıyorum: günün saati, coğrafi kaynak (ipinfo.io üzerinden önbelleğe alınarak), ve kullanıcı adının /etc/passwd'de olup olmadığı. Amaç kural tabanlı sistemleri değiştirmek değil, belirsiz desenlerde hafif bir değerlendirmeyle onları desteklemek.

Fail2ban kullanan ve savunmayı zayıflatmadan yanlış pozitifleri azaltmak isteyen biriysen, yerel bir LLM ile birleştirmeyi deneyebilir. Küçük başla—önce modelin önerilerini sadece logla, hareket etmeden önce. Daha önce syslog ile sudo izleme için LLM kullanımım hakkında yazdığım postumda da belirttiğim gibi, anahtar modeli yerel tutmak ve prompt'ları odaklı tutmaktır.

Bu yaklaşım, belirli bir saldırganı durdurmayacak, ama gürültü seviyesini akıllı hale getirecek—and that's half the battle in log-driven defense.


Kapak görseli: solaranamnesis-pub · CC0 (Openverse / kamu malı) · https://www.flickr.com/photos/202852857@N07/55059766538