Le livre "Bash et cybersécurité: attaque, défense et analyse depuis la ligne de commande Linux"

imageBonjour, habrozhiteli! La ligne de commande peut être un outil idéal pour la cybersécurité. Une flexibilité incroyable et une disponibilité absolue font de l'interface de ligne de commande standard (CLI) une solution fondamentale si vous avez l'expérience appropriée.

Les auteurs Paul Tronkon et Karl Albing parlent des outils et des astuces de la ligne de commande qui aident à collecter des données avec une protection proactive, à analyser les journaux et à surveiller l'état du réseau. Les pentesters apprendront à mener des attaques en utilisant une fonctionnalité colossale intégrée à presque toutes les versions de Linux.


Pour qui est ce livre?


Le livre "Bash et cybersécurité" est destiné à ceux qui veulent apprendre à travailler avec la ligne de commande dans le cadre de la sécurité informatique. Notre objectif n'est pas de remplacer les outils existants par des scripts de ligne de commande, mais plutôt de vous apprendre à utiliser efficacement la ligne de commande pour améliorer les fonctionnalités existantes.

Tout au long du livre, nous fournissons des exemples de méthodes de sécurité telles que la collecte de données, l'analyse et les tests de pénétration. Le but de ces exemples est de démontrer les capacités de la ligne de commande et de vous présenter certaines des méthodes fondamentales utilisées dans les outils de niveau supérieur.

Ce livre n'est pas une introduction à la programmation, bien que certains concepts généraux soient traités dans la partie I.

Surveillance des journaux en temps réel


La capacité d'analyser un magazine après qu'un événement s'est produit est une compétence importante. Mais il est tout aussi important de pouvoir extraire des informations du fichier journal en temps réel afin de détecter les actions malveillantes ou suspectes au moment où elles se produisent. Dans ce chapitre, nous examinerons les méthodes de lecture des écritures au fur et à mesure qu'elles sont créées et formatées pour afficher des analyses et générer des alertes basées sur des indicateurs de menace connus pour le fonctionnement d'un système ou d'un réseau (indicateurs de compromis).

Surveillance du journal de texte


La façon la plus simple de surveiller le journal en temps réel est d'utiliser la commande tail avec le paramètre –f - elle lit en continu le fichier et les affiche dans stdout à mesure que de nouvelles lignes sont ajoutées. Comme dans les chapitres précédents, pour des exemples, nous utiliserons le journal d'accès au serveur Web Apache, mais les méthodes décrites sont pertinentes pour tout journal de texte. Pour suivre le journal d'accès Apache à l'aide de la commande tail, entrez ce qui suit:

tail -f /var/logs/apache2/access.log

La sortie de la commande tail peut être transmise à la commande grep, donc seuls les enregistrements correspondant à certains critères seront affichés. L'exemple suivant suit le journal d'accès Apache et affiche les entrées correspondant à une adresse IP spécifique:

tail -f /var/logs/apache2/access.log | grep '10.0.0.152'

Vous pouvez également utiliser des expressions régulières. Dans cet exemple, seuls les enregistrements renvoyant le code d'état HTTP 404 «Page non trouvée» seront affichés; l'option -i est ajoutée pour ignorer la casse des caractères:

tail -f /var/logs/apache2/access.log | egrep -i 'HTTP/.*" 404'

Pour effacer les informations superflues, la sortie doit être passée à la commande cut. Cet exemple surveille le journal d'accès pour les requêtes menant au code d'état 404, puis utilise la méthode cut pour afficher uniquement la date / heure et la page demandée: Ensuite, pour supprimer les crochets et les guillemets doubles, vous pouvez diriger la sortie vers tr -d ' [] "'.

$ tail -f access.log | egrep --line-buffered 'HTTP/.*" 404' | cut -d' ' -f4-7
[29/Jul/2018:13:10:05 -0400] "GET /test
[29/Jul/2018:13:16:17 -0400] "GET /test.txt
[29/Jul/2018:13:17:37 -0400] "GET /favicon.ico




