Wednesday, December 7, 2011

Raw Socket: IP datagrams


IP datagrams represent data to be routed.
They store informations like IP source and destination address.
Inside <netinet/ip.h> an iphdr struct is defined, allowing us to create a custom ip header. (More detailed information about IP header here)

File: <netinet/ip.h>



struct iphdr
{...};

iphdr.ihl //[4 bit] Internet Header Length, contains the header length measured in 32 bit words.
iphdr.version //[4 bit] Datagram version. ipv4 version's 4.
iphdr.tos //[8 bit] Type of service (we won't use it).
iphdr.tot_len //[16 bit] Datagram total length in byte.
iphdr.id //[16 bit] Used on router fragmentation.
iphdr.frag_off//[3 bit] Fragmentation controls.
iphdr.ttl //[8 bit] Time to live, or max hops allowed before datagramm destruction.
iphdr.protocol //[8 bit] Payload protocol identifier  (6->TCP, 17->UDP, 1->ICMP ...).
iphdr.check //[16 bit] Header checksum (16-bit checksum RFC1071).
iphdr.saddr //[32 bit] IP source address
iphdr.daddr //[32 bit] IP destination address

Now let's define some usefull functions for future use:

int createIpv4Header(Iphdr* buffer, char * srcAddress, char * dstAddress, u_int8_t ttl);

void setPayloadInfo(Iphdr* ipheader, int payloadLength, u_int8_t protocolType);
Time for funny testing!
Editing the previous post code, we can create a function testIP(char* src, char* dest) able to send an empty datagram ip to a custom destination from a custom source.
So we initialize the buffer:

int length = createIpv4Header(ipheader, sourceAddress, destinationAddress, 100);
setPayloadInfo(ipheader, 0, 1);


Calling setPayloadInfo we are setting a ICMP protocol with 0 length (obviously that would be a malformed datagram, but now we want only to test the IP behaviour).
Now let's call the testIP function inside a main(), with parameters ("127.0.0.1", "127.0.0.1").
Compile.

Now let's open our favourite traffic analyzer (like wireshark) and enable capturing on lo (loopback interface, or 127.0.0.1). We'll be able to see our little datagram :).


$ sudo ./test_ip


We will see on wireshark something like that:


We do it!


Here the code:


ip.h
ip.c
testIP.c

Raw Socket: Introduction


Sockets are APIs (application programming interface) for creating comunication flows between two endpoints. Sockets create an interface above the Transport Layer, so we can use them in order to send data on the TCP/IP Application Layer.


Raw Sockets are little different. They create a low-level comunication flow, enabling us to work directly on IP layer or better over the Data-Link Layer. Basically, we have to write the TCP/IP headers and (re)write "freehand" the comunication protocol, like 3-Ways handshake or sliding windows managment.

Only a fool would use such a thing! A fool or someone who wants to analyze/manipulate the traffic. So the creation of a Raw Socket requires root privileges.



Thankfully the OS give us structures for protocol's header (like ip, tcp, udp, icmp, arp...).

The normal execution flow is:
  • Creation of a trasmission buffer, to be filled with IP header ip and payload.
  • IP packet checksum computation.
  • Raw Socket creation.
  • Tell the operating system to avoid adding automatically IP Header.
  • Sending the trasmission buffer using sendto().
  • Wait for a reply using recivefrom(), filling the receive buffer with the answer.
  • <your code go here> :P
  • ...

Start again

So long...
About an years passed since my last post, and I wanna try to start again.
Now I get my Laurea Triennale in Ingegneria Informatica (3 years of Computer Engineering, like Bachelor) and now I'm attending the two years specialization (Laurea magistrale) in order to become a true Computer Engineer.

English is the ICT's lanaguage, and I'll try to write my future posts in english. I don't have a lot of experience, so, like all not-anglophone say: "sorry for my english".

Wednesday, February 2, 2011

DVWA: SQLI in BruteForce Easy

Questo post fa parte della serie DVWA.

In questo post non discuterò della vulnerabilità al brute force della pagina (nessun limite di tentativi, nessun controllo anti-bot, link costante, messaggio di errore deterministico...), ma dell'attacco SQL Injection a cui è vulnerabile.

Provando con il classico tentativo (inserendo ' nei due campi), otteniamo un errore:

[...] for the right syntax to use near '3590cb8af0bbb9e78c343b52b93773c9'' at line 1
Quella stringa di caratteri è un hash (più precisamente è il risultato di md5(') ). Da qui possiamo dedurre che le password siano salvate nel database tramite il loro hash. Dunque un attacco sqli al campo password è impossibile (qualunque stringa inserita è convertita in una stringa esadecimale da 32 caratteri). Tuttavia è possibile un attacco al campo username. Proviamo a dedurre la query:

SELECT * FROM tabella WHERE user = '$user' AND password = $password;

Non si può (come negli altri casi) inserire nel campo user il valore 1' OR '1' = '1, poichè la query risultante sarebbe:

SELECT * FROM tabella WHERE user = '1' OR '1' = '1' AND password = $password;

Se la password non è corretta, la query restituisce false.
Per aggirare questa condizione, possiamo usare il commento SQL: --, in modo da costruire questa query (gli spazi sono importanti!):

SELECT * FROM tabella WHERE user = '1' OR 1 -- AND password = $password;

Se il campo user vale "1' OR 1 -- ", otteniamo il risultato desiderato.

La query è corretta, però se proviamo ad inserire questo valore, non riusciamo a effettuare il login. Perché?

Una pratica molto comune nei casi dove il numero di risultati della query è noto, è quella di effettuare il controllo del numero di risultati.
Nel caso del login il risultato della query deve essere uno solo, poichè deve esistere una sola entry per una coppia (user, password).

A questo punto ci viene in aiuto SQL, con il comando LIMIT, che permette di selezionare indice e numero di risultati forniti dalla query. Mettendo in pratica, scrivendo 
 "1' OR 1 LIMIT 0,1 -- ", la query sarà:

SELECT * FROM tabella WHERE user = '1' OR 1 LIMIT 0, 1 -- 'AND password = $password;

Siamo riusciti ad effettuare il login!

C'è un'altra cosa interessante. In caso di succesful login, viene aggiunta alla pagina una immagine che ha come nome ciò che sembrerebbe il nome dell'utente con cui ci siamo loggati (es: admin.jpg). Perciò inserendo nel campo user 
"1' OR 1 LIMIT x,1 -- ", dove x >= 0, possiamo loggarci come ogni utente del sistema e leggerne il nome dall'immagine caricata.

DVWA: SQL Injection Medium

Questo post fa parte della serie DVWA.
Livello easy: http://danielebellavista.blogspot.com/2011/01/dvwa-sql-injection-easy.html

Anche nel livello Medium è possibile scegliere fra Blind (senza print dell'errore mysql) e non Blind.

Il livello medium è un classico esempio di misure di sicurezza giuste applicate in contesti sbagliati.

Vediamo l'applicazione con non-blind (a scopo didattico, così si possono apprendere certe vulnerabilità che emergono da certi contesti).

Se proviamo inserendo il classico carattere ', otteniamo un errore:
[...] the right syntax to use near '\'' at line 1

Notiamo che è comparsa una slash che genera il carattere di escape \'. In questo modo l'attacco del livello easy (1' OR '1' = '1) perde di efficacia, poichè una volta aggiunte le slash si ottiene 1\' OR \'1\' = \'1Allora perché otteniamo comunque l'errore?

Provando con dei caratteri alfabetici si ottiene il seguente errore:

Unknown column 'a' in 'where clause'

perchè?
Perchè ID è un numero e in SQL, un campo numerico può essere comparato ad un valore senza l'ausilio degli apici. Ragionando su questa strada, l'errore è dovuto proprio a questo! Infatti la query risultate inserendo 1' OR '1' = '1 sarà:

SELECT * FROM tabella WHERE ID = 1\' OR \'1\' = \'1;

Che chiaramente produce un errore. Quindi il valore da inserire è 
1 OR 1 , ottenendo:

SELECT * FROM tabella WHERE ID = 1 OR 1;

Tuesday, February 1, 2011

DVWA: Cross Site Request Forgery (CSRF) Medium

Questo post fa parte della serie DVWA.

(
DVWA: Cross Site Request Forgery (CSRF) Easy)

Provando lo stesso giochino dell'easy (un link da un sito esterno verso la pagina di cambio password), non otteniamo il risultato sperato.

Possiamo ipotizzare che il webmaster abbia inserito degli strumenti di protezione, ma forse (per nostra fortuna) non i più efficaci (tokenizzare la sessione inviando il token come parametro, chiedere la password corrente...). Con un po' di guessing si può intuire che il webmaster faccia un controllo sul referrer.

Il referrer è un campo dell'header http che indica la pagina da cui è partita la richiesta. Se la richiesta è nuova (non è partita da nessuna pagina) il campo referrer non compare.

Possiamo quindi pensare di fare del Referrer Spoofing!

Tramite un proxy locale, modificando la richiesta di cambio password e cambiando il referrer mettendo l'indirizzo ip dell'host di DVWA (nel nostro caso 127.0.0.1), il cambio password va a buon fine. Ora sappiamo che la pagina fa solo un controllo sul referrer,

Purtroppo l'idea dell'attaco è quella di cambiare la password di altri utenti e di certo questi utenti non cambieranno di loro spontanea volontà il referrer!

Per fortuna ci vengono in aiuto tanti proxy online che fanno esattamente questo lavoro. Ne cito uno: 
http://referer.us/Spoof-HTTP-Referer.html.

Questo proxy permette di collegarsi ad un dato URL, spoofando il referrer con un dato url (ovviamente non possiamo usarlo per testarlo su DVWA in localhost, poichè un proxy remoto non può raggiungere il nostro 127.0.0.1).

Supponiamo che la pagina vulnerabile sia http://vulnsite.com/user/changepwd.php, e che per cambiare la password occorra fornire i parametri: newpass=nuovapassword&confirm=nuovapassoword&change=Change , spoofando il referrer con http://vulnsite.com/.

Utilizzando il simpatico form di referer.us, generiamo il link:

http://referer.us/f/?url=http%3A%2F%2Fvulnsite.com%2Fuser%2Fchangepwd.php%3Fnewpass%3Dnuovapassword%26confirm%3Dnuovapassoword%26change%3DChange&referer=http%3A%2F%2Fvulnsite.com%2F


e lo possiamo inserire in una immagine 0x0. Chiunque carichi l'immagine e sia loggato al sito 
http://vulnsite.com/ cambierà inconsciamente la propria password :).

DVWA: File Upload Medium

Questo post fa parte della serie DVWA.

Per cominciare, qual è la vulnerabilità che può comportare un file upload?
Quella più semplice risiede nella possibilità di generare un memory overflow, inserendo file giganteschi, oppure è possibile inserire programmi malevoli, script, effettuare defacing, ecc...

Il form permette di inserire una immagine nel server. Ma è veramente così? Vengono fatti dei controlli sul tipo di file inserito?

Osservando il codice html, si nota l'hidden input MAX_FILE_SIZE che accompagna sempre un file input (php implementa un controllo automatico della dimensione massima del file, basandosi su MAX_FILE_SIZE). Ovviamente questo parametro è decisamente bypassabile (modificando l'html o la request mediante un proxy).

Effettuiamo qualche prova.
Provando ad uploadare un file .php (ad esempio una shell), il form ci avverte che la nostra immagine non è stata uploadata.

Questi controlli sono solitamente fatti in determinati modi:

  • Blacklist: lo script mantiene una lista di estensioni da non accettare
  • Whitelist: lo script mantiene una lista di estensioni da accettare
  • MIME-Type: lo script controlla l'Internet Media Type del file (riportato nel campo Content-Type (eg: Image/jpeg)
  • Controllo indiretto di tipo: lo script invoca una funzione (come getimagesize() ), che fallisce se il file caricato non è una immagine.
Ovviamente il metodo più debole è quello che usa il MIME-Type, infatti, utilizzando un proxy locale, è possibile inserire un header "Content-Type: image/jpeg" nella parte relativa al file da uploadare.

Con la Blacklist, solitamente, si ricava l'estensione del file ricercando l'ultimo '.' della stringa e comparandolo con una lista. Se questa estensione compare nella blacklist, il file non viene uploadato. Ci sono vari modi di bypassare il controllo, il più immediato è quello di passare un file che ha come nome (nell'ipotesi che 'php' non sia ammessa) 'shell.php.' . Quando questo nome viene analizzato, l'estensione risulterà vuota e se non compare nella blacklist, sarà permessa. Inoltre durante la memorizzazione nel filesystem, l'ultimo punto viene ignorato dal sistema operativo, di conseguenza di avrà uploadato il file 'shell.php'.

La Whitelist ha una vulnerabilità strettamente legata al webserver e al modo in cui si comporta con le doppie estensioni. Ad esempio Apache se configurato male, può permettere di bypassare la whitelist, interpretando il file "shell.php.jpg" non come una immagine jpg, ma come un file php (molto raro che succeda).

Il controllo indiretto del tipo può essere ingannato a seconda del tipo di controllo: se è solamente limitato all'header del file, è possibile mettere nel file da uploadare le informazioni necessarie per far apparire il file ciò che in realtà non è. Ovviamene un controllo più diretto non è bypassabile.

In ogni caso, tornando a DVWA, provando ad inserire dei file non immagini si nota che questi non vengono uploadati. Provando con un proxy locale a modificare l'HTTP Request, aggiungendo al file uploadato l'header Content-Type: image/jpeg, qualunque file viene caricato.

Ma la vulnerabilità della pagina non si limita solo a questo, infatti la pagina salva tutti i file in un'unica folder, mentre le buone norme di sicurezza imporrebbero l'utilizzo di folder random-generated.

Monday, January 31, 2011

DVWA: Cross Site Request Forgery (CSRF) Easy

Questo post fa parte della serie DVWA.

Anche questa è una vulnerabilità molto potente. In maniera molto semplice, ci permette di sfruttare i cookie di sessione che rimangono settati nel browser dell'utente, per ottenere indirettamente accesso a pagine o funzioni (più informazioni).

Nella pagina DVWA, è presente un normalissimo form che ci permette di cambiare la password dell'utente. Se proviamo a cambiarla, analizzando l'URL, notiamo che i nostri parametri sono passati nell'URL, es:
http://127.0.0.1:8888/dvwa/vulnerabilities/csrf/?password_new=pippo&password_conf=pippo&Change=Change#

La vulnerabilità non risiede nell'aver messo i parametri come GET, ma nell'avere un URL riproducibile per qualunque utente loggato, poichè non contiene alcun parametro legato all'utente, come l'ID di sessione, o la password vecchia.
Si può pensare di impostare l'attacco in questo modo: se noi sappessimo che il bersaglio è loggato a questo sito e riuscissimo a fargli accedere ad un link come quello sopra, il browser genererebbe una HTTP Request settando il campo Cookie con il cookie di sessione ancora valido, bypassando l'autentificazione (poichè è già avvenuta).
Non è neppure necessario creare un link esplicito, o un redirect, basta una immagine:

<img src="
http://127.0.0.1:8888/dvwa/vulnerabilities/csrf/?password_new=pippo&password_conf=pippo&Change=Change#" width="0" height="0" />

Una immagine 0 per 0, che quando viene valutata il browser inconsciamente si collega alla pagina di cambio password con i parametri settati da noi e con il prorpio Cookie di sessione.

Per testare con efficienza questa vulnerabilità, è meglio testare il link da un server esterno a 127.0.0.1, ad esempio dal proprio blog o dal proprio sito su altervista/google o inviandosi una mail, in questo modo è più realistico (se riuscissimo ad inserire l'immagine sul server del sito web avremmo sfruttato un'altra vulnerabilità.

DVWA: Command Execution Easy

Questo post fa parte della serie DVWA.

SecurityLevel: Easy, entriamo in Command Execution.

È richiesto di inserire un indirizzo ip, se lo facciamo otteniamo sullo schermo l'output dell'operazione di ping.

Possiamo supporre che il codice php sia qualcosa tipo:


exec("ping ".$command);

Se siamo fortunati, non viene fatto alcun controllo sul comando inserito. Abbiamo varie soluzioni da provare (dipendono dal sistema operativo in cui è installato il webserver, nel nostro caso il nostro sistema operativo).
  1. Linux) La shell permette di separare i comandi da eseguire inserendo ";"
  2. Linux) La shell permette di eseguire due comandi concorrentemente separandoli con "&"
  3. Linux) La shell permette di eseguire due comandi sequenzialmente separandoli con "&&"
  4. Windows) cmd permette di eseguire sequenzialmente due programmi separandoli con "&"
  5. Windows) cmd permette di eseguire sequenzialmente due programmi solo se il primo esce con non-error status separandoli con "&&"
  6. Windows) cmd permette di eseguire sequenzialmente due programmi solo se il primo esce con error status separandoli con "||"
