| Accueil | FAQ | Statistiques | Divers | Contact |
Linux : utiliser iptables pour bloquer les chaines de caractères (1ere partie)
Est-ce que "w00tw00t.at.ISC.SANS.DFind:)" vous rappelle quelque chose ? Si vous administrez un serveur, vous avez probablement déjà rencontré "ça" dans vos logs, ou peut-être en avez-vous même fait des cauchemars en tentant, en vain, de vous en débarrasser ?
En général, ça se présente sous cette forme dans vos logs apache :
Nous allons tout simplement utiliser l'excellent iptables et notamment son filtre permettant de rejeter des paquets en se basant sur les chaînes de caractères avec l'option -m string. Pour connaître son fonctionnement, il suffit tout simplement de le lui demander :
Comme nous avons vu qu'il existait plusieurs variantes de notre "w00tw00t", nous allons donc filter sur la partie commune à toutes :
Si votre serveur dispose de plusieurs IP et que celles-ci se suivent, vous pouvez n'utiliser qu'une seule règle et inclure la plage d'IPs avec l'option -m iprange. Dans le cas où elles ne se suivent pas vous devrez créer une règle pour chacune d'elles.
Toujours dans vos logs apache, vous avez peut-être remarqué de nombreuses traces de scans recherchant des vulnérabilités comme des failles php, awstats etc ? Ou pire, des recherches de vulnérabilités IIS alors que vous utilisez un serveur Linux ? Plutôt que de créer des centaines de règles avec mod_security qui, nous l'avons vu, ne vont pas totalement protéger apache mais en plus risquent de terriblement ralentir son temps de réponse, nous allons nous débarasser de la presque (j'insiste sur le "presque" car il y a des exceptions) totalité de ces scanners idiots avec une seule et unique règle iptables.
Voyons à nouveau comment doit se présenter une requête HTTP 1/1. Si l'adresse IP de votre serveur est "110.220.110.220" et que votre nom de domaine est "domaine.com", lorsqu'un utilisateur va demander la page racine de votre site "/", sa requête devra comporter au moins les 2 éléments suivants :
A noter : vous pouvez aussi pour plus de précision dans le filtrage utiliser le paramètre --hex-string en encodant la chaîne de caractères "Host: xxx.xxx.xxx.xxx" en notation héxadécimale et en la faisant précéder et suivre des 2 CR/LF présents dans la requête ("| 0d 0a CHAINE_ENCODEE_HEX 0d 0a|").
213.251.134.23 [16/Nov/2008:07:43:58] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400
213.251.134.23 [16/Nov/2008:07:43:58] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400
213.251.134.23 [16/Nov/2008:07:43:58] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400
213.251.134.23 [17/Nov/2008:05:16:31] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400
On voit ici que le 213.251.134.23, petit serveur ks31944.kimsufi.com hébergé (et piraté) chez OVH, a demandé la page "/w00tw00t.at.ISC.SANS.DFind:)" et apache lui a poliment fait comprendre que la requête ne pouvait aboutir en lui retournant un code 400 et en ajoutant dans le fichier log des erreurs la raison de son refus :
client sent HTTP/1.1 request without hostname (see RFC2616 section 14.23)
Apache rejette cette requête tout simplement parce qu'elle n'est pas conforme. Toute requête HTTP 1.1 se doit de comporter dans son en-tête un champ "Host:" comme cela :
GET /page_demandee.html HTTP/1.1
Host: monsite.com
Dans notre cas il n'y a pas le nom d'hôte donc cette requête est rejetée et, de ce fait, n'est pas dangereuse : votre serveur n'a pas été piraté !
Il ne s'agit que d'un scanner de vulnérabilités (DFind) sans grand intérêt si ce n'est qu'il pollue en permance vos logs. Il en existe plusieurs variantes dont :
/w00tw00t.at.ISC.SANS.DFind:)
/w00tw00t.at.ISC.SANS.test0:)
/w00tw00t.at.ISC.SANS.MSlog:)
/w00tw00t.at.ISC.SANS.ntsvc:)
Comment s'en débarasser ?
# iptables -m string --help
STRING match v1.3.8 options:
--from Offset to start searching from
--to Offset to stop searching
--algo Algorithm
--string [!] string Match a string in a packet
--hex-string [!] string Match a hex string in a packet
Avant d'aller plus loin il est important de noter que les quelques règles décrites ci-dessous sont suffisantes pour vous débarasser des "script-kiddies" qui scannent les IPs au hasard pour trouver quelques vulnérabilités et éviter qu'ils ne polluent vos logs apache, mais qu'elles ne peuvent en aucun cas s'appliquer à un hacker expérimenté qui s'en prendrait spécifiquement à votre serveur, que seule une configuration poussée pourrait bloquer.
GET /w00tw00t.at.ISC.SANS.
Cela représente 26 octets, auxquels nous en ajouterons 44 par sécurité (dont une douzaine pour le champs "Options" de l'en-tête du paquet TCP/IP), ce qui fera une recherche sur un maximum de 70 octets (paramètre --to) :
# iptables -I INPUT -d xxx.xxx.xxx.xxx -p tcp --dport 80 -m string --to 70 \
--algo bm --string 'GET /w00tw00t.at.ISC.SANS.' -j DROP
Remplacez la chaîne 'xxx.xxx.xxx.xxx' par l'IP de votre serveur.
Exemple avec les 5 adresses IP 1.0.0.1, 1.0.0.2, 1.0.0.3, 1.0.0.4 et 1.0.0.5 :
# iptables -I INPUT -p tcp --dport 80 -m iprange --dst-range 1.0.0.1-1.0.0.5 \
-m string --to 70 --algo bm --string 'GET /w00tw00t.at.ISC.SANS.' -j DROP
Vérifiez que la règle est bien en place :
# iptables -L INPUT -nvx
pkts bytes target ...
0 0 DROP ... STRING match "GET /w00tw00t.at.ISC.SANS." ALGO name bm TO 70
Patientez quelques heures afin que votre ami DFind revienne vous voir et, normalement, vous ne devriez plus en avoir aucune trace dans vos logs. Cependant, vous aurez tout de même la joie de pouvoir consulter le nombre de paquets rejetés comme dans cet exemple :
# iptables -L INPUT -nvx
pkts bytes target ...
64 5504 DROP ... STRING match "GET /w00tw00t.at.ISC.SANS." ALGO name bm TO 70
On voit ici que 64 paquets on été "droppés", pour un total de 5504 octets, soit 86 octets/paquets.
Comment se débarasser de (presque) tous les scanners HTTP ?
GET / HTTP/1.1
Host: domaine.com
Maintenant la même requête avec un scanner de vulnérabilité :
GET / HTTP/1.1
Host: 110.220.110.220
Toute la différence se trouve dans le champ "Host:". L'utilisateur connait votre nom de domaine mais le scanner, lui, ne le connait pas. Il scanne les IPs, pas les domaines et de ce fait est très facilement détectable.
Donc nous pouvons bloquer tout simplement ces scanners en rejetant avec iptables toutes les requêtes HTTP entrantes qui utilisent votre IP au lieu de votre nom de domaine :
# iptables -I INPUT -d xxx.xxx.xxx.xxx -p tcp --dport 80 -m string --to 700 \
--algo bm --string 'Host: xxx.xxx.xxx.xxx' -j DROP
Il vous suffit juste de remplacer les 2 séries de 'xxx.xxx.xxx.xxx' avec l'IP de votre serveur. Le filtrage s'effectue ici sur les 700 premiers octets (--to 700) car d'autres champs et variables pourraient se trouver entre les lignes "GET" et "Host:".
Patientez quelques heures et lancez la commande de visualisation des règles # iptables -L INPUT -nvx pour voir le nombre de scanners qui se sont englués dans votre firewall sans avoir eu le temps de polluer vos logs. Sans oublié bien entendu que vous leur avez fait perdre du temps avec le 'DROP' :)
[ 2e partie : affiner la règle >> ] 
![]()