C - Semplice sfruttamento dell'overflow del buffer, in che modo l'EIP viene sovrascritto in diverse funzioni di chiamata di tipo?

2

Sfondo generale: Ho scritto un server di eco cercando di implementare un esempio di BoF in C che utilizza una chiamata di funzione strcpy () come tale:

// .... including the corresponding libraries depending on host environment

#include <stdio.h>                                              // crossed platform headers
#include <string.h>                                             // string header, for strcpy
#include <stdlib.h>                                             // stardard lib, for exit()


void echo(void);                                 // infinite loop echo serving client
char* vuln_func(char* recieved);                                // BoF vulnerable function that uses strcpy from string.h


int main(void)
{
  ... setting up echo server
  echo();

  return 0;
}

void echo(void)
{
  char *send_str;                                                 // declaring the pointer to the string recieved from vulnFunc
  char recv_str[1024];                                            // variable declaration to store input string from client

  // infinite loop to echo serve clients
  while(1)

  {
    ... recieving string from client and storing it starting at location recv_str
    // calling vuln_func and inputting the received string from client

    send_str = vuln_func(recv_str);                       

    ...echoing the send_str back to the client

  }


}

char* vuln_func( char* recieved)
{
  char* sending_str = (char*)calloc(100, sizeof(char));                               

   char buf[100];                                                                 

  int i;                                                                          // declaring counter for loop
  strcpy(buf, recieved);
  for (i = 0; i < strlen(buf); i++)                                              // for loop to populate return string with the send
  {
    sending_str[i] = buf[i];
  }

  return sending_str;                                                             
}

Problema: Quindi, una volta che il server viene alimentato con una stringa di input sufficientemente grande, il server genererà una violazione di accesso con offset 41414141 (che è ciò che volevamo); tuttavia, una volta smontato l'exe in un disassembler / debugger (ho usato l'immunità Debugger) al punto della violazione né l'ESP né l'EIP sono stati sovrascritti con la stringa di As (ad esempio). Mentre il registro EBP è stato sovrascritto con la grande stringa "overflown" di As.

Soluzione: Così ho fatto qualche ricerca su google e ho visto codici di esempio simili dello stesso tipo (Echo Server con un vuln di BoF) e ho provato diverse cose con il vuln_func come tale:

void vuln_func( char* recieved)
{

   char buf[100];                                                                 

  strcpy(buf, recieved);

}

o

int vuln_func( char* recieved)
{

  char buf[100];                                                                 

  strcpy(buf, recieved);

  return 1;

}

e la funzione echo sarà simile a questa:

void echo(void)
{

  char recv_str[1024];                                            // variable declaration to store input string from client

  // infinite loop to echo serve clients
  while(1)

  {
    ... recieving string from client and storing it starting at location recv_str
    // calling vuln_func with string received from client

    vuln_func(recv_str);                       

    ...echoing the recv_str back to the client

  }


}

quindi la funzione echo riporta indietro recv_str invece di send_str che imho sconfigge l'intero scopo della chiamata vuln_func, ma allo scopo di dimostrare questa vulnerabilità del BoF, la lasceremo lì. Dopo aver controllato con Immunity Debugger, entrambi i registri ESP e EIP vengono sovrascritti con successo con la stringa ("A * 128"), problema risolto !! Grande

Domanda: Perché il problema si è comportato in questo modo?

  1. Come mai quando si restituisce un puntatore (indirizzo) a una stringa al la funzione di chiamata impedisce che l'EIP venga sovrascritto, mentre restituisce void, o int causerà la sovrascrittura del registro EIP come atteso
  2. In che modo il registro EIP memorizza il suo valore nei due scanrios
    menzionato sopra (con un vuln_func che restituisce char * e altri vuln_func
    return void)?
  3. Il problema che si comporta in questo modo ha qualcosa a che fare con il allineamento dello stack, so che (avendo EIP sovrascritto) sarebbe un problema se strcpy veniva chiamato in main (), studiando da altro SE messaggi / risposte

Come puoi vedere, il problema è stato risolto ma non capisco perché ha funzionato. Per favore spiega, o indica la direzione di scrittura. Tanti complimenti e grazie in anticipo.

    
posta Rennitbaby 21.03.2018 - 07:09
fonte

2 risposte

3

La mia ipotesi è che hai sovrascritto altre variabili locali (i o sending_str) e quindi hai causato un arresto prematuro.

Dovrai guardare il codice generato per vedere cosa sta succedendo. A seconda delle impostazioni, il compilatore può fare cose interessanti per il tuo codice, inclusa l'inline della funzione chiamata, rendendo così la tua sovrascrittura dell'indirizzo di ritorno che ha effetto molto più tardi, ecc.

    
risposta data 21.03.2018 - 20:12
fonte
2

Votato @manduca per la migliore risposta perché la risposta forniva la direzione della ricerca e altri test. E dopo diversi test, sono stato in grado di concludere la risposta completa alla mia domanda:

  1. il tipo di valore restituito dalla funzione non ha nulla a che fare con il problema, era semplicemente l'assunto sbagliato
  2. per ciascuno dei due scenari nella domanda, l'EIP verrà archiviato l'indirizzo di memoria della prossima istruzione. L'unica volta che lo farà prendi un indirizzo (l'indirizzo di ritorno) che è stato inviato al stack dall'inizio della creazione dello stack frame è alla fine della funzione call / return statement. Quindi l'eccezione lo farà succede non appena sovrascriviamo il nostro buf, e se la prossima riga di l'istruzione NON è la fine della funzione (restituzione del vuoto) o a dichiarazione di ritorno, l'EIP non verrà aggiornato dallo stack, come esso si limiterà a memorizzare nella posizione di memoria dell'istruzione successiva (Che sto indovinando aumentando dalla posizione di memoria del istruzioni precedenti). Ed è per questo che l'EIP non è stato sovrascritto dalla nostra stringa di 10 MB di "A" s. Nel frattempo la soluzione aveva la strcpy chiamata di funzione subito prima dell'istruzione return o alla fine di la chiamata alla funzione vuln_func, quindi l'EIP viene aggiornato mentre lo stack sta esplodendo con il buffer overflow, il che spiega perché il soluzione aveva EIP sovrascritto con i nostri "A" s
  3. No, non penso che questo problema abbia nulla a che fare con lo stack allineamento, che è solo aggiungendo alcuni paddings alla dimensione dello stack (default 16 byte in sistemi a 64 bit), che dovrebbe essere considerato anche se noi stavano provando a fare la manipolazione delle stringhe nell'overflow e di proposito cercando di cambiare l'EIP, onestamente mi sento solo questo problema esistono in main (), quindi evitare di sfruttare main () potrebbe essere una soluzione.
risposta data 22.03.2018 - 06:32
fonte

Leggi altre domande sui tag