AusführungBenutzeraktivitätAnti-Forensik
Shell-History: Befehlslogs von bash, zsh und fish
Befehlshistorie pro Benutzer von bash, zsh und fish unter Linux: was jede Datei erfasst, wann es Zeitstempel gibt und wie sich Umgehung zeigt.
- Speicherort
- ~/.bash_history
- Belegt
- Welche Befehle in einer interaktiven Shell unter einem bestimmten Konto eingegeben wurden, manchmal auch wann
- Zeitstempel
- Sekunden seit der Unix-Epoche (UTC), sofern erfasst: bash nur mit HISTTIMEFORMAT, zsh mit EXTENDED_HISTORY, fish immer
- Zugriff
- Jeder Benutzer für die eigenen Dateien; root für die Home-Verzeichnisse anderer Benutzer
- Aufbewahrung
- Bis zur Kürzung durch HISTFILESIZE/SAVEHIST oder bis zur Löschung
- Sicherung
- UAC, Velociraptor, cp -a, tar
Was es ist
Interaktive Shells führen eine Liste der Befehlszeilen, die ein Benutzer eingegeben hat, und speichern sie in einer Datei pro Benutzer, damit sie in späteren Sitzungen wieder abrufbar sind. Bash, zsh und fish verwenden jeweils eine eigene Datei und ein eigenes Format. Die Dateien sind Klartext (fish nutzt ein YAML-ähnliches Layout), gehören dem Benutzer, sind für ihn beschreibbar und werden nach dem eigenen Rhythmus der Shell geschrieben, nicht bei jedem ausgeführten Befehl.
Für Ermittler ist das nach einer Kontoübernahme oft der direkteste Nachweis von Hands-on-Keyboard-Aktivität. Zugleich ist sie konstruktionsbedingt unvollständig: Was die Shell nie auf die Platte geschrieben hat oder was der Benutzer unterdrückt hat, fehlt schlicht.
Wo es liegt
| Shell | Standarddatei | Hinweise |
|---|---|---|
| bash | ~/.bash_history | Pfad über HISTFILE festgelegt; ist HISTFILE nicht gesetzt oder leer, wird beim Beenden nichts gespeichert |
| bash (root) | /root/.bash_history | Hier landen Befehle nach sudo -i, sudo su - oder su - |
| zsh | Kein Standard; üblich sind ~/.zsh_history oder ~/.zhistory | Wird nur geschrieben, wenn HISTFILE in einer Startdatei gesetzt ist (und SAVEHIST ungleich null) |
| fish | ~/.local/share/fish/fish_history | $XDG_DATA_HOME/fish/, falls gesetzt; die Variable fish_history ändert den Sitzungsnamen in <name>_history, ein leerer Wert deaktiviert das Speichern |
Die Pfade sind unter Debian/Ubuntu, RHEL/Fedora und anderen Familien gleich. Unterschiedlich ist die Standardkonfiguration: So setzt die Skeleton-~/.bashrc von Debian und Ubuntu HISTCONTROL=ignoreboth und aktiviert histappend, während andere Distributionen History-Variablen in /etc/profile, /etc/bashrc oder /etc/profile.d/ setzen können. Lesen Sie immer die tatsächlichen Startdateien im Image (siehe Shell-Startdateien), bevor Sie Lücken interpretieren.
Auch Dienstkonten haben Home-Verzeichnisse: Prüfen Sie /var/www, /var/lib/postgresql, /var/lib/mysql, /opt/* und jedes in /etc/passwd eingetragene Home-Verzeichnis auf verstreute History-Dateien.
Was es belegt
- Welche Befehlszeilen in einer interaktiven Shell unter diesem Konto eingegeben wurden.
- Die relative Reihenfolge, in der eine Shell diese Zeilen geschrieben hat (bei parallelen Sitzungen nicht immer die Ausführungsreihenfolge).
- Mit Zeitstempeln: wann jeder Befehl eingegeben wurde (bei zsh und fish lässt sich außerdem die Sitzungsaktivität eingrenzen).
- Verwendete Werkzeuge, Dateipfade, entfernte Hosts, URLs und Zugangsdaten in Argumenten, die auf weitere Artefakte verweisen.
Es belegt nicht:
- Wer an der Tastatur saß (geteilte, gestohlene oder per
sugewechselte Konten brechen die Zuordnung). - Dass ein Befehl erfolgreich war oder überhaupt lief, wenn er eingetippt und dann abgebrochen wurde.
- Irgendetwas über nicht interaktive Ausführung: Skripte, Cronjobs, Webshells und
ssh host 'cmd'hinterlassen hier normalerweise nichts.
Wichtige Felder
| Format | Aufbau des Eintrags | Bedeutung |
|---|---|---|
| bash, einfach | command line | Ein Eintrag pro Zeile, ohne Zeit |
bash, HISTTIMEFORMAT gesetzt | #1727512345, dann command line | Kommentarzeichen plus Ziffern markiert einen Zeitstempel für den folgenden Eintrag; grenzt zugleich mehrzeilige Einträge ab |
zsh EXTENDED_HISTORY | : <start>:<elapsed>;command | Startzeit in Sekunden seit der Epoche, verstrichene Sekunden, dann der Befehl |
| fish | - cmd: ... / when: ... / optionale Liste paths: | when sind Sekunden seit der Epoche; paths listet Argumente, die fish als existierende Pfade erkannt hat |
Zsh speichert Nicht-ASCII-Bytes in einer "metafied" Kodierung, daher wirken manche Zeichen in einem einfachen Textbetrachter beschädigt.
Zeitstempel
Alle drei Formate verwenden Sekunden seit der Unix-Epoche, also UTC. Die mtime der Datei zeigt, wann eine Shell sie zuletzt geschrieben hat, die ctime die letzte Metadatenänderung (nützlich, wenn eine Datei gekürzt oder durch einen Symlink ersetzt wurde).
# bash with HISTTIMEFORMAT
grep -E '^#[0-9]{9,}$' .bash_history | head -1 | cut -c2- | xargs -I{} date -u -d @{} # first timed entry
# zsh extended history
awk -F'[:;]' '/^: [0-9]+:/ {cmd="date -u -d @" ($2+0) " +%FT%TZ"; cmd | getline t; close(cmd); print t, $0}' .zsh_history
Aufbewahrung
- bash: Beim Beenden werden die letzten
HISTSIZEEinträge (Standard 500) angehängt (mithistappend) oder überschreiben die Datei, die anschließend aufHISTFILESIZEZeilen gekürzt wird. Alte Aktivität fällt oben heraus. - zsh:
SAVEHISTbegrenzt die Datei.APPEND_HISTORYist standardmäßig aktiv;INC_APPEND_HISTORYoderSHARE_HISTORYschreiben jeden Befehl sofort statt erst beim Beenden. - fish:
history clearundhistory deleteentfernen Einträge;history mergeübernimmt Änderungen anderer Sitzungen. - Sitzungen, die mit
SIGKILLbeendet wurden, abgestürzt sind oder zum Zeitpunkt der Sicherung noch offen waren, erreichen die Platte womöglich nie. Eine laufende bash hält sie im Prozessspeicher.
Sicherung
Sichern Sie aus jedem Home-Verzeichnis und aus /root, einschließlich rotierter oder gesicherter Kopien (.bash_history~, .bash_history.*). Die UAC-Artefakte files/shell/* (Teil von ir_triage) decken bash, zsh, fish und weitere Shells ab und werten zudem Startdateien aus, um ein vom Standard abweichendes HISTFILE zu finden.
sudo ./uac -p ir_triage /mnt/usb/case42
# dead box, read-only mount
find /mnt/evidence/root /mnt/evidence/home -maxdepth 4 \
\( -name '.*history*' -o -path '*/fish/fish_history' \) -print0 | tar --null -T - -czf history.tgz
In Velociraptor durchsucht Linux.Sys.BashHistory /{root,home/*}/.*_history auf allen Endpunkten. Wenn die verdächtige Shell noch laufen könnte, sichern Sie zuerst den Arbeitsspeicher (LiME oder AVML): Die Sicherung der Platte schreibt die History aus dem Speicher nicht weg, eine spätere Abmeldung überschreibt aber, was Sie gesehen haben.
Auswertung
- Plaso: Die Text-Plugins
bash_historyundzsh_extended_historysind im Presetlinuxenthalten (Auswahl alstext/bash_historyundtext/zsh_extended_history);fish_historyist ein separater Parser. Nur Einträge mit Zeitstempel werden zu Ereignissen. - Volatility 3:
linux.bash.Bashstellt die History aus laufenden bash-Prozessen wieder her, einschließlich Befehlen, die nie auf die Platte geschrieben wurden. - Für die Durchsicht genügen einfache Werkzeuge:
log2timeline.py --parsers 'text/bash_history,text/zsh_extended_history,fish_history' \
--storage-file hist.plaso /mnt/evidence/home
psort.py -o dynamic --output_time_zone UTC -w hist.csv hist.plaso
Tipps für die Untersuchung
- Werten Sie eine leere, null Byte große oder per Symlink auf
/dev/nullzeigende History bei einem aktiven Konto als Spur. Prüfen Sie diectimedes Symlinks und vergleichen Sie diemtimeder Datei mit Anmeldungen in wtmp und lastlog. - Suchen Sie in den Historien anderer Shells, in Startdateien und im Arbeitsspeicher nach Umgehungsbefehlen:
unset HISTFILE,HISTFILE=/dev/null,HISTSIZE=0,set +o history,history -c,history -d,kill -9 $$. - Fehlende Befehle, die mit führendem Leerzeichen eingegeben wurden, sind zu erwarten, wenn
ignorespace/ignorebothoder bei zshHIST_IGNORE_SPACEgesetzt ist, und fish verwirft solche Zeilen grundsätzlich. Das ist eine Voreinstellung, kein Beweis für Absicht. - Sind in einer bash-Datei nur teilweise
#epoch-Zeilen vorhanden, warHISTTIMEFORMATirgendwann aktiviert; Zeilen ohne Zeit sind älter oder stammen aus einer Shell ohne diese Einstellung. - Machen Sie nach
sudo -iodersu -in/root/.bash_historyweiter und korrelieren Sie mit den sudo-Logs. - Wo auditd
EXECVEprotokolliert, liefert es unabhängige Ausführungsdatensätze mit Zeitstempel, die History-Einträge bestätigen (siehe auditd). - Editoren, Pager und REPLs führen eigene Historien, die Angreifer selten bereinigen: siehe viminfo und lesshst.
Siehe auch
Verwandte Artefakte
Ausführliche Leitfäden
Glossar
- Volatility 3Englisch
- Super TimelineEnglisch
- UAC (Unix-like Artifacts Collector)Englisch