2013-07-21 6 views
31

Sono su CentOS 6.4 32 bit e sto provando a causare un buffer overflow in un programma. All'interno di GDB funziona. Ecco l'output:L'overflow del buffer funziona in gdb ma non senza di esso

[[email protected] bufferoverflow]# gdb stack 
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1) 
Copyright (C) 2010 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "i686-redhat-linux-gnu". 
For bug reporting instructions, please see: 
<http://www.gnu.org/software/gdb/bugs/>... 
Reading symbols from /root/bufferoverflow/stack...done. 
(gdb) r 
Starting program: /root/bufferoverflow/stack 
process 6003 is executing new program: /bin/bash 
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6_4.2.i686 
sh-4.1# 

Tuttavia quando eseguo lo stack di programma solo da solo, seg segna i guasti. Perché potrebbe essere?

+0

'seg faults' è dovuto al buffer overflow, hai fatto, correggi, quando esegui il tuo codice OS invia SIGSEGV al tuo processo (= programma in esecuzione) sulla violazione della memoria che ti dà errore di segmentazione del messaggio - questo segnale è dovuto a te sta facendo un accesso non valido alla memoria valida. (Immagino tu stia cercando di scrivere/modificare su '" constantstring "' alla fine) –

+0

... Lo so. Dovrebbe eseguire una shell. In GDB esegue la shell. Quando eseguo il programma al di fuori di GDB, non gira la shell, quindi il numero predefinito – thaweatherman

+0

è dovuto al fatto che quando si esegue il codice al di fuori di GDB esso - Comportamento non definito in C standard. Mentre GDB gestisce il segnale SIGSEGV in modo che possa darti il ​​punto di errore di segmentazione –

risposta

77

Lo sviluppo degli exploit può causare seri mal di testa se non si tiene adeguatamente conto dei fattori che introducono e non determinismo nel processo di debug. In particolare, gli indirizzi di stack nel debugger potrebbero non corrispondere agli indirizzi durante l'esecuzione normale. Questo artefatto si verifica perché il caricatore del sistema operativo pone entrambe le variabili di ambiente e argomenti del programma prima dell'inizio dello stack:

Process layout

Dal momento che il programma vulnerabile non prende alcun argomento, le variabili di ambiente sono probabilmente il colpevole . Mare sicuri che siano uguali in entrambe le invocazioni, nella shell e nel debugger. A tal fine, si può avvolgere la vostra invocazione in env:

env - /path/to/stack 

E con il debugger:

env - gdb /path/to/stack 
($) show env 
LINES=24 
COLUMNS=80 

Nell'esempio di cui sopra, ci sono due variabili d'ambiente fissati dalla gdb, che si può ulteriormente disabilitare :

unset env LINES 
unset env COLUMNS 

Ora show env dovrebbe restituire una lista vuota. A questo punto, puoi avviare il processo di debug per trovare l'indirizzo di stack assoluto che intendi passare (ad es., 0xbffffa8b) e inserirlo nel tuo exploit.

Un altro sottile ma importante dettaglio: c'è una differenza tra chiamare ./stack e /path/to/stack: dal argv[0] tiene il programma esattamente come è stato richiamato, è necessario garantire le stringhe uguali invocazione. Ecco perché ho utilizzato /path/to/stack negli esempi precedenti e non solo ./stack e gdb stack.

Quando imparare a sfruttare con vulnerabilità di sicurezza memoria, vi consiglio di utilizzare il programma involucro sotto, che fa il lavoro pesante e garantisce offset uguali pila:

$ invoke stack   # just call the executable 
$ invoke -d stack  # run the executable in GDB 

Ecco lo script:

#!/bin/sh 

while getopts "dte:h?" opt ; do 
    case "$opt" in 
    h|\?) 
     printf "usage: %s -e KEY=VALUE prog [args...]\n" $(basename $0) 
     exit 0 
     ;; 
    t) 
     tty=1 
     gdb=1 
     ;; 
    d) 
     gdb=1 
     ;; 
    e) 
     env=$OPTARG 
     ;; 
    esac 
done 

shift $(expr $OPTIND - 1) 
prog=$(readlink -f $1) 
shift 
if [ -n "$gdb" ] ; then 
    if [ -n "$tty" ]; then 
    touch /tmp/gdb-debug-pty 
    exec env - $env TERM=screen PWD=$PWD gdb -tty /tmp/gdb-debug-pty --args $prog "[email protected]" 
    else 
    exec env - $env TERM=screen PWD=$PWD gdb --args $prog "[email protected]" 
    fi 
else 
    exec env - $env TERM=screen PWD=$PWD $prog "[email protected]" 
fi 
+1

Ho fatto come suggerito e ho eseguito il programma come/root/bufferflow/stack e ha funzionato correttamente. Grazie – thaweatherman

+0

L'esempio è sbagliato. Invece di '--gdb' dovrebbe esserci '-d'. – molnarg

+0

@molnarg: Grazie, risolto. – mavam

0

