notsocomplicated | scratch your head

Sécurisons Apache avec fail2ban

Un matin, en regardant mes logs,  j’ai vu ça :

[Tue Feb 02 14:16:54 2010] [error] [client 192.168.1.20] File does not exist: /var/www/favicon.ico
[Tue Feb 02 14:16:57 2010] [error] [client 192.168.1.20] File does not exist: /var/www/favicon.ico
[Tue Feb 02 14:28:36 2010] [error] [client 82.230.79.111] File does not exist: /var/www/favicon.ico
[Tue Feb 02 14:28:39 2010] [error] [client 82.230.79.111] File does not exist: /var/www/favicon.ico
[Tue Feb 02 18:27:07 2010] [error] [client 88.164.111.127] File does not exist: /var/www/favicon.ico
[Tue Feb 02 18:27:10 2010] [error] [client 88.164.111.127] File does not exist: /var/www/favicon.ico
[Wed Feb 03 05:55:12 2010] [error] [client 84.244.181.86] File does not exist: /var/www/roundcubemail
[Wed Feb 03 05:55:12 2010] [error] [client 84.244.181.86] File does not exist: /var/www/rc
[Wed Feb 03 05:55:12 2010] [error] [client 84.244.181.86] File does not exist: /var/www/webmail
[Wed Feb 03 05:55:12 2010] [error] [client 84.244.181.86] File does not exist: /var/www/roundcube
[Wed Feb 03 05:55:12 2010] [error] [client 84.244.181.86] File does not exist: /var/www/mail
[Wed Feb 03 05:55:13 2010] [error] [client 84.244.181.86] File does not exist: /var/www/README

Ce qui signifie plusieurs choses :

Pas de favicon

Je n’ai pas de favicon, et le navigateur la demande. Résolvons l’erreur, ça coûte rien et ça rend mes logs plus lisibles ; on se déplace dans le répertoire web par défaut /var/www/, puis on crée un fichier vide appelé favicon.ico, et enfin on lui attribue les bons droits :

~$ cd /var/www/
~$ sudo touch favicon.ico
~$ sudo chown 777 favicon.ico

Ouh le coquin

Un petit canaillou s’amuse à essayer de trouver un dossier qui n’existe pas. À la lecture du log, on voit bien qu’il ne me veut pas que du bien. J’avais déjà installé fail2ban, mais je n’avais créé de jail que pour SSH. Il va falloir en créer pour Apache : d’après mes recherches, il existe quelques jails classiques. On va éditer le fichier de config de fail2ban pour les ajouter.

sudo vim /etc/fail2ban/jail.local

Tant qu’on y est, on va faire en sorte de ne pas pouvoir bannir une adresse locale : chez moi, une adresse locale a la forme

192.168.1.*

On va donc compléter la ligne ignoreip comme suit :

ignoreip = 127.0.0.1 192.168.1.0/24

Et on ajoute nos jails :

# Jail pour les attaques dictionnaire qui visent phpmyadmin
[apache-admin]

enabled = true
port    = http
filter  = apache-admin
logpath = /var/log/apache*/error*.log
maxretry = 6

# Jail pour les curieux qui essaient de trouver un dossier au pif
[apache-404]

enabled = true
port    = http
filter  = apache-404
logpath = /var/log/apache*/error*.log
maxretry = 10

# Jail pour les attaques par requêtes DFind w00tw00t
[apache-w00tw00t]

enabled = true
filter  = apache-w00tw00t
action  = iptables[name=Apache-w00tw00t,port=80,protocol=tcp]
logpath = /var/log/apache2/access*.log
maxretry = 1

Maintenant, les filtres associés à ces jails :

On crée le fichier pour la jail apache-admin

~$ sudo vim /etc/fail2ban/filter.d/apache-admin.conf

Et on y colle

# Fail2Ban configuration file
#
# Author: Cyril Jaquier
#
# $Revision: 471 $
#

[Definition]

# Option:  failregex
# Notes.:  regex to match the password failure messages in the logfile. The
#          host must be matched by a group named "host". The tag "<HOST>" can
#          be used for standard IP/hostname matching.
# Values:  TEXT
# [client x.x.x.x] File does not exist: /home/www/admin/admin,
failregex = [[]client <HOST>[]] File does not exist: .*admin|PMA|mysql

#
# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
#
ignoreregex =

Ensuite on crée le fichier pour la jail apache-404

~$ sudo vim /etc/fail2ban/filter.d/apache-404.conf

Et on y colle

# Fail2Ban configuration file
#
# Author: Cyril Jaquier
#
# $Revision: 471 $
#

[Definition]

# Option:  failregex
# Notes.:  regex to match the password failure messages in the logfile. The
#          host must be matched by a group named "host". The tag "<HOST>" can
#          be used for standard IP/hostname matching.
# Values:  TEXT
# [client x.x.x.x] File does not exist: /home/www/admin/admin,
failregex = [[]client <HOST>[]] File does not exist: .*

