Das Buch "Bash and Cybersecurity: Angriff, Verteidigung und Analyse über die Linux-Befehlszeile"

BildHallo habrozhiteli! Die Befehlszeile kann ein ideales Werkzeug für die Cybersicherheit sein. Unglaubliche Flexibilität und absolute Verfügbarkeit machen die Standard-Befehlszeilenschnittstelle (CLI) zu einer grundlegenden Lösung, wenn Sie über die entsprechende Erfahrung verfügen.

Die Autoren Paul Tronkon und Karl Albing sprechen über Befehlszeilentools und Tricks, mit denen Sie Daten mit proaktivem Schutz sammeln, Protokolle analysieren und den Netzwerkzustand überwachen können. Pentester lernen, wie man Angriffe mit kolossalen Funktionen ausführt, die in fast jede Linux-Version integriert sind.


Für wen ist dieses Buch?


Das Buch "Bash and Cybersecurity" richtet sich an diejenigen, die lernen möchten, wie man im Kontext der Computersicherheit mit der Befehlszeile arbeitet. Unser Ziel ist es nicht, vorhandene Tools durch Befehlszeilenskripte zu ersetzen, sondern Ihnen beizubringen, wie Sie die Befehlszeile effektiv nutzen können, um vorhandene Funktionen zu verbessern.

Im gesamten Buch finden Sie Beispiele für Sicherheitsmethoden wie Datenerfassung, Analyse und Penetrationstests. Der Zweck dieser Beispiele besteht darin, die Befehlszeilenfunktionen zu demonstrieren und Ihnen einige der grundlegenden Methoden vorzustellen, die in übergeordneten Tools verwendet werden.

Dieses Buch ist keine Einführung in die Programmierung, obwohl einige allgemeine Konzepte in Teil I behandelt werden.

Protokollüberwachung in Echtzeit


Die Fähigkeit, ein Magazin nach dem Eintreten eines Ereignisses zu analysieren, ist eine wichtige Fähigkeit. Genauso wichtig ist es jedoch, Informationen in Echtzeit aus der Protokolldatei extrahieren zu können, um böswillige oder verdächtige Aktionen zum Zeitpunkt ihres Auftretens zu erkennen. In diesem Kapitel werden Methoden zum Lesen von Journaleinträgen betrachtet, wenn diese erstellt und formatiert werden, um Analysen anzuzeigen und Warnungen basierend auf bekannten Bedrohungsindikatoren für den Betrieb eines Systems oder Netzwerks zu generieren (Indikatoren für Kompromisse).

Textprotokollüberwachung


Die einfachste Möglichkeit, das Protokoll in Echtzeit zu überwachen, besteht darin, den Befehl tail mit dem Parameter –f zu verwenden. Er liest die Datei kontinuierlich und zeigt sie in stdout an, wenn neue Zeilen hinzugefügt werden. Wie in den vorherigen Kapiteln wird beispielsweise das Zugriffsprotokoll des Apache-Webservers verwendet, die beschriebenen Methoden sind jedoch für jedes Textprotokoll relevant. Geben Sie Folgendes ein, um das Apache-Zugriffsprotokoll mit dem Befehl tail zu verfolgen:

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

Die Ausgabe des Befehls tail kann an den Befehl grep übergeben werden, sodass nur Datensätze angezeigt werden, die bestimmten Kriterien entsprechen. Im folgenden Beispiel wird das Apache-Zugriffsprotokoll verfolgt und Einträge angezeigt, die einer bestimmten IP-Adresse entsprechen:

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

Sie können auch reguläre Ausdrücke verwenden. In diesem Beispiel werden nur Datensätze angezeigt, die den HTTP 404-Statuscode "Seite nicht gefunden" zurückgeben. Die Option -i wird hinzugefügt, um den Fall von Zeichen zu ignorieren:

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