Remarque: l'option --line-buffering de la commande egrep est utilisée ici. Cela force egrep à imprimer sur stdout chaque fois qu'un saut de ligne se produit. Sans ce paramètre, la mise en mémoire tampon se produira et la sortie ne sera pas envoyée à la commande cut tant que la mémoire tampon n'est pas pleine. Nous ne voulons pas attendre aussi longtemps. Cette option permet à la commande egrep d'écrire chaque ligne telle qu'elle est trouvée.

TAMPONS DE LIGNE DE COMMANDE

Que se passe-t-il pendant la mise en mémoire tampon? Imaginez que egrep trouve un grand nombre de chaînes correspondant au modèle spécifié. Dans ce cas, egrep aura beaucoup de sortie. Mais la sortie (en fait, toute entrée ou sortie) coûte beaucoup plus cher (prend plus de temps) que le traitement des données (recherche de texte). Ainsi, moins il y aura d'appels d'E / S, plus le programme sera efficace.

grep , , . . grep . , grep 50 . , 50 , , . 50 !

egrep, , . egrep , , . , , , , . , .

, , tail -f ( ), . , « », . . .

, egrep , . , .


Vous pouvez utiliser les commandes tail et egrep pour surveiller le journal et afficher toutes les entrées qui correspondent à des schémas connus d'activité suspecte ou malveillante, souvent appelés IOC. Vous pouvez créer un système de détection d'intrusion (IDS) simple. Créez d'abord un fichier contenant les modèles d'expression régulière pour l'IOC, comme illustré dans l'exemple 8.1.

Exemple 8.1. ioc.txt (1) Ce modèle (../) est un indicateur d'une attaque de répertoire détourné: un attaquant tente de quitter le répertoire de travail en cours et d'accéder à des fichiers qui ne lui sont pas accessibles. (2) Les fichiers Linux etc / passwd et etc / shadow sont utilisés pour l'authentification du système et ne doivent jamais être accessibles via un serveur Web. (3)

\.\./ (1)
etc/passwd (2)
etc/shadow
cmd\.exe (3)
/bin/sh
/bin/bash





Le traitement des fichiers cmd.exe, / bin / sh ou / bin / bash est une indication de la connexion inverse renvoyée par le serveur Web. Une connexion inverse indique souvent une tentative d'opération réussie.

Notez que les IOC doivent être au format regex, car ils seront utilisés plus tard par la commande egrep.

Le fichier ioc.txt peut être utilisé avec l'option egrep -f. Ce paramètre indique à egrep de rechercher les modèles d'expression régulière dans le fichier spécifié. Cela vous permet d'utiliser la commande tail pour surveiller le fichier journal et, à mesure que chaque enregistrement est ajouté, la ligne de lecture est comparée à tous les modèles du fichier IOC, affichant tout enregistrement correspondant. Voici un exemple:

tail -f /var/logs/apache2/access.log | egrep -i -f ioc.txt

De plus, la commande tee peut être utilisée pour afficher simultanément des avertissements à l'écran et les enregistrer pour un traitement ultérieur dans son propre fichier: Encore une fois, l'option --line-buffered est nécessaire pour garantir qu'aucun problème ne soit causé par la mise en mémoire tampon de la sortie de la commande.

tail -f /var/logs/apache2/access.log | egrep --line-buffered -i -f ioc.txt |
tee -a interesting.txt




Surveillance des journaux Windows


Comme déjà mentionné, vous devez utiliser la commande wevtutil pour accéder aux événements Windows. Bien que cette commande soit universelle, elle n'a pas de fonctionnalité telle que tail, qui peut être utilisée pour récupérer de nouveaux enregistrements entrants. Mais il existe un moyen de sortir - utilisez un simple script bash qui peut fournir les mêmes fonctionnalités (exemple 8.2).

Exemple 8.2. wintail.sh

#!/bin/bash -
#
# Bash  
# wintail.sh
#
# :
#    tail   Windows
#
# : ./wintail.sh
#

WINLOG="Application" (1)

