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 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 auditd 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
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
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
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
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 checkinstall 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 jq 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;'
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