Introduzione
Tempo fa mi era stato chiesto da un professore che doveva svolgere una prova d'esame in laboratorio di rendere il server Linux "sicuro", facendo sì che gli studenti non potessero copiare l'uno dall'altro.
Siccome non sono un amministratore molto esperto (ma sto studiando per diventarlo), ho deciso che, visto il poco tempo che avevo a disposizione, piuttosto che tappare tutti i potenziali buchi di sicurezza del sistema (che su una distribuzione installata di fresco sono per forza di cose una mezza infinità), sarebbe stato meglio mettere a punto una sorveglianza molto stretta e sistematica delle operazioni compiute dagli utenti. L'idea migliore che mi sia venuta (ben lungi dall'essere la migliore in assoluto) è stata quella di loggare tutti i comandi dati a una bash in un unico, comodo file, da cui "greppare -v" i comandi ovvi, e greppare ulteriormente i comandi sospetti.
L'approccio
Naturalmente una semplice scrittura su un file fatta dalla bash non sarebbe bastata, poichè il file, essendo la bash eseguita con i permessi dell'utente, avrebbe dovuto essere scrivibile da tutti, e quindi chiunque avrebbe altrettanto facilmente potuto cancellare le tracce dei propri misfatti.
È qui che viene in aiuto l'architettura client-server: ci vuole un server che sia l'unico processo ad avere accesso al log, e la bash, anzichè scrivere il suo log direttamente, lo fa scrivere al server in questione.
La cosa è abbastanza facile da implementare con le named pipes.
Il codice
Per un programmatore alle prime armi come me, capire qualcosa dei sorgenti della bash è abbastanza un'impresa. Comunque mi sono armato di coraggio e ho portato la seguente modifica al file bashhist.c
void
maybe_add_history (line)
char *line;
{
int should_add;
int pipefd, uid;
FILE *logfile;
HIST_ENTRY *temp;
/* istruzioni aggiuntive per loggare i comandi della shell dati dai singoli utenti */
uid = getuid();
logfile = fopen("/var/log/shlogp", "a");
fprintf(logfile, "[uid %d] %s\n", uid, line);
fclose(logfile);
Dovrebbe risultare abbastanza chiaro che le variabili che ho aggiunto sono pipefd, uid e logfile. Come detto precedentemente,
/var/log/shlogpè una named pipe, che si crea con il comando
mknod /var/log/shlogp p
All'altro capo, ci vorrà una qualche specie di demone che legga da questa named pipe e scriva sul log. Niente di più semplice: basta il seguente script in bash:
while true; do cat /var/log/shlogp >> /var/log/bash.log; done
ed ecco che con un semplice tail -f /var/log/bash.log (noto anche come "il miglior amico del paranoico") noi aspiranti Grandi Fratelli abbiamo tutto sotto controllo.
Controindicazione
La modifica, però, proprio perchè è stata fatta in poco più di cinque minuti, non è senza controindicazioni. La prima, e più evidente, è la seguente: pensate bene prima di modificare gratuitamente i sorgenti, ovvero: non fate come me.
La seconda, ovvia, controindicazione è che quando un processo chiama una scrittura su una named pipe,rimane bloccato fino a che un altro processo non legge dalla named pipe. Quindi, prima di mettere la bash modificata al posto di quella normale, assicuratevi che almeno root abbia una bash "normale", altrimenti il sistema rimarrà bloccato in eterno se non è prima stato avviato il demone che scrive il log.
Migliorie
Naturalmente a questa "sporca" si può portare un certo numero di migliorie, che però, mancando la necessità, non ho sperimentato personalmente (diciamo che le lascio come esercizio allo studente).
Una è che si potrebbero mandare sulla rete dei pacchetti UDP contenenti i comandi. In questo modo il sistema non rimarrebbe bloccato come con la named pipe se il "server" non fosse su. Un'altra potrebbe essere quella di usare i meccanismi standard di logging (syslogd), che però io personalmente non so usare. Infine, la cosa forse più importante di tutte è non mettere completamente da parte la propria umiltà, e ricordarsi che con la "security by obscurity" non si guadagna niente in fatto di sicurezza. Nel mio caso sarebbe stato molto meglio rattoppare i buchi piuttosto che intervenire con la forza bruta, anche perchè ad un utente smaliziato sarebbe bastato avviare un altra shell per rendere inutile il mio lavoro.