Esempio di vulnerabilità double-free in C

0

Spero che questo sia il forum corretto per chiedere la domanda che ho: Al momento stiamo discutendo di vulnerabilità double-free nella nostra classe di sicurezza del software, motivo per cui so che il codice riportato di seguito viene considerato come un esempio di come un double-free può essere sfruttato. Ora, sto cercando di capire questo esempio e spero che qualcuno qui possa aiutarmi con questo.

La prima cosa fatta in questo codice è una definizione di una struct auth. Usiamo questa struttura definendo un puntatore a tale struttura: struct auth *auth;

Ok. Penso che una vulnerabilità possa essere solo dove sono stati usati malloc o free . Ma cosa potrebbe essere sfruttato in questo specifico codice? Io non lo vedo Ricordo dalla classe che il problema con l'applicazione di free allo stesso puntatore due volte è che ora il puntatore avanti e indietro del chunk punta a questo stesso pezzo in cui sono memorizzati. Ciò riguarda il punto in cui finisce la mia conoscenza.

Sarei così felice di trovare qualcuno qui, che potrebbe aiutarti!

struct auth {
  char name[32];
  int auth;
};

struct auth *auth;
char *service;

int main(int argc, char **argv)
{
  char line[128];

  while(1) {
      printf("[ auth = %p, service = %p ]\n", auth, service);

      if(fgets(line, sizeof(line), stdin) == NULL) break;

      if(strncmp(line, "auth ", 5) == 0) {
          auth = malloc(sizeof(struct auth));
          memset(auth, 0, sizeof(struct auth));
          if(strlen(line + 5) < 31) {
              strcpy(auth->name, line + 5);
          }
      }
      if(strncmp(line, "reset", 5) == 0) {
          free(auth);
      }
      if(strncmp(line, "service ", 7) == 0) {
          service = strdup(line + 8);
      }
      if(strncmp(line, "login", 5) == 0) {
          if(auth->auth) {
              printf("you have logged in already!\n");
          } else {
              printf("please enter your password\n");
          }
      }
  }
}

Piccola modifica: con le risposte date al post, ho trovato una soluzione. Digita semplicemente le seguenti righe:

auth me
reset
service AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
login

L'input scritto dopo service è di 36 caratteri. Ora, cosa sta succedendo in questo programma? auth me alloca 36 byte di memoria sull'heap. reset libera questa memoria, tuttavia non è impostata su NULL. Ora service alloca ancora 36 byte di memoria sull'heap. È molto probabile che venga allocata la stessa memoria allocata in precedenza da auth . In questa memoria possiamo ancora trovare il nome me . Questo è scritto negli ultimi 4 byte di questa area di memoria.

    
posta user503842 27.11.2018 - 20:00
fonte

2 risposte

0

Il programma richiede ripetutamente all'utente di eseguire un'operazione, prendendo come input una stringa che dovrebbe iniziare con "auth", "reset", "service" o "login" (non gestirà alcun altra stringa molto elegantemente). Supponendo che la stringa di input sia accettabile, il programma eseguirà alcune operazioni e le richiederanno nuovamente. In particolare, questo significa che puoi inserire lo stesso comando due volte di seguito.

  • "auth" causerà l'allocazione di una struct auth (una delle tre cose con quel nome, o lo sviluppatore è terribile o il codice sta deliberatamente confondendo) dall'heap e assegnerà il suo indirizzo al puntatore auth variabile. Chiamando questo più di una volta si verificherà una perdita di memoria a meno che il struct auth puntato su auth venga liberato tra una chiamata e l'altra.
  • "reset" libererà la memoria puntata dalla variabile puntatore auth . Ciò è sicuro se auth punta a NULL o se auth punta a un buffer di memoria valido, allocato all'heap (come il struct auth assegnato dall'operazione "auth"). Tuttavia, chiamando free su un puntatore non lo reimposta su NULL , quindi se fai un "auth" seguito da due "reset" s (senza un altro "auth" in tra), quindi riceverai un doppio-gratuito . Ciò che accade a quel punto non è definito dalla specifica C, quindi dipende dalle particolari implementazioni di malloc e free , ma in pratica è generalmente sfruttabile per il danneggiamento della memoria e quindi potenzialmente per l'esecuzione arbitraria di codice.
  • "il servizio" è intricato di bug (controlla solo i primi 7 caratteri, non lo spazio, quindi puoi potenzialmente chiamare strdup sulla memoria che non ha byte null prima di colpire una pagina non mappata, nel qual caso il il programma si bloccherà). Inoltre, non libera mai la memoria che strdup alloca, quindi l'utilizzo di "servizio" più di una volta comporterà una perdita di memoria. Probabilmente non è rilevante qui, però.
  • "login" tenterà di dereferenziare la variabile puntatore auth e controllare il valore del campo puntato a struct auth che è anche chiamato auth ed è un numero intero. Ciò fallirà con una violazione segfault / di accesso se la variabile puntatore auth è nullo o punta a un indirizzo non valido (non mappato) (o meglio, se nessuno dei 33 ° -36 ° byte oltre quell'indirizzo non è mappato). Anche questo probabilmente non è rilevante qui.

Quindi, ora sai come attivare una chiamata a doppio-libero in questo codice. In realtà sfruttando ciò è lasciato come esercizio per lo studente. Porta un debugger.

    
risposta data 28.11.2018 - 01:27
fonte
0

Il codice presenta alcuni problemi che dovresti correggere.

  1. Se l'utente digita "reset" la prima volta, hai a disposizione qualcosa che non hai assegnato, anche il puntatore dovrebbe essere inizializzato su null per aiutare (auth = NULL)

  2. Se l'utente digita "login" per la prima volta, il tuo codice genererà un SIGSEV su auth- > auth, non hai assegnato l'auth correttamente.

  3. sulla chiamata malloc dovresti verificare che il valore restituito non sia nullo.

Ci sono altri problemi nel codice, ma sono più legati a cattive pratiche di programmazione di una sicurezza correlata dal mio punto di vista

    
risposta data 27.11.2018 - 21:42
fonte

Leggi altre domande sui tag