27/02/2012

Tipi di attacco CSRF

In questo post ho descritto il concetto su cui si basa l'attacco CSRF, mentre in quest'altro post ho provato ad elencare alcuni rimedi da utilizzare per mitigare tale tipologia di attacco.

 

csrf,refrected,login,stored,token,html,form,javascript,xss

Adesso vedremo quali sono i diversi tipi di attacco CSRF.

Login CSRF

L'attaccante invia una URL trappola alla vittima, contenente le proprie credenziali di accesso sul sito vulnerabile. In questo modo, appena la vittima effettuerà il login e se il sito lo consente, l'attaccante riuscirà a tenere traccia dei suoi comportamenti (sezioni visitate, link cliccati et similia), semplicemente accedendo al proprio profilo in un secondo momento (vedi YouTube).

Stored CSRF

Il sito vulnerabile consente l'inserimento di codice lato client (Javascript e/o HTML) da parte degli utenti autenticati. Questa in realtà è una vulnerabilità agli attacchi XSS che però può essere utilizzata per creare delle richieste CSRF. Supponiamo che l'attaccante utilizzi i campi di input di un form per iniettare del codice HTML contenente un ulteriore form caratterizzato da diversi campi hidden. Tali campi verranno popolati ad-hoc in modo da creare le giuste variabili da inviare al server tramite HTTP POST.

Ad esempio si potrebbe avere un form del tipo:

<form name="csrf" id="csrf" method="post" action="pagina.php">
<input type="hidden" name="nome" value="Mario" />
<input type="hidden" name="cognome" value="Rossi" />
<input type="hidden" name="telefono" value="06676785" />
</form>

e la seguente immagine "trappola":

<img src="images/immagine.jpg" alt="immagine" onclick="javascript:document.forms['csrf'].submit()" />

L'utente vittima, cliccando sull'immagine, invierebbe i dati al server, i quali verrebbero così processati (si pensi alla classica transazione finanziaria).

Tale tipologia di attacco CSRF è quella che ha un ottimo margine di riuscita, in quanto l'attaccante è certo che l'utente vittima sia effettivamente loggato al sito vulnerabile (altrimenti non potrebbe accedere al form precedentemente forgiato).

Reflected CSRF

L'attacco ha come sorgente "terze parti", ad esempio siti esterni, applicazioni di instant messaging, client di posta et similia. I margini di riuscita sono relativamente bassi, in quanto l'attaccante non può sapere a priori se la vittima è loggata o meno sul sito vulnerabile nel momento in cui viene sferrato l'attacco vero e proprio.

Le metodologie di attacco sono quelle classiche, ovvero creazione di una URL "trappola" oppure l'uso di un form creato ad hoc.

Il form che l'attaccante potrebbe creare è simile a quello visto in precedenza, eccezion fatta per l'attributo action:

<form name="csrf" id="csrf" method="post" action="http://www.sitovulnerabile.it/pagina.php">
<input type="hidden" name="nome" value="Mario" />
<input type="hidden" name="cognome" value="Rossi" />
<input type="hidden" name="telefono" value="06676785" />
</form>

<img src="images/immagine.jpg" alt="immagine" onclick="javascript:document.forms['csrf'].submit()" />

Dai miei esempi si evince come l'HTTP POST offra dei margini di sicurezza migliori rispetto al GET, ma è comunque soggetto ad attacchi CSRF. Per questo, è opportuno utilizzare il token anche se il vostro sito accetta solo dati inviati mediante POST.

Inoltre, nell'ambito degli stored CSRF, se il sito non presenta vulnerabilità XSS (grazie a politiche di input sanitization), il metodo POST associato al controllo del referer HTTP, rappresenta una buona contromisura al CSRF, anche se non ottimale.

Proprio per questo motivo, consiglio di utilizzare i token sempre e comunque.

A presto.

10:00 Scritto da: nazarenolatella in Sicurezza | Link permanente | Commenti (0) | Segnala | Tag: csrf, refrected, login, stored, token, html, form, javascript, xss | OKNOtizie |  Facebook

25/02/2012

Contromisure agli attacchi CSRF

