Questa è la traduzione dell'articolo Hacking Web 2.0 Applications with Firefox di Shreeraj Shah pubblicato originariamente su SecurityFocus il 10 novembre 2006. La traduzione viene qui presentata con il consenso dell'editore.
Introduzione
Ajax e i Web service formano l'ossatura delle applicazioni cosiddette "Web 2.0". La trasformazione tecnologica in atto porta con sé nuove sfide per gli esperti di sicurezza.
Questo articolo ha lo scopo di indagare alcuni metodi, strumenti e stratagemmi per analizzare in profondità applicazioni Web 2.0 (gestite con Ajax) e per scoprire bug di sicurezza con il solo aiuto di Firefox e di alcune sue estensioni. Questo articolo si propone di far comprendere:
- L'architettura delle applicazioni Web 2.0 e le loro implicazioni nel campo della sicurezza.
- Alcune tecniche di sicurezza, tra le quali: scoperta di chiamate nascoste, problemi di navigazione e messa a nudo della logica Ajax
- L'analisi delle chiamate XmlHttpRequest (XHR) con l'estensione Firebug per Firefox.
- La simulazione di eventi automatici del browser con l'estensione Chickenfoot per Firefox.
- Il debugging delle applicazioni web dal punto di vista della sicurezza con il debugger di Firebug.
- Un approccio metodologico per la scoperta di vulnerabilità.
Uno sguardo alle applicazioni Web 2.0
Il termine "Web 2.0" fa riferimento ad una nuova generazione di applicazioni web nate grazie all'adozione di di nuovi strumenti tecnologici. I Web service basati su XML eseguiti grazie a SOAP, XML-RPC e REST stanno potenziando le componenti server-side. Utilizzando Ajax e componenti del tipo RIA (Rich Internet Application), come quelle offerte da Flash, le interfacce per gli utenti finali diventano più ricche.
Queste mutazioni tecnologiche hanno un impatto sull'intera architettura delle applicazioni web e sui sistemi di comunicazione fra client e server. Allo stesso tempo questo cambiamento ha aperto nuove sfide e nuovi problemi per quanto riguarda la sicurezza.
Nuovi worm come Yamanner, Samy and Spaceflash sono riusciti a sfruttare per le proprie finalità nocive le infrastrutture "client-side" gestite con Ajax inaugurando nuovi tipi di attacchi informatici e compromettendo informazioni confidenziali
Come viene mostrato nella figura, i processi che coinvolgono il browser, visibili nella parte sinistra, possono essere suddivisi nei seguenti livelli:
- Il livello di presentazione: HTML e CSS forniscono l'intero aspetto dell'applicazione all'interno della finestra del browser.
- Logica e processo: il motore JavaScript del browser offre alle applicazioni le capacità di svolgere i compiti di esecuzione e di comunicazione. Tutti i componenti gestiti da Ajax vengono inclusi all'interno di questo livello.
- Trasporto: XMLHttpRequest (XHR). Questo oggetto provvede alla gestione delle comunicazioni asincrone e allo scambio di dati basato su XML tra il client e il server e attraverso il protocollo HTTP(S).
Le componenti lato server mostrate nella parte destra della figura 1, solitamente collocate all'interno dell'infrastruttura aziendale dietro un firewall, possono includere sia Web service sia tradizionali risorse proprie delle applicazioni web. Una risorsa Ajax che viene eseguita all'interno del browser può interfacciarsi direttamente con i Web service basati su XML e scambiare informazioni e dati senza necessità di eseguire un refresh della pagina. L'intero processo di comunicazione è nascosto all'utente finale: in altre parole questi non si accorgerà di nessun redirect (rindirizzamento). L'uso di refresh e redirect sono tipici della logica di funzionamento delle applicazioni Web di prima generazione. Nelle applicazioni Web 2.0, grazie all'uso di Ajax, questi fenomeni sono molto ridotti.
Le sfide della sicurezza Web 2.0
In questa infrastruttura asincrona l'applicazione non deve eseguire diversi refresh e redirect di pagina. Il risultato è che molte delle risorse server side che possono essere sfruttate da un aggressore sono nascoste. Sono almeno tre le sfide cui devono far fronte quegli esperti di sicurezza che cercano di comprendere la natura delle applicazioni Web 2.0.
- La scoperta di chiamate nascoste. È importantissima la possibilità di identificare le chiamate XHR generate dalle pagine caricate all'interno del borwser. Questi utilizza JavaScript e il canale HTTP(S) per eseguire le chiamate al server.
- Il crawling dell'applicazione. Le tradizionali applicazioni di crawling falliscono da due punti di vista. Primo: nel replicare i comportamenti del browser; secondo: nell'identificare le risorse chiave del processo che risiedono nella componente lato server. Se una risorsa è raggiunta da un oggetto XHR via JavaScript allora diventa molto più che probabile che l'applicazione dedicata al crawling non la riesca ad intercettare.
- Analisi della logica. Le applicazioni web moderne sono basate su JavaScript ed è difficile isolare la logica di un singolo evento. Ogni pagina HTML potrebbe eseguire tre o quattro risorse JavaScript dal server. Ognuno di questi file potrebbe contenere diverse funzioni ma gli eventi associati ad esse potrebbero essere nascosti in una piccolissima porzione di quel file.
Abbiamo per questo motivo bisogno di studiare e identificare la metodologia e gli strumenti necessari per superare questi ostacoli durante la valutazione di sicurezza di un'applicazione web. In questo articolo useremo il browser Firefox e cercheremo di sfruttare alcune sue estensioni per affrontare le sfide indicate sopra.
Far emergere le chiamate nascoste
Le applicazioni Web 2.0 potrebbero caricare dal server un singolo documento ma potrebbero anche eseguire, per mezzo dell'oggetto XHR, diverse chiamate al server per comporre la pagina. Queste chiamate potrebbero inoltre richiedere sia del contenuto sia codice JavaScript in modalità asincrona. In questo caso nostro compito è quella di determinare tutte le chiamate XHR e tutte le risorse che vengono richiamate dal server. Queste sono informazioni che ci saranno utili per identificare tutte le risorse dell'applicazione e le possibili vulnerabilità ad esse associate. Cominciamo con un semplice esempio.
Poniamo che il nostro obiettivo è quello di ricevere alcune notizie pubblicate su un sito ospitato all'indirizzo http://example.com/news.aspx. La pagina visualizzata nel browser assomiglierà alla figura 2 mostrata qui sotto:
Poiché si tratta di un'applicazione Web 2.0, le comunicazioni con il server sono basate su Ajax e sull'uso dell'oggetto XHR. Noi possiamo venire a capo di queste comunicazioni usando uno strumento chiamato Firebug. Si tratta di un'estensione per il browser Firefox che ha la capacità di identificare le chiamate eseguite dall'oggetto XHR.
Prima di visualizzare una pagina per mezzo dell'estensione, assicuriamoci che l'opzione relativa alle chiamate XHR sia selezionata, così come riportato dalla figura 3 [per visualizzare la finestra di Firebug fate clic sulla piccola icona verde che verrà mostrata in basso a destra dopo l'installazione dell'estensione e il riavvio del browser, Ndt]
Figure 3: impostare Firebug per intercettare le chiamate XMLHttpRequest
Dopo aver abilitato l'opzione relativa al tracciamento delle chiamate XMLHttpRequest, puntiamo il browser sulla stessa pagina per scoprire tutte le chiamate XHR eseguite da questa pagina al server. Le comunicazioni eseguite sono mostrate nella figura 4.
Come possiamo vedere, sono diverse le chiamate eseguite dal browser mediante l'oggetto XHR. Questo ha caricato dal server Dojo, un framework Ajax, nello stesso momento in cui ha eseguito una richiesta di visualizzazione degli articoli con le notizie (http://example.com/ getnews.aspx?date=09262006 ).
Se diamo un'occhiata al codice più da vicino possiamo notare la seguente funzione JavaScript getNews()
:
function getNews() { var http; http = new XMLHttpRequest(); http.open("GET", "getnews.aspx?date=09262006", true); http.onreadystatechange = function() { if (http.readyState == 4) { var response = http.responseText; document.getElementById('result').innerHTML = response; } } http.send(null); }
Il codice visualizzato sopra esegue una chiamata asincrona al Web server per richiedere la risorsa getnews.aspx?date=09262006
. Il contenuto di questa pagina viene visualizzato nel punto definito dall'id result
contenuto nella pagina HTML mostrata dal browser. Questa è una semplice chiamata Ajax che utilizza l'oggetto XHR.
Analizzando l'applicazione da questo punto di vista possiamo identificare sia gli URL vulnerabili interni sia le querystring e le richieste di tipo POST. Ad esempio, continuando ad utilizzare l'esempio di sopra, il parametro date
è vulnerabile ad un attacco di tipo SQL Injections.
Nella seconda parte dell'articolo verificheremo i problemi di crawling di un'applicazione Web 2.0 ed eseguiremo un vero e proprio debug dell'applicazione.
Nella prima parte di questo articolo abbiamo introdotto i compiti che devono affrontare gli esperti di sicurezza nelle moderne applicazioni di tipo Web 2.0. Abbiamo introdotto l'estensione Firebug e con essa abbiamo cominciato ad analizzare le richieste XHR nascoste in una pagina Ajax.
Problemi di crawling e simulazione di un browser
Un importante strumento di riconoscimento utilizzato nelle verifiche di sicurezza di applicazioni web è il web crawler. Un web crawler segue ogni singola pagina e colleziona tutti i collegamenti HREF (link). Ma cosa accade quando alcuni di questi collegamenti indirizzano verso una funzione JavaScript che esegue delle chiamate Ajax con l'oggetto XHR? In questo caso il web crawler potrebbe saltare del tutto queste informazioni.
In alcuni casi diventa davvero difficoltoso simulare questa situazione. Ad esempio, questi che seguono sono alcuni semplici collegamenti:
<a href="#" onclick="getMe(); return false;">go1</a><br />
<a href="/hi.html">go2</a><br />
<a href="#" onclick="getMe(); return false;">go3</a><br />
Il collegamento go1
quando viene cliccato esegue la funzione getMe()
. Il codice per la funzione getMe()
è mostrato in basso. È importante ricordare che questo codice potrebbe anche essere anche incluso in file esterni.
function getMe()
{
var http;
http = new XMLHttpRequest();
http.open("GET", "hi.html", true);
http.onreadystatechange = function()
{
if (http.readyState == 4) {
var response = http.responseText;
document.getElementById('result').innerHTML = response;
}
}
http.send(null);
}
Il codice mostrato qui sopra esegue una semplice chiamata Ajax alla risorsa hi.html
che è conservata nel server.
È possibile simulare un clic su questo link usando uno strumento automatico? La risposta è sì. Ecco un approccio basato sull'estensione Chickenfoot per Firefox che offre delle API basate su JavaScript ed estende l'interfaccia di programmazione al browser stesso.
Usando l'estensione Chickenfoot è possibile scrivere del semplice codice JavaScript per automatizzare i comportamenti del browser. Con questo approccio alcuni semplici compiti, come ad esempio la navigazione delle pagine web, possono essere resi automatici senza difficoltà. Ad esempio, il seguente script di esempio eseguirà dei clic su ogni collegamento che contiene eventi onClick
. Il vantaggio di questa estensione rispetto ai tradizionali Web crawler è chiara: ognuno di questi eventi onClick
esegue chiamate Ajax basate sull'oggetto XHR che potrebbero sfuggire ai crawler tradizionali perchè questi, sebbene siano in grado di interpretare JavaScript e collezionare i possibili link, non possono rimpiazzare i reali eventi onClick
.
l=find('link') for(i=0;i<l.count;i++){ a = document.links[i]; test = a.onclick; if(!(test== null)){ var e = document.createEvent('MouseEvents'); e.initMouseEvent('click',true,true,document.defaultView,1,0,0,0, 0,false,false,false,false,0,null); a.dispatchEvent(e); } }
È possibile caricare questo script all'interno della console di Chickenfoot ed eseguirlo così come mostrato in figura 5.
In questo modo chiunque può creare JavaScript e valutare applicazioni basate su Ajax dall'interno stesso del browser Firefox. Ci sono molte chiamate API che possono essere utilizzate con l'estensione Chickenfoot. Un'altra di grande utilità è il comando fetch
da usare per creare uno strumento di crawling.
Scoperta della logica e analisi dell'applicazione
Per analizzare minutamente il versante client di un'applicazione basata su Ajax è necessario seguire ogni evento con molta attenzione al fine di comprendere la logica dei processi. Un modo per determinare la logica dell'applicazione è quello di analizzare passo passo ogni linea di codice. Spesso ognuna di queste chiamate ad evento può eseguire solamente poche funzioni da uno specifico file. Per questo motivo vi è la necessità di usare una tecnica per seguire da vicino il codice che viene eseguito all'interno di un browser.
Ci sono pochi debugger per JavaScript che possono essere utilizzati per raggiungere gli obiettivi che ci siamo proposti. Firebug è uno di questi. Un altro è Venkman, ma nei nostri esempi continueremo ad usare Firebug.
Vediamo un semplice esempi di un processo di login. La pagina login.html
accetta un nome utente e una password così come mostrato nella figura 6. Dobbiamo usare la funzione Inspect di Firebug per determinare le proprietà dei moduli.
Dopo aver esaminato le proprietà di un modulo diventa chiaro che esso esegue una chiamata alla funzione auth
. Ora possiamo passare alla funzione di debugging di Firebug così come illustrato nella figura 7 e isolare la logica interna di un singolo evento.
In questo modo possono essere visualizzare tutte le dipendenze JavaScript di questa singola pagina. Le chiamate sono eseguite agli script ajaxlib.js
e validation.js
. Questi due script devono includere diverse funzioni che, si deduce. vengono utilizzate dal processo di login. Possiamo allora utilizzare un "breakpoint" per seguire passo passo l'intera applicazione. Dopo aver impostato un breakpoint [lo si fa cliccando sul numero di riga a partire dalla finestra Debugger di Firebug, Ndt], possiamo inserire le informazioni di login, cliccare sul pulsante Submit e controllare l'esecuzione del processo. Nel nostro esempio abbiamo impostato un breakpoint al livello della funzione auth
così come mostrato in figura 8.
Ora possiamo seguire passo passo il processo di debug cliccando sul pulsante "step in" evidenziato nella figura 8.
L'esecuzione dello script procede verso un'altra funzione, userval
, che è inclusa all'interno del file validation.js
così come mostrato in figura 9.
La figura 9 mostra l'espressione regolare che viene usata per validare il campo nome utente. una volta che la validazione è superata, l'esecuzione dello script ci porta ad un'altra funzione chiamata callGetMethod
così come mostrato all'interno della figura 10.
Infine, come ultimo passaggio della sequenza del processo, possiamo osservare come la chiamata al web service viene eseguita per mezzo di un oggetto XHR. Questo processo è mostrato in figura 11.
In questo modo siamo riusciti a identificare l'indirizzo in cui è disponibile il Web service, precisamente alla pagina http://example.com/2/auth/ws/login.asmx/getSecurityToken?username=amish&password=amish
La precedente risorsa identifica inequivocabilmente un Web service che viene eseguito all'interno della piattaforma .NET. Questo processo di sezionamento dell'applicazione ci ha portato come risultato un interessante dettaglio: abbiamo trovato un'istruzione di validazione che può essere aggirata senza troppe difficoltà. In altre parole: una potenziale minaccia di sicurezza all'intera applicazione web.
Portando la nostra analisi di sicurezza un po' oltre potremmo accedere al Web serivice e al suo endpoint usando direttamente un file WDSL e cercando di eseguire un attacco bruteforce al servizio. Potremmo anche lanciare diversi attacchi di tipo injection - SQL o XPath - con degli strumenti come wsChess.
In questo caso particolare l'applicazione è vulnerabile ad una XPath Injection. Tuttavia la metodologia per analizzare la sicurezza di un Web service è differente ed è al di fuori degli scopi che ci siamo prefissati con questo articolo. Ma questa tecnica passo passo aiuta a identificare diversi diversi attacchi lato client, come XSS [Cross-site scripting, Ndt], manipolazione del DOM, aggiramento dei controlli di sicurezza lato client, esecuzione di codice Ajax nocivo e così via.
Conclusioni
Applicazioni orientate ai servizi (SOA), Ajax, Rich Internet Application (RIA) e i web service sono componenti critiche all'interno delle applicazioni Web di futura generazione. Per avere a che fare senza problemi con queste tecnologie e per far fronte alle future sfide di sicurezza è necessario sviluppare e progettare differenti metodologie e differenti strumenti di analisi. Una delle metodologie più efficaci per valutare la sicurezza di un'applicazione Web è l'uso di un browser.
In questo articolo abbiamo visto tre tecniche per mettere alla prova le applicazioni Web 2.0. Usando queste tecniche è possibile identificare e isolare diverse vulnerabilità legate ad Ajax. Script automatici caricati all'interno del browser possono aiutarci nell'analisi delle risorse basate sul Web e nell'identificare le vulnerabilità delle risorse lato server.
Le applicazioni di futura generazione usano molto intensamente codice JavaScript. Semplici strumenti di debugging sono i nostri amici più fidati. Tutte le tecniche analizzate in questo articolo sono un buon punto di partenza per la valutazione di sicurezza di applicazioni Web 2.0 usando un browser come Firefox.
L'autore
Shreeraj Shah, BE, MSCS, MBA, è il fondatore di Net Square ed è a capo delle attività di consulenza, formazione e ricerca e sviluppo di Net Square. Ha lavorato prima in Foundstone, Chase Manhattan Bank e IBM. È anche l'autore di Hacking Web Services (Thomson) e co-autore di Web Hacking: Attacks and Defense (Addison-Wesley). Oltre a ciò ha pubblicato diversi advisory di sicurezza, software e whitepaper e ha presenziato in numerose conferenze come RSA, AusCERT, InfosecWorld, HackInTheBox, Blackhat, OSCON, Bellua, Syscan e altre. Ha un blog all'indirizzo http://shreeraj.blogspot.com/.