Paolo Perego
Paolo Perego Specialista di sicurezza applicativa e certificato OSCE e OSCP, amo spaccare e ricostruire il codice in maniera sicura. Sono cintura nera di taekwon-do, marito e papà. Ranger Caotico Neutrale, scrivo su @codiceinsicuro.

Scopriamo insieme la superficie d'attacco

Scopriamo insieme la superficie d'attacco Photo by on Unsplash
1486 parole - Lo leggerai in 8 minuti

Un software engineer non ha bisogno di troppi rimandi alle cose basilari di application security. Parlando con alcuni sistemisti di heartbleed, è spuntato qualche sviluppatore in grado di indirizzare subito il problema evidenziando come fosse necessario revocare anche tutti i certificati dei server vulnerabili.

Tuttavia, non tutte le persone che scrivono codice sono software engineer e ci sono molte persone con sensibilità differenti al problema della sicurezza delle informazioni.

C’è anche una categoria di persone che, avendo programmato un gestionale in Visual Basic è convinta di scrivere codice di qualità. Non tratteremo di loro in questo blog.

Ci ritroviamo, appena dopo i banchetti per la Pasqua con un post leggero e molto discorsivo che vuole evidenziare un concetto semplice: il vostro software offre all’attaccante dei punti di attacco dei quali voi, sviluppatori, dovete essere consapevoli.

Il Tempo, l’ignoranza e l’incapacità di dire NO

Il tempo è il primo punto d’attacco della vostra nuovissima applicazione web o funzionalità. Su questo punto la vostra bravura è, purtroppo, un’invariante.

Il business viene da voi oggi, venerdì prima di Pasqua ed ha deciso che vuole lanciare una nuovissima funzionalità per il vostro sito che deve essere online martedì mattina. Questa nuova funzionalità è, ovviamente molto semplice e non richiederà più di qualche ora di lavoro, quindi siete pregati di mettervi subito sotto perché l’account vorrebbe vedere una prima demo lunedì nel pomeriggio.

Sappiamo tutti molto bene che lavorerete come matti e nessun account guarderà il primo pomeriggio del Lunedì di Pasqua il vostro lavoro, che comunque dovrete produrre in tempo per contratto. Sappiamo tutti molto bene che la semplicità della funzionalità e la stima del tempo sono considerazioni partorite da una persona che non ha alcun background informatico e che non saprebbe scrivere neppure un Hello world! a video. Probabilmente dovrete mettere mano al sistema di gestione della sessione della vostra applicazione web, rivedere il carrello e la procedura di pagamento e forse anche la navigazione di alcune porzioni del sito.

Al primo giro di cronometro siete già drammaticamente in ritardo. Purtroppo non siamo abituati a dire NO ad una richiesta insensata, impossibile da realizzare. Lo sapevamo fare da bambini ma adesso, nel dorato mondo del lavoro soprattutto in un periodo di crisi quando davanti alla porta ce ne sono mille come te, siamo impossibilitati a dire NO.

Avete rilasciato. La demo, ovviamente è saltata e voi 30 minuti dopo il rilascio state implementando un paio di altre funzionalità carinissime che non erano state pianificate.

Avete fatto modifiche importanti e nuovi sviluppi che non sono stati testati a sufficienza, o che forse non sono stati testati affatto. Figuriamoci se avete poi pensato alla validazione dell’input o altro… ci si affida al tanto deprecabile mantra ma chi vuoi che buchi proprio me.

La richiesta HTTP

La richiesta è proprio il primo punto di contatto tra l’attaccante ed il vostro codice. La richiesta HTTP porta con sé due cose fondamentali.

  • l’url e tutti i suoi parametri;
  • gli header della richiesta stessa, propri del protocollo HTTP.

Prendiamo questa richiesta:

GET http://localhost:4000/purchase/cart/23?lang=en&k=32 HTTP/1.1
Host: localhost:4000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:26.0) Gecko/20100101 Firefox/26.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3
Referer: http://localhost:4000/
Connection: keep-alive

Come prima cosa, tutti gli header http (Host, User-Agent, Referer, …) sono tutti potenziali punti dove un attaccante vorrà interagire con il vostro codice.

Se ad esempio voi usate il campo Referer come unico mezzo per controllare il flusso di navigazione dell’utente e quindi per controllare che il vostro carrello (in questo esempio) sia stato riempito correttamente e che siete pronti al checkout sappiate che vi state fidando di qualcosa che non potete controllare, il campo Referer appunto. Se un attaccante lo valorizza opportunamente, potrebbe bypassare alcuni controlli da voi piazzati.

Questa URL poi presenta due cose interessanti, lato attaccante. Un numero e due parametri: lang e k. I parametri sono proprio il primo punto dove fare un po’ di richieste malformate a piacere per vedere come si comporta l’applicazione. Una cosa a mio avviso fondamentale, è capire cosa fanno i parametri prima di darsi al tampering1 selvaggio così, un po’ per distinguersi dallo script kiddie che lancia il tool con l’opzione –auto-p0wn.

