Recherche de site Web

Comment créer un système de détection d’intrusion de base avec Bash


Introduction

Pour la plupart d’entre nous, le cryptage WEP est devenu une blague. Le WPA prend rapidement le même chemin grâce à de nombreux outils tels que Aircrack-ng. En plus de cela, les réseaux câblés ne sont pas étrangers aux invités indésirables. Toute personne sérieuse en matière de sécurité devrait avoir un bon système de détection d’intrusion dans sa boîte à outils.

Il existe déjà de très bons IDS (systèmes de détection d’intrusion) disponibles. Pourquoi quelqu’un voudrait-il réinventer la roue dans Bash ??? Il y a plusieurs raisons à cela. De toute évidence, les scripts Bash peuvent être très légers. Surtout par rapport à certains des programmes d’interface graphique qui existent. Bien que des programmes comme Etherape nous aspirent avec de jolies couleurs, ils nécessitent une surveillance constante pour savoir quand le réseau a changé. Si vous êtes comme la plupart d’entre nous, vous n’utilisez l’ordinateur que pour deux choses, travailler et jouer. En utilisant la cloche du système pour alerter les nouveaux clients en ligne, vous pouvez laisser ce script en cours d’exécution et ne pas avoir à avoir une surveillance constante. Si vous décidez d’inspecter de plus près ce que fait un client suspect, vous pouvez toujours ouvrir etherape, wireshark ou l’outil de votre choix. Mais jusqu’à ce que vous ayez un problème, vous pouvez jouer ou travailler sur d’autres choses.

Un autre avantage de ce programme est qu’il n’affichera que les adresses IP sur les réseaux connectés à votre ordinateur. Si vous hébergez un serveur occupé ou si vous téléchargez la dernière distribution Linux via un client torrent, un IDS peut être inondé de connexions. La recherche d’un nouveau client malveillant peut s’apparenter à la recherche d’une aiguille dans une botte de foin. Bien que ce script puisse sembler simple par rapport à d’autres IDS, la simplicité peut aussi avoir ses avantages.

Ce dont vous aurez besoin

Nmap est nécessaire pour que ce script fonctionne. Nous n’effectuerons aucun balayage de port. Cependant, pour rendre ce script rapide, nous avions besoin de quelque chose de mieux qu’un ping régulier. Le paramètre -sP de Nmap n’utilisera qu’un scan ping pour vérifier si un client est opérationnel. Il y avait quelques variations dans la façon dont Nmap génère des informations entre les versions. Jusqu’à présent, ce script n’a été testé qu’avec Nmap 5.00 (Debian Squeeze) et 5.21 (Debian Sid). Vous aurez peut-être de la chance avec d’autres distributions et versions de Nmap. Cependant, avec toutes les possibilités, je ne pouvais subvenir aux besoins que d’un couple à ce moment-là.

Vous devrez également vous assurer que vous utilisez la version 4.0 ou supérieure de Bash. Vous devriez trouver cela dans n’importe quelle distribution stable ou plus récente. Mais toutes les versions de Bash inférieures ne prendront pas en charge les tableaux utilisés dans ce script. Un accès root est également requis, sinon la commande arp ne sera pas trouvée pour bloquer les clients.

note: Ce script ne fonctionne pas bien avec les interfaces de réseau virtuel telles que VMware, VirtualBox, etc.

Exécution du script

Pour exécuter ce script, il suffit d’exécuter :

chmod +x leecher.sh; ./leecher.sh

Pour le moment, il n’y a pas de paramètres à définir.

Comment fonctionne ce script

Ignorez toutes les fonctions de début pour l’instant afin que nous puissions voir le flux réel du script. La première chose que nous faisons est de vérifier que l’utilisateur est root et que nmap est installé sur le système actuel. Si ce n’est pas le cas, le script expliquera que les privilèges root sont requis ou que nmap est une dépendance ici et quitte. Si ces conditions sont remplies, le script passe à un message d’accueil à l’utilisateur et explique certaines fonctionnalités. J’ai utilisé setterm pour désactiver le curseur. C’était définitivement une plaie esthétique.