In questo post ho parlato degli attacchi CSRF (Cross Site Request Forgery). Ora vediamo quali sono le possibili contromisure per evitare (o minimizzare) gli effetti nefasti che tale minaccia può provocare.

 

sechttp.jpg

La semplice definizione del metodo HTTP (GET oppure POST) utilizzato per l'invio del contenuto dei form al server non è sufficiente come contromisura. Infatti, se lato server tali variabili non vengono processate nel modo corretto, una richiesta di tipo POST può essere facilmente trasformata in una richiesta di tipo GET, quindi vulnerabile ai CSRF. Nella fattispecie, pur avendo un form simile al seguente:

<form method="post" action="page.php">

<fieldset>
<legend>Inserisci Contatto</legend>

<input type="text" name="nome" id="nome"/>nome:
<input type="text" name="cognome" id="cognome"/>cognome:
<input type="text" name="telefono" id="telefono"/>telefono:
<input type="submit" name="invia" id="invia" value="Invia"/>

</fieldset>

</form>

dove tutti i campi sono obbligatori, lo si potrebbe facilmente tradurre in questa chiamata HTTP GET:

http://www.nomesito.it/page.php?nome=Mario&cognome=Rossi&telefono=06676754&invia=Invia

Quindi, se un attaccante mandasse un'email contenente la suddetta URL alla vittima, e quest'ultima (che ha una sessione attiva su www.nomesito.it) cliccasse sul collegamento, automaticamente verrebbe salvato nel database un record Mario Rossi 06676754.

Pensate a cosa potrebbe succedere se il sito vulnerabile fosse quello di una banca e la URL trappola portasse l'utente vittima ad effettuare (a sua insaputa) un bonifico di N € sul c/c dell'attaccante...

Per fortuna si può correre ai ripari impostando alcuni meccanismi di sicurezza.

Per prima cosa, occorre scindere lato server (ad esempio nel codice PHP) le chiamate HTTP POST dalle chiamate HTTP GET, utilizzando le giuste variabili globali, ovvero $_POST nel primo caso e $_GET nel secondo.

Se si utilizzano la variabile $_POST ed il filtro sul referer HTTP i margini di sicurezza sono buoni (ma non ottimali), in quanto non potrà funzionare la tecnica enunciata in precedenza, ovvero la trasformazione delle chiamate HTTP POST in chiamate HTTP GET e non verranno accettate richieste provenienti da siti esterni.

Se invece si sceglie il GET come metodo di invio dei dati, oppure non si fa una scelta esplicita e si gestiscono i dati diretti al server mediante la variabile globale $_REQUEST (che non fà alcuna distinzione tra GET e POST), allora è assolutamente necessario procedere in questo modo:

1) si crea un stringa random (token);

2) tale token lo si associa automaticamente ad un campo di input hidden (nascosto);

3) si richiede che il valore del suddetto campo hidden sia uguale a quello del token affinchè si possano salvare i dati nel database.

Per intenderci, si potrebbe utilizzare il seguente codice PHP:

session_start();

$token = sha1(time());

$_SESSION['token'] = $token;

session_write_close();

nella pagina del login, mentre in tutte le altre pagine il codice sarà:

session_start();

$token = $_SESSION['token'];

session_write_close();

if(isset($_REQUEST['invia']))
{
    if(isset($_REQUEST['token']) && $_REQUEST['token'] == $token)
    {
          //invia i dati
    }

    else
    {
          die('Non hai i permessi per visualizzare la pagina');
    }
}

Il campo di input hidden è così definito:

<input type="hidden" name="token" id="token" value="<?php echo $token ?>"/>

Attraverso questa tecnica l'attaccante non potrà conoscere a priori il valore del token e quindi non sarà in grado di "forgiare" una URL malevola. Inoltre, è consigliabile utilizzare tale procedura anche se si utilizza la variabile $_POST, poichè il token è l'unica contromisura quasi infallibile contro gli attacchi in questione.

Un'altro metodo per mitigare i CSRF consiste nella verifica del campo HTTP_REFERER relativo all'header HTTP.

