Linux: Benutzerbefehle revisionssicher protokollieren
Shell-Historien sind kein Audit-Trail. Vergleichen Sie sudo, Sitzungsaufzeichnung, Shell-Hooks und auditd execve-Regeln und senden Sie Logs vom Server weg.
Was tatsächlich die von Benutzern auf Ihrem Server ausgeführten Befehle protokolliert
Wenn Sie prüfen möchten, welche Befehle Benutzer auf Ihrem Server ausgeführt haben, benötigen Sie einen Datensatz, den der jeweilige Benutzer nicht bearbeiten kann. Die Shell-Historie ist kein solcher Datensatz. Sie ist eine Komfortdatei im Besitz des Accounts, der sie geschrieben hat. Jeder, der Befehle in dieser Shell eingeben kann, kann die Aufzeichnung deaktivieren oder die Datei löschen.
Vier Ebenen erstellen tatsächlich einen solchen Datensatz. Jede Ebene verursacht jedoch einen bestimmten Aufwand. sudo schreibt für jeden Befehl eine Zeile in syslog. Die sudo-I/O-Protokollierung erfasst eine vollständige Sitzung für einen Account. Ein Shell-Hook wie PROMPT_COMMAND protokolliert, was ein interaktiver bash-Benutzer eingibt. Das Kernel-Audit-Subsystem protokolliert den execve-Systemaufruf selbst. Deshalb ist es die einzige Ebene, die jeden Prozess erfasst. Dieser Leitfaden geht diese Ebenen schrittweise durch, zeigt die Grenzen jeder Ebene und endet mit dem entscheidenden Punkt: Die Protokolle müssen vom Rechner weg übertragen werden, bevor die überwachte Person darauf zugreifen kann.
Bevor Sie beginnen, ist eine Warnung erforderlich. Das Audit-Subsystem arbeitet im Kernel. Deshalb kann keine dieser Funktionen in einem Container getestet werden, der den Kernel des Hosts gemeinsam nutzt. Führen Sie diese Befehle auf einem KVM-VPS aus, dessen Kernel Sie selbst verwalten.
Warum die Shell-History kein Audit-Protokoll ist
~/.bash_history ist aus vier alltäglichen Gründen kein Beweismittel. Dafür braucht es keinen besonders geschickten Angreifer.
Sie gehört dem Benutzer. Die Datei hat den Modus 600 und gehört dem jeweiligen Account. Deshalb benötigt rm ~/.bash_history überhaupt keine besonderen Rechte. Die Datei lässt sich auch in einem Editor öffnen, und die zwanzig relevanten Zeilen können entfernt werden.
Sie wird beim Beenden der Shell geschrieben. Eine Sitzung, die mit kill -9 $$ oder durch eine abgebrochene Verbindung endet, schreibt nichts. history -c vor exit hat denselben Effekt und sieht so aus, als wäre nichts passiert.
Sie lässt sich mit einem Wort deaktivieren. unset HISTFILE verhindert, dass die Datei für diese Sitzung geschrieben wird. set +o history beendet die Aufzeichnung sofort. HISTCONTROL=ignorespace blendet jeden Befehl aus, der mit einem führenden Leerzeichen eingegeben wurde. Das alles steht in man bash, weil die Einstellungen unter der Kontrolle des Benutzers liegen sollen.
Sie zeichnet auf, was eingegeben wurde, nicht was ausgeführt wurde. Ein Alias oder eine Shell-Funktion bewirkt, dass der Text in der Datei nicht dem Programm entspricht, das der Kernel ausgeführt hat.
Zeitstempel gibt es ebenfalls nicht, außer HISTTIMEFORMAT war beim Schreiben des Eintrags gesetzt. bash schreibt seine #1755043200-Markierungszeilen nur, wenn diese Variable gesetzt ist.
Bei einem gemeinsam verwendeten Login kann die Datei außerdem nicht feststellen, wer den Befehl ausgeführt hat. Drei Personen, die denselben deploy-Account verwenden, erzeugen eine einzige vermischte Datei unter einer UID. Keine Protokollierungsschicht kann eine Aktion einer bestimmten Person zuordnen, wenn zwei Personen dieselbe UID verwenden. Genau deshalb sollte jede Person einen eigenen nicht privilegierten Account statt eines gemeinsamen Logins verwenden.
Die Shell-History erfüllt ihren eigentlichen Zweck gut: Sie hilft dabei, den Befehl vom Vortag erneut einzugeben. Verwenden Sie sie als Hinweis. Stellen Sie sie niemals als Beweis dar.
Was sudo protokolliert, und wo die Protokollierung endet
sudo sendet für jeden ausgeführten Befehl eine Zeile an die Syslog-Facility authpriv.
sudo grep 'sudo:' /var/log/auth.log | tail -5
journalctl -t sudo -n 5Jede Zeile nennt den Benutzer, das Terminal, das Arbeitsverzeichnis, den Zielbenutzer und den Befehl:
sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/apt updateWenn /var/log/auth.log nicht vorhanden ist, ist rsyslog auf diesem Image nicht installiert. Die entsprechenden Einträge befinden sich dann nur im Journal. Prüfen Sie, dass das Journal nicht flüchtig ist, bevor Sie sich darauf verlassen:
journalctl --list-bootsWenn nur der aktuelle Boot aufgeführt wird, ist /var/log/journal nicht vorhanden. Das Journal liegt dann in /run, und jeder Eintrag geht beim nächsten Reboot verloren. Machen Sie das Journal persistent:
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journaldNun zur Einschränkung. sudo protokolliert den Befehl, den es ausführen soll. Es protokolliert nicht, was dieser Befehl anschließend tut. Daher endet die Nachverfolgung mit einer einzigen Zeile:
sudo -iDas Log erhält einen einzelnen Eintrag für die Shell. Jeder in dieser Root-Shell eingegebene Befehl bleibt für sudo unsichtbar, weil sudo nicht mehr im Ausführungspfad liegt. sudo su -, sudo bash und sudo vim /etc/shadow gefolgt von :!bash haben alle dasselbe Muster. Eine sudoers-Regel, die ein beliebiges Programm mit einem Shell Escape wie vim oder find erlaubt, gewährt damit Root-Zugriff ohne Protokollierung. Prüfen Sie, worauf ein Account tatsächlich zugreifen kann, bevor Sie seinen Logeinträgen vertrauen:
sudo -l -U aliceAufzeichnen einer vollständigen Sitzung für ein Konto
Ermitteln Sie zuerst, welches sudo Sie verwenden, da diese Funktion in der Rust-Neufassung nicht vorhanden ist:
sudo --version | head -1Wenn die Ausgabe sudo-rs nennt, überspringen Sie diesen Abschnitt und verwenden Sie das Audit-Subsystem. Die Ubuntu-Dokumentation für die Releases 25.10 und 26.04 führt die I/O-Protokollierung und sudoreplay als nicht unterstützt auf. Das war auch im August 2026 noch der Fall. Das ist relevant, weil sudo-rs in diesen Releases der Standard-sudo ist. Ein Upgrade kann daher eine Kontrolle entfernen, von der Sie angenommen haben, dass sie weiterhin vorhanden ist. Die vollständige Liste der Verhaltensänderungen von sudo-rs sollten Sie lesen, bevor Sie eine Protokollierung auf sudo-Basis planen.
Mit dem ursprünglichen sudo, das Ubuntu 24.04 LTS weiterhin ausliefert, aktivieren Sie die I/O-Protokollierung für ein Konto:
sudo visudo -f /etc/sudoers.d/iologDefaults:deploy log_output
Defaults!/usr/bin/sudoreplay !log_outputVerwenden Sie visudo statt eines Editors, weil der Befehl das Speichern einer Datei verweigert, die sich nicht parsen lässt. Eine fehlerhafte sudoers-Datei sperrt alle Benutzer von sudo aus. Geben Sie anschließend eine Sitzung wieder:
sudo sudoreplay -l user=deploy
sudo sudoreplay 000001sudoreplay -l listet die Sitzungen mit ihren IDs auf und gibt nichts aus, wenn log_output bei diesem Benutzer nie angewendet wurde. Der Aufwand: Jedes Byte, das das Terminal durchläuft, wird unter /var/log/sudo-io gespeichert. Eine ausführliche Sitzung erzeugt daher große Dateien. Die zweite sudoers-Zeile verhindert, dass eine Wiedergabe sich selbst aufzeichnet. Das eigentliche Risiko sind Geheimnisse, weil ein I/O-Protokoll alle eingegebenen und ausgegebenen Inhalte enthält. Dazu gehört auch ein Passwort, das innerhalb der Sitzung an einer Eingabeaufforderung eingegeben wurde. Das Protokoll benötigt daher denselben Schutz wie ein Passwortspeicher. Auch die Abdeckung ist begrenzt. Erfasst werden Befehle, die über sudo ausgeführt werden. Meldet sich jemand an und arbeitet vollständig unter dem eigenen Konto, wird dies überhaupt nicht aufgezeichnet.
Shell-Hooks und wie sie genau umgangen werden
Das Rezept für „jeden Befehl protokollieren“, das häufig weitergegeben wird, ist ein PROMPT_COMMAND-Hook in /etc/profile.d/:
# /etc/profile.d/00-cmdlog.sh
PROMPT_COMMAND='logger -p local6.info -t cmdlog "$(whoami) $$ $(history 1 | sed "s/^ *[0-9]* *//")"'bash führt PROMPT_COMMAND vor jeder Ausgabe des Prompts aus. Dadurch wird eine Zeile bereits beim Eingeben und nicht erst beim Beenden an syslog übergeben. logger schreibt über den System-Logging-Daemon. Die Dateiberechtigungen des Benutzers spielen dabei keine Rolle. Öffnen Sie eine neue Login-Shell und prüfen Sie das Ergebnis mit sudo tail -f /var/log/syslog oder mit journalctl -t cmdlog -f auf einem Image ohne rsyslog.
Danach funktioniert es nicht mehr. Dafür gibt es fünf Ursachen, die Sie jeweils innerhalb einer Minute reproduzieren können.
- Nicht interaktive Shells geben keinen Prompt aus.
ssh you@server 'id'führt den Befehl aus und wird beendet. Es wird nichts protokolliert, weilPROMPT_COMMANDnie ausgewertet wurde. - Es handelt sich um eine Variable.
unset PROMPT_COMMANDdeaktiviert sie für den Rest der Sitzung und erfordert keine Berechtigung. - Die Datei wird von Login-Shells gelesen.
bash --noprofile --norcbindet/etc/profile.d/überhaupt nicht ein. - Die Funktion ist bash-spezifisch.
zsh,sh,python3 -c 'import os; os.system("id")'und:!idinnerhalb vonvimstarten Programme, die kein bash-Prompt-Hook erfassen kann. - Die Zeile wird so protokolliert, wie sie eingegeben wurde. Ein Alias oder eine Funktion kann daher weiterhin den tatsächlich ausgeführten Befehl verbergen.
Verwenden Sie einen Shell-Hook als praktische Unterstützung. Für kooperative Benutzer beantwortet er die Frage „Was habe ich letzten Dienstag ausgeführt?“. Lassen Sie eine Checkliste jedoch nicht behaupten, dass er eine Sicherheitskontrolle darstellt.
The kernel audit subsystem sees every execve
The Linux audit subsystem, driven by the auditd daemon, is the only layer here that a user cannot step around, because the record is made inside the kernel at the moment the syscall runs. If a process executes a program, there is an event. The shell, the language and the presence of a terminal make no difference.
sudo apt update && sudo apt install -y auditd audispd-plugins
sudo systemctl enable --now auditd
sudo auditctl -sauditctl -s prints the daemon state. enabled 1 with a non-zero pid means it is running, and lost 0 means no records have been dropped yet. Remember that lost counter, it comes back later.
auid is the field that makes audit worth the trouble. PAM sets a login uid when a session starts, and the kernel carries it on every child process from then on. Check yours:
cat /proc/self/loginuidAn interactive SSH session prints your uid, because /etc/pam.d/sshd includes pam_loginuid.so. A value of 4294967295 means the loginuid was never set, which is normal for a process started by a system daemon at boot. The important part is that sudo -i does not change it: a root shell opened by alice still carries auid 1000, so every command inside it is attributable to alice. That is exactly the gap sudo leaves open. Changing a loginuid once set needs CAP_AUDIT_CONTROL, which ordinary users do not have, and sudo auditctl --loginuid-immutable closes it for root as well until the next reboot.
Check that /etc/pam.d/sshd, /etc/pam.d/login and /etc/pam.d/cron each include pam_loginuid.so, or events will arrive with nobody attached to them. That is the same file list you touch when hardening SSH access on a VPS, so do the two jobs together.
Eine Ausgangsregelmenge für auditd
Die Regeln befinden sich in /etc/audit/rules.d/*.rules. augenrules fügt sie in Dateinamenreihenfolge zu einer einzigen Liste zusammen. Die Reihenfolge bestimmt das Verhalten, weil der Kernel bei der ersten passenden Regel stoppt. Lesen Sie zuerst, was bereits vorhanden ist, bevor Sie etwas hinzufügen. Ein -D in einer späteren Datei löscht alle zuvor geladenen Regeln.
ls /etc/audit/rules.d/
cat /etc/audit/rules.d/audit.rulesSchreiben Sie anschließend /etc/audit/rules.d/50-exec.rules:
## Suppressions first: the kernel takes the first matching rule.
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-deb
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-query
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-split
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-trigger
## Every program started by a logged-in human.
-a always,exit -F arch=b64 -S execve,execveat -F auid>=1000 -F auid!=unset -k exec
-a always,exit -F arch=b32 -S execve,execveat -F auid>=1000 -F auid!=unset -k exec
## Changes to who may become root.
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
## Changes to the audit configuration itself.
-w /etc/audit/ -p wa -k auditconfigLaden Sie die Regeln und prüfen Sie das Ergebnis:
sudo augenrules --load
sudo auditctl -lWenn auditctl -l Ihre Regeln wieder ausgibt, sind sie aktiv. No rules bedeutet, dass das Laden fehlgeschlagen ist. journalctl -u auditd -n 20 nennt die Datei und die Zeile, die der Parser abgelehnt hat. Ältere Audit-Userspace-Versionen verstehen das Schlüsselwort unset nicht. Wenn der Loader dieses Feld beanstandet, schreiben Sie stattdessen -F auid!=4294967295. Das ist derselbe Wert in ausgeschriebener Form.
Lesen Sie nun die Ereignisse aus:
sudo ausearch -k exec -ts recent -i | tail -40
sudo ausearch -ul 1000 -ts today -i
sudo aureport -k --summary -i-i wandelt UIDs und Syscall-Nummern in Namen um. In der Praxis ist diese Option daher unverzichtbar. -ts recent umfasst die letzten zehn Minuten. Jede Ausführung erzeugt eine Gruppe von Datensätzen: einen SYSCALL-Datensatz mit UID, AUID, Exit-Status und Schlüssel, einen EXECVE-Datensatz mit der vollständigen Argumentliste sowie CWD- und PATH-Datensätze für den Kontext.
Eine wichtige Einschränkung, die häufig übersehen wird: audit protokolliert Syscalls, aber ein Shell-Builtin führt selbst keinen Syscall aus. cd /root startet kein Programm. Auch echo evil >> /etc/passwd an einer bash-Eingabeaufforderung startet kein Programm, weil sowohl echo als auch die Umleitung innerhalb des bereits laufenden Shell-Prozesses ausgeführt werden. Daher erfassen die execve-Regeln die Programme und die -w-Regeln die Schreibvorgänge. Keine der beiden Regelarten reicht allein aus.
Sperren Sie abschließend die Konfiguration:
## /etc/audit/rules.d/99-finalize.rules
-e 2-e 2 macht die Regelmenge bis zum nächsten Reboot unveränderlich. Nach dem Laden meldet auditctl -s den Status enabled 2. Jeder Versuch, eine Regel hinzuzufügen oder zu löschen, schlägt dann mit Operation not permitted fehl, auch für root. Fügen Sie diese Datei zuletzt hinzu. Planen Sie bei jeder Regeländerung einen Reboot ein. Genau darin besteht der Zweck: Eine Regelmenge, die jeder unbemerkt deaktivieren kann, ist kein Beleg.
Ein Audit-Log, das niemand liest, ist nur ein Compliance-Artefakt
Das Problem bei auditd ist nicht, dass Ereignisse fehlen. Das Problem ist, dass so viele Ereignisse aufgezeichnet werden, dass sie niemand liest. Dann existiert das Log nur noch, um eine Checkliste abzuhaken, statt eine Frage zu beantworten.
Führen Sie die Berechnung auf Ihrem eigenen System durch, bevor Sie etwas abstimmen:
sudo aureport -k --summary -i
sudo du -sh /var/log/auditEin einzelnes sudo apt upgrade startet Tausende kurzlebiger Prozesse. Jeder dieser Prozesse übernimmt Ihre auid. Deshalb kann ein einzelnes Paketupdate mehr Einträge erzeugen als eine ganze Woche manueller Eingaben. Aus diesem Grund nennen die obigen Unterdrückungen dpkg und seine Hilfsprogramme. Unterdrücken Sie nach ausführbarer Datei, niemals nach Benutzer: Eine Ausnahme für /usr/bin/dpkg lässt sich in einem Satz beschreiben. Eine Ausnahme für ein Konto hat dagegen exakt die Form dessen, was Sie eigentlich erfassen wollten.
Der Schlüssel -k in jeder Regel macht das Log auch einen Monat später noch durchsuchbar. ausearch -k sudoers ist eine Frage mit einer Antwort. ausearch ohne Filter ist eine Textwand, die Sie darauf konditioniert, nicht mehr zu lesen. Wenn Ihr Collector statt des nativen Formats JSON benötigt, ist laurel ein auditd-Plugin, das jedes Ereignis als einzelnes JSON-Objekt mit decodierten Argumenten neu schreibt. Es wird wie jedes andere Plugin in /etc/audit/plugins.d/ registriert, und auditd übernimmt Plugin-Änderungen bei sudo pkill -HUP auditd.
Was auditd tatsächlich kostet
Jeder passende Systemaufruf wird zu einem Datensatz, den der Kernel formatiert und an den Userspace übergibt. Die Kosten entstehen an zwei Stellen. Beide lassen sich anhand Ihrer eigenen Arbeitslast messen, statt eine veröffentlichte Zahl aus einer anderen Umgebung zu übernehmen.
- CPU und Latenz. Ein Rechner, der ständig Prozesse forkt, ein Build-Host oder ein CI-Runner erzeugt für jedes
execeinen Datensatz. Wenn sich der Kernel-Backlog füllt, sorgt--backlog_wait_timedafür, dass der Kernel den Prozess anhält, der das Ereignis erzeugt hat, bis wieder Platz vorhanden ist. auditd zeigt sich dann als langsame Builds und nicht als bestimmter CPU-Prozentsatz. Überwachen Siebacklogundlostinsudo auditctl -sunter realer Last. Ein steigender Wert inlostbedeutet, dass Datensätze verworfen wurden. Ein Log mit unbemerkten Lücken ist schlechter als gar kein Log, weil Sie ihm weiterhin vertrauen werden. - Festplatte. Lesen Sie
/etc/audit/auditd.confund legen Sie bewusst fest, was bei voller Festplatte geschehen soll, weil die mitgelieferten Werte lediglich Vorgaben sind.max_log_file,num_logsundmax_log_file_actionsteuern die Rotation.space_left_action,admin_space_left_actionunddisk_full_actionsteuern den Notfall. Einige der verfügbaren Aktionen, darunterhaltundsingle, fahren den Rechner herunter, statt einen Datensatz zu verlieren.
Die Zeile -f in /etc/audit/rules.d/audit.rules trifft dieselbe Entscheidung auf Kernel-Ebene: -f 1 meldet einen Audit-Fehler an syslog, und -f 2 löst eine Kernel-Panic aus. Wählen Sie 2 nur, wenn Sie den Server tatsächlich lieber verlieren würden als einen Datensatz. Auf einem VPS, von dem andere abhängig sind, sollten Sie stattdessen rotieren und das Speicherproblem vom Server weg verlagern.
Logs nahezu in Echtzeit vom Server weiterleiten
Genau das wird in Untersuchungsberichten immer wieder bestätigt. Logs, die auf dem kompromittierten Host verbleiben, können von der Person geändert werden, die den Host kompromittiert hat. root kann /var/log/auth.log überschreiben, /var/log/audit/audit.log löschen und den Daemon stoppen. -e 2 verhindert, dass die Regeln entladen werden. Gegen rm hilft es nicht. Jede darüberliegende Schutzschicht liefert nur dann Beweise, wenn zunächst eine Kopie den Rechner verlässt.
Der eigene Transport von Audit ist das audisp-remote-Plugin aus audispd-plugins. Aktivieren Sie es in /etc/audit/plugins.d/au-remote.conf:
active = yes
direction = out
path = /usr/sbin/audisp-remote
type = always
format = stringPrüfen Sie path gegen command -v audisp-remote, bevor Sie die Konfiguration neu laden. Ein falscher Pfad erzeugt außer einer Zeile im Journal keine Ausgabe. Setzen Sie remote_server und port in /etc/audit/audisp-remote.conf. Setzen Sie auf dem Collector tcp_listen_port = 60 in dessen eigener auditd.conf. Laden Sie die Konfiguration mit sudo pkill -HUP auditd neu. Auf vielen Images wird systemctl restart auditd abgelehnt, weil die Unit-Datei RefuseManualStop=yes setzt. Daher ist das Signal der zuverlässige Weg.
Die andere Option schreibt Audit in den Syslog-Datenstrom, den Sie bereits weiterleiten. /etc/audit/plugins.d/syslog.conf wird mit active = no ausgeliefert. Setzen Sie es auf yes und laden Sie die Konfiguration neu. Danach werden Audit-Ereignisse zusammen mit den sudo-Zeilen und allen anderen Meldungen weitergeleitet. Leiten Sie anschließend alles mit rsyslog über TLS (Transport Layer Security) weiter. Dafür wird das Paket rsyslog-gnutls benötigt:
# /etc/rsyslog.d/60-forward.conf
*.* action(type="omfwd"
target="logs.example.net" port="6514" protocol="tcp"
StreamDriver="gtls" StreamDriverMode="1"
StreamDriverAuthMode="x509/name"
StreamDriverPermittedPeers="logs.example.net"
action.resumeRetryCount="-1"
queue.type="linkedList" queue.filename="fwd" queue.saveOnShutdown="on")Die Warteschlangeneinstellungen sind dabei entscheidend. action.resumeRetryCount="-1" führt bei Fehlern unbegrenzt neue Versuche aus. Die datenträgergestützte Warteschlange mit queue.saveOnShutdown="on" speichert Datensätze, solange der Collector nicht erreichbar ist, und sendet sie, sobald er wieder verfügbar ist. Ohne diese beiden Einstellungen hinterlässt ein Neustart des Collectors eine Lücke in Ihren Beweisen. Außerdem gibt es keinen Hinweis darauf, dass diese Lücke entstanden ist. Wenden Sie die Konfiguration mit sudo systemctl restart rsyslog an. Prüfen Sie anschließend auf dem Collector, ob die Datensätze tatsächlich ankommen, bevor Sie der Konfiguration vertrauen.
Eine Lücke muss noch geschlossen werden: Der Collector muss ein Rechner sein, bei dem sich die überwachten Personen nicht anmelden können. Wenn dieselbe Administratorgruppe root-Zugriff auf dem Logserver hat, haben Sie die Datei nur kopiert, nicht geschützt. Verwenden Sie getrennte Zugangsdaten, getrennte Schlüssel und möglichst ein separates Provider-Konto. Aus demselben Grund lohnt es sich, eine zentrale Verwaltung mehrerer Linux-Server einzurichten, bevor Sie sie benötigen. Das ist entscheidend für den Unterschied zwischen einer nützlichen und einer nutzlosen ersten Stunde, wenn Sie einen kompromittierten VPS untersuchen.
Prüfen, dass ein normaler Benutzer den Datensatz nicht überschreiben kann
Prüfen Sie diese Aussage, statt sie einfach anzunehmen. Führen Sie die Prüfung mit einem gewöhnlichen Konto und ohne sudo aus:
echo test >> /var/log/auth.log
cat /var/log/audit/audit.log
auditctl -D
id -nGErwarten Sie die Ergebnisse in dieser Reihenfolge: Permission denied, weil auth.log dem Benutzer syslog, der Gruppe adm und dem Modus 640 gehört; erneut Permission denied, weil das Audit-Log den Modus 600 hat und root gehört; einen Fehler, der die Ausführung verweigert, weil Änderungen an Audit-Regeln CAP_AUDIT_CONTROL erfordern; sowie eine Gruppenliste, die weder adm noch systemd-journal enthält.
Die letzte Prüfung wird häufig übersehen. Die Mitgliedschaft in adm gewährt Lesezugriff auf /var/log/auth.log. Die Mitgliedschaft in systemd-journal gewährt Lesezugriff auf das gesamte Journal. Keine dieser Mitgliedschaften gewährt Schreibzugriff. Daher ermöglicht keine von beiden eine Manipulation. Beide erlauben einer Person, jede Authentifizierungszeile auf dem System zu lesen. Das sollte eine bewusste Entscheidung sein und nicht dadurch entstehen, dass eine usermod -aG-Zeile aus einer Forenantwort kopiert wird.
Bestätigen Sie abschließend die beiden Bedingungen, die einen Reboot überstehen müssen:
sudo auditctl -s
systemctl is-enabled auditdenabled 2 bedeutet, dass der Regelsatz bis zum nächsten Bootvorgang gesperrt ist. enabled aus dem zweiten Befehl bedeutet, dass auditd nach diesem Bootvorgang wieder startet. Ein Regelsatz, der nur bis zum nächsten Kernel-Update bestehen bleibt, ist ebenfalls kein Audit-Trail.
FAQ
Wie sehe ich jeden Befehl, den ein bestimmter Benutzer ausgeführt hat?
Ermitteln Sie seine uid mit id -u alice und durchsuchen Sie dann das Audit-Log nach der Login-uid: sudo ausearch -ul 1000 -ts today -i. Ergänzen Sie -k exec, um die Ausgabe auf die execve-Regel zu beschränken. Die Login-uid wird bei der Anmeldung gesetzt und bleibt über su und sudo -i hinweg erhalten. Dadurch werden auch Befehle erfasst, die innerhalb einer von diesem Konto geöffneten root-Shell ausgeführt wurden. Das funktioniert nur für Befehle, die nach dem Laden der Regeln ausgeführt wurden, da audit keine Historie von Ereignissen führt, deren Aufzeichnung nicht konfiguriert war. sudo aureport -k --summary -i liefert die Zähler pro Regel, wenn Sie zunächst die Struktur der Daten sehen möchten.
Kann ein Benutzer seine Bash-Historie löschen, um ausgeführte Befehle zu verbergen?
Ja, dafür sind keine besonderen Berechtigungen erforderlich. ~/.bash_history gehört diesem Benutzer und hat den Modus 600. Der Benutzer kann die Datei daher bearbeiten, leeren oder löschen. Außerdem kann er mit unset HISTFILE verhindern, dass sie geschrieben wird, mit set +o history die Aufzeichnung während der Sitzung stoppen oder einzelne Befehle verbergen, indem er sie mit einem vorangestellten Leerzeichen eingibt, wenn HISTCONTROL=ignorespace gesetzt ist. Bash schreibt die Datei beim Beenden der Shell. Wird eine Sitzung mit kill -9 $$ beendet, wird daher nichts aufgezeichnet. Behandeln Sie die Shell-Historie als Hinweis, niemals als Beweis.
Protokolliert sudo, was innerhalb von sudo -i geschieht?
Nein. sudo protokolliert den Befehl, den es ausführen soll. sudo -i erzeugt daher eine Zeile für die Shell, aber keine weiteren Einträge. Jeder in dieser root-Shell eingegebene Befehl ist für sudo unsichtbar, weil sudo nicht mehr beteiligt ist. sudo su -, sudo bash und jedes erlaubte Programm mit einer Shell-Escape-Funktion verhalten sich genauso. Zwei Maßnahmen schließen diese Lücke: Audit-Regeln für execve, die jedes Programm mit der ursprünglichen Login-uid erfassen, und sudoers-Regeln, die gar keine Shell bereitstellen.
Verlangsamt auditd meinen Server?
Das hängt vollständig davon ab, wie viele Prozesse Ihre Arbeitslast startet. Messen Sie daher, statt einer allgemeinen Zahl zu vertrauen. Ein Server, der hauptsächlich Anfragen beantwortet, führt nur wenige exec-Aufrufe aus und wird keinen merklichen Unterschied zeigen. Ein Build-Host oder CI-Runner führt ständig exec-Aufrufe aus und kann eine deutliche Verlangsamung zeigen. Wenn der Audit-Backlog des Kernels voll ist, wird der Prozess, der das Ereignis erzeugt hat, angehalten, bis wieder Platz vorhanden ist. Führen Sie sudo auditctl -s unter realer Last aus und beobachten Sie backlog und lost. Ein lost über null bedeutet, dass Datensätze verworfen wurden. Das ist der schlechteste Fall, weil das Log dann unsichtbare Lücken enthält.
Wo sollten die Audit-Logs gespeichert werden?
Auf einem anderen Rechner, mit einer Verzögerung von wenigen Sekunden. Jeder, der root-Zugriff auf dem überwachten Host erlangt, kann /var/log/audit/audit.log löschen und /var/log/auth.log umschreiben. Lokale Kopien beantworten daher nur Fragen zu Vorfällen, bei denen niemand versucht hat, Spuren zu verbergen. Leiten Sie die Daten mit dem audisp-remote-Plugin an einen zentralen auditd weiter. Alternativ aktivieren Sie das audit-syslog-Plugin und leiten den gesamten Syslog-Datenstrom mit rsyslog über TLS weiter. Verwenden Sie für den Collector eigene Zugangsdaten. Stellen Sie außerdem sicher, dass die überwachten Konten keinen Zugriff darauf haben.