ByPassing DEP y ASLR

Para compilar el programa name.c para este artículo es necesario desactivar DEP:

gcc -m32 -fno-stack-protector name.c -o name

Esta vez no hay que desactivar ASLR, si estuviese desactivado se puede activar de la siguiente forma:

echo 2 > /proc/sys/kernel/randomize_va_space

En los dos capítulos previos estudiamos las protecciones DEP y ASLR y rompimos su seguridad por separado. Lógicamente este artículo va a ir sobre como conseguir atacar satisfactoriamente un programa protegido por estas dos protecciones.

Lo primero que hay que tener en cuenta es que ahora ya no podemos ejecutar desde la zona de datos (porque DEP protege contra tal acto) y además no tenemos una zona fija donde almacenar datos (puesto que ASLR aleatoriza el espacio de direcciones de un proceso).

Hay varias soluciones para afrontar este problema. Aquí voy a explicar una bastante sencilla basada en técnicas usadas en artículos anteriores, por lo que este artículo no será muy largo.

Para empezar hemos hecho una pequeña reforma a nuestro programa vulnerable:

Vemos que los principales cambios es añadir la función exit(0) en vez de return 0 y el uso de la función system() en vez de printf.

En este ejemplo en concreto queda raro y forzado, pero no es raro encontrar estas funciones en programas.

¿Por que hemos hecho estos cambios? Básicamente porque vamos a emplear una técnica llamada Return to PLT que es similar a Return to Libc. Si recordamos bien, Return to Libc la utilizamos cuando quisimos saltarnos DEP y básicamente consistia en proporcionar en EIP la dirección de una función de Libc (en nuestro caso fue de system).

Ahora no podemos usar Return to Libc porque no podemos proporcionar una dirección exacta de la función system debido a la protección ASLR. Pero aquí viene en nuestro ayuda la PLT.

PLT significa Procedure Linkage Table y es usada junto a GOT (Global Offset Table) para que el loader del Sistema Operativo sepa linkar nuestro programa con las librerías compartidas. Básicamente nuestro programa tiene una PLT donde almacena las llamadas a procedimientos de librerias compartidas. La primera vez que nuestro programa llama a una de estas funciones, la tabla se rellena con la dirección real de dicha función. Por tanto, la primera vez que llamamos a printf, nuestro programa consulta PLT ve que no tiene la dirección de printf y la resuelve en tiempo de ejecución, la próxima vez que se llame a printf su direccion real ya estará resuelta y no hará falta resolverla de nuevo. PLT y GOT se escapan del ámbito de estos artículos pero se puede encontrar mucha información sobre ellos buscando sobre Linkers y Loaders.

Y no, la tabla PLT no se ve afectada por la aleatorizacion de ASLR.

Conclusión, tenemos una tabla con las direcciones a funciones que nuestro programa usa, y estas direcciones son fijas ¡incluso con ASLR activado!. La desventaja es que la llamada a dicha función se debe encontrar dentro de nuestro programa (de ahí que hayamos tenido que usarla de una forma un tanto forzada).

Vale, tenemos un programa vulnerable con una función system y que podemos llamar gracias a PLT, pero a system hay que pasarle un argumento y seguimos teniendo ASLR activo por lo que nuestro argumento tendrá una dirección variable de memoria.

¿Os acordais del artículo anterior? En él introdujimos nuestro exploit en una variable de entorno con una gran cantidad de NOP's para que una vez que caiga en el primer NOP se vaya desplazando hasta llegar a nuestro shellcode real. Pues esta vez vamos a emplear algo parecido, solo que en vez de introducir en nuestra variable de entorno un shellcode, vamos a introducir la orden “/bin/sh” que nos va a proporcionar una shell pero, como en el artículo anterior, esto nos arrojaria muchos fallos, hasta el punto de tener que usar un ataque de fuerza bruta de miles de intentos, así que vamos a meter también un colchon de NOPs para que una vez que la dirección proporcionada como argumento de system caiga en nuestra variable de entorno, esta se vaya desplazando hasta encontrar el comando /bin/sh.