LASTLOG=$(wevtutil qe "$WINLOG" //c:1 //rd:true //f:text) (2)

while true
do
      CURRENTLOG=$(wevtutil qe "$WINLOG" //c:1 //rd:true //f:text) (3)
      if [[ "$CURRENTLOG" != "$LASTLOG" ]]
      then
            echo "$CURRENTLOG"
            echo "----------------------------------"
            LASTLOG="$CURRENTLOG"
      fi
done

(1) Cette variable définit le journal Windows que vous souhaitez suivre. Pour obtenir la liste des journaux actuellement disponibles sur le système, vous pouvez utiliser la commande wevtutil el.

(2) Ici, wevtutil est exécuté pour demander le fichier journal spécifié. Le paramètre c: 1 renvoie une seule entrée de journal. Le paramètre rd: true permet à la commande de lire l'entrée de journal la plus récente. Enfin, f: text renvoie le résultat en texte brut, pas au format XML, ce qui facilite la lecture du résultat à l'écran.

(3)Les quelques lignes suivantes exécutent à nouveau la commande wevtutil et l'entrée de journal nouvellement reçue est comparée à la dernière imprimée à l'écran. S'ils diffèrent les uns des autres, cela signifie qu'il y a eu des modifications dans le journal. Dans ce cas, une nouvelle entrée s'affiche. Si les enregistrements comparés sont identiques, rien ne se produit et la commande wevtutil revient en arrière et recommence la recherche et la comparaison.

Création d'histogramme en temps réel


La commande tail -f fournit le flux de données actuel. Mais que se passe-t-il si vous souhaitez compter le nombre de lignes qui ont été ajoutées au fichier pendant un certain temps? Vous pouvez observer ce flux de données, démarrer une minuterie et effectuer un comptage sur une période de temps spécifiée; alors le comptage doit être arrêté et les résultats rapportés.

Ce travail peut être divisé en deux processus de script: un script lira les lignes et l'autre surveillera l'heure. Le temporisateur notifie le compteur de lignes à l'aide d'un mécanisme de communication interprocessus POSIX standard appelé signal. Un signal est une interruption logicielle et il existe différents types de signaux. Certains d'entre eux sont fatals - ils conduisent à la fin du processus (par exemple, une exception dans une opération à virgule flottante). La plupart de ces signaux peuvent être ignorés ou capturés. Une action est entreprise lorsqu'un signal est capté. Beaucoup de ces signaux ont une fonction prédéfinie dans le système d'exploitation. Nous utiliserons l'un des deux signaux disponibles pour les utilisateurs. Il s'agit du signal SIGUSR1 (l'autre est SIGUSR2).

Les scripts shell peuvent intercepter des interruptions à l'aide de la commande trap intégrée. Avec son aide, vous pouvez sélectionner une commande qui détermine l'action que vous souhaitez effectuer lorsqu'un signal est reçu, et une liste de signaux qui déclenchent un appel à cette commande. Par exemple:

trap warnmsg SIGINT

cela provoque l'appel de la commande warnmsg (notre propre script ou fonction) chaque fois que le script shell reçoit un signal SIGINT, par exemple, lorsque vous appuyez sur Ctrl + C pour interrompre un processus en cours d'exécution.

L'exemple 8.3 montre un script qui effectue un comptage.

Exemple 8.3 looper.sh

#!/bin/bash -
#
# Bash  
# looper.sh
#
# :
#    
#
# : ./looper.sh [filename]
# filename —  ,   ,
#  : log.file
#

function interval ()                                           (1)
{
      echo $(date '+%y%m%d %H%M%S') $cnt                       (2)
      cnt=0
}

declare -i cnt=0
trap interval SIGUSR1                                          (3)

shopt -s lastpipe                                              (4)

tail -f --pid=$$ ${1:-log.file} | while read aline             (5)
do
     let cnt++
done

(1) La fonction d'intervalle sera appelée à la réception de chaque signal. Bien sûr, l'intervalle doit être défini avant de pouvoir le nommer et utiliser trap dans notre expression.

(2) La commande date est invoquée pour fournir un horodatage pour la valeur de la variable cnt que nous imprimons. Une fois le compteur affiché, nous remettons cette valeur à 0 pour commencer le compte à rebours de l'intervalle suivant.

(3) Maintenant que l'intervalle est défini, nous pouvons indiquer que la fonction est appelée chaque fois que notre processus reçoit le signal SIGUSR1.

(4)Ceci est une étape très importante. Habituellement, lorsqu'il existe un pipeline de commandes (par exemple, ls-l | grep rwx | wc), des parties du pipeline (chaque commande) sont exécutées sur des sous-réseaux et chaque processus se termine par son propre identificateur de processus. Cela pourrait être un problème pour ce scénario, car la boucle while sera dans un sous-shell avec un identificateur de processus différent. Quel que soit le processus démarré, le script looper.sh ne connaîtra pas l'identifiant du processus de boucle while pour lui envoyer un signal. En outre, la modification de la valeur de la variable cnt dans le sous-shell ne modifie pas la valeur cnt dans le processus principal, de sorte que le signal du processus principal définira à chaque fois la valeur sur 0. Vous pouvez résoudre ce problème avec la commande shopt, qui définit le paramètre (-s) sur lastpipe. Il indique au shell de ne pas créer de sous-shell pour la dernière commande du pipeline,et exécutez cette commande dans le même processus que le script lui-même. Dans notre cas, cela signifie que la commande tail sera exécutée dans un sous-shell (c'est-à-dire dans un autre processus), et la boucle while fera partie du processus de script principal. Remarque: cette option de shell est disponible uniquement dans la version bash 4.x et supérieure et uniquement pour les shells non interactifs (c'est-à-dire les scripts).

(5) Il s'agit de la commande tail -f avec un autre paramètre --pid. Nous indiquons l'identifiant du processus qui, à la fin de ce processus, mettra fin à la commande tail. Nous spécifions l'ID de processus du script shell courant $$ à afficher. Cette action vous permet de nettoyer les processus et de ne pas laisser la commande tail exécutée en arrière-plan (si, par exemple, ce script s'exécute en arrière-plan; exemple 8.4).

