Tip: Befehle protokollieren mit auditd

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
heisenberg
Beiträge: 3473
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Tip: Befehle protokollieren mit auditd

Beitrag von heisenberg » 31.10.2022 15:10:49

Hallo zusammen,

ich hatte ja vor einiger Zeit einmal einen Beitrag zum Thema Änderungen Konfigurationsdateien in Echtzeit überwachen mit auditd geschrieben.

Thematisch ähnlich möchte ich jetzt eine Möglichkeit vorstellen, wie man jegliche Systembefehle protokollieren und nachschlagen kann. Dabei geht es mir um Nachvollziehbarkeit und nicht um lückenlose Überwachung. Also z. B. so: Man möchte ein System, dass man allein oder mit anderen gemeinsam administriert auf administrative Kommandos prüfen, die dort ausgeführt worden sind, z. B. um Fehlerursachen auf die Schliche zu kommen. D. h. mögliche Bedienerfehler festzustellen, um das in Zukunft zu vermeiden. Im Vergleich zur Bash-History ist das schon einmal deutlich umfassender, vollständiger und zuverlässiger.

Die Methode setzt grundsätzlich Bereitschaft zur Kooperation voraus. Ich verfolge hier keinen sicherheitsorientierten Ansatz, der dazu geeignet ist, sicher und zuverlässig die Zuordnung von sämtlichen Befehlen zu realen persönlichen Accounts zu gewährleisten. Möglichkeiten das zu umgehen kann man - bestimmt zum großen Teil - eliminieren. Doch das würde den Aufwand erheblich steigern.

Was braucht es?
  • auditd - Protokollierung der Systemaufrufe
  • sudo oder su - als Brücke zwischen Benutzer- und root-Account
  • PAM - Setzen der tatsächlichen User-ID
  • aushape - Parser für das Audit Log
  • jq - JSON-Parser
  • ein kleines Script - als Admin-CLI-Frontend
auditd

auditd ist eine Software unter Linux, die vielfältige Systemaufrufe überwachen und protokollieren kann. D. h. Zugriffe auf Dateien und Verzeichnisse, sowie Systemaufrufe.

Zunächst muss dafür Debianauditd installiert werden.

Anschließend vergrößere ich noch das Log, um weiter in die Vergangenheit schauen zu können. Die Logmenge ist durchaus erheblich. Ich habe die Logfilegröße von 8 MB auf 50 MB erhöht. Das geht in der Datei /etc/auditd/audit.conf:

Code: Alles auswählen

max_log_file=50
Weiterhin lege ich noch zwei Regeln an, die mir die Protokollierung aller Kommandos sowohl für 64-Bit Programme als auch für 32-Bit Programme einschalten. Dazu lege ich in /etc/auditd/rules.d eine Datei namens command-logging.rules an mit folgendem Inhalt:

Code: Alles auswählen

-a always,exit -F arch=b32 -S execve -F key=command_logging
-a always,exit -F arch=b64 -S execve -F key=command_logging
Anschließend noch mittels systemctl restart auditd den Dienst neu starten und mit Hilfe des folgenden Befehls prüfen, ob die Regeln auch tatsächlich korrekt geladen wurden, was bei der folgenden Ausgabe der Fall ist:

Code: Alles auswählen

# auditctl -l
-a always,exit -F arch=b32 -S execve -F key=command_logging
-a always,exit -F arch=b64 -S execve -F key=command_logging
sudo / su

Das interessante an dieser Protokollierung, ist der Bezug vom aktuellen Benutzer für privilegierte Kommandos, idR root zu einem persönlichen Account, z. B. linus.torvalds. Damit dieser gegeben ist, dürfen keine direkten Root-Logins benutzt werden. Jeder Nutzer muss sich zunächst mit seinem normalen Benutzeraccount anmelden(z. B. per SSH) und dann mittels sudo oder su zum root-user oder einem anderen administrativen Account wechseln.

Die Pakete su/sudo können dabei nach persönlicher Präferenz konfiguriert werden.

PAM: pam_loginuid.so