Bueno, basta de teoría, pasemos a la práctica. Primero tenemos que hacernos con las direcciones de memoria de system@plt y exit@plt, para ello usamos gdb y desensamblamos la funcion main

0

En la imagen podemos ver como mi binario tiene la función system@plt en la dirección 0x8048370 y la función exit@plt en la dirección 0x8038390. Vamos a exportar ahora una variable de entorno que contenga una gran cantidad de comandos inútiles (o incluso inválidos, en mi caso usaré estos ultimos porque mi shell no me permite introducir espacios) y un comando “/bin/sh”

export xploit=`python -c "print 'echo_a;'*18000+'/bin/sh'"`

Una vez más hay que tener en cuenta que la variable de entorno debe ser bastante grande pero hay que tener cuidado porque algunas shells imponen límites de tamaño para las variables de entorno, en mi caso la variable es de 6*18000+7 bytes, lo que hace un total de 9007 bytes. Vamos a ejecutar ahora nuestro ya conocido programa getenv que nos devuelve la dirección de una variable de entorno con respecto al programa vulnerable.

1

Lo ejecutamos unas cuantas veces y vemos que efectivamente la dirección de memoria varía. Ahora elegimos una, la que sea, por ejemplo, en mi caso voy a elegir la última 0xfff3733e. Y si recordamos el artículo sobre Return to Libc sabremos que tendremos que pasar los argumentos de la siguiente forma

AAAA...AAAA + DIRECCIÓN_SYSTEM + DIRECCIÓN_EXIT + DIRECCIÓN_PARÁMETRO_SYSTEM

para que la pila quede así

DIRECCIÓN_PARÁMETRO_SYSTEM
DIRECCIÓN_EXIT
DIRECCIÓN_SYSTEM
AAAA...AAAA

Pero esto, es un ataque de fuerza bruta, por tanto deberemos crear una shellscript como hicimos en el artículo anterior para ir probando hasta que obtengamos una shell. El script puede ser el siguiente

damos permisos de ejecución al script mediante

chmod +x xploit.sh

y ejecutamos mediante

./xploit.sh

2

¡Tachan! ¡Volvimos a obtener una shell con DEP y ASLR activado!

Conclusiones

Aquí acaba esta serie de artículos, nos hemos dejado en el camino muchas técnicas y algunas protecciones pero hemos estado viendo lo básico sobre stacks overflows y como romper dos protecciones usadas en entornos reales.

En el camino nos hemos dejado una protección implementada por el compilador basada en cookies o canaries, estas técnicas se basan en poner un número en una dirección de memoria entre nuestro buffer y el valor de EIP, al regresar de la función, si este valor no coincide con el almacenado en un lugar seguro por el programa entonces se detendrá la ejecución. Además algunas de estas ténicas del compilador son capaces de reorganizar nuestras variables para situar a los buffers en las primeras zonas de memoria después del valor de EIP, dejando variables primitivas y punteros debajo de los buffers.

En GCC, el estandar es Stack Smash Protector o ProPolice que es capaz de usar 2 canaries distintos, o bien uno generado aleatoriamente y que es comprobado por el programa siempre que se va a recuperar el valor de EIP, o bien usar un canary prefijado: 0x000aff0d. Este canary está muy bien pensando y rompe nuestros ataques completamente, 0x00 es el byte null por lo que acabaria con los ataques basados en string, 0x0a es el salto de línea \n y acabaria con los desbordamientos mediante las familias gets, 0xff es el indicador de fin de archivo y 0x0d es el carater \r. Esta protección en algunas distribuciones Linux viene desactivada por defecto, en mi ubuntu viene activada y en cada programa vulnerable he tenido que desactivarla. En efecto, esta protección se corresponde a la opción -fno-stack-protector, si quitamos esa opción cuando compilamos, ninguno de los ataques empleados aquí tendría efecto.

3

Si realizamos el ataque de este artículo sobre el mismo programa pero quitando la opción -fno-stack-protector, veremos que el programa detecta que se ha desbordado el buffer y termina.

También se nos ha quedado en el tintero los ataques de heap overflow y los de las cadenas de formato.

Es posible que en un futuro escriba algo sobre ello.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *