Home > GNU/Linux, Sicurezza e GNU/Linux > Sicurezza e GNU/Linux (parte 2): Vulnerabilità/1

Sicurezza e GNU/Linux (parte 2): Vulnerabilità/1

I programmi non sono invulnerabili come lui

Una vulnerabilità è tutto ciò che permette, almeno potenzialmente, ad un attaccante di indurre un comportamento non previsto e non desiderabile in un software (o un insieme di software).

Social engineering

Seguendo lo stesso ordine del post precedente, partiamo dal social engineering. Parlando di social engineering non è corretto dire che esso sfrutta delle vulnerabilità del software, perché invece si basa su azioni volontarie dell’utente. Tuttavia in alcuni casi, il compito di indurre l’utente a fare qualcosa di non desiderabile è facilitato dal software stesso.
Ad esempio, alcuni worm che sfruttano l’autorun su Windows inducono l’utente ad accettare la loro esecuzione perché la finestra di dialogo presenta un’icona e messaggi ritenuti affidabili.
Questo è un esempio di come si può presentare la finestra di dialogo che chiede l’autorizzazione ad eseguire un malware che si basa sull’autorun (come il famoso confliker):

Come si vede, ci sono due voci per aprire il file manager per vedere il contenuto della cartella, ma solo una è quella autentica: l’altra è il realtà il worm che ha usato la stessa icona e lo stesso messaggio. Purtroppo quella malevole è proprio la prima voce, distinguibile solo dal sottotitolo.

Una finestra di dialogo simile è prevista anche dal formato PDF, che può contenere oggetti attivi (contenuti multimediali, form, persino eseguibili). In tal caso, il messaggio di dialogo può essere modificato inducendo l’utente a credere di autorizzare una operazione lecita.

Vulnerabilità software dovute ad errori di programmazione

Praticamente tutte le vulnerabilità dovute ad errori di programmazione sono collegate, in modo diretto o indiretto, ad una errata gestione dell’input del programma, ovvero alla mancanza o debolezza dei controlli sull’input stesso.
Per input si intende qualsiasi dato che entra nel programma per venire elaborato: ciò che l’utente scrive da tastiera, i dati ricevuti da Internet, un file, ecc.
I modi di sfruttare questi mancati controlli sono molteplici e dipendono da come è strutturato il programma. Molto spesso sono collegate alle istruzioni che nei linguaggi di programmazione lasciano al programmatore il controllo dei dati inseriti, in particolare della lunghezza. Se l’area di memoria dove viene memorizzato l’input inserito dall’utente è più piccola dell’input effettivamente inserito, la parte eccedente va a coprire aree adiacenti della memoria del computer.
Questo fenomeno è chiamato buffer overflow (straripamento) e può provocare vari effetti a seconda di cosa rappresenta l’area della memoria viene sovrascritta. In particolare vi sono due casi:

a) la parte eccedente va a modificare il contenuto di un’altra variabile, modificando così il comportamento del programma, a seconda di cosa quella variabile corrotta contiene; ad esempio può generare dei risultati falsati, oppure può sovrascrivere un contatore di un ciclo (cioè una sequenza di istruzioni ripetuta più volte) sicché il ciclo si ripete troppe volte, o troppo poche volte o addirittura all’infinito; oppure può modificare una password, il nome di un file o altro ancora;
b) la parte eccedente va a modificare la parte dello stack dove è memorizzato l’indirizzo di ritorno di una subroutine: spiegato per chi non conosce la programmazione, significa che è possibile indurre il processore ad eseguire del codice non voluto, facendo “saltare” l’esecuzione verso altre istruzioni.

Nel caso b) si può trattare di istruzioni già presenti nel programma (ma che non devono essere eseguite in quel momento) oppure di istruzioni inserite appositamente come input malevolo (in tal caso si parla di code injection, iniezione di codice); in questo modo è possibile in pratica far fare al programma quasi tutto ciò che si vuole, sempre che sia abbia abbastanza spazio. Spesso non è difficile: pensate ad un programma che apre una immagine o un file molto grande. Posso riempire questa immagine di codice eseguibile e sfruttare un eventuale buffer overflow per far saltare il processore verso il mio pezzo di codice camuffato da immagine. A quel punto, davvero posso fare di tutto. Una azione comune è quella di ottenere l’accesso alla shell in modo che l’attaccante possa eseguire ciò che più gli aggrada.
Vedremo che esistono tecniche per prevenire l’esecuzione di codice presente nelle aree dati di un programma, in modo da rendere inefficace queste vulnerabilità.

