Newsgroup: it.comp.sicurezza.varie
Titolo: SERIO: Buffer overflow, come funziona?

Ciao, volevo chiedervi se gentilmente mi potreste spiegare come funziona il
buffer overflow, sapete...č una curiositŕ che non riesco a tagliarmi dalla
testa :-)
Allora, prendiamo 
ad.es
. Outlook, che come esempio per me č semplice
(perchččččč??): come voleva fare il toscanaccio, se io nel campo_subject
inserisco un numero di caratteri superiori ad un tot (facciamo 256, ok?) i
caratteri che vanno dal 257 al XXX vengono allocati a casaccio nella memoria
di sistema.
Cioč: i caratteri da 1 a 256 vanno dall'indirizzo 000000000 a 0000000FF (č
solo un esempio) mentre tutti gli altri negli indirizzi superiori, e questo
perchč i programmi che soffrono di questo bug non hanno un controllo che
impedisca di allocare i ti in piů, giusto? Essendo i dati in surplus
allocati cmq, un birbaccione qualunque potrebbe usarli per far eseguire dei
comandi nel sistema target. Ed č qui che io mi perdo: ma perchč quei dati in
piů dovrebbero essere eseguiti? Ma chi lo dice al S.O. di eseguire quei
dati? Eppoi, facciamo che io dal carattere 257 in poi scrivi un intero
programma birbaccione: ma dove va a finire la formattazione del codice
sorgente? Come facio a scrivere un programma nel campo_subject di Outlook?
Come dichiaro le variabili? E le funzioni? Eppoi la stessa domanda di prima:
ma perchč il S.O. dovrebbe eseguire quella roba?
Beh, spero di non avervi annoiato. Magari se qualcuno di voi ha qualche
minuto libero....magari potrebbe....
Beh, ciao e buon lavoro.

minuto libero....magari potrebbe....
Formattarti il sistema a distanza? 
No, grazie, ho altro da fare.
-- 
           |Save our planet!
  Ciao     |Save wildlife;
  roberto  |For your E-MAIL use only recycled Bytes !!
           |roberto poggi  
rpo...@softhome.net

 No, grazie, ho altro da fare.
No, no...intendevo...darmi i numeri vincenti del Superenalnove.
Ciao.

No, no...intendevo...darmi i numeri vincenti del Superenalnove.
Dieci.


 Beh, ciao e buon lavoro.
Mandi! ;-)
-- 
http://www.fantoibed.com
  -linux addicted-  
fant...@iname.com

di sistema.
Consideriamo questo pezzo di codice in C:
char *add_subject_reply(char *subject)
{
	char old_subject[256];
	strcpy(old_subject, "Re: ");
	strcat(old_subject, subject);
	return old_subject;
}
...tu gli mandi "Pippo", lui ritorna "Re: Pippo" (non e' detto, dato che
il buffer non e' statico, ma lasciamo stare, ok?).
Vediamo piu' in dettaglio cosa succede nel sistema.
Il programma sta facendo qualcos'altro, per esempio
	read_subject(subject, stream);
e poi fa una chiamata alla funzione di cui sopra:
	read_subject(subject, stream);
	subject = add_subject_reply(subject);	// Programmato col culo
Andiamo piu' in dettaglio e vediamo cosa fa la CPU:
	00A001B4 PUSH SUBJECT
	00A001B8 PUSH STREAM
	00A001BC CALL READ_SUBJECT
	00A001C0 PUSH SUBJECT
	00A001C4 CALL ADD_SUBJECT_REPLY
e, ancora piu' ingrandito:
	00A001C0 PUSH SUBJECT
	00A001C4 PUSH $HERE+4
	00A001C4 JMP ADD_SUBJECT_REPLY
 
cioe' la CPU salva sullo stack il punto in cui si trova, e poi salta
al nuovo indirizzo; questa e' una "chiamata a subroutine". Quando la
subroutine inserisce un
	00B3020C RETF
questo equivale a 
	00B3020C POP $ADDR
	00B3020C JMP $ADDR
 
...recuperare dallo stack il ricordo di dov'era prima, e andarci.
Ora, quando il controllo passa alla routine di cui sopra, nello stack
c'e' questa roba:
	[SUBJECT]
	[$HERE+4]
ma, molto alla grossa, quando io scrivo buffer[256]... quei 256 bytes
sono presi dallo stack. Quindi quando arrivo a strcpy() lo stack e':
	[SUBJECT]
	[$HERE+4]
	[ 256 bytes ]
Se io in quel buffer di 256 bytes riesco a farcene finire altri 4, l'
indirizzo $HERE+4 sara' sostituito da quello che io inserisco. Posso,
a questo punto, immaginare due scenari:
	a) $HERE+4 e' l'indirizzo di una routine tipo system(), e, se
           la funzione chiamata esegue un RETF, invece di ritornare a
           casa, CS:IP atterra su system()... e mi apre una shell.
	b) $HERE+4 adesso punta ALL'INTERNO DEL BUFFER, quindi quando
	   (uh, cacofonico) la funzione torna, eseguira' il contenuto
	   del buffer, ma stavolta come se fosse codice.