Però, poichè tale controllo è facilmente aggirabile (basti pensare che alcuni browser, tra i quali Firefox, non inviano per default il referer e che tale campo risulta comunque spoofabile, utilizzando ad esempio cULR), solitamente dedico il suo impiego alle sole pagine "riservate" (ovvero accesibili solo dopo autentica da parte dell'utente) che non prevedono l'invio di dati al server.

Il codice PHP è il seguente:

if($_SERVER['HTTP_REFERER'] != '' && !strstr($_SERVER['HTTP_REFERER'], "http://www.nomesito.it"))
{
        die('non hai i permessi per visualizzare la pagina');
}

In soldoni, verifico che il referer HTTP sia vuoto (per non penalizzare utenti legittimi che adoperano un browser che non invia i referer) oppure che contenga il dominio del mio sito, "accertandomi" così che l'utente non provenga da domini "esterni".

Fine del post, fatene buon uso.

A presto.

23/02/2012

SSL e Diffie-Helman

Il protocollo SSL (Secure Socket Layer) prevede l'uso di alcuni algoritmi di cifratura nell'ambito dell'handshake. Uno di questi è il Diffie-Helman, che può essere adoperato in 3 varianti:

1) Anonymous Diffie-Helman (A_DH): il numero primo p e la radice primitiva a ad esso associata vengono inviati senza autentica. In realtà questa è la modalità di funzionamento "standard" del Diffie-Helman;

2) Fixed Diffie-Helman (F_DH): p ed a del server https vengono firmati mediante un certificato X.509 trusted. La chiave segreta è statica, ovvero è la medesima per ogni sessione.

3) Ephemeral Diffie-Helman (E_DH): viene generata una secret key (relativa al protocollo DH) temporanea (one-time o ephimeral), ovvero valida per una sola sessone, firmata mediante la propria chiave segreta RSA (o DSS). La controparte ne verificherà l'autenticità attraverso la chiave pubblica del mittente. Anche in questo caso si possono utilizzare dei certificati X.509 contenenti i paramentri a e p per semplificare le operazioni di autentica dei due peer.

Fine del post, alla prossima.

SHA-1, questo sconosciuto...

Usando continuamente lo SHA-1 come algoritmo di cifratura per le password salvate in MySQL, ho deciso di capire meglio come funziona e qual è la logica secondo la quale vengono creati i digest (impronte). Infatti, lo SHA-1 (acronimo di Secure Hash Algorithm), è il tipico esempio di algoritmo di cifratura one-way, ovvero non reversibile. Ciò significa che una volta cifrato il messaggio, non deve essere possibile dal punto di vista computazionale risalire al testo in chiaro. Nonostante questo, lo SHA-1 presenta comunque delle vulnerabilità: recentemente è stato infatti scoperto un attacco basato sulla crittoanalisi in grado di generare facilmente delle collisioni (sono proprio le collisioni il tallone di Achille di tutti gli algoritmi di cifratura one-way). Nella fattispecie, si ha una collisione quando due testi in chiaro producono lo stesso digest, compromettendo quindi in tutto o in parte la sicurezza delle informazioni criptate.

Fatta questa breve premessa, vediamo più da vicino il meccanismo utilizzato dallo SHA-1 per cifrare i messaggi.

Supponiamo che la stringa che si vuole cifrare abbia dimensione (in bit) inferiore a 2^64. In questo caso sarà necessario effettuare del padding (ovvero del riempimento), in modo da rendere la lunghezza L del messaggio espanso un multiplo intero di 512 bit (Nx512).

Il padding avviene nel seguente modo: si aggiunge in coda alla sequenza di bit che identifica il messaggio cifrato un bit pari a 1, diversi bit pari a 0 e due word da 64 bit ciascuna (128 bit in tutto). Esse servono proprio a rappresentare la lunghezza L del messaggio prima che su di esso venga effettuato del riempimento. Ma andiamo per ordine, supponiamo che il messaggio da cifrare sia identificato dalla seguente stringa di bit:

00010001 11001100 111001101 11110011 11101111

come si può facilmente notare, la lunghezza L della sequenza di bit è pari a 40 (L = 40). Poichè tale lunghezza è inferiore a 2^64 bit, allora devo usare del padding.

1) Aggiungo un bit pari a 1 in coda alla sequenza di bit sopra riportata:

00010001 11001100 111001101 11110011 11101111 1

2) Aggiungo tanti bit pari a 0 quanti ne servono per ottenere una dimensione pari a 448 bit (448 - 41 = 407 zeri), in modo tale da avere, successivamente all'aggiunta delle due word da 128 bit complessivi, una lunghezza del messaggio espanso pari a 512 bit (dimensione usata appositamente per rendere più esplicativo l'esempio).

00010001 11001100 111001101 11110011 11101111 10000000 00000000 00000000 00000000 ecc.

3) Creo le due word da 64 bit ciascuna. Se la dimensione del messaggio (ovvero L) è inferiore a 2^32 bit, la prima word sarà costituita da 64 bit pari a 0. La seconda word, invece, è la conversione in binario del numero intero 40, che è proprio la lunghezza L. Quindi avrò:

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 prima word;

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00101000 seconda word.

Una volta che il padding verrà completato, il testo espanso ci apparirà nel modo seguente:

00010001 11001100 111001101 11110011 11101111 10000000 00000000 00000000 00000000 ecc... 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00101000

Bene, supponiamo ora che il messaggio espanso abbia una dimensione che sia un multiplo di 512 bit. Esso verrà quindi suddiviso in Mn (leggasi M con n, dove n è il pedice) blocchi da 512 bit ciascuno. Tali blocchi andranno in ingresso ad una funzione F, il cui funzionamento verrà descritto più avanti. Occorre notare che la prima funzione F, quella cioè relativa al blocco M1, riceverà in ingresso 5 word da 32 bit ciascuna (160 bit in tutto) appartenenti ad un IV (vettore di inizializzazione), che chiameremo h0, h1, h2, h3 ed h4.

In particolare, esse vengono inizializzate ai seguenti valori (in esadecimale):

h0 = 67452301

h1 = EFCDAB89

h2 = 98BADCFE

h3 = 10325476

h4 = C3D2E1F0

Vediamo come appare lo schema di cifratura dello SHA-1:

SHA-1.JPG

Come potete notare, la prima funzione F (da sinistra) riceve in ingresso M1 e l'IV, la seconda riceve in ingresso M2 ed il risultato della somma tra l'IV e l'output della prima funzione F, generando H1 e con questa logica vengono generati H2,H3, H4, fino ad arrivare ad Hn, ovvero il digest vero e proprio (da 160 bit).

Ma cosa fa effettivamente F? Per capirlo osserviamo il seguente schema che si riferisce al primo blocco, ovvero M1:

 

Sha-1-2.JPG

Il blocco M1 viene suddiviso in 16 blocchetti w (da 0 a 15). Poichè però la funzione F consta di 80 iterazioni, i 64 blocchetti rimanenti (80 in tutto) vengono generati nel modo seguente:

w[t] = (w[t-3] XOR w[t-8] XOR w[t-14] XOR w[t-16]) << 1 con 16<=t<=79

dove << 1 rappresenta uno shift verso sinistra del risultato ottenuto (ed è proprio questa l'unica differenza esistente tra lo SHA, altrimenti conosciuto come SHA-0, e lo SHA-1).

Ogni iterazione riceve in ingresso le word a, b, c, d, ed e (ovviamente coincidenti con h0, h1, h2, h3 ed h4 per la prima iterazione), il blocco w[t] ed una costante additiva Kt, con Kt inizializzata nel modo seguente:

Kt = 5A827999  per 0 <= t <= 19

Kt = 6ED9EBA1 per 20 <= t <= 39

Kt = 8F1BBCDC per 40 <= t <= 59

Kt = CA62C1D6 per 60 <= t <= 79

Ad ogni iterazione viene generata una variabile temporanea TEMP, dove TEMP = (a << 5) + f + e + Kt + w[t] e la funzione f, che dipende da t, ovvero dall'iterazione considerata e dalle word b, c, ed e, sarà data da:

(b AND c) OR ((NOT b) AND d) per 0 <= t <= 19

b XOR c XOR d per 20 <= t <= 39

(b AND c) OR (b AND d) OR (c AND d) per 40 <= t <= 59

b XOR c XOR d per 60 <= t <= 79

Una volta creata la variabile TEMP, l'iterazione effettuerà le seguenti operazioni di sostituzione e di shifting:

1) la variabile TEMP viene salvata in a;

