Impossibile capire $ EIP cambia con Buffer Overflow

2

Sto imparando l'overflow del buffer, quindi la domanda potrebbe sembrare sciocca, ma eccola qui. Ho iniziato con questo semplicissimo programma buggy

int main(int argc, char *argv[])
{
  char buf[128];
  printf("You entered value %s\n", argv[1]);
  strcpy(buf,argv[1]);
  printf("%s\n", buf);
  printf("Program is exitting normally!!\n\n\n");
  return 0;
}

Ora, quando gira su gdb e lo eseguo con un semplice set di input HElooooooooooooooooooooooooo , funziona normalmente con eip impostato sull'istruzione next dopo la funzione strcpy .

0x565555ce <+81>:   call   0x56555400 <strcpy@plt>
0x565555d3 <+86>:   add    $0x10,%esp
0x565555d6 <+89>:   sub    $0xc,%esp
0x565555d9 <+92>:   lea    -0x98(%ebp),%eax

$eip contiene 0x565555d3 e posso vedere la versione di Little Endian del mio input senza intoppi. Le cose funzionano bene.

(gdb) x/40x $esp
0xffffd260: 0xffffd270  0xffffd566  0xf7ffdaf8  0x56555598
0xffffd270: 0x6f6c4548  0x6f6f6f6f  0x6f6f6f6f  0x6f6f6f6f
0xffffd280: 0x6f6f6f6f  0x6f6f6f6f  0x6f6f6f6f  0x00000000
0xffffd290: 0x00000000  0x00000001  0xf7ffd940  0x000000c2

Ma quando lo fornisco con 1000 A's . Prevedo di vedere un'area corrotta intorno a $esp e un valore corrotto atteso di $eip qualcosa come 0x41414141 , ma nessuno dei due accade.

Dopo la corruzione, l'area intorno a $esp sembra abbastanza normale

(gdb) x/40x $esp
0xffffd27c: 0x565555d3  0xffffd290  0x00000000  0xf7ffdaf8
0xffffd28c: 0x56555598  0x00000000  0xf7fdff8b  0x5655523c
0xffffd29c: 0xffffd2fc  0xf7ffda9c  0x00000001  0xf7fcf410
0xffffd2ac: 0x00000001  0x00000000  0x00000001  0xf7ffd940
0xffffd2bc: 0x000000c2  0x00000000  0x00ca0000  0x00000000
0xffffd2cc: 0xf7ffd000  0x00000000  0x00000000  0x00000000
0xffffd2dc: 0xa7a40500  0x00000009  0xffffd56c  0xf7e03fa9
0xffffd2ec: 0xf7fac748  0xf7fa9000  0xf7fa9000  0x00000000

e $eip diventa 0xf7e62238 che ovviamente non è il valore corretto dell'istruzione successiva dopo strcpy quindi significa che qualcosa lo ha cambiato.

Ora non riesco a trovare due cose.

  1. Dove sono tutti A ?

  2. In che modo $eip è cambiato in questo modo?

Sto usando il seguente comando per disabilitare la protezione più ho cambiato /proc/sys/kernel/randomize_va_space a 0. gcc version is 7.3.0 .

gcc -fno-stack-protector -zexecstack -m32 -o overflow overflow.c

C'è qualcosa che impedisce l'overflow che ho perso o qualcos'altro?

    
posta aneela 30.05.2018 - 19:45
fonte

2 risposte

0

Prova a usare lo switch "-g", quando compili il tuo c File con gcc.

Oppure c'è qualcosa con le Funzionalità di sicurezza che impediscono il tuo codice.

Hai provato a infrangere il tuo codice?

es.

"break main" and "break 5" and "break 8"

on "break 8" you might try to examine the buffer "x/s buf" or "x/40x buf" ?

Prima di terminare il programma dovresti vedere un messaggio che non può accedere all'indirizzo 0x41414141. Dopo aver proseguito dovresti vedere un messaggio di errore.

    
risposta data 30.05.2018 - 21:14
fonte
0

Innanzitutto, è meglio provare a eseguire il overflow del eip salvato di una funzione normale, non di main() . Non è molto diverso, ma la funzione main() è un po 'specifica e potrebbe darti una visione distorta della realtà.

Proviamo con questo codice:

#include <stdio.h>
#include <string.h>

void foo(char *msg)
{
  char buf[64];
  printf ("You entered value %s\n", msg);
  strcpy (buf, msg);
  printf ("%s\n", buf);
}

int main (int argc, char *argv[])
{
  if (argc > 1)
    foo(argv[1]);

  printf ("Program is exiting normally!\n");
  return 0;
}

Per prima cosa, compilarlo:

$> gcc -Wall -Wextra -std=c11 -m32 -g -o vulnerable vulnerable.c

Quindi, inizialo con gdb :

$> gdb -q ./vulnerable
Reading symbols from ./vulnerable...done.
(gdb) b foo
Breakpoint 1 at 0x11db: file vulnerable.c, line 7.
(gdb) r $(python -c 'print("A" * 64)')
Starting program: /tmp/vulnerable $(python -c 'print("A" * 64)')

Breakpoint 1, foo (msg=0xffffd53a 'A' <repeats 64 times>) at vulnerable.c:7
7     printf ("You entered value %s\n", msg);
(gdb) 

Ora, siamo proprio nel punto in cui possiamo sovrascrivere il buffer e sovrascrivere il eip salvato che è memorizzato nello stack. Tuttavia, abbiamo inserito solo il 64% di% in% di spazio (la dimensione del buffer) e abbiamo bisogno di sapere quanti "% diA" dobbiamo inserire per raggiungere il A salvato nello stack.