Mi raccomando: spiegato male e alla carlona. Caveat emptor!
Leonardo
-- 
And where the black and corkscrew towers climb
Lost and athirst the ragged pack abides,
Old as the aeons, trapped in tombs of time,
Sailing the tortuous temporal tides...

>quindi quando
	   (uh, cacofonico) la funzione torna, >eseguira' il contenuto
	   del buffer, ma stavolta come se fosse >codice.
quindi per evitare il buffer overflow, basta non allocare mai memoria, sia
staticamente che dinamicamente ( malloc o new ), "superflua", nel senso che
va "riempita tutta".
Nel tuo esempio bastava dichiarare il vettore "old_subject" come:
char old_subject[6];    // compreso "/0"
Basta questo o non ho capito una mazza?
Ciao grazie Gianni.
P.S.: non fare di questi esempi che poi mi flippo a capire, mentre dovrei
studiare Elettronica applicata :-), purtroppo non riesco a
resistereeeeeeeeeeeeeeeeeeeeeee
-- 
Posted from 
c000-h011.c000.muc.cp.net
 [209.228.29.35] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

Diciamo che, in maniera mooooooooolto generale, *MI PARE* di aver capito.
Cmq grazie, a buon rendere! (tipo: vuoi un mio racconto di sci-fi?)
:-D

 Dieci.
Si, ma gli altri? :-)
Grazie ancora per la pazienza.

Beh, prima ti ho detto di averci forse capito....ora ri-leggendo il tuo
reply posso dire di essere ASSOLUTAMENTE CERTO di *NON* aver capito :-) [1]
[1] anche perchè io non conosco l'ASM nè il C, nè so come funzionano gli
stack e roba varia :-) [1.bis]
[1.bis] potresti a questo punto domandarmi perchè diavolo allora mi sto
imbarbicando su ste cose. Risposta: perchè sono curioso :-)

