:: Lezione di ESP del 16 Ventoso 216 ::
Altrimenti noto come 6 marzo 2008
Torna alla pagina di ESP
Covert Channel & affini
Le comunicazioni avvengono tramite canali. I canali legittimi sono quelli stabiliti dal sistema per far colloquiare le parti in gioco. A questi si possono aggiungere dei canali illegittimi, e farli operare secondo protocolli di comunicazione inusuali e soprattutto insospettabili. Solo chi sa che cosa cercare si accorge del tentativo di comunicazione illecito.
Per fare un esempio, se durante una stampa il primo carattere della terza riga viene modificato in una a, indipendentemente dalla parola, la spia che osserva e che sa che cosa vuol dire dedurrebbe che è imminente un attacco nucleare a Crema.
In termini più precisi, ogni variazione rispetto alla rappresentazione corretta di un dato codifica un singolo bit di informazione, il quale viene poi interpretato in un particolare modo. Ecco perché sopra ho parlato di un protocollo.
Storage channel
Uno storage channel sfrutta la presenza o assenza in memoria di certi oggetti, per codificare un bit di informazione.
Un sistema è la presenza o assenza di files in un certo posto. Per esempio, la presenza del file prurru.txt in c:\ può voler dire una cosa, la sua assenza un'altra. Occorre però che sia il programma di servizio che il programma spia abbiano accesso alla stessa risorsa.
Un altro sistema è la quota disco. Su certi sistemi, ad esempio UNIX & co., è possibile assegnare una quota massima di utilizzo del filesystem ad un certo utente. Supponiamo che il programma di servizio tenti di scrivere un file di grosse dimensioni. Se vi riesce, vuol dire che vi è spazio disponibile. Se non vi riesce, vuol dire che quello spazio è occupato da qualcos'altro. Il programma spia riconosce questi eventi, e deduce l'esistenza del qualcos'altro.
Come si può notare, è necessario che i 2 programmi, quello di servizio e quello spia, oltre ad avere accesso alle stesse risorse, devono anche avere una nozione di tempo condivisa: quando il programma di servizio comunica o meno, il programma spia deve essere in ascolto. Ciò non è così semplice come pare.
Timing Channel
Qui andiamo a livelli ancora più balordi: se il programma spia usa o non usa il suo tempo di computazione assegnatogli dal SO, codifica un bit di informazione. Nomino solo il multitasking come indice dell'estrema complessità di questo sistema...
Come identificare i Covert Channel
L'identificazione di questi canali non è per niente facile, per il motivo che usano sistemi "standard", poi interpretati in un certo modo dal programma spia.
Un sistema è quello di controllare le risorse condivise, perché proprio sulla presenza di queste i covert channel funzionano.
Si costruisce una matrice in cui le righe sono le risorse, e le colonne i processi che possono accedervi. Nelle celle metto R se quel processo può leggere quella risorsa, o M se la può modificare. Poi cerco dei pattern a quadrato, ovvero in cui 2 processi hanno accesso a 2 risorse diverse. Potrebbe essere indizio di maliziosità.
Altro sistema è l'analisi del flusso di info, in cui si analizza il codice sorgente dei programmi, e si stabilisce il flusso delle informazioni.
Un assegnamento di valore ad una variabile, ad esempio a = b; significa che c'è un flusso da b verso a. Una cosa come if (d == 1) b = a; rappresenta un flusso implicito tra d e a. Idem per le chiamati di funzione: b = funzione(parametro) sposta info verso b.
Ma come avete potuto capire, si tratta di sistemi che possono solo dire: "eh controlla meglio che forse forse c'è qualcosa di losco". Non possono dire molto di più.
Buffer overflow
OCIO
La qualità degli appunti seguenti è molto bassa, in quanto le condizioni di attenzione di quell'ora erano scarsissime...:)
Il buffer è un area di memoria che serve per memorizzare temporaneamente dei dati. Nello stack essa ha una certa dimensione assegnata, ma confina con l'area destinata all'indirizzo di ritorno, ovvero l'indirizzo della funzione che ha chiamato la parte di codice proprietaria di questo stack.
Il buffer overflow sfrutta una caratteristica di diverse funzioni che utilizzano buffer per immagazzinare dati. Esse si aspettano una certa quantità di dati in ingresso. E quelle scritte male, anche se ne arrivano di più, non fanno nessuna storia. Ma il sistema ha assegnato al buffer una quantità fissa di spazio. Se arriva più roba, dove la metto? Semplice: sovrascrivo le aree dello stack circostanti!
Con un po' di abilità e fortuna, posso inviare dati maliziosi i quali sovrascrivano allegramente l'indirizzo di ritorno, mettendoci al suo posto l'indirizzo del mio codice malizioso, o comunque dati che possono inficiare il buon funzionamento del programma.
Per metterci un altro indirizzo, occorre però sapere esattamente dove in memoria il mio codice si trovi, e non è affatto una cosa banale.
Posso anche modificare i valori di ritorno, causando chissà quali danni. O mettere addirittura il codice eseguibile nello stack, passandolo come parametro.
Il buffer overflow dipende quindi dall'implementazione delle funzioni in un particolare linguaggio di programmazione. Per evitare debolezze del genere, si possono usare linguaggi come Java, che sono sicuri da questo punto di vista, o stabilire che lo stack non sia eseguibile.
Torna alla pagina di ESP