Il comando in comune che agisce sequenzialmente è && (se non si conosce il sistema operativo occorre avere l'accortezza di inserire un ip raggiungibile e pingabile in modo da non far fallire il comando ping).
Proviamo inserendo:
74.125.232.114 && echo Vuln!
Se alla fine del ping otterrete "Vuln!", significa che il codice è vulnerabile! Ora la fantasia entra in gioco! Possiamo ad esempio ottenere il codice php di qualsiasi pagina, es:

74.125.232.114 && cat path/pagina.php

Oppure, se l'OS è linux, probabilmente possiamo caricare un programma malevolo del server con wget e poi eseguirlo...



Permettere una simile vulnerabilità nel proprio sito web, è veramente da idioti.

Sunday, January 30, 2011

DVWA: SQL Injection Easy

Questo post fa parte della serie DVWA.


Impostiamo il Security Level a Easy ed entriamo in "SQL Injection".
La differenza rispetto a "SQL Injection", è che in "SQL Injection (Blind)", non viene riportato l'errore causato da una malformazione del parametro di input.

È meglio cominciare con la versione non blind, per poter osservare eventuali errori.
Cominciamo inserendo un campo intuitivamente conforme a ID (un numero piccolo), come 1.
In ouput viene visualizzato qualcosa.
Proviamo ora ad inserire dei caratteri non alfanumerici.

Provando con ', otteniamo un errore.

Abbiamo scoperto che il form è vulnerabile a SLQ Injection. Cosa possiamo farci?

Se siamo "fortunati" e anche lo script di elaborazione dei risultati è fatto male, possiamo ad esempio pensare di ottenere le informazioni su tutti gli utenti.

Possiamo intuire la struttura della query:

SELECT * FROM tabella WHERE ID = $id;
Oppure
SELECT * FROM tabella WHERE ID = '$id';

Ipotizziamo la prima e proviamo a costruire questa query:
SELECT * FROM tabella WHERE ID = 1 OR 1;

Mettiamo nel form "1 OR 1", ma non otteniamo il risultato voluto, allora probabilmente è la seconda forma. Proviamo a mettere nel form "1' OR '1' = '1", in modo da ottenere:
SELECT * FROM tabella WHERE ID = '1' OR '1' = '1';

L'output è proprio quello desiderato: la lista di tutti gli utenti del database.