Um fremde Informationen zu löschen, sollte die Ausgabe an den Befehl cut übergeben werden. In diesem Beispiel wird das Zugriffsprotokoll auf Abfragen überwacht, die zum Statuscode 404 führen, und anschließend mit der Schnittmethode nur das Datum / die Uhrzeit und die angeforderte Seite angezeigt: Um die eckigen Klammern und doppelten Anführungszeichen zu entfernen, können Sie die Ausgabe an tr -d 'weiterleiten. [] "'.

$ 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




Hinweis: Hier wird die Option --line-buffering des Befehls egrep verwendet. Dies zwingt egrep, jedes Mal, wenn ein Zeilenumbruch auftritt, auf stdout zu drucken. Ohne diesen Parameter erfolgt eine Pufferung und die Ausgabe wird erst an den Befehl cut gesendet, wenn der Puffer voll ist. Wir wollen nicht so lange warten. Mit dieser Option kann der Befehl egrep jede gefundene Zeile schreiben.

BEFEHLSLINIENPUFFER

Was passiert beim Puffern? Stellen Sie sich vor, egrep findet viele Zeichenfolgen, die dem angegebenen Muster entsprechen. In diesem Fall wird egrep viel ausgegeben. Die Ausgabe (in der Tat jede Eingabe oder Ausgabe) ist jedoch viel teurer (nimmt mehr Zeit in Anspruch) als die Datenverarbeitung (Textsuche). Je weniger E / A-Aufrufe vorhanden sind, desto effizienter ist das Programm.

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

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

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

, egrep , . , .


Mit den Befehlen tail und egrep können Sie das Protokoll überwachen und alle Einträge anzeigen, die bekannten Mustern verdächtiger oder böswilliger Aktivitäten entsprechen, die häufig als IOCs bezeichnet werden. Sie können ein einfaches Intrusion Detection System (IDS) erstellen. Erstellen Sie zunächst eine Datei mit den Mustern für reguläre Ausdrücke für das IOC (siehe Beispiel 8.1).

Beispiel 8.1. ioc.txt (1) Diese Vorlage (../) ist ein Indikator für einen Verzeichnis-Bypass-Angriff: Ein Angreifer versucht, das aktuelle Arbeitsverzeichnis zu verlassen und auf Dateien zuzugreifen, auf die er nicht zugreifen kann. (2) Linux-Dateien etc / passwd und etc / shadow werden zur Authentifizierung des Systems verwendet und sollten niemals über einen Webserver aufgerufen werden. (3)

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





Das Bereitstellen der Dateien cmd.exe, / bin / sh oder / bin / bash ist ein Hinweis auf die vom Webserver zurückgegebene umgekehrte Verbindung. Eine umgekehrte Verbindung zeigt häufig einen erfolgreichen Betriebsversuch an.

Beachten Sie, dass IOCs im Regex-Format vorliegen müssen, da sie später vom Befehl egrep verwendet werden.

Die Datei ioc.txt kann mit der Option egrep -f verwendet werden. Dieser Parameter weist egrep an, die Muster für reguläre Ausdrücke aus der angegebenen Datei zu durchsuchen. Auf diese Weise können Sie den Befehl tail verwenden, um die Protokolldatei zu überwachen. Wenn jeder Datensatz hinzugefügt wird, wird die Lesezeile mit allen Vorlagen in der IOC-Datei verglichen und der entsprechende Datensatz angezeigt. Hier ist ein Beispiel:

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

Darüber hinaus kann der Befehl tee verwendet werden, um Warnungen gleichzeitig auf dem Bildschirm anzuzeigen und zur späteren Verarbeitung in einer eigenen Datei zu speichern: Auch hier ist die Option --line-buffered erforderlich, um sicherzustellen, dass keine Probleme durch das Puffern der Ausgabe des Befehls auftreten.

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




Windows-Protokollüberwachung