Le script tailcount.sh démarre et arrête le script avec un chronomètre (timer) et compte les intervalles de temps.

Exemple 8.4. tailcount.sh

#!/bin/bash -
#
# Bash  
# tailcount.sh
#
# :
#    n 
#
# : ./tailcount.sh [filename]
#     filename:  looper.sh
#

#  —    
function cleanup ()
{
      [[ -n $LOPID ]] && kill $LOPID          (1)
}

trap cleanup EXIT                             (2)
bash looper.sh $1 &                           (3)
LOPID=$!                                      (4)
#   
sleep 3

while true
do
      kill -SIGUSR1 $LOPID
      sleep 5
done >&2                                      (5)

(1) Étant donné que ce script exécutera d'autres scripts, il devrait être nettoyé après le travail. Si l'identifiant du processus a été stocké dans LOPID, la variable stockera la valeur, donc la fonction enverra un signal à ce processus en utilisant la commande kill. Si vous ne spécifiez pas de signal spécifique dans la commande kill, le signal SIGTERM sera envoyé par défaut.

(2) La commande EXIT n'est pas un signal. Il s'agit d'un cas particulier lorsque l'instruction trap indique au shell d'appeler cette fonction (dans ce cas le nettoyage) si le shell exécutant ce script est sur le point de s'arrêter.

(3)Maintenant, le vrai travail commence. Le script looper.sh est lancé, qui s'exécutera en arrière-plan: pour que ce script fonctionne tout au long du cycle (sans attendre que la commande termine le travail), il est déconnecté du clavier.

(4) Ici, l'identifiant du processus de script que nous venons de démarrer en arrière-plan est stocké.

(5) Cette redirection est simplement une précaution. Toutes les sorties provenant d'une boucle while ou des instructions kill / sleep (bien que nous ne nous y attendions pas) ne doivent pas être mélangées avec des sorties de la fonction looper.sh, qui, bien que fonctionnant en arrière-plan, les envoie quand même à stdout. Par conséquent, nous redirigeons les données de stdout vers stderr.