Quello che cercheremo di fare è:

  • Ottieni l'indirizzo del buffer;
  • Ottieni l'indirizzo del eip salvato nello stack;
  • Ottieni la differenza tra questi due indirizzi che dovrebbero darci la dimensione esatta del padding che dobbiamo inserire per raggiungere il eip salvato.

Andiamo:

(gdb) p &buf
$1 = (char (*)[64]) 0xffffd280

(gdb) info frame
Stack level 0, frame at 0xffffd2d0:
 eip = 0x565561db in foo (vulnerable.c:7); saved eip = 0x56556249
 called by frame at 0xffffd300
 source language c.
 Arglist at 0xffffd2c8, args: msg=0xffffd53a 'A' <repeats 64 times>
 Locals at 0xffffd2c8, Previous frame's sp is 0xffffd2d0
 Saved registers:
  ebx at 0xffffd2c4, ebp at 0xffffd2c8, eip at 0xffffd2cc

(gdb) p 0xffffd2cc-0xffffd280
$3 = 76

Ora, sappiamo che se alimentiamo il programma con 76 caratteri di padding, sovrascriviamo eip salvato con i 4 caratteri successivi (siete qui a 32-bit).

Proviamo:

(gdb) r $(python -c 'print("A" * 76 + "\xde\xad\xbe\xef"[::-1])')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/vulnerable $(python -c 'print("A" * 76 + "\xde\xad\xbe\xef"[::-1])')

Breakpoint 1, foo (
    msg=0xffffd52a 'A' <repeats 76 times>, <incomplete sequence 6>)
    at vulnerable.c:7
7     printf ("You entered value %s\n", msg);
(gdb) n
You entered value AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAᆳ�
8     strcpy (buf, msg);
(gdb) info frame
Stack level 0, frame at 0xffffd2c0:
 eip = 0x565561f0 in foo (vulnerable.c:8); saved eip = 0x56556249
 called by frame at 0xffffd2f0
 source language c.
 Arglist at 0xffffd2b8, args: 
    msg=0xffffd52a 'A' <repeats 76 times>, <incomplete sequence 6>
 Locals at 0xffffd2b8, Previous frame's sp is 0xffffd2c0
 Saved registers:
  ebx at 0xffffd2b4, ebp at 0xffffd2b8, eip at 0xffffd2bc
(gdb) n
9     printf ("%s\n", buf);
(gdb) info frame
Stack level 0, frame at 0xffffd2c0:
 eip = 0x56556202 in foo (vulnerable.c:9); saved eip = 0xdeadbeef
 called by frame at 0xffffd2c4
 source language c.
 Arglist at 0xffffd2b8, args: 
    msg=0xffffd500 "S07Q73
(gdb) x /32x $esp
0xffffd270: 0x41414141  0x41414141  0x41414141  0x41414141
0xffffd280: 0x41414141  0x41414141  0x41414141  0x41414141
0xffffd290: 0x41414141  0x41414141  0x41414141  0x41414141
0xffffd2a0: 0x41414141  0x41414141  0x41414141  0x41414141
0xffffd2b0: 0x41414141  0x41414141  0x41414141  0xdeadbeef
0xffffd2c0: 0xffffd500  0xffffd384  0xffffd390  0x5655622b
0xffffd2d0: 0xffffd2f0  0x00000000  0x00000000  0xf7de79a1
0xffffd2e0: 0xf7fa4000  0xf7fa4000  0x00000000  0xf7de79a1
4x(5\ri686" Locals at 0xffffd2b8, Previous frame's sp is 0xffffd2c0 Saved registers: ebx at 0xffffd2b4, ebp at 0xffffd2b8, eip at 0xffffd2bc

Ora abbiamo il controllo completo del% co_de salvato, dato che abbiamo appena scritto eip su di esso. Quindi, possiamo controllare l'esecuzione una volta che usciamo da questa funzione eip .

Se vuoi vedere cosa hai appena scritto nello stack, ora puoi fare:

#include <stdio.h>
#include <string.h>

void foo(char *msg)
{
  char buf[64];
  printf ("You entered value %s\n", msg);
  strcpy (buf, msg);
  printf ("%s\n", buf);
}

int main (int argc, char *argv[])
{
  if (argc > 1)
    foo(argv[1]);

  printf ("Program is exiting normally!\n");
  return 0;
}

Come puoi vedere, trovi tutti i 76 ' 0xdeadbeef ' seguiti da foo() . In effetti, questo è il tuo buffer A , seguito dal% co_de salvato e dal% co_de salvato che hai appena riscritto.

Un'ultima nota sull'ASLR e sullo stack non eseguibile. Queste due protezioni non stanno giocando alcun ruolo qui. Devono essere disabilitati solo se si desidera eseguire uno shellcode che si inietta attraverso questo overflow. L'ASLR rende più difficile scrivere un indirizzo significativo al posto di 0xdeadbeef perché il contesto della memoria cambierà continuamente. E lo stack non eseguibile rovinerà i tuoi tentativi di eseguire codice sullo stack.

Se vuoi solo controllare buf salvato, devi solo disabilitare i canaries di stack (opzione ebp ). Il resto sarà significativo solo quando tenterai di utilizzare questo controllo per reindirizzare il codice a un tuo codice.

    
risposta data 30.07.2018 - 14:42
fonte

Leggi altre domande sui tag