Una delle cose principali che gdb non si verifica al di fuori di gdb è la memoria zero. Più che probabile da qualche parte nel codice non stai inizializzando la tua memoria e sta ottenendo dei valori spazzatura. Gdb cancella automaticamente tutta la memoria allocata nascondendo questi tipi di errori.

Ad esempio: la seguente dovrebbe funzionare in gdb, ma non fuori di esso:

int main(){ 
    int **temp = (int**)malloc(2*sizeof(int*)); //temp[0] and temp[1] are NULL in gdb, but not outside 
    if (temp[0] != NULL){ 
     *temp[0] = 1; //segfault outside of gdb 
    } 
    return 0; 
}

provare a eseguire il programma sotto Valgrind per vedere se è in grado di rilevare questo problema.

+0

Il programma vulnerabile legge effettivamente un file in un buffer, quindi il file è la stringa di exploit. Quindi chiama una funzione che esegue una strcpy del buffer originale in un buffer molto più piccolo. Quindi non inizializza mai la memoria al di fuori di quelle funzioni – thaweatherman

6

Il motivo per cui l'overflow del buffer funziona con gdb e segfaults altrimenti è che gdb disabilita la randomizzazione del layout dello spazio degli indirizzi. Credo che questo è stato attivato per impostazione predefinita in versione gdb 7.

È possibile controllare questo eseguendo questo comando:

show disable-randomization 

e impostarlo con

set disable-randomization on 

o

set disable-randomization off 
+1

È disabilitato in GDB. Ho anche pensato di disattivarlo nel sistema operativo con sysctl -w kernel.randomize_va_space = 0 – thaweatherman

0

Sono su CentOS 6.4 32 bit e sto provando a causare un overflow del buffer in un programma ... Tuttavia quando eseguo lo stack del programma da solo, seg segna i guasti.

È inoltre necessario assicurarsi che FORTIFY_SOURCE non influenzi i risultati. L'errore del segmento suona come FORTIFY_SOURCE potrebbe essere il problema perché FORTIFY_SOURCE inserirà chiamate di funzioni "più sicure" per evitare alcuni tipi di overflow del buffer. Se il compilatore può dedurre le dimensioni del buffer di destinazione, la dimensione viene controllata e viene chiamato abort() in violazione (ad esempio, l'errore seg).

Per disattivare FORTIFY_SOURCE per i test, è necessario compilare con -U_FORTIFY_SOURCE o -D_FORTIFY_SOURCE=0.

6

L'indirizzo del puntatore del frame dello stack quando si esegue il codice in gdb è diverso dall'esecuzione normale. Quindi potresti danneggiare l'indirizzo di ritorno in modalità gdb, ma potrebbe non essere corretto quando si esegue in modalità normale. La ragione principale di ciò è che le variabili di ambiente differiscono tra le due situazioni.

Poiché questa è solo una demo, è possibile modificare il codice della vittima e stampare l'indirizzo del buffer. Quindi cambia il tuo indirizzo di ritorno in offset + indirizzo del buffer.

In realtà, tuttavia, è necessario indovinare l'indirizzo di ritorno aggiungere NOP sled prima del codice dannoso. E puoi indovinare più volte per ottenere un indirizzo corretto, in quanto la tua ipotesi potrebbe essere errata.

Spero che questo possa aiutarti.

1

Ho provato la soluzione accettata qui e non funziona (per me). Sapevo che gdb ha aggiunto le variabili di ambiente e per questo motivo l'indirizzo dello stack non corrisponde, ma anche rimuovendo quelle variabili non posso lavorare il mio exploit senza gdb (ho anche provato lo script pubblicato nella soluzione accettata).

Ma la ricerca nel web ho trovato altro script che funziona per me: https://github.com/hellman/fixenv/blob/master/r.sh

L'uso è sostanzialmente la stessa che lo script nella soluzione accettata:

  • r.sh gdb ./program [ args] per eseguire il programma in gdb
  • r.sh ./program [args] per eseguire il programma senza gdb

E questo script funziona per me.

1

Ecco un modo semplice di esecuzione del programma con pile identiche nel terminale e in gdb:

In primo luogo, assicurarsi che il programma viene compilato senza la protezione dello stack,

gcc -m32 -fno-stack-protector -z execstack -o shelltest shelltest.c -g

ed e ASLR è disabilitato:

echo 0 > /proc/sys/kernel/randomize_va_space

NOTA: il valore predefinito sulla mia macchina era 2, si noti il ​​proprio prima di cambiarlo.

Quindi eseguire il programma in questo modo (terminale e gdb rispettivamente):

env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 /root/Documents/MSec/shelltest 
env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 gdb /root/Documents/MSec/shelltest 

All'interno gdb, assicurarsi di unsetLINES e COLUMNS.

Nota: ho ottenuto quelle variabili di ambiente giocando con un test program.

Queste due esecuzioni forniranno puntatori identici in cima allo stack, quindi non è necessario eseguire scansioni di script remoti se si sta tentando di sfruttare un binario ospitato in remoto.

Problemi correlati