Pour résumer, nous voyons que bien que la fonction looper.sh ait été placée en arrière-plan, son identifiant de processus est stocké dans une variable shell. Toutes les cinq secondes, le script tailcount.sh envoie un signal SIGUSR1 à ce processus (qui est exécuté dans la fonction looper.sh), qui, à son tour, appelle le script looper.sh pour imprimer le nombre actuel de lignes qui y sont fixées et redémarrer le décompte. Après avoir quitté, le script tailcount.sh sera effacé en envoyant un signal SIGTERM à la fonction looper.sh pour l'interrompre.

À l'aide de deux scripts - un script qui effectue le comptage de lignes et un script avec un chronomètre (minuterie) qui contrôle le premier script - vous pouvez obtenir une sortie (le nombre de lignes pour une certaine période), sur la base de laquelle le script suivant construira un histogramme. Cela s'appelle comme ceci:

bash tailcount.sh | bash livebar.sh

Le script livebar.sh lit les données de stdin et imprime la sortie sur stdout, une ligne pour chaque ligne d'entrée (exemple 8.5).

Exemple 8.5 livebar.sh

#!/bin/bash -
#
# Bash  
# livebar.sh
#
# :
#    «» 
#
# :
# <output from other script or program> | bash livebar.sh
#

function pr_bar ()                                         (1)
{
      local raw maxraw scaled
      raw=$1
      maxraw=$2
      ((scaled=(maxbar*raw)/maxraw))
      ((scaled == 0)) && scaled=1 #   
      for((i=0; i<scaled; i++)) ; do printf '#' ; done
      printf '\n'

} # pr_bar

maxbar=60     #         (2)
MAX=60
while read dayst timst qty
do
      if (( qty > MAX ))                                   (3)
      then
           let MAX=$qty+$qty/4    #   
           echo "                      **** rescaling: MAX=$MAX"
      fi
      printf '%6.6s %6.6s %4d:' $dayst $timst $qty         (4)
      pr_bar $qty $MAX
done

(1) La fonction pr_bar affiche une chaîne de hashtags qui sont mis à l'échelle en fonction des paramètres fournis à la taille maximale. Cette fonctionnalité peut sembler familière, comme nous l'avons précédemment utilisée dans le script histogram.sh.

(2) Il s'agit de la taille de ligne de hashtag la plus longue que nous pouvons autoriser (à faire sans retour à la ligne).

(3)Quelle sera la taille des valeurs à afficher? Sans le savoir à l'avance (bien que ces données puissent être fournies au script comme argument), le script suivra le maximum. Si ce maximum est dépassé, la valeur commencera à «mettre à l'échelle» et les lignes qui sont maintenant affichées, et les lignes futures seront également mises à l'échelle à un nouveau maximum. Le script ajoute 25% à la valeur maximale, il n'a donc pas à mettre à l'échelle la valeur si la nouvelle valeur suivante augmente à chaque fois de 1 à 2% seulement.

(4)printf définit la largeur minimale et maximale des deux premiers champs à imprimer. Ce sont des horodatages qui seront tronqués si les valeurs de largeur sont dépassées. Pour afficher la valeur entière, spécifiez sa largeur de quatre caractères. Dans ce cas, malgré les restrictions, toutes les valeurs seront imprimées. Si le nombre de caractères dans les valeurs est inférieur à quatre, les caractères manquants seront complétés par des espaces.

Comme ce script est lu depuis stdin, vous pouvez l'exécuter vous-même pour voir comment il se comporte. Voici un exemple:

$ bash  livebar.sh
201010 1020 20
201010     1020 20:####################
201010 1020 70
                       **** rescaling: MAX=87
201010     1020 70:################################################
201010 1020 75
201010 1020 75:###################################################
^C

Dans cet exemple, l'entrée est mélangée à la sortie. Vous pouvez également mettre une entrée dans un fichier et la rediriger vers un script pour ne voir que la sortie:

$ bash livebar.sh < testdata.txt
bash livebar.sh < x.data
201010 1020 20:####################
                 **** rescaling: MAX=87
201010 1020 70:################################################
201010 1020 75:###################################################
$

»Plus d'informations sur le livre peuvent être trouvées sur le site Web de l'éditeur
» Contenu
» Extrait

pour Khabrozhiteley 25% de réduction sur le coupon - Bash

Lors du paiement de la version papier du livre, un livre électronique est envoyé par e-mail.

All Articles