Benutzer-Werkzeuge


fail2ban Logfile überwachen

fail2ban ist eine Python Software, welche man sehr gut zur automatisierten Überwachung der Systemlogfiles verwenden kann. fail2ban bietet die Möglichkeit Muster für Logverletzungen vorzugeben und Aktionen zu definieren, welche ausgeführt werden sollen. Meist verwendet man als Aktion, dass die entsprechende IP in der Firewall des Systems geblockt wird. Das „Schöne“ an fail2ban ist, dass man sowohl Muster als auch Aktionen sehr fein steuern kann. Das Konzept von fail2ban basiert auf sogenannten Jails. Pro Jail kann man ein Logfile und eine Aktion vorgeben.

Hier soll es aber nicht darum gehen fail2ban zu installieren. Wahrscheinlich gibt es ein ipkg Paket und sonst lässt es sich direkt aus den Quellen schnell und einfach installieren, da es ja auf Python basiert. Und Python gibt es als ipkg Paket. Ich möchte hier ein paar kleine Scripte zeigen, die die Fähigkeiten von fail2ban erweitern können.

Konkret geht es bei dem Script um folgendes: Für fail2ban sind alle „Übeltäter“ gleich d.h. sie werden alle genau gleich bestraft (aka gesperrt). Nun ist das nicht gerade sinnvoll, denn „Ersttäter“ will man ja kaum gleich bestrafen wie „Wiederholungstäter“. Daher suchte ich nach einer Möglichkeit die Wiederholungstäter sehr lange zu sperren und Ersttäter hingegen relativ kurz. Im fail2ban Manual wird ein Weg beschrieben wie man das auch mit den Mitteln von fail2ban erreichen kann, allerdings wird dort dann explizit die Verwendung von zwei Firewalls empfohlen (iptables und shorewall). Das war keine Lösung für mich und darum ist das folgende Script entstanden

Voraussetzungen

  • fail2ban muss installiert sein und korrekt arbeiten
  • die Scripte sind für die Bash geschrieben. Andere Shells sollten funzen ich garantiers aber ned Mittlerweile hat es wohl doch bashspezifisches darin und andere Shells dürften nicht funzen
  • das Script liest die Logfiles von fail2ban, was per default nur root erlaubt ist
  • per default wird eine Mail verschickt wenn eine IP geblockt wird, daher muss ein Mailprogramm installiert sein (z.B. mailx) in der aktuellsten Version legt ein Parameter im daemon $MAILBLK fest ob eine Mail verschickt werden soll. Per default deaktiviert

Scripte

Das Ganze besteht aus 3 Scripten: Einmal ein Client, der die Steuerung des Daemons übernimmt (Bash). Dann der Daemon selber, ebenfalls Bash. Dann noch ein PHP Script, welches die „Auswertung“ der verdächtigen Logzeilen übernimmt und festlegt welche IPs gesperrt werden müssen

Client

Der Client nimmt die üblichen Parameter entgegen (start|stop|restart) und steuert damit den Daemon

#!/bin/bash
 
INSTALLDIR=$(readlink -f $0)
INSTALLDIR=$(dirname $INSTALLDIR)
cd $INSTALLDIR > /dev/null 2>&1
[ $? -ne 0 ] && echo "$(date +'%a %d.%m.%y %T') ERROR: $INSTALLDIR could not be found or is not accessable" && exit 1
 
checkStatus(){
 ii=$(ps aux | grep ban4ever-daemon | grep -v grep | awk '{print $2}')
 if [ ! "x$ii" = 'x' ] ; then
  echo "$ii"
 fi
}
 
startService(){
 [[ ! -e ./ban4ever-daemon.sh || ! -x ./ban4ever-daemon.sh ]] && echo "$(date +'%a %d.%m.%y %T') ERROR: Daemon File not found OR it's not executable" && echo "$(date +'%a %d.%m.%y %T') ERROR: Daemon File not found OR it's not executable" >> ./ban4ever.log && exit 5
 status=$(checkStatus)
 [ ! "x$status" = 'x' ]  && echo "$(date +'%a %d.%m.%y %T') INFO: service already runnig see PID(s) $status" && echo "$(date +'%a %d.%m.%y %T') INFO: service already runnig see PID(s) $status" >> ./ban4ever.log && exit 0
 bash ./ban4ever-daemon.sh >> ./ban4ever.log 2>&1 &
 status=$(checkStatus)
 [ "x$status" = 'x' ] && echo "$(date +'%a %d.%m.%y %T') ERROR: could not start" && echo "$(date +'%a %d.%m.%y %T') ERROR: could not start" >> ./ban4ever.log && exit 7
 [ ! "x$status" = 'x' ] && echo "$(date +'%a %d.%m.%y %T') INFO: sucessfully started see PID $status" && echo "$(date +'%a %d.%m.%y %T') INFO: sucessfully started see PID $status" >> ./ban4ever.log
}
 