Je définis un trap control-C pour faire arrêter le script. Bien que vous puissiez penser 'Attendez, Control-C arrête généralement le programme en ligne de commande de toute façon !' Bien que cela soit normalement vrai, j’ai trouvé que la boucle forever que nous utilisons plus tard posait des problèmes pour arrêter le script avec Control-C. En utilisant un piège avec SIGINT, nous avons pu faire en sorte que cela fonctionne. Nous définissons quelques variables dans l’instruction if suivante pour vérifier quelle version de nmap prise en charge nous utilisons ici. Ceci est important car le résultat est complètement différent entre ces versions. La première chose que nous avons faite ici a été de faire une boucle qui obtiendra d’abord la version de nmap que nous utilisons ici. Ceci est important car le résultat est complètement différent entre ces versions. La prochaine chose que nous avons faite ici a été de faire une boucle qui obtiendra d’abord les adresses IP de toutes nos interfaces qui sont actuellement en ligne. Nous utilisons également awk ici pour filtrer 127.0.0.1 car il n’est pas nécessaire d’analyser l’adresse de bouclage. De plus, nous utilisons awk pour couper l’octet de fin dans ces adresses IP. Par exemple, si l’interface eth0 a une adresse IP de 192.168.1.12, nous n’avons pas besoin de la terminaison 12. Un balayage normal d’un sous-réseau comme celui-ci serait « nmap -sP 192.168.1.0/24 » Donc, pour l’instant, cette boucle supprimera toutes les adresses IP de toutes les interfaces actives et les transmettra à la fois à nmap jusqu’à ce que nous ayons terminé. À l’intérieur de la boucle, nous recevons la valeur pour ip une interface et ajoutons « .0/24 » pour scanner l’ensemble du réseau dans cette plage. (ou 0-255) Nous passerons les variables correctes pour la version de nmap afin que awk sache où obtenir les adresses IP renvoyées à chaque scan. Toutes les valeurs renvoyées par chaque balayage seront branchées dans un tableau. Après le premier scan de tous vos réseaux d’interfaces, nous utiliserons simplement une autre boucle pour afficher les premiers résultats à l’utilisateur.

Je dois souligner ici ce que dit le nouveau message suivant à l’utilisateur. Si vous souhaitez entendre la sonnerie du système, elle doit être activée dans les paramètres de votre bureau. L’emplacement de cela variera en fonction de la version de KDE, Gnome, Xface ou du bureau que vous utilisez. Cependant, vous pensez peut-être que ce n’est pas parce que vous avez déjà entendu une cloche qu’elle est activée. J’ai remarqué que mon système d’exploitation avait une cloche similaire pour m’informer que la batterie de mon ordinateur portable était sur le point de mourir. Veuillez vérifier comment activer la cloche système sur votre distribution si vous rencontrez des problèmes.

Vient ensuite la boucle forever pour maintenir l’analyse et la surveillance de ce script constantes. Si vous êtes nouveau sur Bash ou les boucles éternelles, cela pourrait vous amener à vous demander pourquoi nous utiliserions quelque chose qui est une boucle infinie. Beaucoup d’entre vous ont sans doute été avertis du danger des boucles infinies et de la façon dont elles peuvent faire planter une machine. Comme vous l’avez peut-être remarqué, nous avons utilisé une déclaration de sommeil après le premier scan. Nous l’utiliserons à nouveau dans notre boucle forever et certaines des fonctions qu’elle inclut. La mise en veille permet à l’exécution de s’interrompre et de redonner temporairement des ressources à l’ordinateur. J’ai testé ce script sur un processeur assez modeste et je n’ai rencontré aucun problème. Mais si vous utilisez une machine très ancienne, ou si vous avez déjà des ressources sollicitées, vous pouvez modifier le nombre de secondes pendant lesquelles la veille est utilisée ici.