Wichtig ist eine Änderung des PAM-Subsystems, so dass pam_loginuid.so bei allen betreffenden Diensten eingebunden wird. Dies sorgt dafür, dass die UID des ursprünglichen Benutzers gesetzt wird, welche von auditd dann als Feld auid protokolliert wird. Wird das nicht gesetzt, ist diese essentielle Information nicht verfügbar.

Für SSH(andere Login-Dienste analog!) ist in der Datei /etc/pam.d/sshd das aktivieren folgender Zeile nötig:

Code: Alles auswählen

session    required     pam_loginuid.so
aushape

Um das audit-Log vernünftig verarbeiten zu können ist ein guter Parser notwendig. Die mitgelieferten Programme empfinde ich für weitere Verarbeitung der Daten als unzureichend. Deswegen nutze ich hier aushape[1], ein Programm(beta!), dass das auditlog gut parsen kann und als JSON- oder XML-Datenstruktur ausgibt.

Das Programm muss selbst übersetzt werden und benötigt zusätzlich unter Bullseye noch die Pakete libauparse0 und libauparse-dev .

Ich empfehle ansonsten noch Debiancheckinstall als Quick'n'Dirty-Lösung um das wieder rückstandsfrei entfernen zu können.

jq

Um die JSON-Ausgabe von aushape dann einfach via Shell verarbeiten zu können bietet sich noch Debianjq an. Das Schweizer Taschenmesser für JSON-Parsing und Bearbeitung.

Das Admin-Frontend Script

Jetzt sind wir beim letzten Schritt angekommen. Mit einem kleinen Script wird jetzt das audit-Log ausgelesen und aufbereitet.

Hier mal ein Beispiel(Ich nenne es mal cmdlog) dazu:

Code: Alles auswählen

#!/bin/bash

export PATH=/bin:/usr/bin:/usr/local/bin
AUDIT_LOG=/var/log/audit/audit.log
PROCESS_LINES=50000

# Anmerkungen:
# 
#  - JQ-Select: Alle Zeilen mit einer leeren(=Wert: null) auid wegfiltern(die kommen von Daemons, auch cron)
#  - JQ: Eine Zeile zusammensetzen aus interessanten Informationselementen:
#	+ "ses"       => Sitzungs-ID. D. h. die Shell (Alle Befehle mit der gliechen Sitzungsid wurden in der 
#                        gleichen Shell ausgeführt. So kann man sich alle Befehle einer Shell anschauen).
#       + "auid"      => Der Ursprungsbenutzer
#       + "uid"       => Der aktuelle Benutzer
#       + "proctitle" => Das ausgeführte Kommando
#   - AWK: Alle Befehle wegfiltern, die als auid oder uid ein "unset" gesetzt haben. Erklärung siehe JQ-Select
#

tail -n $PROCESS_LINES $AUDIT_LOG | aushape                             \
        | jq -r '.[] | select(.data.syscall.auid[0]!=null) |
                  .time +" "+
                 (.data.syscall.ses[0]|tostring)+" "+
                  .data.syscall.auid[0]+" "+
                  .data.syscall.uid[0]+" "+
                  .data.proctitle[][0]'                                 \
        | awk '$2 == "unset" || $3== "unset" {next} 1;'

Beispielaufruf

Möchte ich also jetzt mal schauen, was der Benutzer linus.torvalds auf meinem System das letzte mal gemacht hat, kann ich dieses Kommando ausführen:

Code: Alles auswählen