stopService(){
 status=$(checkStatus)
 [ "x$status" = 'x' ] && echo "$(date +'%a %d.%m.%y %T') INFO: Not running" && echo "$(date +'%a %d.%m.%y %T') INFO: Not running" >> ./ban4ever.log
 for i in $status ; do
  kill -9 $status > /dev/null 2>&1
 done
 status=$(checkStatus)
 [ "x$status" = 'x' ] && echo "$(date +'%a %d.%m.%y %T') INFO: succesfully terminated" && echo "$(date +'%a %d.%m.%y %T') INFO: succesfully terminated" >> ./ban4ever.log
 [ ! "x$status" = 'x' ] && echo "$(date +'%a %d.%m.%y %T') ERROR: could not terminate. check PID $status" &&  echo "$(date +'%a %d.%m.%y %T') ERROR: could not terminate. check PID $status" >> ./ban4ever.log && exit 1
}
 
case "$*" in
 'start')
  startService && exit 0
 ;;
 'stop')
  stopService && exit 0
 ;;
 'restart')
  stopService
  startService && exit 0
 ;;
 'start-force')
  stopService
  startService && exit 0
 ;;
 *)
 echo 'USAGE: start|stop|restart|start-force'
 ;;
esac

Daemon

Auch der Daemon ist ein Bash Script. Es läuft eine Endlosschleife welche alle 30 Sekunden die Daten des fail2ban Logs auf Logzeilen mit gebannten IPs untersucht. Diese Zeilen werden in ./ban4ever.txt geschrieben.

#!/bin/bash
 
echo "$(date +'%a %d.%m.%y %T') ban4ever started"
PAUSE=0
LOGMATCH=0
MAILBLK=0
RCVR='0'
PHP=$(which php)
MAIL=/usr/bin/mailx
 
while true ; do
 sleep 30
 touch ./ban4ever.txt.tmp && echo > ./ban4ever.txt.tmp
 for i in $(grep Ban /var/log/fail2ban.log | awk '{print $7}') ; do
  echo $i >> ./ban4ever.txt.tmp
 done
 mv ./ban4ever.txt.tmp ./ban4ever.txt
 $PHP ./ban4ever.php > /dev/null 2>&1
 for i in $(cat ./ban4ever_act.txt) ; do
  [ "$(iptables -L OFFENDERS -n | grep  $i)" ] && continue
  iptables -A OFFENDERS -s $i -j DROP
  if [ $? -eq 0 ] ; then
   echo "$(date +'%a %d.%m.%y %T') IP $i added to block"
   [ $MAILBLK -eq 1 ] && [ "$RCVR" != '0' ] && echo "$(date +'%a %d.%m.%y %T') IP $i added to block $(whois $i)" | $MAIL -s "IP $i blocked" $RCVR
   [ $LOGMATCH -eq 1 ] && iptables -I OFFENDERS -s $i -j LOG --log-level 0 --log-prefix "$i " && echo "$(date +'%a %d.%m.%y %T') Successfully added logging rule for $i"
  else
   echo "$(date +'%a %d.%m.%y %T') WARNING: $ip could not be added to iptables"
  fi
 done
 ii=`expr $PAUSE % 120`
 [ $ii -eq 0 ] && echo "$(date +'%a %d.%m.%y %T') Status up and running"
 PAUSE=`expr $PAUSE + 1`
done

PHP Script

Das oben erstellte File ./ban4ever.txt wird vom PHP Script abgearbeitet und IPs welche den Schwellenwert überschreiten werden ermittelt und in ein neues File ./ban4ever_act.txt geschrieben. Dieses File verwendet dann der Daemon um die IPs effektiv zu sperren

#!/usr/bin/php
 
<?php
 $action_limit = 1;
 $str = '';
 $array = file('./ban4ever.txt');
 $ip = array();
 for($i=0;$i<count($array);$i++){
  if(array_key_exists(trim($array[$i]),$ip) === false){
   $ip[trim($array[$i])] = 1;
  }else{
   $ip[trim($array[$i])]++;
  }
 }
 foreach($ip as $key=>$wert){
  if($wert > $action_limit) {
   $str .= "$key\n";
  }
 }
 if($str != ''){
  $fp = fopen('./ban4ever_act.txt','w');
  fwrite($fp,$str);
  fclose($fp);
 }
?>

$action_limit legt den Schwellenwert fest, ab dem IPs gesperrt werden sollen. Dabei ist folgendes wichtig: fail2ban selber hat bereits einen Schwellenwert pro Jail ab dem reagiert werden soll. Sagen wir der Wert liegt bei 3 erlaubten Fehlversuchen seitens von fail2ban. Wenn jetzt action_limit 1 ist heisst dies dass ab 2 Verletzungen im fail2ban Log reagiert wird d.h. es wurden effektiv mindestens 6 Fehlversuche seitens fail2ban festgestellt. Dieser Unterschied ist wichtig weil fail2ban erst ins Log schreibt wenn er eine IP sperrt und nicht jeden Fehlversuch, der noch unterhalb der Grenze liegt

Melden Sie sich an, um einen Kommentar zu erstellen.

Seiten-Werkzeuge