2) la word a viene salvata in b;

3) la word b viene salvata in c e successivamente c viene spostata di 30 posizioni verso sinistra;

4) la word c viene salvata in d;

5) la word d viene salvata in e.

Le word così ottenute andranno in ingresso all'iterazione immediatamente successiva.

Inutile dirvi che comprendere a pieno tale algoritmo di cifratura non è banale come non è per niente semplice cercare di spiegarlo in modo chiaro. Spero comunque di esservi stato d'aiuto. A presto. 

10:18 Scritto da: nazarenolatella in Crittografia | Link permanente | Commenti (0) | Segnala | OKNOtizie |  Facebook

13/02/2012

Securimage: captcha PHP semplice ed efficace

Qualunque form HTML che si rispetti, deve garantire delle contromisure valide contro gli spammer bot, avvelendosi di un sistema captcha.

Dopo aver fatto un breve "giro in rete" mi sono imbattuto in questo prodotto (open source).

securimage.jpg

Diciamo che le operazioni di implementazione e quelle di personalizzazione sono estremamente semplici ed intuitive, basta leggere questa Quickstart Guide per comprendere appieno il funzionamento del tool in questione.

Non vi resta che includere i file PHP richesti, inserire l'apposito campo di input nel vostro form ed il gioco è fatto.

Alla prossima.

10:00 Scritto da: nazarenolatella in Web Editing | Link permanente | Commenti (3) | Segnala | Tag: captcha, form, input, spammer, bot, securimage, image | OKNOtizie |  Facebook

08/02/2012

Pulsante "like" di Facebook: alcuni trucchetti utili

Ormai il pulsante "like" di Facebook è diventato una moda ed in quanto tale sono sempre di più i siti che usufruiscono di questo gadget. L'inserimento del suddetto pulsante all'interno del codice HTML del proprio sito è praticamente un gioco da ragazzi (basta copiare ed incollare il sorgente autogenerato mediante questa interfaccia user-friendly). I problemi, però, iniziano quando si vuole customizzare pesantemente il "like" di Facebook, ad esempio implementando un evento on click oppure "nascondendo" la barra dei commenti.

fb-like.jpg

Nel primo caso è sufficiente utilizzare un codice javascript simile al seguente

<!--
window.fbAsyncInit = function() {
FB.Event.subscribe('edge.create', function(href, widget) {
//action
});
 };
//-->

Se ad esempio si volesse implementare l'apertura di una finestra pop-up immediatamente dopo il click sul "like", il codice diventerebbe:

<!--
window.fbAsyncInit = function() {
FB.Event.subscribe('edge.create', function(href, widget) {
window.open('vostraurl', '_blank');
});
 };
//-->

Nel caso in cui, invece, si volesse nascondere la barra dei commenti, è necessario lavorare di CSS. Nella fattispecie, occorre attribuire un display:none alla classe .fb_edge_widget_with_comment, utilizzando la keyword !important per evitare possibili sovrascritture di tali impostazioni all'interno della pagina HTML (attraverso il tag style):

.fb_edge_widget_with_comment span.fb_edge_comment_widget iframe.fb_ltr {
display: none !important;}

Ed il gioco è fatto.

A presto.

06/02/2012

Configurazione del firewall embedded di un Cisco 827v4

Affinchè si possa realizzare la configurazione che sto per descrivere, è necessario che la IOS del nostro Cisco 827v4 supporti le funzionalità tipiche di un firewall (anche se MOLTO ridotte).

827.jpg

Nello specifico, il nome della IOS deve contenere la sigla o oppure o3, dove o sta appunto per firewall ed o3 sta per firewall/IDS. Nel mio caso, posso dirvi che ho a disposizione una IOS che supporta solo il firewall, quindi tale configurazione si limita a ciò che ho potuto effettivamente testare.