Wie bereits erwähnt, müssen Sie den Befehl wevtutil verwenden, um auf Windows-Ereignisse zuzugreifen. Obwohl dieser Befehl universell ist, verfügt er nicht über Funktionen wie tail, mit denen neue eingehende Datensätze abgerufen werden können. Es gibt jedoch einen Ausweg: Verwenden Sie ein einfaches Bash-Skript, das dieselbe Funktionalität bietet (Beispiel 8.2).

Beispiel 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) Diese Variable definiert das Windows-Protokoll, das Sie verfolgen möchten. Für eine Liste der derzeit auf dem System verfügbaren Protokolle können Sie den Befehl wevtutil el verwenden.

(2) Hier wird wevtutil ausgeführt, um die angegebene Protokolldatei anzufordern. Der Parameter c: 1 gibt nur einen Protokolleintrag zurück. Mit dem Parameter rd: true kann der Befehl den neuesten Protokolleintrag lesen. Schließlich gibt f: text das Ergebnis im Klartext und nicht im XML-Format zurück, wodurch das Lesen des Ergebnisses auf dem Bildschirm vereinfacht wird.

(3)In den nächsten Zeilen wird der Befehl wevtutil erneut ausgeführt, und der neu empfangene Protokolleintrag wird mit dem zuletzt auf dem Bildschirm gedruckten verglichen. Wenn sie sich voneinander unterscheiden, bedeutet dies, dass Änderungen im Protokoll vorgenommen wurden. In diesem Fall wird ein neuer Eintrag angezeigt. Wenn die verglichenen Datensätze identisch sind, geschieht nichts und der Befehl wevtutil geht zurück und beginnt erneut zu suchen und zu vergleichen.

Erstellung eines Echtzeit-Histogramms


Der Befehl tail -f stellt den aktuellen Datenstrom bereit. Was aber, wenn Sie die Anzahl der Zeilen zählen möchten, die für einen bestimmten Zeitraum zur Datei hinzugefügt wurden? Sie können diesen Datenstrom beobachten, einen Timer starten und über einen bestimmten Zeitraum zählen. dann sollte die Zählung gestoppt und die Ergebnisse gemeldet werden.

Diese Arbeit kann in zwei Skriptprozesse unterteilt werden: Ein Skript liest die Zeilen und das andere überwacht die Uhrzeit. Der Timer benachrichtigt den Leitungszähler unter Verwendung eines Standard-POSIX-Interprozess-Kommunikationsmechanismus, der als Signal bezeichnet wird. Ein Signal ist ein Software-Interrupt, und es gibt verschiedene Arten von Signalen. Einige von ihnen sind schwerwiegend - sie führen zum Ende des Prozesses (z. B. eine Ausnahme bei einer Gleitkommaoperation). Die meisten dieser Signale können entweder ignoriert oder abgefangen werden. Es wird eine Aktion ausgeführt, wenn ein Signal abgefangen wird. Viele dieser Signale haben im Betriebssystem einen vordefinierten Zweck. Wir werden eines von zwei Signalen verwenden, die den Benutzern zur Verfügung stehen. Dies ist das Signal SIGUSR1 (das andere ist SIGUSR2).

Shell-Skripte können Interrupts mit dem integrierten Trap-Befehl abfangen. Mit ihm können Sie einen Befehl auswählen, der bestimmt, welche Aktion Sie ausführen möchten, wenn ein Signal empfangen wird, sowie eine Liste von Signalen, die einen Aufruf dieses Befehls auslösen. Beispiel:

trap warnmsg SIGINT

Dadurch wird der Befehl warnmsg (unser eigenes Skript oder unsere eigene Funktion) immer dann aufgerufen, wenn das Shell-Skript ein SIGINT-Signal empfängt, z. B. wenn Sie Strg + C drücken, um einen laufenden Prozess zu unterbrechen.

Beispiel 8.3 zeigt ein Skript, das eine Zählung durchführt.

Beispiel 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) Die Intervallfunktion wird beim Empfang jedes Signals aufgerufen. Natürlich muss das Intervall definiert werden, bevor wir es benennen und Trap in unserem Ausdruck verwenden können.

