Fondamenti di macOS e Linux · Lezione 4 di 5
Log Linux: journald, log di autenticazione, wtmp e btmp
13 min di lettura
Su un server Linux, alla domanda «chi ha effettuato l'accesso, da dove, quando e quali operazioni ha eseguito come root» rispondono i log testuali, il journal di systemd e piccoli registri binari degli accessi. Questa lezione illustra dove si trova ciascuna di queste fonti sui sistemi di tipo Debian e Red Hat, come leggerle offline, come convertirne i timestamp in valori UTC esatti e come riscontrare un singolo accesso SSH in tutte queste fonti.
Log testuali in /var/log
I log testuali vengono scritti da un demone syslog, solitamente rsyslog, secondo le regole contenute in /etc/rsyslog.conf e /etc/rsyslog.d/. Consultare tali regole nell'immagine: mostrano quale file ha ricevuto quali messaggi e se i messaggi sono stati inoltrati a un host di log remoto non raggiungibile dall'attaccante.
| Contenuto | Debian e Ubuntu | Famiglia RHEL (RHEL, Rocky, Alma, Fedora) |
|---|---|---|
| Autenticazione, sudo, su, modifiche agli account | /var/log/auth.log | /var/log/secure |
| Messaggi generali di sistema | /var/log/syslog | /var/log/messages |
| Messaggi del kernel | /var/log/kern.log | in messages |
| Attività pianificate | in syslog (a meno che non sia abilitato cron.log) | /var/log/cron |
| Servizi | directory proprie, ad es. /var/log/apache2/, /var/log/nginx/ | directory proprie, ad es. /var/log/httpd/ |
Le configurazioni Debian meno recenti scrivevano anche daemon.log e user.log. Le impostazioni predefinite cambiano, quindi occorre riportare ciò che contiene l'immagine. In particolare, le nuove installazioni di Debian 12 e versioni successive non includono necessariamente rsyslog; quando è assente, /var/log/auth.log non esiste e il journal è l'unico registro degli accessi.
Rotazione
logrotate (configurato in /etc/logrotate.conf e /etc/logrotate.d/) rinomina i log secondo una pianificazione. Su Debian, i file di rsyslog vengono in genere ruotati settimanalmente, conservando quattro copie precedenti e applicando una compressione differita, ottenendo così auth.log, auth.log.1, auth.log.2.gz, auth.log.3.gz e auth.log.4.gz. I sistemi della famiglia RHEL aggiungono solitamente una data invece di un numero (secure-20260308). Acquisire tutti i file ruotati, effettuare ricerche in quelli compressi con zgrep e ordinarli in base al contenuto, non al nome.
Timestamp
Il formato syslog classico (stile RFC 3164) inizia ogni riga con Mar 14 14:20:31: senza anno né fuso orario. L'ora è l'ora locale del sistema al momento della scrittura della riga. Per convertirla è necessario stabilire:
- Anno: dall'ora di modifica del file, dalla sequenza di rotazione e da fonti datate come il journal o wtmp. Prestare attenzione alle righe di dicembre presenti in un file chiuso a gennaio.
- Fuso orario: da
/etc/localtimenell'immagine (solitamente un collegamento simbolico all'interno di/usr/share/zoneinfo/; risolverlo all'interno dell'immagine, non sulla macchina di analisi) e, su Debian, da/etc/timezone.
rsyslog può invece scrivere timestamp RFC 3339 e i pacchetti rsyslog di Debian 12 e Ubuntu 24.04 lo fanno per impostazione predefinita, con microsecondi e uno scostamento, ad es. 2026-03-14T10:43:52.104312-03:00. Questo formato include l'anno e lo scostamento, quindi la conversione non richiede assunzioni.
Il journal di systemd
systemd-journald memorizza i log in un formato binario indicizzato. I file persistenti si trovano in /var/log/journal/<machine-id>/, dove l'ID della macchina è il valore di 32 cifre esadecimali contenuto in /etc/machine-id. I file volatili si trovano in /run/log/journal/, risiedono in RAM, vengono persi al riavvio e sono assenti da un'immagine del disco. La scelta dipende dall'impostazione Storage= in /etc/systemd/journald.conf; il valore predefinito auto memorizza i dati in modo persistente solo se esiste /var/log/journal.
Il file attivo è system.journal (oltre a user-<UID>.journal per le sessioni utente). I file archiviati sono denominati system@….journal. Un file non chiuso correttamente, ad esempio dopo un arresto anomalo, viene rinominato system@….journal~; questi file sono spesso ancora leggibili e devono anch'essi essere acquisiti.
Ogni voce è un insieme di campi. I campi con un trattino basso iniziale vengono aggiunti da journald, quindi il programma che genera il log non può falsificarli; due trattini bassi contrassegnano i metadati di indirizzamento.
| Campo | Significato |
|---|---|
MESSAGE | Il testo del log, ad es. la riga di sshd |
SYSLOG_IDENTIFIER | Etichetta del programma, ad es. sshd, sudo |
_PID, _UID, _COMM | ID del processo, ID utente e nome del comando del mittente |
_SYSTEMD_UNIT | Unità di servizio, ad es. ssh.service |
_BOOT_ID | Identificatore a 128 bit dell'avvio durante il quale è stata scritta la voce |
__REALTIME_TIMESTAMP | Microsecondi trascorsi dal 1970-01-01 00:00:00 UTC al momento in cui journald ha ricevuto la voce |
Leggere un journal offline con journalctl -D /case/var/log/journal (una directory) oppure journalctl --file '/case/var/log/journal/<machine-id>/system@*.journal'. Utilizzare una versione recente di journalctl; una versione precedente può rifiutare file che utilizzano funzionalità di formato più recenti. Opzioni utili:
--utcper visualizzare l'ora UTC; specificare--since "2026-03-14 13:00:00 UTC"e--untilcon un suffissoUTCesplicito.-u sshper l'unità OpenSSH su Debian e Ubuntu (-u sshdsu RHEL), oppure_COMM=sshd. A partire da OpenSSH 9.8, le operazioni relative a ciascuna connessione sono eseguite dasshd-session, quindi le righe possono riportare questo nome.-o jsonoppure-o verboseper mostrare tutti i campi, incluso__REALTIME_TIMESTAMP;-o short-iso-preciseper orari leggibili con precisione al microsecondo.--list-bootsper elencare gli ID di avvio con le rispettive prime e ultime voci, quindi-b <boot ID>;--verifyper verificare la coerenza dei file.
Significato delle righe di autenticazione
Le stesse righe compaiono nel journal e, quando rsyslog è in esecuzione, in auth.log o secure.
| Riga (processo) | Significato |
|---|---|
Accepted password for alice from 198.51.100.23 port 51744 ssh2 (sshd) | Accesso con password riuscito: account, IP di origine, porta di origine |
Accepted publickey for root from 198.51.100.23 port 51790 ssh2: ED25519 SHA256:<fingerprint> (sshd) | Accesso con chiave; l'impronta digitale identifica la chiave |
Failed password for root from 203.0.113.77 port 40210 ssh2 (sshd) | Password errata per un account esistente |
Invalid user admin from 203.0.113.77 port 40212 e Failed password for invalid user admin from … (sshd) | L'account non esiste su questo sistema |
Disconnected from user alice 198.51.100.23 port 51744 (sshd) | Fine della connessione SSH |
pam_unix(sshd:session): session opened for user alice(uid=1001) by (uid=0) | Inizio della sessione PAM (le versioni meno recenti omettono l'UID dopo il nome); session closed ne indica la fine |
alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/tar czf /tmp/h.tgz /home (sudo) | Comando eseguito come root: da chi, da quale terminale e directory, con quale identità ed esattamente quale comando |
(to root) alice on pts/0 (su) | Passaggio a un altro account con su |
new user: name=svc-upd, UID=1002, …, add 'svc-upd' to group 'sudo', password changed for svc-upd (useradd, usermod, passwd) | Creazione e modifiche degli account, registrate da shadow-utils e PAM |
Per collegare un accesso publickey a una chiave, eseguire ssh-keygen -lf sul file ~/.ssh/authorized_keys dell'account presente nell'immagine; il comando visualizza l'impronta digitale SHA256 di ogni chiave e il campo commento della riga corrispondente spesso ne indica il proprietario.
Registri binari degli accessi
| File | Contenuto | Comando offline |
|---|---|---|
/var/run/utmp | Sessioni correnti; risiede in RAM, quindi è disponibile solo nelle acquisizioni dal vivo | who /path/to/utmp |
/var/log/wtmp | Cronologia di accessi e disconnessioni, riavvii e arresti, con host o IP di origine | TZ=UTC last -f wtmp -i -x --time-format iso |
/var/log/btmp | Accessi falliti, un record per tentativo, inclusi nomi utente inesistenti | TZ=UTC lastb -f btmp -i --time-format iso |
/var/log/lastlog | Ultimo accesso per UID: ora, terminale, host | analizzare direttamente (vedere sotto) |
last e lastb visualizzano gli orari nel fuso orario della macchina di analisi, da cui la necessità di TZ=UTC; -i visualizza ut_addr_v6 in forma numerica; utmpdump wtmp estrae tutti i campi con i microsecondi.
utmp, wtmp e btmp condividono la struct utmp di glibc, con record da 384 byte su Linux x86-64: ut_type all'offset 0 (7 USER_PROCESS accesso, 8 DEAD_PROCESS disconnessione, 2 BOOT_TIME riavvio), ut_pid a 4, ut_line (32 byte, ad es. pts/0) a 8, ut_user (32 byte) a 44, ut_host (256 byte) a 76, ut_tv (secondi a 32 bit e microsecondi trascorsi dall'epoca Unix, UTC) a 340 e ut_addr_v6 (16 byte) a 348. La dimensione di un file integro è un multiplo di 384. last associa un accesso alla disconnessione successiva sullo stesso ut_line. Il campo dei secondi a 32 bit va in overflow a gennaio 2038, quindi le distribuzioni recenti stanno abbandonando questi file. Debian 13 non include più last, lastb o lastlog: gli accessi vengono registrati in wtmpdb (/var/lib/wtmpdb/wtmp.db, leggibile con wtmpdb last) e lastlog2 (/var/lib/lastlog/lastlog2.db) quando installati, mentre gli accessi falliti potrebbero essere presenti solo nel journal. Verificare quali file contiene effettivamente l'immagine e, su un host di analisi Debian 13, analizzare wtmp/btmp con utmpdump o uno script.
lastlog contiene record da 292 byte (ll_time 4 byte, ll_line 32, ll_host 256) indicizzati per UID all'offset UID × 292. È un file sparso: un UID elevato ne rende enorme la dimensione apparente, pur utilizzando poco spazio su disco. Il comando lastlog legge per impostazione predefinita il file del sistema in esecuzione, quindi, su un'immagine, leggere il record all'offset calcolato.
Forza bruta e manomissione
Un attacco di forza bruta si manifesta con centinaia di righe Failed password e Invalid user e di record btmp provenienti da un unico IP nell'arco di pochi minuti, spesso provando in sequenza nomi come root, admin e test. Il riscontro decisivo è una successiva riga Accepted proveniente dallo stesso IP. Il password spraying presenta caratteristiche diverse: pochi tentativi per account provenienti da molti IP. rsyslog può accorpare righe consecutive identiche in message repeated N times, quindi occorre contare sia i record btmp sia le righe testuali.
Gli indicatori di manomissione includono lacune durante attività note, un log corrente vuoto accanto a log ruotati pieni, numeri di rotazione mancanti, record wtmp composti interamente da zeri, dimensioni non multiple di 384 e discrepanze tra journal e auth.log; il Modulo 7 tratta la cancellazione dei log.
Esempio svolto: ricostruzione di un'intrusione SSH
Un server Debian il cui /etc/localtime punta ad America/Sao_Paulo (UTC−3, senza ora legale nel 2026) utilizza rsyslog con il formato tradizionale e un journal persistente.
- Tentativi falliti.
TZ=UTC lastb -f btmp -i --time-format iso | grep -c 203.0.113.77restituisce 1.240 record, il primo alle 2026-03-14T13:02:15Z, l'ultimo alle 13:39:48Z. Durata: 37 min 33 s = 2.253 s, quindi 1.240 / 2.253 ≈ 0,55 tentativi al secondo. Se btmp contiene solo questi record, la sua dimensione deve essere 1.240 × 384 = 476.160 byte. - Accesso riuscito.
journalctl -D /case/var/log/journal _COMM=sshd -o jsonmostraAccepted password for backup from 203.0.113.77 port 40122 ssh2con__REALTIME_TIMESTAMP1773495667482913. Scomposizione: 1.773.495.667 secondi e 482.913 microsecondi. 1.773.495.667 / 86.400 = 20.526 giorni con resto di 49.267 s; 49.267 s = 13 h 41 min 7 s; il giorno 20.526 dopo il 1970-01-01 è il 2026-03-14. Risultato: 2026-03-14T13:41:07.482913Z, confermato conpython3 -c "import datetime as d; print(d.datetime(1970,1,1,tzinfo=d.timezone.utc)+d.timedelta(microseconds=1773495667482913))". - Uso dei privilegi.
auth.log.1contieneMar 14 10:43:52 srv01 sudo: backup : TTY=pts/0 ; PWD=/var/backups ; USER=root ; COMMAND=/usr/bin/tar czf /tmp/.c.tgz /etc /home. Assunzioni: anno 2026 (l'ora di modifica del file e il journal), ora locale UTC−3 da/etc/localtimee orologio corretto (lezione 3.5). 10:43:52 + 3 h = 2026-03-14T13:43:52Z, corrispondente alla voce del journal relativa alla stessa riga. - Sessione.
TZ=UTC last -f wtmp -i --time-format isomostrabackup pts/0 203.0.113.77 2026-03-14T13:41:07+00:00 - 2026-03-14T14:12:40+00:00 (00:31), corrispondente aDisconnected from user backup 203.0.113.77 port 40122alle 14:12:40Z nel journal. - Ultimo accesso. Su Debian,
backupè un account di sistema con UID 34, quindi il relativo record lastlog si trova a 34 × 292 = 9.928 byte:ll_timeviene decodificato come 13:41:07Z,ll_hostè203.0.113.77. Poichébackupnormalmente ha una password bloccata e la shell/usr/sbin/nologin, verificare/etc/passwd,/etc/shadowe sudoers (lezione 6.3) per determinare come abbia ottenuto una password, una shell e i diritti sudo.
Domanda → log → comando
| Domanda | Log | Comando (offline) |
|---|---|---|
| Chi ha effettuato l'accesso, da quale IP e quando? | wtmp; journal; auth.log/secure | TZ=UTC last -f wtmp -i --time-format iso; journalctl -D … --utc -u ssh |
| Quanti tentativi falliti e da dove? | btmp; auth.log | TZ=UTC lastb -f btmp -i; zgrep "Failed password" auth.log* |
| Quale chiave è stata utilizzata? | auth.log/journal; authorized_keys | ssh-keygen -lf authorized_keys |
| Che cosa è stato eseguito come root? | righe di sudo | journalctl -D … _COMM=sudo |
| Sono stati creati o modificati account? | auth.log/journal | zgrep -e "new user" -e usermod -e "password changed" auth.log* |
| Qual è l'ora esatta al microsecondo? | journal | journalctl -D … -o json (__REALTIME_TIMESTAMP) |
| Quando è stato avviato il sistema? | journal; wtmp | journalctl -D … --list-boots; last -f wtmp -x reboot |
Focus sull'esame: È possibile che venga richiesto di riportare un IP di origine di un accesso o un orario UTC ricavato dai log Linux e di convertire correttamente un valore__REALTIME_TIMESTAMPo una riga syslog priva di anno. Sapere quale file contiene gli accessi falliti (btmp), la cronologia degli accessi (wtmp) e il nome del log di autenticazione su RHEL (secure). Essere pronti a esplicitare le assunzioni alla base di una conversione syslog: anno, fuso orario e orologio.
Punti chiave
- Gli eventi di autenticazione vengono registrati in
auth.log(Debian/Ubuntu) osecure(famiglia RHEL); acquisire ogni copia ruotata, inclusi i file.gz. - Gli orari syslog classici non includono né anno né fuso orario; le versioni recenti di Debian e Ubuntu scrivono orari RFC 3339 con uno scostamento e i nuovi sistemi Debian 12+ potrebbero avere solo il journal.
- Il journal si trova in
/var/log/journal/<machine-id>/(persistente) o/run/log/journal(perso al riavvio); leggerlo conjournalctl -De--utc;__REALTIME_TIMESTAMPindica i microsecondi trascorsi dall'epoca Unix, UTC. - utmp, wtmp e btmp utilizzano record da 384 byte con orari espressi rispetto all'epoca Unix in UTC; eseguire
lastelastbconTZ=UTC. - lastlog è indicizzato per UID a UID × 292 byte; analizzarlo direttamente da un'immagine.
- Riscontrare un accesso confrontando btmp, la riga di sshd, wtmp, lastlog e le righe di sudo.
Domande di esercitazione
Verifica la tua comprensione. Queste domande non contano per l’esame.
Accedi per salvare i tuoi progressi e riprendere da dove hai lasciato. È gratuito. Accedi