Per prima cosa accediamo alla modalità enable del router:

NightRouter>ena
Password:
NightRouter#conf t

entriamo nel menù di configurazione:

NightRouter#conf t

e creiamo le policy del nostro firewall:

NightRouter(config)#ip inspect name fw http
NightRouter(config)#ip inspect name fw ftp
NightRouter(config)#ip inspect name fw icmp
NightRouter(config)#ip inspect name fw smtp
NightRouter(config)#ip inspect name fw fragment
NightRouter(config)#ip inspect name fw rcmd

in questo modo, il nostro router terrà d'occhio i pacchetti relativi ai protocolli specificati. Esistono altri protocolli che possono essere monitorati, basta lanciare il comando:

NightRouter(config)#ip inspect name <nomepolicy> ?

per averne una lista completa.

In particolare, l'output di tale comando sarà il seguente:

 cuseeme      CUSeeMe Protocol
  fragment     IP fragment inspection
  ftp          File Transfer Protocol
  h323         H.323 Protocol (e.g, MS NetMeeting, Intel Video Phone)
  http         HTTP Protocol
  icmp         ICMP Protocol
  netshow      Microsoft NetShow Protocol
  rcmd         R commands (r-exec, r-login, r-sh)
  realaudio    Real Audio Protocol
  rpc          Remote Prodedure Call Protocol
  rtsp         Real Time Streaming Protocol
  sip          SIP Protocol
  skinny       Skinny Client Control Protocol
  smtp         Simple Mail Transfer Protocol
  sqlnet       SQL Net Protocol
  streamworks  StreamWorks Protocol
  tcp          Transmission Control Protocol
  tftp         TFTP Protocol
  udp          User Datagram Protocol
  vdolive      VDOLive Protocol

Successivamente, si dovrà associare la policy di firewalling all'interfaccia dia0, ovvero quella direttamente esposta su Internet.

Il comando da utilizzare è il seguente:

NightRouter(config)#int dia0
NightRouter(config-if)#ip inspect fw in

Infine, salviamo la configurazione con il classico copy run start:

NightRouter(config)#exit
NightRouter#copy run start

ed abbiamo finito.

A presto.

NB: dai test che ho effettuato sembrerebbe che il router non riesca a gestire correttamente una grande mole di traffico dopo aver abilitato il firewall. Proprio per questo motivo, vi consiglio di non ispezionare il payload dei pacchetti ma soltanto l'header degli stessi, evitando ad esempio delle policy del tipo:

NightRouter(config)#ip inspect name fw tcp

oppure

NightRouter(config)#ip inspect name fw udp

01/02/2012

Javascript e catch del tasto "enter"

Ecco una semplice funzione Javascript che consente di ottenere l'invio del contenuto di un campo di input semplicemente pigiando il tasto enter:

<script type="text/javascript">
  function onEnter(evt, frm)
  {
      var keyCode = null;
   
    if( evt.which )
    {
         keyCode = evt.which;
     }
    else if( evt.keyCode )
    {
         keyCode = evt.keyCode;
     }
    
    if( 13 == keyCode )
    {
         document.searchForm.searchbutton.click();
         return false;
     }
   
     return true;
  }
  </script>

javascript11.jpg

Il codice HTML ad essa associato è il seguente:

<form id="searchForm" name="searchForm" class="searchform">
                <input id="input" name="input" type="text" value="Search..." onFocus="if (this.value == 'Search...') {this.value = '';}" onBlur="if (this.value == '') {this.value = 'Search...';}" onKeyPress="return onEnter(event,this.form)"/>
                <input id="searchbutton" name="searchbutton" class="searchbutton" type="button" value="a" onClick="document.forms['searchForm'].submit()"/>
</form>

Alla prossima.

11:00 Scritto da: nazarenolatella in Web Editing | Link permanente | Commenti (0) | Segnala | Tag: javascript, enter, keypress, submit, form | OKNOtizie |  Facebook

Tutti gli articoli