lang sembra suggerire il locale dell’applicazione, verifichiamolo mettendo codici noti di lingue (it, de, fr, es, …) e vediamo come si comporta l’applicazione. Se cambia la localizzazione dell’interfaccia grafica abbiamo indovinato. Proviamo ora con codici sconosciuti (gg, 99, 3, !): esiste un linguaggio di default che viene usato come fallback oppure causiamo un’errore applicativo (magari con qualche informazione interessante come versione delle librerie utilizzate, path applicativi, chiamate interessanti, …)?

k magari rappresenta il vostro codice cliente, stiamo stiracchiando l’esempio potrebbe essere ovviamente un parametro di controllo sulla cui natura non possiamo dire nulla. Provando a mettere una lettera al posto di un numero cosa otteniamo? L’eventuale errore applicativo ci dice qualcosa in più sulla natura del parametro? Riusciamo a causare qualche inconsistenza tra codice del carrello e codice cliente cambiando questo valore? Sono effettivamente legati in qualche modo quindi cambia l’anagrafica cliente legata al checkout?

Quel numero, 23, suggerisce poi che quest’applicazione abbia un controller purchase con un’azione (o un metodo) cart e 23 sia un parametro dinamico che indica l’id del carrello in questione. Punto ideale per due prove:

  • SQL injection
  • direct object reference: provo eventualmente ad enumerare i carrelli attivi in quel momento se il backend non è opportunamente scritto.

Abbiamo quindi almeno una decina di possibili attacchi nati da una singola richiesta con un paio di parametri. Sarebbe interessante chiedere all’ipotetico sviluppatore se era a conoscenza e se aveva previsto questo quando ha scritto quel metodo.

Il tuo stack applicativo

Sia che tu ti basi su uno stack formato da Linux, PostgresSQL, Apache, Passenger, Rails 4.0.3, sia che tu abbia un’applicazione basata su Linux, MySQL, Apache e PHP 5.0.3, la tua applicazione vive all’interno di un’ecosistema complesso, un po’ come gli esseri viventi.

Supponiamo tu abbia scritto un’applicazione veramente robusta e tu abbia speso tempo e soldi in attività di penetration test applicativo e remediation. Se la tua applicazione usa una versione di Rails la cui componente active_record soffre di una SQL Injection per come vengono gestiti i parametri allora anche la tua applicazione erediterà una SQL Injection per l’uso che viene fatto del framework2.

Se quella particolare versione di mod_php soffre di una vulnerabilità per la quale il codice sorgente della pagina viene stampato a video se l’url termina con un particolare carattere, non importa quanto robusto sia il tuo codice: tutta Internet lo vedrà3.

Non importa quindi solamente scrivere codice sicuro. Occorre aggiornare costantemente il software a bordo della macchina, sia quello di sistema che le librerie di terze parti che utilizziamo, al fine di non ereditare vulnerabilità terze.

Off by one

Un buon software engineer ha quindi la percezione di essere costantemente sotto scacco da molti punti di vista. Non basta solo validare l’input per vivere sereni il proprio business sul web, qualunque esso sia. Significa costruire una fortezza partendo da solide fondamenta che implicano anche una conoscenza profonda delle stesse. Significa conoscere il proprio sistema operativo, il proprio application server e le varie opzioni del framework o della libreria che implementa quella particolare funzionalità.

Ovviamente parte dei compiti sistemistici, possono essere demandati a chi gestisce per noi l’infrastruttura. Credo tuttavia che avere il polso della situazione e richiedere un particolare atteggiamento riveli un SW Eng di classe da uno di fascia media che magari si è accontentato di leggere qualche hint su questo blog4.

L’avevo proposto qualche anno fa su armoredcode.com, ma ne scriverò qui in forma aggiornata. A questo punto occorre vedere un po’ di codice per automatizzare la parte di discovery della superficie d’attacco.

Enjoy it!

  1. con tampering si intende la sostituzione di valori leciti con pattern d’attacco o con input malformato allo scopo di vedere come si comporta l’applicazione. 

  2. github soffrì nel Marzo 2012 di una SQL Injection, dovuta proprio ad una vulnerabilità di active_record e che portò un attaccante a scrivere in repository arbitrari senza ovviamente ne avesse i permessi (link). 

  3. un paio di anni fa emerse una problematica legata a mod_php e ad un flag che, se passato come parametro dell’url, veniva interpretato correttamente dall’interprete PHP installato sulla macchina e a video veniva stampato il codice sorgente della pagina (link). 

  4. questo blog ha lo scopo di parlare di application security, qualche cosa magari te la potrà insegnare o ti potrà dare qualche spunto ma è il caso che tu approfondisca la particolare tecnologia che tu utilizzi ogni giorno. 

Vuoi aiutarmi a portare avanti il progetto Codice Insicuro con una donazione? Fantastico, allora non ti basta che premere il pulsante qui sotto.

Supporta il progetto

comments powered by Disqus
Codice Insicuro, blog di Cyber Security, sviluppo sicuro, code review e altro.   Non perdere neanche un post, iscriviti ora alla mailing list