La première chose que notre boucle forever fera est de passer à la fonction nommée engine(). Ce que nous faisons ici est exactement la même chose que notre premier balayage, sauf que nous le mettons dans un tableau différent. Une fois cette fonction exécutée, nous revenons maintenant à notre boucle forever où une instruction if comparera si ces deux tableaux sont identiques. S’ils sont identiques, le tableau du deuxième balayage sera vidé pour éviter les valeurs en double lors de l’itération suivante de la boucle. Cependant, si la valeur est une différence dans ces deux tableaux, nous passerons à la clause else qui nous redirige vers notre fonction d’interruption.

Si l’adresse mac existe, nous l’ajoutons à une règle iptables qui bloquera cet utilisateur de toute connexion à notre ordinateur. Je dois noter ici que cela ne vous empêche pas d’envoyer des paquets à cette machine, mais seulement le trafic entrant vers vous. Cependant, cela ne protège pas l’ensemble de votre réseau. Uniquement la machine que vous utilisez jusqu’à ce que vos règles iptables soient vidées. Si vous bloquez accidentellement un client auquel vous devez vous connecter, vous pouvez libérer cette règle avec quelques commandes iptables simples. L’instruction if continue en indiquant à l’utilisateur que l’adresse mac de l’adresse IP saisie est maintenant bloquée et affiche les clients actuels en ligne. Le client bloqué apparaîtra toujours dans cette liste car nous l’avons uniquement bloqué pour nous, pas pour le réseau. Si l’utilisateur avait choisi de ne pas bloquer un client, nous aurions simplement affiché le changement sur le réseau et retourné à notre boucle permanente.

Indépendamment de ce que l’utilisateur a fait dans la fonction d’interruption, nous devons maintenant mettre à jour les valeurs de nos tableaux. Étant donné que le deuxième tableau contient actuellement les nouvelles valeurs de notre réseau, nous devons les transmettre à l’autre tableau avant que la fonction du moteur ne le remplisse à nouveau. Nous effacons d’abord ce tableau pour éviter les valeurs en double, puis nous copions le contenu du deuxième tableau dans le premier tableau. Maintenant, utilisez empty le deuxième tableau et nous sommes prêts à recommencer la boucle avec la fonction moteur.

Bien sûr, il y avait une fonction que j’ai sautée jusqu’à présent. Vous avez peut-être remarqué que notre premier message à l’utilisateur disait d’appuyer sur Ctrl-C à tout moment pour bloquer des clients supplémentaires ou quitter. Notre piège appelle la première fonction nommée control_c(). Tout ce que j’ai fait ici, c’est demander à l’utilisateur dans une instruction if s’il veut bloquer un utilisateur presque de la même manière qu’avant. Vous remarquerez que si l’utilisateur répond oui à l’instruction if, il y a une nouvelle ligne ici. « bash leecher.sh » est utilisé pour redémarrer ce script. Si vous avez nommé ce script d’une manière différente, vous devez le fournir ici. Nous réexécutons notre script car l’interruption veut toujours envoyer SIGINT et tuer le script. La création d’une nouvelle instance empêche le script de mourir involontairement. Toutefois, la création de la nouvelle instance ne permet pas à SIGINT de se terminer.

Vous avez peut-être également remarqué que nous avons également utilisé le sommeil un peu plus longtemps. C’est uniquement pour donner à l’utilisateur le temps de lire ce qui se passe avant de passer à notre nouvelle instance du script qui prendra le relais de ce terminal. Si l’utilisateur avait choisi « non » au lieu de « oui », la clause else permettrait simplement au script de se terminer. Nous nous assurerons également d’utiliser setterm pour retourner notre curseur, sinon nous n’en aurons pas dans ce terminal même si le script est sorti.

Le but d’avoir un blocage à la volée est facile. Il se peut que vous ayez plus d’un client à bloquer s’il y a plusieurs clients agressifs. Vous pouvez décider plus tard, après avoir sauté la chance, de bloquer un client dans la fonction d’interruption dont vous avez besoin. Ou peut-être savez-vous que quelque chose ne va pas dès que vous commencez le script. Si aucun nouveau client n’arrivait ou ne partait sur le réseau en question, nous n’aurions aucune chance de bloquer quoi que ce soit jusqu’à ce qu’ils le fassent.

Comment ce script peut être amélioré

De toute évidence, entendre la cloche du système se déclencher constamment pour les faux positifs peut être ennuyeux. Rendre ce script capable de mettre sur liste blanche des clients en qui vous avez confiance réduirait probablement cela. La cloche du système peut certainement être gênante si une personne a du mal à rester connectée pendant de longues périodes.
Parfois, vous remarquerez peut-être que certains clients passent de l’adresse IP aux noms d’hôte. De nombreux programmes, comme Etherape, font la même chose. Si votre routeur agit comme votre DNS affichera probablement le nom d’hôte en continu. Je ne pense pas qu’aucun d’entre vous ne voudra bloquer les connexions avec votre routeur. Cependant, proposer un paramètre pour passer à l’adresse IP uniquement pourrait être intéressant pour certains d’entre vous.
Il y a aussi un petit problème avec la bifurcation de script lorsqu’un utilisateur bloque un client avec Control-C. Cela ne présente aucun danger, sauf si un utilisateur décide de bloquer des milliers de clients avec Control-C. Cependant, toutes les instances du script sont tuées à la sortie. Mais puisque nous optons pour le basic ici, cela devrait aller.

Un système de détection d’intrusion avec BASH

#!/bin/bash

Interupt and Exit Function
control_c()
{
   clear
   echo -e "Would you like to block connections with a client?\n"
   echo -e "Enter y or n: "
   read yn

    if [ "$yn" == "y" ]; then

      echo -e "\nEnter Ip Address to Block: \n"
      read ip

                if [ -n $ip ]; then

                        echo -e "\nNow retrieving mac address to block...\n"
                        ping -c 1 $ip > /dev/null
                        mac=`arp $ip | grep ether | awk '{ print $3 }'`

                        if [ -z $mac ]; then
                                clear
                                echo -e "\n***Client does not exist or is no longer\
                                         on this network***"
                                echo -e "\nSkipping action and resuming monitoring.\n\n"
                                sleep 2
                                bash leecher.sh
                                exit 0

                        else
                                iptables -A INPUT -m mac --mac-source $mac -j DROP
                                clear
                                echo -e "\nClient with mac address $mac is now\
                                          blocked.\n"
                                echo -e "We will continue monitoring for changes\
                                         in clients\n\n"
                                sleep 2
                                bash leecher.sh
                                exit 0
                        fi
                fi


    else
          clear
          echo -e "\n\nLeecher has exited\n\n"
          setterm -cursor on
          rm -f $pid
          exit 0
    fi
}

Print the scan from the engine()
twice(){
  g=0
  len=${#second[@]}
  for (( g = 0; g < $len; g++ ));
  do
       echo -e "${second[$g]}\n"
  done
}

If there's a change in the network, ask to block ips.
interupt(){
   clear
   echo -e "\nList of Clients has Changed!\n"
   twice
   echo -e '\a'
   echo -e "Would you like to block connections with a client?\n"
   echo -e "Enter y or n: "
   read yn

   if [ "$yn" == "y" ]; then

      echo -e "\nEnter Ip Address to Block: \n"
      read ip
                if [ -n $ip ]; then
                        ping -c 1 $ip > /dev/null
                        mac=`arp $ip | grep ether | awk '{ print $3 }'`

                        if [ -z $mac ]; then
                                clear
                                echo -e "\n***Client does not exist or is no longer on\
                                         this network***"
                                echo -e "\nSkipping action and resuming monitoring.\n\n"
                        else
                                iptables -A INPUT -m mac --mac-source $mac -j DROP
                                clear
                                echo -e "\nClient with mac address $mac is now blocked.\n"
                                echo -e "We will continue monitoring for changes\
                                         in clients\n\n"
                                echo -e "Current clients are: \n"
                                twice
                                echo -e "\nResuming monitoring..."
                        fi
                fi
    else
           clear
           echo -e "Current clients are: \n"
           twice
           echo -e "Resuming monitoring..."
    fi
}

Function to keep monitoring for any changes
engine()
{
        # Scan networks again for comparison of changes.
        for subnet in $(/sbin/ifconfig | awk '/inet addr/ && !/127.0.0.1/ && !a[$2]++\
                        {print substr($2,6)}')
        do
                  second+=( "$(nmap -sP ${subnet%.*}.0/24 | awk 'index($0,t)\
                  { print $i }' t="$t" i="$i" )" )
                  sleep 1
        done
}

Make sure user is logged in as root
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 1>&2
   exit 1
fi

Check if nmap is installed
ifnmap=`type -p nmap`
        if [ -z $ifnmap ]; then

                echo -e "\n\nNmap must be installed for this program to work\n"
                echo -e "Only Nmap 5.00 and 5.21 are supported at this time\n"
                echo -e "Please install and try again"
                exit 0
        fi

clear
echo -e "\nNow finding clients on your local network(s)"
echo -e "Press Control-C at any time to block additional clients or exit\n"


Remove temp files on exit and allow Control-C to exit.
trap control_c SIGINT

Turn off cursor
setterm -cursor off

Make some arrays and variables
declare -a first
declare -a second
sid=5.21

Check for which version of nmap
if [ 5.21 = $(nmap --version | awk '/Nmap/ { print $3 }') ]; then
    i=5  t=report
else
    i=2  t=Host
fi

Get ip's from interfaces and run the first scan
for subnet in $(/sbin/ifconfig | awk '/inet addr/ && !/127.0.0.1/ && !a[$2]++ {print \
                substr($2,6)}')
do
          first+=( "$(nmap -sP ${subnet%.*}.0/24 | awk 'index($0,t) { print $i }' \
                  t="$t" i="$i" )" )
          sleep 1
done

                echo -e "Current clients are: \n"

                        #Display array elements and add new lines
                        e=0
                        len=${#first[@]}
                        for (( e = 0; e < $len; e++ ));
                        do
                                echo -e "${first[$e]}\n"
                        done

                echo -e "Leecher is now monitoring for new clients."
                echo -e "\nAny changes with clients will be reported by the system bell."
                echo -e "If bell is not enabled details will log to this console."

Forever loop to keep monitoring constant
for ((  ;  ; ))
do
        engine

        if [[ ${first[@]} == ${second[@]} ]]; then

                second=( )
        else
                interupt
                sleep 1
                first=( )
                first=("${second[@]}")
                second=( )
        fi

done

Exemple de sortie

Now finding clients on your local network(s)
Press Control-C at any time to block additional clients or exit

Current clients are: 

192.168.12.1
192.168.12.9
192.168.12.43

Mephistolist
10.0.0.121
10.0.0.137
10.0.0.140

Leecher is now monitoring for new clients.

Any changes with clients will be reported by the system bell.
If bell is not enabled details will log to this console.

==============================================================

List of Clients has Changed!

192.168.12.9
192.168.12.43

Mephistolist
10.0.0.140


Would you like to block connections with a client?

Enter y or n: 
y

Enter Ip Address to Block: 

192.168.12.9

============================================================

Client with mac address 7c:ed:8d:9c:93:8e is now blocked.

We will continue monitoring for changes in clients

============================================================

Articles connexes: