Articolo Pubblicazioni
Sicurezza dei sistemi operativi: utenti, permessi e hardening, dalle basi a oggi
di Vincenzo Calabrò · Pubblicato il 5 giugno 2000 - Aggiornato il 14 novembre 2026 · Tratto da «Corso sulla Sicurezza del Sistema Operativo»
Abstract
L’articolo riprende il corso sulla sicurezza del sistema operativo tenuto nel giugno 2000 e ne ordina i contenuti per chi studia o amministra sistemi oggi. Tratta l’autenticazione degli utenti, gli attacchi dall’interno come buffer overflow, trojan horse, bombe logiche e trap door, quelli dall’esterno come worm e virus, il controllo degli eventi sospetti, il codice mobile e i meccanismi di protezione basati su domini, liste di controllo degli accessi e capability. Una sezione finale indica che cosa è cambiato in venticinque anni e quali principi restano validi.
SCARICA LE SLIDE: «Corso sulla Sicurezza del Sistema Operativo» Calabrò V., 2000, PDF di 68 pagine
Il problema della sicurezza
Un sistema operativo va protetto dagli accessi non autorizzati, dalla modifica o dalla cancellazione fraudolenta dei dati e dalla perdita o dall’incoerenza accidentale dei dati, causata per esempio da un incendio o da un guasto dell’hardware. Il corso partiva da un’osservazione che vale ancora. Difendersi dagli abusi intenzionali sembra il compito più difficile, eppure la maggior parte dei problemi nasce da eventi accidentali.
L’autenticazione degli utenti
Quando un utente si collega, il sistema deve riconoscerlo per assegnargli privilegi e permessi. L’autenticazione si basa su tre principi:
- qualcosa che l’utente conosce, come una password;
- qualcosa che l’utente possiede, come una tessera o una smart card;
- una caratteristica fisica dell’utente, rilevata con tecniche biometriche.
Password e salt
Per violare un sistema basato su password servono un nome di login valido e la password corrispondente. I sistemi operativi rendono il furto più difficile in vari modi. Non mostrano i caratteri digitati, danno meno informazioni possibili dopo un login errato e rifiutano le parole chiave troppo deboli, per esempio quelle sotto i sette caratteri, senza maiuscole e minuscole o senza cifre e caratteri speciali.
Le password non vanno conservate in chiaro. Il sistema ne memorizza l’impronta, calcolata con una funzione unidirezionale. Lo schema di Morris e Thompson aggiunge a ogni password un numero casuale di n bit, il salt, che cambia a ogni modifica della password e viene salvato in chiaro accanto all’impronta. Un dizionario di password probabili preparato prima dell’attacco deve così essere ricalcolato per ognuno dei 2n valori possibili del salt.
One-time password e challenge-response
Il meccanismo di one-time password ideato da Leslie Lamport nel 1981 permette di collegarsi a un server remoto anche se il traffico viene intercettato. L’utente sceglie un segreto e un numero n, e le password si ottengono applicando più volte al segreto una funzione unidirezionale. Il server conserva solo l’ultimo valore della catena. A ogni accesso l’utente invia il valore precedente, il server ne calcola la funzione e confronta il risultato con quello memorizzato. Chi intercetta una password può ricavare soltanto quelle già usate.
Nello schema challenge-response il server invia un numero casuale e il client risponde con il risultato di una funzione nota, calcolata sul numero e su una chiave segreta installata in precedenza sul server. La chiave non transita mai in rete, purché la funzione sia abbastanza complessa da non permettere di ricavarla dalle risposte osservate.
Oggetti posseduti e biometria
Le schede magnetiche contenevano circa 140 byte su una banda incollata sul retro. Le chip card si dividevano in stored value card, con circa 1 KB di memoria, e smart card. Le smart card del 2000 avevano una CPU a 8 bit a 4 MHz, 16 KB di ROM, 4 KB di EEPROM e 512 byte di RAM, ed erano piccoli computer capaci di dialogare con un altro computer. La biometria prevede la registrazione delle caratteristiche fisiche e il confronto al momento dell’accesso. Il nome di login resta necessario, perché le misure sono imprecise e due persone possono avere caratteristiche simili.
Gli attacchi dall’interno del sistema
Buffer overflow
Gran parte dei sistemi operativi e dei programmi di sistema è scritta in C, un linguaggio che non controlla i limiti dei vettori. Se il vettore è locale a una funzione si trova sullo stack, e un indice oltre il limite può sovrascrivere l’indirizzo di ritorno. L’attaccante dirotta così l’esecuzione verso uno shellcode, un breve programma in assembly che apre una shell. Le slide mostravano un esempio completo in cui un programma di sistema vulnerabile, con il bit setuid attivo, portava un utente qualsiasi a una shell di root.
Trojan horse e login spoofing
Un trojan horse è un programma in apparenza innocuo che modifica, cancella o cifra file, oppure li copia e li spedisce all’attaccante. Spesso viene distribuito dentro un programma gratuito e appetibile. Per farlo eseguire si sfrutta la variabile PATH, dando al trojan il nome di un comando comune scritto con un errore di battitura frequente, come
la al posto di ls. Se la directory corrente compare in testa al PATH, basta un trojan chiamato come un comando di sistema nella home di un utente per ingannare l’amministratore che va a controllare.Il login spoofing usa un trojan che imita la schermata di accesso, raccoglie nome utente e password e poi restituisce la schermata vera, lasciando credere alla vittima di avere sbagliato a digitare. Per questo sistemi come Windows NT e 2000 chiedono una combinazione di tasti, Ctrl+Alt+Canc, che i programmi utente non possono intercettare.
Bombe logiche e trap door
Una bomba logica è codice inserito da un dipendente che resta inattivo fino a un evento, come la scomparsa del suo nome dal libro paga, e poi cancella, altera o cifra i dati. Una trap door è un nome utente o una password speciali, lasciati dal programmatore per saltare i controlli durante lo sviluppo e dimenticati, a volte di proposito, nella versione rilasciata. Il rimedio indicato era la revisione periodica del codice, in cui ogni programmatore spiega riga per riga il proprio lavoro ai colleghi.
Worm e virus, gli attacchi dall’esterno
Un worm è un programma autonomo che si replica attraverso la rete. Il primo, il worm di Morris del 1988, sfruttava difetti di finger e sendmail nei sistemi UNIX. Un virus è invece un frammento di codice che si inserisce in programmi legittimi. Il corso ne descriveva diverse famiglie:
- i companion virus, che si fanno eseguire al posto di un programma con lo stesso nome, per esempio un
.comche precede il.exe; - i virus che infettano gli eseguibili, sostituendoli, aggiungendosi in testa o in coda oppure occupando gli spazi liberi del file;
- i virus residenti in memoria, che si agganciano ai vettori di interrupt;
- i virus del settore di boot e quelli dei device driver, che partono con il sistema;
- i macro virus, che viaggiano nei documenti attivi come quelli di Word;
- i source code virus, che inseriscono chiamate al proprio codice nei sorgenti C.
Gli antivirus dell’epoca cercavano nei file la firma dei virus noti, controllavano le checksum dei file e sorvegliavano le chiamate di sistema sospette, come l’accesso al settore di boot. I virus rispondevano comprimendo o cifrando il proprio codice, oppure cambiandolo a ogni copia con istruzioni inutili e riordini. Erano i virus polimorfi, generati da appositi mutation engine.
Il controllo degli eventi sospetti
Molti login falliti consecutivi possono indicare un tentativo di indovinare una password. Il registro di audit, con data, ora, utente e tipo di accesso, serve sia a ricostruire un attacco sia a migliorare la politica di sicurezza. A questi strumenti si aggiungevano le scansioni periodiche alla ricerca di vulnerabilità note e una serie di controlli:
- password corte o facili da indovinare;
- programmi non autorizzati con setuid attivo o presenti nelle directory di sistema;
- processi che restano in esecuzione troppo a lungo;
- permessi impropri su directory e file di configurazione;
- directory pericolose nel PATH;
- modifiche ai programmi di sistema, rilevate con le checksum.
Il codice mobile
Applet nelle pagine web, agenti eseguiti su siti remoti, perfino file PostScript inviati alle stampanti sono codice che arriva da fuori e gira in locale. Eseguirlo in un processo separato è insufficiente, perché il processo può comunque usare tutte le risorse dell’utente. Il corso presentava tre meccanismi.
- La sandbox confina il codice in un intervallo di indirizzi. In uno spazio a 32 bit si possono ricavare, per esempio, 256 sandbox da 16 MB, una per il codice e una per i dati di ogni applet. I riferimenti dinamici alla memoria vengono controllati a run-time e le chiamate di sistema passano da un reference monitor, che le autorizza secondo regole di configurazione.
- L’interpretazione fa eseguire il codice da un interprete che controlla ogni istruzione. Era l’approccio dei browser con le applet Java.
- La firma del codice accetta solo il codice firmato da fornitori fidati, verificando la firma digitale del produttore.
Java era nato con questi problemi in mente. Il linguaggio è type-safe e il bytecode viene verificato prima dell’esecuzione. Il modello di sicurezza è passato dalla distinzione fra applet locali e remote del JDK 1.0, alle applet firmate considerate fidate del JDK 1.1, fino alle politiche configurabili applet per applet del JDK 1.2.
Domini, ACL e capability
La parte finale distingueva la sicurezza in senso ampio, che comprende aspetti tecnici, organizzativi e legali, dai meccanismi di protezione del sistema operativo. Il concetto centrale è il dominio di protezione, un insieme di coppie formate da un oggetto e dai diritti esercitabili su di esso. In UNIX il dominio di un processo è dato dalla coppia UID e GID.
In teoria il sistema potrebbe rappresentare domini, oggetti e diritti con una matrice. La matrice però è enorme e quasi vuota, e i sistemi reali ne memorizzano solo le celle piene. Letta per colonne diventa una lista di controllo degli accessi (ACL), associata a ogni oggetto. Letta per righe diventa una lista di capability, associata a ogni processo. Le capability vanno protette da manipolazioni con un’architettura a tag, come nell’IBM AS/400, conservandole nel kernel oppure lasciandole in spazio utente con un controllo crittografico.
Che cosa è cambiato dal 2000
I concetti di quel corso sono ancora la base della materia, mentre le difese si sono evolute. Contro il buffer overflow i sistemi moderni usano lo stack non eseguibile, la randomizzazione dello spazio di indirizzamento e i canary sullo stack, e linguaggi con controllo della memoria come Rust entrano anche nei kernel. Per conservare le password le funzioni di hash veloci come MD5 e SHA hanno lasciato il posto a funzioni lente e con salt, come bcrypt, scrypt e Argon2, e l’autenticazione a più fattori è diventata la regola per gli accessi amministrativi.
Le applet sono sparite dai browser. Sandbox, interpretazione controllata e firma del codice restano invece i tre modi con cui si esegue codice non fidato, dai browser agli smartphone. Molti controlli elencati nel 2000, dal PATH ai programmi setuid, sono oggi parte dell’hardening, cioè della riduzione delle funzioni attive e della configurazione sicura di ciò che resta.
Vedi anche: l’articolo del 2019 Hardening di un sistema informativo.
Vincenzo Calabrò | Ingegnere informatico specializzato in sicurezza informatica e investigazioni digitali. Funzionario informatico del Ministero dell'Interno; su incarico autorizzato si occupa di sicurezza informatica e di perizie informatiche forensi. Autore di articoli e saggi. Lecturer, Speaker, Trainer.Profili: Google Scholar · ORCID · ResearchGate · Academia.edu · CyberSecurity360 · AgendaDigitale · ICT Security Magazine · LinkedIn