Si, ma gli altri? :-)
Beh, sforzati, crea una serie di pippopallico, e completala.


 
E meno male che era alla carlona: se lo spiegavi bene c'era il
disassemblato di outlook???
Comunque grande spiegazione!
-- 
Roberto Tagliaferri<-> r.tagliaferri@(forse)
tosnet.it
	Povero Carlo.. E` l' unico a cui hanno rifilato 
	una Camilla scaduta senza neanche il coccio del
	Mulino Bianco!!!

va "riempita tutta".
Non proprio. La regola e': "Quando riempi qualcosa, accertati PRIMA che
ci stia tutto" (in inglese suona piu' divertente e vagamente scurrile -
e ovviamente la cosa e' voluta).
Quindi, se proprio devo copiare il buffer alpha dentro beta:
	n = strlen(alpha)+1;
	beta = malloc(n);
	if (beta==NULL)
	{
		jprintf(J_WARNING, "malloc(%d) failed", n);
		return NULL;
	}
	strncpy(beta, alpha);	
	return beta;
...e a questo punto hai problemi in piu' per gestire il fatto che prima
o poi beta lo dovrai liberare, e quindi compare il rischio di leaks. Il
vero *programmatore della domenica* evita il rischio di leaks in cambio
di un rischio di buffer overflow, ripetendo il mantra "Non succedera'".


sempre delle istruzioni Assembly o cmq del codice compilato?
Qualsiasi cosa finisce in coda di esecuzione e' considerato CODICE. Se
e' codice, meglio; se non lo e', si pianta tutto.
"SPQR" e' una sigla ASCII - ma se la mandi alla CPU, e' ANCHE l'ordine
di salvare un po' di registri :-)


stack e roba varia :-) [1.bis]
In realta' lo sai, ma non sai di sapere.
Diciamo che sei al supermarket e stai comprando la pizza surgelata,
quando squilla il telefonino e il tuo SO [1] ti dice di comprare un
pacco di spaghetti. Smetti di fare quello che stai facendo, e vai a
comprare gli spaghetti; oppure continui, e POI vai a comprarli.
In entrambi i casi, tu, puoi fare una sola cosa per volta, come una
CPU; ma le cose da fare son due. Quella delle due che non fai viene
"parcheggiata" in una lista.
Quando sei libero, guardi nella lista se c'e' qualcos'altro da fare
e, se c'e', lo togli dalla lista e lo fai.
Se la regola e' "Faccio sempre la prima cosa in lista; se arriva un
nuovo compito, lo parcheggio al primo posto in lista... e quindi l'
ultimo arrivato e' il primo servito", hai una lista LIFO (Last In -
First Out), cioe' uno "stack".
Supponi ora che, sul pacco di pizza surgelata, ci sia un comando di
tipo subliminale che dice "GLI SPAGHETTI SONO RIGATONI".
Prima di prendere la pizza, il tuo stack era:
                     | [--FINE STACK--]
                     | [prendere l'auto]    
                     | [pagare alla cassa]
[prendere pizza]     | [prendere spaghetti] 
e un attimo dopo averla presa e':
                     | [--FINE STACK--]
                     | [prendere l'auto]    
                     | [pagare alla cassa]
[prendere pizza]     | [prendere rigatoni] 
ancora un istante e:
                     | [--FINE STACK--]
                     | [prendere l'auto]    
[prendere rigatoni]  | [pagare alla cassa]
...ti dirigi ai rigatoni.
Questo scherzo lo potresti fare se l'ordine che arriva fosse:
	"Mi prendi una Pizza Pazza Con Prendere Rigatoni?".
In questo caso, prepari il sistema per ricevere l'ordine, cioe'
salvi quel che stavi facendo ("prendere spaghetti") nello stack
                     | [--FINE STACK--]
                     | [prendere l'auto]    
                     | [pagare alla cassa]
 (spazio vuoto)      | [prendere spaghetti] 
e nello spazio vuoto cosi' ottenuto copi l'ordine:
                     | [--FINE STACK--]
                     | [prendere l'auto]    
                     | [pagare alla cassa]
prendere pizza pazza con prendere rigatoni]
...il sistema traballa un attimo e converte:
                     | [--FINE STACK--]
                     | [prendere l'auto]    
                     | [pagare alla cassa]
prendere pizza pazza | [prendere rigatoni]
e ZAC, ecco dimenticati gli spaghetti.
+--------------------+
Ora immaginiamo un web server stupido. Questo server stupido immaginario
[2] serve le pagine cosi':
	- prendi la richiesta
	- verifica se c'e' il file
	- leggi il file
	- invia i dati
e dunque lo stack diventa
                     [ inviare i dati ]
                     [ leggere il file ]
                     [ verificare se c'e' il file ]
[ prendi richiesta ]
Ora, supponiamo che la richiesta ipotetica sia
 GET /index.html HTTP/1.00000000000000C:\SERVER\CREDITCARDS\LIST.TXT\n\n
...lo stack diventa:
                     [ inviare i dati ]
                     [ leggere il file ]
 GET /index.html     [ file = C:\SERVER\CREDITCARDS\LIST.TXT ]
...e, poco dopo, sul display dell'ignoto attaccante comincia a scorrere
una sequenza di cifre casuali, tipo
4512 3456 7890 1234 02/2002 SERNI LEONARDO
...
4534 5678 9012 3456 99/3000 GATES WILLIAM HENRY III
...
Leonardo si parva licet componere magnis
[1] Significant Other
[2] Imaginary Stupid Server, per gli anglofoni


e ovviamente la cosa e' voluta).
esplicita please :-)
Ciao e grazie Gianni.


 di salvare un po' di registri :-)
Non prima di aver stampato, a video, ``Sono Pazzi Questi Romani''. :-)
-- 
Emmanuele Bassi         |  Linux: [ 
http://digilander.iol.it/ebassi/linux/
 ]
                        |   SLRN: [ 
http://digilander.iol.it/ebassi/slrn/
  ]
emmanue...@iol.it
  |   SETI: [ 
http://digilander.iol.it/ebassi/seti/
  ]
  GnuPG Key Fingerprint: 9747 635E B95A B0B3 4370 1CAA CAF7 512B 945C A44C

 ti e' venuto per caso? ;-)
č venuto a caso...perchč, che significa??
Cmq grazie mille per la spiegazione usando l'esempio della pizza :-)
divertente ed utile. Spiegassero tutti cosě non ci vorrebbe niente ad
imparare le cose.
Ciao e FORZA ROMA. Tu sei toscano ERGO della Fiorentina: GRAZIE PER AVERCI
DATO BATISTUTA :-P

Ciao, un avviso: ho quotato tutto, il mio reply è quasi nel mezzo. Scusa!

Leonà....fin qui tutto chiaro, ma il seguito mi sfugge: perchè "Pizza
pazza..." e perchè dopo il primo elemento dello stack è uno spazio vuoto?
Scusa se ho quotato così, ma non mi è venuto in mente un modo più pratico.
:-)

Infinite grazie!

 disassemblato di outlook???
Secondo me, conoscendo Leo quello _è_ il disassemblato di Autlucc.
Per questo è alla carlona...  ;-))
Bye, G.

esplicita please :-)
Suvvia. Se non ti viene in mente il doppio senso perverso, allora hai
scelto la carriera sbagliata :-)


 Consideriamo questo pezzo di codice in C:
      ____   ______   __  __    ______   ______   ______   ______   __
     /   /  |_    _| |  ||  |  |      | |      | |      | |  ____| |  |
    /   /     |  |   |  ||  |  |   __ | |  ()  | |  ()  | | |___   |  |
    \   \     |  |   |  ||  |  |  |     |  ()  | |      | |  ___|  |  |
     \   \    |  |   |  ||  |  |  |     |      | |   /| | | |____  |__|
     /___/    |  |   |______|  |__|     |______| |__/ |_| |______|  __
                                                                   |__|
                          %%%%%%%%%%%%            
                        %%%%%%%%%%%%%%%%
                      %%%%%%%%%%%%%%%%%%%%               
                     %%%%%%  _ _ _ _  %%%%%%
                    %%%%%   _ _ _ _ _   %%%%% 
                     %%%%  _ _ _ _ _ _  %%%%
                      %%%               %%%
                       %% / \     / \   %%
                       |                | 
                       |  &&&     &&&   |
                       | &   &   &   &  |
                       |  &*&  |  &*&   |
                       |       |        |
                       |      / \       |
                       |     _____      |
                       |    /     \     |
                        \   \_____/    /
                         \            /
                          \          /
                           \________/

Secondo me, conoscendo Leo quello _鑏 il disassemblato di Autlucc.
Assolutamente no. E' codice random che mi ha mandato un amico hacker
da San Pietroburgo tempo fa. L'ha trovato su non so piu' che server,
e me l'ha spedito perche' mi ci facessi quattro risate.


Scusa se ho quotato così, ma non mi è venuto in mente un modo più pratico.
Quando fai un buffer overflow, sei costretto a mettere certe cose in
certi punti precisi. E "prendere rigatoni" deve partire dal medesimo
punto dove c'era "prendere spaghetti": la CPU e' si' scema... ma non
COSI' TANTO scema.
Nel caso del linguaggio naturale, sei costretto a trovare un qualche
articolo che abbia una lunghezza di 11 caratteri: "Pizza Pazza". Nel
caso delle CPU sei messo meglio perche' esistono codici nulli che si
possono usare per "allungare" il codice (90h, o NOP).
D'altra parte, per spedire del codice macchina a una macchina dovrai
anche tenere conto di alcune limitazioni.
Un server Web, per esempio, potrebbe accettarti in input solo codici
ASCII da 21h a 7Fh, e magari neanche tutti. Oppure potrebbe alterare
i codici "%" mangiando i due caratteri successivi, ecc..
E allora sei costretto a costruire sequenze macchina usando solo dei
caratteri precisi, e senza usarne altri. Ci vuole una pazienza molto
sviluppata ed una precisione maniacale. Per esempio EICAR (lo pseudo
virus) e' un programma eseguibile, scritto solo con caratteri ASCII,
ed ugualmente eseguibile. Se lo mandassi a un sito Web, passerebbe i
controlli sull'input non-ASCII (e poi sarebbe seccato perche' non e'
una richiesta HTTP valida).
Leonardo


e me l'ha spedito perche' mi ci facessi quattro risate.
ahh,  si l'amico di Dimitri, quello che sullo stesso dominio
ha infilato una backdoor ad un niubbo pochi giorni dopo :-))
ciao
boogy
-- 
Boogyman
the most scalcinato Linux-user living :-))
i post con "R:" li killa
e 
news.libero.it
 killa quelli in HTML