#
# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
#
ignoreregex =

Et puis on crée le fichier pour la jail apache-w00tw00t

~$ sudo vim /etc/fail2ban/filter.d/apache-w00tw00t.conf

Et on y colle

[Definition]

failregex = ^<HOST> -.*"GET \/w00tw00t\.at\.ISC\.SANS\.DFind\:\).*".*

ignoreregex =

Ça, c’est fait. On recharge les préférences de fail2ban :

~$ sudo fail2ban-client reload

Et on vérifie que nos jails on bien été créées :

~$ sudo fail2ban-client status
Status
|- Number of jail:    4
`- Jail list:        apache-admin, apache-w00tw00t, ssh, apache-404

On retrouve bien nos trois nouvelles jails (celle pour ssh était déjà là avant), tout va bien !

Un plugin Munin pour fail2ban

C’est bien beau tout ça, mais comment je sais si j’ai attrapé quelqu’un dans mes filets ?

Très simple, on va dire à Munin qu’il faut aussi surveiller fail2ban.

Créer le fichier /usr/share/munin/plugins/fail2ban

~$ sudo vim /usr/share/munin/plugins/fail2ban

On y colle :

#! /bin/bash
#
# script venant de Majorxtrem’s Blogs (merci)
# http://www.majorxtrem.be/2009/08/14/plugins-fail2ban-pour-munin/
PROGNAME=fail2ban
STATEDIR=/var/lib/munin/plugin-state
LISTJAIL=$(fail2ban-client status | grep " Jail list:" | sed 's/`- Jail list:\t\t//g' | sed 's/,//g')
if [ "$1" = "config" ]
then
 echo 'system.type ABSOLUTE'
 echo 'graph_title Fail2ban'
 echo 'graph_vlabel Number of ban'
 echo 'graph_category Security'
 for f in $LISTJAIL; do
# replace - with _
 echo "$(echo "$f.label" | tr - _) $f"
 done
 exit 0
fi
for f in $LISTJAIL; do
# replace - with _
 echo "$(echo "$f.value" | tr - _) $(fail2ban-client status $f | grep  " Currently banned:" | sed 's/ |- Currently banned:\t//g')"
done

Comme Munin n’aime pas les tirets (?), le plugin les remplace par des underscores.

On fait un lien symbolique du plugin dans le dossier des plugins Munin :

~$ sudo ln -s /usr/share/munin/plugins/fail2ban /etc/munin/plugins/

Et on rend le plugin exécutable :

sudo chmod +x /usr/share/munin/plugins/fail2ban

Pour que Munin puisse utiliser fail2ban, il doit avoir des privilèges plus élevés. On édite

~$ sudo vim /etc/munin/plugin-conf.d/munin-node

Et on ajoute

[fail2ban]
user root

Il n’y a plus qu’à redémarrer Munin :

~$ sudo /etc/init.d/munin-node restart

Et peu de temps après, bingo ! On a notre premier client :

~$ sudo vim /var/log/fail2ban.log
2010-02-08 11:21:49,698 fail2ban.filter : ERROR  No 'host' found in '[Mon  2010] [error] [client 205.244.148.43] File does not exist: /var/www/mysql' using '<_sre.SRE_Pattern object at 0xb17c50>'
2010-02-08 11:21:51,312 fail2ban.actions: WARNING [apache-404] Ban 205.244.148.43
2010-02-08 11:31:52,146 fail2ban.actions: WARNING [apache-404] Unban 205.244.148.43

Du côté de Munin :

jail apache-404

Bon évidemment, il n’ a été banni que 600 secondes, durée par défaut (ça fait 10 minutes, croyez-le ou non). Je vais augmenter ce temps, histoire de lui apprendre qu’on ne foule pas impunément mon territoire.

~$ sudo vim /etc/fail2ban/jail.local

Trouver la ligne bantime et mettre un nombre de secondes dissuasif :

bantime  = 86400    #te voilà en taule pour 24h, brigand !

On recharge la configuration de fail2ban :

~$ sudo fail2ban-client reload

Et nous voilà débarrassés de cette engeance.

Billet tiré des pages suivantes :

  • Plugin corrigé pour régler le problème des tirets : dans les commentaires de la page ci-dessus, d’après Didier Mission, mais le formatage casse le plugin. Ma version fonctionne pour de vrai ;)

[apache-admin]

enabled = true
port = http
filter = apache-admin
logpath = /var/log/apache*/error*.log
maxretry = 6

[apache-404]

enabled = true
port = http
filter = apache-404
logpath = /var/log/apache*/error*.log
maxretry = 10

Ecrire un commentaire

*

XHTML: Vous pouvez utiliser ces balises: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 

:~#