Domanda

void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
   int *ret;

   ret = buffer1 + 12;
   (*ret) += 8;//why is it 8??
}

void main() {
  int x;

  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}

È possibile che questo demo è da qui:

http://insecure.org/stf/smashstack.html

Ma non funziona qui:

D:\test>gcc -Wall -Wextra hw.cpp && a.exe
hw.cpp: In function `void function(int, int, int)':
hw.cpp:6: warning: unused variable 'buffer2'
hw.cpp: At global scope:
hw.cpp:4: warning: unused parameter 'a'
hw.cpp:4: warning: unused parameter 'b'
hw.cpp:4: warning: unused parameter 'c'
1

E non capisco perché è 8 se l'autore pensa:

  

Un po 'di matematica ci dice la distanza è   8 byte.

Il mio gdb discarica come richiesto:

Dump of assembler code for function main:
0x004012ee <main+0>:    push   %ebp
0x004012ef <main+1>:    mov    %esp,%ebp
0x004012f1 <main+3>:    sub    $0x18,%esp
0x004012f4 <main+6>:    and    $0xfffffff0,%esp
0x004012f7 <main+9>:    mov    $0x0,%eax
0x004012fc <main+14>:   add    $0xf,%eax
0x004012ff <main+17>:   add    $0xf,%eax
0x00401302 <main+20>:   shr    $0x4,%eax
0x00401305 <main+23>:   shl    $0x4,%eax
0x00401308 <main+26>:   mov    %eax,0xfffffff8(%ebp)
0x0040130b <main+29>:   mov    0xfffffff8(%ebp),%eax
0x0040130e <main+32>:   call   0x401b00 <_alloca>
0x00401313 <main+37>:   call   0x4017b0 <__main>
0x00401318 <main+42>:   movl   $0x0,0xfffffffc(%ebp)
0x0040131f <main+49>:   movl   $0x3,0x8(%esp)
0x00401327 <main+57>:   movl   $0x2,0x4(%esp)
0x0040132f <main+65>:   movl   $0x1,(%esp)
0x00401336 <main+72>:   call   0x4012d0 <function>
0x0040133b <main+77>:   movl   $0x1,0xfffffffc(%ebp)
0x00401342 <main+84>:   mov    0xfffffffc(%ebp),%eax
0x00401345 <main+87>:   mov    %eax,0x4(%esp)
0x00401349 <main+91>:   movl   $0x403000,(%esp)
0x00401350 <main+98>:   call   0x401b60 <printf>
0x00401355 <main+103>:  leave
0x00401356 <main+104>:  ret
0x00401357 <main+105>:  nop
0x00401358 <main+106>:  add    %al,(%eax)
0x0040135a <main+108>:  add    %al,(%eax)
0x0040135c <main+110>:  add    %al,(%eax)
0x0040135e <main+112>:  add    %al,(%eax)
End of assembler dump.

Dump of assembler code for function function:
0x004012d0 <function+0>:        push   %ebp
0x004012d1 <function+1>:        mov    %esp,%ebp
0x004012d3 <function+3>:        sub    $0x38,%esp
0x004012d6 <function+6>:        lea    0xffffffe8(%ebp),%eax
0x004012d9 <function+9>:        add    $0xc,%eax
0x004012dc <function+12>:       mov    %eax,0xffffffd4(%ebp)
0x004012df <function+15>:       mov    0xffffffd4(%ebp),%edx
0x004012e2 <function+18>:       mov    0xffffffd4(%ebp),%eax
0x004012e5 <function+21>:       movzbl (%eax),%eax
0x004012e8 <function+24>:       add    $0x5,%al
0x004012ea <function+26>:       mov    %al,(%edx)
0x004012ec <function+28>:       leave
0x004012ed <function+29>:       ret

Nel mio caso la distanza dovrebbe essere -? = 5, giusto Ma non sembra lavorare ..

Perché esigenze function 56 byte per le variabili locali? (sub $0x38,%esp)

È stato utile?

Soluzione

joveha sottolineato , il valore di PEI salvato nello stack (indirizzo di ritorno) dall'istruzione call deve essere incrementato di 7 byte (0x00401342 - 0x0040133b = 7 ) per saltare l'istruzione x = 1; (movl $0x1,0xfffffffc(%ebp)).

Lei ha ragione che 56 byte sono riservati per le variabili locali (sub $0x38,%esp), in modo che il pezzo mancante è il numero di byte buffer1 passato sullo stack è l'EIP salvato.


Un po 'di codice di test e assemblaggio in linea mi dice che il valore di magia è 28 per la mia prova. Non posso fornire una risposta definitiva sul perché è 28, ma vorrei assumere il compilatore è l'aggiunta di imbottitura e / o di canarini pila .

  

Il seguente codice è stato compilato utilizzando GCC 3.4.5 (MinGW) e testato su Windows XP SP3 (x86).


unsigned long get_ebp() {
   __asm__("pop %ebp\n\t"
           "movl %ebp,%eax\n\t"
           "push %ebp\n\t");
}

void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
   int *ret;

   /* distance in bytes from buffer1 to return address on the stack */
   printf("test %d\n", ((get_ebp() + 4) - (unsigned long)&buffer1));

   ret = (int *)(buffer1 + 28);

   (*ret) += 7;
}

void main() {
   int x;

   x = 0;
   function(1,2,3);
   x = 1;
   printf("%d\n",x);
}

ho potuto avere gdb altrettanto facilmente utilizzato per determinare questo valore.

(compilato w / -g per includere i simboli di debug)

(gdb) break function
...
(gdb) run
...
(gdb) p $ebp
$1 = (void *) 0x22ff28
(gdb) p &buffer1
$2 = (char (*)[5]) 0x22ff10
(gdb) quit

(0x22ff28 + 4) - 0x22ff10 = 28

(valore EBP + dimensione della parola) - indirizzo del buffer1 = numero di byte


Oltre a Smashing La Pila per divertimento e profitto , vorrei suggerire la lettura di alcune delle gli articoli che ho citato in mia risposta ad una precedente interrogazione di vostro e / o altro materiale sull'argomento. Avere una buona comprensione di come esattamente questo tipo di exploit opere dovrebbe aiutare a scrivere codice più sicuro .

Altri suggerimenti

E 'difficile prevedere cosa buffer1 + 12 fa veramente. Il compilatore può mettere buffer1 e buffer2 in qualsiasi posizione sulla pila che desidera, andando anche al punto di non risparmiare spazio per buffer2 a tutti. L'unico modo per sapere davvero dove buffer1 va è quello di guardare l'output del compilatore assembler, e c'è una buona possibilità che sarebbe saltato in giro con diverse impostazioni di ottimizzazione o di differenti versioni dello stesso compilatore.

Non testare il codice sulla mia macchina ancora, ma vi ho preso l'allineamento di memoria in considerazione? Prova a smontare il codice con gcc. Penso che un codice assembly può darvi una maggiore comprensione del codice. : -)

Questo codice stampa i 1 e su OpenBSD e FreeBSD, e dà un errore di segmentazione su Linux.

Questo tipo di exploit dipende fortemente sia l'insieme di istruzioni della particolare macchina, e le convenzioni di chiamata del sistema operativo e compilatore. Tutto ciò che riguarda il layout dello stack è definito dall'implementazione, non il linguaggio C. L'articolo si presuppone Linux su x86, ma sembra che si sta usando Windows, e il sistema potrebbe essere a 64 bit, anche se è possibile passare gcc a 32-bit con -m32.

I parametri si dovrà modificare sono 12, che è l'offset dalla punta dello stack per l'indirizzo di ritorno, e 8, che è il numero di byte di main si vuole saltare. Come dice l'articolo, è possibile utilizzare gdb per ispezionare lo smontaggio della funzione per vedere (a) fino a che punto lo stack viene spinto quando si chiama function, e (b) gli offset di byte delle istruzioni in main.

La parte +8 byte è di quanto vuole l'EIP salvato al incrementato con. Il PEI è stato salvato in modo che il programma potrebbe tornare all'ultima assegnazione dopo la function è fatto -. Ora vuole saltare con l'aggiunta di 8 byte per l'EIP salvato

Quindi, tutto cerca di è "saltare" il

x = 1;

Nel tuo caso il PEI salvato punterà 0x0040133b, la prima istruzione dopo ritorna function. Per saltare l'assegnazione è necessario fare il punto EIP salvato 0x00401342. Ecco 7 byte.

E 'davvero un "pasticcio con RET EIP", piuttosto che un esempio di buffer overflow.

E per quanto riguarda i 56 byte per le variabili locali va, che potrebbe essere qualsiasi cosa il tuo compilatore esce con imbottitura come, canarini pila, ecc.

Modifica:

Questo dimostra quanto sia difficile fare buffer overflow esempi in C. L'offset di 12 da buffer1 assume un certo stile imbottitura e compilare le opzioni. GCC sarà lieto di inserire canarini pila al giorno d'oggi (che diventa una variabile locale che "protegge" l'EIP salvato) a meno che non gli si dice di non farlo. Inoltre, il nuovo indirizzo che vuole saltare (le istruzioni di avvio per la chiamata printf) ha davvero essere risolto manualmente dal gruppo. Nel suo caso, il suo machie, con il suo sistema operativo, con il suo compilatore, in quel giorno .... è stato 8.

Si sta compilando un programma C con il compilatore C ++. Rinominare hw.cpp per hw.c e lo troverete compilerà.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top