Non sempre però è possibile attaccare in programma in modo così sofisticato, perché, ad esempio, le variabili in gioco sono poche (o piccole) e lo spazio di manovra si riduce. In tal caso però può bastare riempire una variabile oltre il suo limite andando a sforare l’area di memoria assegnata al programma (a seconda dell’area coinvolta si parla di stack overflow ed heap overflow) oppure facendo saltare l’esecuzione in un punto casuale della memoria, fuori da quella del programma stesso. In tal caso il sistema operativo per sicurezza termina il programma. Può sembrare il minimo, ma se il programma è ad esempio un server che gestisce le transazioni bancarie, di fatto ho bloccato l’intero business di un istituto di credito. In questo caso parliamo di Denial of Service.

Un particolare caso di iniezione di codice si ha quando il programma è scritto in un linguaggio interpretato o semicompilato come Python, Java, i linguaggi della piattaforma .Net di Microsoft e il linguaggio dei database SQL.
In questi linguaggi è possibile eseguire codice contenuto in stringhe. E’ una funzione voluta, non un errore. Tuttavia se non vengono prese le giuste cautele, può capitare che il codice contenuto in una stringa sia malevolo.

Infine, possiamo considerare il caso di programmi che, anche senza che vi sia un qualche overflow, aspettano un certo input e ne ricevono un altro. Ad esempio, un programma potrebbe aspettarsi che un file di testo contenga un tag che indica la fine di un paragrafo. Ma se quel tag non arriva mai, il programma potrebbe cercarlo all’infinito, entrando in loop e, in certi casi, questo può voler dire alta occupazione della CPU o saturazione della memoria.

Gli errori di programmazione illustrati sono molto comuni, soprattutto in linguaggio C, perché molte funzioni standard non fanno alcun controllo sull’input e sui dati che manipolano. Un esempio  sono le funzioni di input come scanf() e quelle che manipolano le stringhe come strcpy(). Vedremo come il compilatore gcc e la libreria glibc cercano di ovviare a questi problemi.

Infine va detto che l’errore potrebbe non essere nel programma che scrivo, ma nelle librerie che uso (o nel compilatore che utilizzo per renderlo eseguibile, o nell’interprete che fa girare il programma). In questo caso è più difficile accorgersi della sua esistenza, a meno di non studiare il codice della libreria o tentare tutti i casi limite che il programma potrebbe incontrare nella sua esecuzione.

Concludendo, aggiungiamo solo che le vulnerabilità possono essere locali se per sfruttarle serve essere sulla stessa macchina o remote se lo si può fare da una macchina collegata in rete (caso comune ad esempio per i programmi server).

Nella prossima puntata vedremo esempi di vulnerabilità di design e di vulnerabilità per configurazione debole.

  1. Luigi
    2 aprile 2011 alle 19:01

    Bell’articolo!
    Mi piace leggere questo tipo di post e non come ultimamente accade in qualsiasi blog di linux, ubuntu, software libero ecc… della sfida all’ultimo sangue fra Unity e Gnome Shell!
    Ciao

  2. FrancoP
    3 aprile 2011 alle 9:54

    Ottimo articolo davvero, lo sono riuscito a capire persino io. Grazie e aspetto con interesse il prossimo

  3. Lorenzo
    3 aprile 2011 alle 11:45

    Bell’articolo, ho imparato tante cose che non conoscevo, grazie!

  4. Nico
    3 aprile 2011 alle 18:03

    Bell’articolo! Le ho appena studiate all’università queste cose ma come le spieghi tu nessuno!🙂

  5. hug
    4 aprile 2011 alle 19:49

    soluzioni ?

    • 5 aprile 2011 alle 9:55

      ne parlerò in seguito

      • 7 aprile 2011 alle 17:19

        le tecniche di narrazione di Lost applicate alla divulgazione informatica🙂

        • 7 aprile 2011 alle 23:12

          il bello è che non ho mai visto Lost!

  6. 20 settembre 2014 alle 18:22

    Hey there, You’ve done an incredible job. I’ll definitely digg it and personally recommend to
    my friends. I am sure they’ll be benefited from this site.

  7. 21 settembre 2014 alle 6:48

    Today, I went to the beachfront with my kids. I found
    a sea shell and gave it to my 4 year old daughter
    and said “You can hear the ocean if you put this to your ear.” She put the shell to her
    ear and screamed. There was a hermit crab inside and it pinched her ear.

    She never wants to go back! LoL I know this is totally off topic
    but I had to tell someone!

  8. 22 settembre 2014 alle 23:35

    Hello, I desire to subscribe for this blog to get newest updates, therefore where can i do it
    please help out.

  1. 6 dicembre 2011 alle 23:02

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: