Siguiendo con las opciones clásicas de compilación de GCC para tratar de tener binarios más robustos, en esta entrega vamos a hablar de las opciones -fpie y -fPIE, que permiten compilar ejecutables como “Position Independent Executables” y permiten que sus secciones se carguen en posiciones aleatorias.
PaX Team presentó en 2001 ASLR (Address Space Layout Randomization), un parche para introducir aleatoriedad en las direcciones usadas por un programa. ASLR trata de evitar que las direcciones de memoria sean conocidas y así prevenir ataques que dependen del conocimiento de estas direcciones (tipo return2libc y otros). Hoy en día, Windows, Linux, Mac OS X, Android e iOs implementan alguna variante de ASLR.
ASLR se configura mediante el parámetro /proc/sys/kernel/randomize_va_space en Linux. Un valor 0 deshabilita ASLR, tendremos este valor cuando nuestra arquitectura no soporte la aleatorización o cuando nuestro kernel haya booteado con la opción norandmaps. Un 1 habilita la aleatorización de las bibliotecas compartidas (shared libraries), las direcciones base de mmap y la pila. Finalmente, un 2 tiene las opciones de 1 y añade la aleatorización del heap. En los sistemas actuales tendremos la opción 2, sin embargo, antiguamente (en tiempos pre-mmap) se utilizaban las llamadas del sistema brk y sbrk para reservar y liberar memoria, ASLR es posterior a esto. Por tanto, si CONFIG_COMPAT_BRK está activado por razones de compatibilidad hacia atrás, por ejemplo en binarios viejos que usen libc5 (no confundir con glibc), tendremos únicamente una aleatorización de tipo 1.
Por ejemplo, comprobamos la posición de libc en 5 procesos de /proc/X/maps con ASLR desactivado (32 bits):
start-end perm offset major:minor inode image
f7dfe000-f7fa6000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
f7dfe000-f7fa6000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
f7dfe000-f7fa6000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
f7dfe000-f7fa6000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
f7dfe000-f7fa6000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
y podemos ver que la dirección es siempre la misma; mientras que con ASLR activado:
start-end perm offset major:minor inode image
f7508000-f76b0000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
f751d000-f76c5000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
f7533000-f76db000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
f75eb000-f7793000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
f7566000-f770e000 r-xp 00000000 08:05 262413 /lib/i386-linux-gnu/libc-2.19.so
Tenemos un offset que siempre cambia.
Una vez que sepamos si nuestro sistema soporta ASLR haciendo $ cat /proc/sys/kernel/randomize_va_space podremos utilizar ASLR en nuestros binarios si están compilados con las opciones -fpie y -fPIE.
Hay que subrayar que ASLR es una defensa estadística, y por tanto limitada. El rango de entropía de ASLR está limitado por la memoria virtual disponible, y se ha demostrado que los sistemas de 32 bits son susceptibles a ataques de de-aleatorización. Por otro lado ASLR puede superarse con info leaks, como se muestra en un famoso artículo de Phrack.
¿Es esto suficiente? Lo descubriremos en los siguientes posts.