Protostar – Heap Buffer Overflow - Heap 0

Tempo di lettura: 6 minuti
Data pubblicazione: May 25, 2020

Continuando con la serie Protostar, in questo articolo andremo ad analizzare una tecnica più avanzata rispetto allo Stack Buffer Overflow. Per questo motivo ho deciso di dividere in più articoli la serie Heap, facendo un livello per articolo.

Introduzione

Quando un programma viene eseguito, viene allocata dinamicamente della memoria per contenere i dati dello stesso. Lo heap è quindi un blocco di memoria assegnato ad un processo di dimensione definita a run-time.

Struttura dati di un programma
Struttura dati di un programma

L’allocazione della memoria in C avviene tramite diverse funzioni, tra le principali:

  • Malloc(size): utilizzata per allocare un’area di memoria di una certa dimensione
  • Free(*p): utilizzata per deallocare la memoria allocata in precedenza alla posizione *p

Per una descrizione più approfondita consiglio questo articolo.

Queste funzioni, se non gestite in maniera corretta, possono essere suscettibili ad overflow nel caso in cui si possa inserire una quantità di dati superiore alla memora allocata e di conseguenza andare a sovrascrivere aree di memoria adiacenti. La differenza con lo stack, dal punto di vista dell’attaccante, è che nell’area heap sono memorizzati solo puntatori e di conseguenza bisogna creare una chain di shellcode per ottenere un exploit funzionante.

[Per comprendere meglio su GDB i processi interni ho deciso di installare PwnGDB e Peda-Heap, che consiglio vivamente]

Heap 0

[Codice Heap 0](https://exploit-exercises.lains.space/protostar/heap0/)
[Codice Heap 0](https://exploit-exercises.lains.space/protostar/heap0/)

In questo caso l’esercizio è molto simile alla serie stack, in quanto a riga 36 possiamo vedere come la funzione strcpy copi la variabile passata a linea di comando all’interno di name (che fa parte della struct data) senza nessun controllo. Di conseguenza, sarà possibile andare a sovrascrivere il puntatore fp ed inserire al suo posto il puntatore a winner.

Se proviamo ad inserire un breakpoint alla fine ed eseguirlo con un semplice AAAA, possiamo analizzare cosa succede dietro le quinte.

Esecuzione del programma con GDB
Esecuzione del programma con GDB

Come si può vedere, la variabile _data _e fp risiedono nello heap e fp è assegnato alla funzione nowinner (che ha stampato Level has not been passed). Andando a guardare nel dettaglio

Contenuto dello heap
Contenuto dello heap

Con il primo comando analizziamo la struttura dati del processo, con il secondo gli indirizzi di memoria dello heap (dove vediamo il nostro AAAA), mentre con il terzo il contenuto di fp.

Avendo capito il giro, ora ci basterà:

  1. Trovare l’offset per andare a sovrascrivere il puntatore a nowinner e modificarlo con winner. Questo lo otteniamo con il comando

     osboxes@osboxes:~/Desktop/Protostar$ echo $((0x804b050 - 0x804b008))
     72
    
  2. Trovare l’indirizzo della variabile winner da gdb

     gdb-peda$ p *winner
     $1 = {void ()} 0x804849b
    

Unendo le due cose, possiamo eseguire il programma con il payload cosi formato

Livello superato
Livello superato

Vediamo come ora la situazione sia cambiata, e ESP punta a winner

L'heap contiene ora la chiamata alla funzione winner
L'heap contiene ora la chiamata alla funzione winner

La sovrascrittura ha funzionato perfettamente e abbiamo puntato ad una funzione diversa rispetto a quella originale.

Possiamo ovviamente fare lo stesso giro direttamente fuori da GDB

Esecuzione del programma fuori da GDB
Esecuzione del programma fuori da GDB

Conclusione

Sebbene questo esercizio sia molto simile ai precedenti, abbiamo iniziato a scalfire solo la punta dell’iceberg. Esistono diversi attacchi allo heap, e nel prossimo esercizio il discorso sarà già molto più approfondito e con una metodologia decisamente diversa. Come approfondimento per ora consiglio solo questo piccolo libro, in modo tale da avere le idee chiare per il prossimi esercizio