2011-09-05 17 views
10

Voglio comprendere la differenza esatta tra questi due tipi di attacco. Da quello che ho letto:Differenza tra - buffer overflow e return in libc attack

Overflow del buffer: sovrascrive l'indirizzo di ret sullo stack per puntare a un'altra sezione del codice in cui è inserito il codice dannoso. Così efficacemente - qui abbiamo bisogno di modificare il codice sorgente del programma per eseguire effettivamente l'attacco.

Torna a Libc- Qui invece di modificare il codice sorgente, vengono utilizzate le chiamate di funzioni di tempo fornite dalla libreria C (per esempio aprono una shell). Qui i parametri utilizzati per la chiamata di funzione vengono anche passati nel buffer di sovrascrittura, finendo dopo la parte ret dello stack.

È la descrizione sopra riportata?

E un'altra domanda correlata: sarebbe possibile avere un attacco di overflow del buffer senza effettivamente modificare il codice sorgente del programma originale? Probabilmente se scriviamo un nuovo programma e permettiamo di modificare alcune sezioni di memoria (che è il nuovo indirizzo nella pila corrotta del programma originale). Inoltre, penso che questo potrebbe non essere possibile a causa della protezione della memoria offerta tra i processi nel kernel.

risposta

12

Nel classico exploit di buffer overflow, il buffer di stack in overflow è stato riempito sia con il codice macchina da eseguire (chiamato shellcode, perché in genere ha invocato un processo shell) che il nuovo indirizzo di ritorno. Il nuovo indirizzo di ritorno verrebbe creato per fare il punto all'interno del buffer di stack overflow. Ovviamente, ciò richiede conoscere o indovinare l'indirizzo di quel buffer di stack nel processo attaccato.

In quei giorni, il layout di memoria di processi era tipicamente altamente deterministico - la posizione del buffer di stack potrebbe solito essere previsto abbastanza bene da un aggressore (in particolare se sapessero esattamente quale versione del software di destinazione veniva attaccato). Per migliorare le possibilità di successo quando c'era qualche congettura, lo shellcode attivo veniva spesso preceduto da una grande quantità di codice macchina eseguibile che non eseguiva nessuna operazione utile - chiamata "slitta NOP" o "diapositiva NOP", dove "NOP" è il nome tipico per un'istruzione di codice macchina che esegue "Nessuna operazione". Il ritorno a un punto in qualsiasi punto della slitta NOP avrebbe l'effetto desiderato.

Un exploit "return-to-libc", d'altra parte, non causa il ritorno del processo dirottato direttamente allo shellcode. Invece, fa sì che il processo ritorni, uno alla volta, all'inizio di una catena di funzioni di libreria. Queste funzioni di libreria possono eseguire direttamente le operazioni richieste dall'attore, ma più comunemente verranno utilizzate per eseguire indirettamente lo shellcode dell'attaccante.

0

In realtà, in un attacco bufferoverflow, si inserisce il codice dannoso mentre si ignora il puntatore ret. Non è necessario modificare nulla per questo, quindi come conclusione non riesco a vedere la differenza tra entrambi gli attacchi menzionati.

Per esempio:

char* str[5];
cin << str;

Questo è un codice che può essere exploided, se un utente inserisce una stringa maggiore di 5 caratteri, tutto nello stack che segue verranno sovrascritti. E poiché il ret-ptr è "inferiore" nello stack, puoi ignorarlo, se ottieni la distanza corretta. L'intenzione, mentre si esegue l'override, è di lasciar puntare all'inizio del proprio input, in cui è stato inserito un codice malevolo (assemblatore), che verrebbe eseguito non appena viene richiamato il ret-ptr e eseguito il "salto".

4

La parte di sovrascrittura di un indirizzo ret è condivisa tra entrambi gli attacchi. Come indica la risposta di cui sopra, era sufficiente tornare al codice assembly che avevi scritto. Quindi, questo codice assembly produrrebbe una shell utente root.

In nessuno dei due attacchi si "sovrascrive" il codice sorgente. Guardandolo da una prospettiva di assemblaggio, il codice sorgente si trova nel segmento .text ed è sempre stato (o almeno per tutto il tempo che conosco) protetto da scrittura. Quello che hai usato per trarre vantaggio era scrivere codice che avevi precedentemente assemblato in segmenti di memoria, e poi saltare a questo codice. Il codice si trovava di solito nel o vicino al "segmento di stack" e, traboccando qualsiasi cosa scegliate di sovraccaricare, dovevate reindirizzare il traffico dall'indirizzo ret (diciamo) lì. Altri luoghi di attacco includevano una variabile ambientale creata precedentemente e riempita con lo shellcode; o anche l'heap, i puntatori di funzione o il PLT. Il codice così inserito di solito usava la chiamata system() per eseguire ciò che si desiderava, ma per questo, è necessario essere in grado di "eseguire" su aree di memoria (o avere le voci di trasferimento che si intende utilizzare dichiarate modificabili).

La differenza tra i due attacchi è che, una volta che la memoria era stata resa in gran parte non eseguibile, il tipo di attacco a (overflow dello stack) era praticamente rovinato. Un tentativo di aggirare questo tipo di attacco è stato quindi, come si scrive, per accedere direttamente alle funzioni della libreria condivisa, ovvero non era più necessario scrivere il codice prima nel segmento dello stack o altrove e eseguirlo lì. Tuttavia, credo che anche gli attacchi di tipo libc siano ampiamente rattoppati; Non ho i dettagli a portata di mano; e forse mi sbaglio.

Se vuoi vedere come uno di questi attacchi vengono ostacolati in questi giorni, o almeno di leggere su alcuni concetti chiave, google 'Smashing stack nel 2011' (o 2010) per iniziare.

+0

Puoi spiegare cosa intendi facendo - memoria eseguibile (o non eseguibile). E l'altro dubbio (parte della mia domanda originale) è - credo che un codice C non avrebbe accesso a tutte le parti della memoria principale. Quindi, come viene accertato dove viene inserito il codice assembly dannoso in memoria. Perché penso che per la maggior parte delle regioni di memoria - sarebbe solo contrassegnare un errore di segmentazione quando si torna lì. – Hari

+0

Il nucleo del codice di exploit che è stato inserito in genere utilizzava ed exec() lo stile di famiglia. Ciò significa, alimentando i parametri appropriati, si potrebbe avere, ad esempio, generare una shell/bin/sh come utente root. Questo è * l'esecuzione * di un programma e non puoi più. Ci sono molte diverse misure di sicurezza, ma questo sarebbe descritto, ad esempio, in – gnometorule

+0

http://en.wikipedia.org/wiki/NX_bit – gnometorule

4

direi buffer overflow è una classe di errore di programmazione e ritorno alla libc è una tecnica sfruttamento. È meglio non mescolare i concetti insieme.

Ad esempio, è possibile utilizzare ritorno alla libc di sfruttare un buffer overflow vulnerabilità. Oppure puoi utilizzare altre tecniche come per tornare a .text o tornare allo shellcode. Al contrario, è anche possibile utilizzare per tornare a libc per sfruttare altri bug come la stringa di formato .

Problemi correlati