Forensik von wtmp, btmp, lastlog, wtmpdb und lastlog2
Linux-Login-Einträge in der Ermittlung: struct utmp auf x86_64 und aarch64, btmp, lastlog-Slots, die SQLite-Dateien wtmpdb und lastlog2 sowie Manipulation.
Kurzfassung. wtmp ist der Verlauf interaktiver Sitzungen und Neustarts, btmp enthält die fehlgeschlagenen Logins, utmp die gerade offenen Sitzungen und lastlog den letzten Login jeder UID. Es sind binäre Einträge fester Größe, die außerhalb von syslog geschrieben werden; sie überstehen daher eine Bearbeitung der Textlogs und widersprechen ihnen, wenn diese nicht mitbearbeitet werden. Lesen Sie sie mit einem Parser, der die Eintragsgröße der Quell-Architektur kennt, und suchen Sie auf neueren Distributionen nach ihren SQLite-Nachfolgern wtmp.db und lastlog2.db.
Die Dateien
| Datei | Pfad | Leseprogramm | Inhalt |
|---|---|---|---|
| wtmp | /var/log/wtmp, wtmp.1 | last | Logins, Logouts, Starts, Shutdowns |
| btmp | /var/log/btmp, btmp.1 | lastb | Fehlgeschlagene Logins (nur für root, sensibel) |
| utmp | /run/utmp | who, w | Aktuelle Sitzungen, beim Systemstart geleert |
| lastlog | /var/log/lastlog | lastlog | Ein Slot pro UID |
| wtmpdb | /var/lib/wtmpdb/wtmp.db, /var/log/wtmp.db (Debian 13) | wtmpdb last | SQLite-Ersatz für wtmp |
| lastlog2 | /var/lib/lastlog/lastlog2.db | lastlog2 | SQLite-Ersatz für lastlog |
logrotate rotiert wtmp und btmp typischerweise monatlich und behält eine ältere Generation; rechnen Sie also mit ein bis zwei Monaten. lastlog behält einen Eintrag pro UID unbegrenzt.
struct utmp: 384 Bytes oder 400
wtmp, btmp und utmp teilen sich struct utmp:
| Feld | Inhalt |
|---|---|
ut_type | 1 RUN_LVL, 2 BOOT_TIME, 5 INIT_PROCESS, 6 LOGIN_PROCESS, 7 USER_PROCESS (Login), 8 DEAD_PROCESS (Logout) |
ut_pid | PID des Login-Prozesses (sshd bei SSH) |
ut_line | Terminal, pts/1, tty1, 32 Bytes |
ut_user | Benutzername, 32 Bytes; leer bei Logout-Einträgen |
ut_host | Remote-Host oder IP; Kernelversion bei Neustart-Einträgen; 256 Bytes |
ut_tv | Sekunden und Mikrosekunden, UTC |
ut_addr_v6 | Remote-Adresse |
Mit der glibc auf x86_64 ist der Eintrag 384 Bytes groß: Die Zeitfelder sind aus Kompatibilität mit 32-Bit-Programmen 32 Bit breit. Auf aarch64 sind sie 64 Bit breit, und der Eintrag umfasst 400 Bytes. last liest Einträge mit dem Layout des Systems, auf dem es läuft; eine aarch64-wtmp, die mit last auf einer x86_64-Workstation gelesen wird, liefert daher Datenmüll oder gar nichts. Führen Sie last auf passender Architektur aus oder verwenden Sie einen Parser, der das Layout anhand der Dateigröße und der Plausibilität der Felder erkennt.
Ein Logout ist ein DEAD_PROCESS-Eintrag auf derselben ut_line mit leerem Benutzer; last paart sie. Ein Login ohne passenden Logout erscheint als gone - no logout oder als crash, wenn ein Boot-Eintrag folgt.
lastlog: ein Slot pro UID
/var/log/lastlog ist ein nach UID indiziertes Array von struct lastlog: 292 Bytes pro Slot auf x86_64 (32-Bit-Zeit, 32-Byte-Leitung, 256-Byte-Host), 296 auf aarch64. Der Offset von UID 1001 ist 1001 × 292. Die Datei ist eine Sparse-Datei: Ein Login von UID 100000 lässt sie riesig erscheinen, obwohl nur wenige Blöcke belegt sind. Sichern Sie sie mit tar --sparse.
Der lastlog-Wert wird bei jedem Login überschrieben und verrät daher nur den letzten, wird aber unabhängig von wtmp geschrieben. Eine lastlog-Zeit, zu der wtmp keine Sitzung hat, ist ein starkes Signal dafür, dass wtmp einen Eintrag verloren hat.
wtmpdb und lastlog2
Die 32-Bit-Zeitfelder laufen 2038 über, daher wechseln neuere Distributionen zu SQLite:
- wtmpdb: Tabelle
wtmp(ID, Type, User, Login, Logout, TTY, RemoteHost, Service).LoginundLogoutsind Mikrosekunden seit der Epoche;Typeist 1BOOT_TIME, 2RUNLEVEL, 3USER_PROCESS. Eine Zeile pro Sitzung, deren Logout beim Sitzungsende eingetragen wird, dazu der PAM-NameService(sshd,login), den das klassische Format nie hatte. - lastlog2: Tabelle
Lastlog2(Name, Time, TTY, RemoteHost, Service)mitTimein Sekunden und einer Zeile pro Benutzername.
openSUSE Tumbleweed verwendet sie standardmäßig. Debian 13 hat last, lastb und lastlog entfernt und legt die wtmpdb-Datei unter /var/log/wtmp.db ab; die Pakete müssen separat installiert werden, sodass ein aktualisierter trixie-Host unter Umständen gar keine Login-Datenbank hat. Sichern Sie die -wal-Datei neben einer Datenbank, falls vorhanden: Neuere Zeilen können noch darin stehen.
sqlite3 wtmp.db "SELECT User, TTY, RemoteHost, Service, datetime(Login/1000000,'unixepoch'), datetime(Logout/1000000,'unixepoch') FROM wtmp;"
sqlite3 lastlog2.db "SELECT Name, datetime(Time,'unixepoch'), TTY, RemoteHost, Service FROM Lastlog2;"
btmp: fehlgeschlagene Logins
btmp verwendet dasselbe Eintragslayout. Jeder fehlgeschlagene Versuch ist ein Eintrag mit dem versuchten Benutzernamen, dem Quellhost und der Zeit. Es ist eine dritte, unabhängige Kopie des Passwortratens, das auch in auth.log und im Journal steht, nützlich, wenn diese bereinigt wurden. Behandeln Sie btmp als sensibel: Benutzer tippen ihr Passwort manchmal in das Feld für den Benutzernamen.
Wie Manipulation aussieht
- Geleerte Einträge. Log-Cleaner überschreiben einen Login-Eintrag mit Nullen, statt ihn zu löschen, sodass die Dateigröße ein Vielfaches der Eintragsgröße bleibt.
lastüberspringt ihn einfach. In der Ausgabe vonutmpdumperscheint er als Eintrag mit Typ 0, ohne Benutzer und mit einem Datum aus 1970. - Unvollständiger Eintrag am Ende. Eine Dateigröße, die kein Vielfaches von 384 (bzw. 400) ist, bedeutet einen abgebrochenen Schreibvorgang oder eine Datei, die während des Schreibens kopiert wurde.
- Rückwärts laufende Zeit zwischen aufeinanderfolgenden Einträgen.
- wtmp oder btmp mit null Bytes und alter Änderungszeit auf einem Server, der in Betrieb ist.
- Eine interaktive SSH-Sitzung in auth.log, Journal und audit.log, aber nicht in wtmp, obwohl wtmp diesen Zeitraum abdeckt.
Denken Sie an den harmlosen Fall: ssh host command, scp und sftp öffnen kein Terminal und hinterlassen oft keinen wtmp-Eintrag. Vergleichen Sie nur interaktive Sitzungen (ein pts-Terminal in den Logs).
Befehle
TZ=UTC last -F -i -x -f wtmp # vollständige Daten, IPs, Neustarts
TZ=UTC lastb -F -i -f btmp
utmpdump wtmp > wtmp.txt # jeder Eintrag, auch geleerte
wtmpdb last -F -f wtmp.db
lastlog2 -d lastlog2.db
last gibt Zeiten in der Zone des Analysesystems aus, sofern TZ=UTC nicht gesetzt ist.
Im Browser
Linux Log Parser liest wtmp, btmp und utmp sowohl im 384-Byte- als auch im 400-Byte-Layout, lastlog, wtmp.db und lastlog2.db; er meldet geleerte, unvollständige und rückwärts laufende Einträge, paart Logins mit Logouts, führt sie mit sshd-, logind- und Audit-Sitzungen zusammen und kennzeichnet interaktive Logins ohne wtmp-Eintrag. Siehe den Leitfaden zur Manipulationserkennung und den wtmp-Spickzettel.