(2) Der Befehl date wird aufgerufen, um einen Zeitstempel für den Wert der zu druckenden cnt-Variablen bereitzustellen. Nachdem der Zähler angezeigt wurde, setzen wir diesen Wert auf 0 zurück, um den Countdown des nächsten Intervalls zu starten.

(3) Nachdem das Intervall definiert ist, können wir anzeigen, dass die Funktion immer dann aufgerufen wird, wenn unser Prozess das Signal SIGUSR1 empfängt.

(4)Dies ist ein sehr wichtiger Schritt. Wenn eine Pipeline von Befehlen vorhanden ist (z. B. ls-l | grep rwx | wc), werden normalerweise Teile der Pipeline (jeder Befehl) in Subnetzen ausgeführt und jeder Prozess endet mit einer eigenen Prozesskennung. Dies könnte ein Problem für dieses Szenario sein, da sich die while-Schleife in einer Subshell mit einer anderen Prozesskennung befindet. Unabhängig davon, welcher Prozess gestartet wird, kennt das Skript looper.sh die Kennung des while-Schleifenprozesses nicht, um ein Signal an ihn zu senden. Darüber hinaus ändert das Ändern des Werts der Variablen cnt in der Unterschale nicht den Wert von cnt im Hauptprozess, sodass das Signal für den Hauptprozess jedes Mal den Wert auf 0 setzt. Sie können dieses Problem mit dem Befehl shopt lösen, der den Parameter (-s) auf lastpipe setzt. Es weist die Shell an, keine Subshell für den letzten Befehl in der Pipeline zu erstellen.und führen Sie diesen Befehl im selben Prozess wie das Skript selbst aus. In unserem Fall bedeutet dies, dass der Befehl tail in einer Subshell (dh in einem anderen Prozess) ausgeführt wird und die while-Schleife Teil des Hauptskriptprozesses wird. Hinweis: Diese Shell-Option ist nur in Bash-Version 4.x und höher und nur für nicht interaktive Shells (d. H. Skripte) verfügbar.

(5) Dies ist der Befehl tail -f mit einem anderen Parameter --pid. Wir geben die Kennung des Prozesses an, der nach Abschluss dieses Prozesses den Befehl tail ausführt. Wir geben die Prozess-ID des aktuellen Shell-Skripts $$ an, das angezeigt werden soll. Mit dieser Aktion können Sie Prozesse bereinigen und den Befehl tail nicht im Hintergrund ausführen lassen (wenn dieses Skript beispielsweise im Hintergrund ausgeführt wird; Beispiel 8.4).

Das Skript tailcount.sh startet und stoppt das Skript mit einer Stoppuhr (Timer) und zählt die Zeitintervalle.

Beispiel 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) Da dieses Skript andere Skripte ausführt, sollte es nach der Arbeit bereinigt werden. Wenn die Prozesskennung in LOPID gespeichert wurde, speichert die Variable den Wert, daher sendet die Funktion mit dem Befehl kill ein Signal an diesen Prozess. Wenn Sie im Befehl kill kein bestimmtes Signal angeben, wird standardmäßig das SIGTERM-Signal gesendet.

(2) Der Befehl EXIT ist kein Signal. Dies ist ein Sonderfall, wenn die Trap-Anweisung die Shell anweist, diese Funktion aufzurufen (in diesem Fall Bereinigung), wenn die Shell, die dieses Skript ausführt, heruntergefahren werden soll.

(3)Jetzt beginnt die eigentliche Arbeit. Das Skript looper.sh wird gestartet, das im Hintergrund ausgeführt wird: Damit dieses Skript während des gesamten Zyklus funktioniert (ohne darauf zu warten, dass der Befehl die Arbeit abschließt), wird es von der Tastatur getrennt.

(4) Hier wird die Kennung des Skriptprozesses gespeichert, den wir gerade im Hintergrund gestartet haben.