# cmdlog | grep linus.torvalds | nl
     1  2022-10-31T14:51:11.418+01:00 355592 linus.torvalds root /usr/sbin/sshd -D -R
     2  2022-10-31T14:51:11.454+01:00 355593 linus.torvalds root (systemd)
     3  2022-10-31T14:51:11.454+01:00 355593 linus.torvalds linus.torvalds (systemd)
     4  2022-10-31T14:51:11.470+01:00 355593 linus.torvalds linus.torvalds /usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator
     5  2022-10-31T14:51:11.478+01:00 355593 linus.torvalds linus.torvalds /bin/bash /usr/lib/systemd/user-environment-generators/90gpg-agent
     6  2022-10-31T14:51:11.482+01:00 355593 linus.torvalds linus.torvalds awk -F: BEGIN{ret=1} /^gpg-agent:/{if ($5 == "1") { ret=0; exit 0 } } END {exit ret}
     7  2022-10-31T14:51:11.482+01:00 355593 linus.torvalds linus.torvalds gpgconf --check-options gpg-agent
     8  2022-10-31T14:51:11.486+01:00 355593 linus.torvalds linus.torvalds gpg-agent --gpgconf-test
     9  2022-10-31T14:51:11.494+01:00 355593 linus.torvalds linus.torvalds gpgconf --list-options gpg-agent
    10  2022-10-31T14:51:11.494+01:00 355593 linus.torvalds linus.torvalds awk -F: /^enable-ssh-support:/{ print $10 }
    11  2022-10-31T14:51:11.498+01:00 355593 linus.torvalds linus.torvalds gpg-agent --gpgconf-list
    12  2022-10-31T14:51:11.502+01:00 355593 linus.torvalds linus.torvalds /usr/lib/systemd/user-generators/systemd-xdg-autostart-generator /run/user/1020/systemd/generator /run/user/1020/systemd/generat
    13  2022-10-31T14:51:11.654+01:00 355593 linus.torvalds linus.torvalds /bin/systemctl --user set-environment DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1020/bus
    14  2022-10-31T14:51:11.662+01:00 355593 linus.torvalds linus.torvalds /usr/bin/pipewire
    15  2022-10-31T14:51:11.670+01:00 355592 linus.torvalds root /bin/sh /etc/update-motd.d/10-uname
    16  2022-10-31T14:51:11.670+01:00 355592 linus.torvalds root uname -snrvm
    17  2022-10-31T14:51:11.682+01:00 355593 linus.torvalds linus.torvalds /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
    18  2022-10-31T14:51:11.690+01:00 355593 linus.torvalds linus.torvalds /usr/bin/pulseaudio --daemonize=no --log-target=journal
    19  2022-10-31T14:51:11.706+01:00 355593 linus.torvalds linus.torvalds /usr/bin/pipewire-media-session
    20  2022-10-31T14:51:11.718+01:00 355592 linus.torvalds linus.torvalds -bash
    21  2022-10-31T14:51:11.718+01:00 355592 linus.torvalds linus.torvalds id -u
    22  2022-10-31T14:51:11.750+01:00 355592 linus.torvalds linus.torvalds dircolors -b
    23  2022-10-31T14:51:14.622+01:00 355592 linus.torvalds linus.torvalds ls --color=auto -tlra
    24  2022-10-31T14:51:21.386+01:00 355592 linus.torvalds linus.torvalds sudo su -
    25  2022-10-31T14:51:21.406+01:00 355592 linus.torvalds root su -
    26  2022-10-31T14:51:21.418+01:00 355592 linus.torvalds root -bash
    27  2022-10-31T14:51:21.422+01:00 355592 linus.torvalds root id -u
    28  2022-10-31T14:51:21.450+01:00 355592 linus.torvalds root mesg n
    29  2022-10-31T14:51:26.577+01:00 355592 linus.torvalds root vi /etc/apache2/apache2.conf
    30  2022-10-31T14:51:29.901+01:00 355592 linus.torvalds root /bin/bash /usr/local/bin/cmdlog
    31  2022-10-31T14:51:29.905+01:00 355592 linus.torvalds root tail -n 5000000 /var/log/audit/audit.log
    32  2022-10-31T14:51:29.905+01:00 355592 linus.torvalds root aushape
    33  2022-10-31T14:51:29.905+01:00 355592 linus.torvalds root jq -r .[] | select(.data.syscall.auid[0]!=null) |
    34  2022-10-31T14:51:29.905+01:00 355592 linus.torvalds root awk $2 == "unset" || $3== "unset" {next} 1;



Ich sehe also - mit genauen Zeitangaben - dass sich linus.torvalds via SSH eingeloggt hat(Zeile 1). Dann jede Menge uninteressanten Shell-Initialisierungskram. Weiterhin sehe ich, dass er mittels sudo su - zu root gewechselt ist(Zeile 24) und ich sehe dass er u. a. den Editor für apache2.conf gestartet hat(Zeile 29).

[1] https://github.com/Scribery/aushape
... unterhält sich hier gelegentlich mangels wunschgemäßer Gesprächspartner mal mit sich selbst.

Antworten