(5) Diese Weiterleitung ist lediglich eine Vorsichtsmaßnahme. Alle Ausgaben, die von einer while-Schleife oder von kill / sleep-Anweisungen stammen (obwohl wir sie nicht erwarten), sollten nicht mit Ausgaben der Funktion looper.sh gemischt werden, die sie, obwohl sie im Hintergrund funktioniert, trotzdem an stdout sendet. Daher leiten wir Daten von stdout nach stderr um.

Zusammenfassend sehen wir, dass die Funktion looper.sh zwar im Hintergrund platziert wurde, ihre Prozesskennung jedoch in einer Shell-Variablen gespeichert ist. Alle fünf Sekunden sendet das Skript tailcount.sh ein Signal SIGUSR1 an diesen Prozess (der in der Funktion looper.sh ausgeführt wird), der seinerseits das Skript looper.sh aufruft, um die aktuelle Anzahl der darin festgelegten Zeilen zu drucken und die Zählung neu zu starten. Nach dem Beenden wird das Skript tailcount.sh gelöscht, indem ein SIGTERM-Signal an die Funktion looper.sh gesendet wird, um es zu unterbrechen.

Mithilfe von zwei Skripten - einem Skript, das die Zeilenzählung durchführt, und einem Skript mit einer Stoppuhr (Timer), die das erste Skript steuert - können Sie die Ausgabe (die Anzahl der Zeilen für einen bestimmten Zeitraum) abrufen, auf deren Grundlage das nächste Skript ein Histogramm erstellt. Es heißt so:

bash tailcount.sh | bash livebar.sh

Das Skript livebar.sh liest Daten aus stdin und druckt die Ausgabe in stdout, eine Zeile für jede Eingabezeile (Beispiel 8.5).

Beispiel 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) Die Funktion pr_bar zeigt eine Zeichenfolge von Hashtags an, die basierend auf den angegebenen Parametern auf die maximale Größe skaliert werden. Diese Funktion scheint vertraut zu sein, da wir sie zuvor im Skript histogram.sh verwendet haben.

(2) Dies ist die längste Hashtag-Zeilengröße, die wir zulassen können (ohne Zeilenumbruch).

(3)Wie groß werden die anzuzeigenden Werte sein? Ohne dies vorher zu wissen (obwohl diese Daten dem Skript als Argument zur Verfügung gestellt werden können), verfolgt das Skript das Maximum. Wenn dieses Maximum überschritten wird, beginnt der Wert zu „skalieren“ und die jetzt angezeigten Linien. Zukünftige Linien werden ebenfalls auf ein neues Maximum skaliert. Das Skript addiert 25% zum Maximalwert, sodass der Wert nicht skaliert werden muss, wenn der nächste neue Wert jedes Mal nur um 1-2% erhöht wird.

(4)printf definiert die minimale und maximale Breite der ersten beiden zu druckenden Felder. Dies sind Datums- und Zeitstempel, die abgeschnitten werden, wenn die Breitenwerte überschritten werden. Geben Sie die Breite von vier Zeichen an, um den gesamten Wert anzuzeigen. In diesem Fall werden trotz der Einschränkungen alle Werte gedruckt. Wenn die Anzahl der Zeichen in den Werten weniger als vier beträgt, werden die fehlenden durch Leerzeichen ergänzt.

Da dieses Skript von stdin gelesen wird, können Sie es selbst ausführen, um zu sehen, wie es sich verhält. Hier ist ein Beispiel:

$ 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

In diesem Beispiel wird die Eingabe mit der Ausgabe gemischt. Sie können auch Eingaben in eine Datei einfügen und diese in ein Skript umleiten, um nur die Ausgabe anzuzeigen:

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

»Weitere Informationen zum Buch finden Sie auf der Website des Herausgebers.
» Inhalt
» Auszug

für Khabrozhiteley 25% Rabatt auf den Gutschein - Bash

Nach Zahlung der Papierversion des Buches wird ein elektronisches Buch per E-Mail verschickt.

All Articles