La aleatoriedad en la disposición del espacio de direcciones (conocida por las siglas en inglés ASLR) es una técnica de seguridad informática relacionada con la explotación de vulnerabilidades basadas en la corrupción de memoria. Con el fin de impedir que un atacante salte de forma fiable a, por ejemplo, una función explotable en concreto de la memoria, ASLR dispone de forma aleatoria las posiciones del espacio de direcciones de las áreas de datos clave de un proceso, incluyendo la base del ejecutable y las posiciones de la pila, el heap y las librerías.
Historia
El proyecto PaX de Linux fue el primero en acuñar el término "ASLR", y publicó el primer diseño e implementación de ASLR en julio de 2001 en forma de un parche para el núcleo Linux. Se la considera una implementación completa, y proporciona también un parche para la aleatoriedad de la pila del núcleo desde octubre de 2002.
El primer sistema operativo popular en soportar ASLR por defecto fue la versión 3.4 de OpenBSD en 2003, seguido por Linux en 2005.
Beneficios
La aleatoriedad del espacio de direcciones entorpece la labor de ciertos ataques contra la seguridad haciendo más difícil para un atacante predecir las direcciones de destino. Por ejemplo, los atacantes que intentan llevar a cabo ataques de retorno a libc deben primero localizar el código a ejecutar, mientras que los que intentan ejecutar código shell inyectado en la pila necesitan primero encontrar la propia pila. En ambos casos, el sistema oculta a ojos de los atacantes las direcciones de memoria que necesitan. Estos valores tienen que deducirse, y un error de deducción no suele ser recuperable puesto que conlleva el cuelgue de la aplicación.
Efectividad
La aleatoriedad en la disposición del espacio de direcciones se basa en la baja probabilidad de que un atacante pueda adivinar las localizaciones de áreas dispuestas de forma aleatoria. La seguridad mejora aumentando el espacio a buscar. Por lo tanto, la aleatoriedad del espacio de direcciones es más eficaz cuando está presente una mayor entropía en la aleatoriedad. La entropía aumenta elevando el tamaño del área de memoria virtual sobre la que se aplica la aleatoriedad, o bien reduciendo el período sobre el que tiene lugar la aleatoriedad. Este período suele implantarse de forma que sea lo más pequeño posible, así que la mayoría de los sistemas deben incrementar la aleatoriedad del área de memoria virtual.
Para superar el problema de la aleatoriedad, los atacantes deben ser capaces de adivinar con éxito las posiciones de todas las áreas que desean atacar. En el caso de áreas de datos como son la pila y el heap, donde se puede cargar código a medida o información útil, puede atacarse a más de un estado utilizando secuencias NOP para código o copias repetidas de datos. Esto permite a un atacante tener éxito si la aleatoriedad del área la ha situado finalmente en un rango de unos pocos valores. A menudo estas áreas se mezclan, por ejemplo se inyectan marcos de pila en la pila y se retorna una entrada a una librería.
Pueden declararse las siguientes variables:
(bits en entropía del tope por arriba de la pila) (bits de entropía de la base mmap()) (bits de entropía de la base del ejecutable principal) (bits de entropía de la base del heap) (bits atacados por cada intento de entropía de la pila) (bits atacados por cada intento de entropía de la base mmap()) (bits atacados por cada intento de entropía del ejecutable principal) (bits atacados por cada intento de entropía de la base del heap) (intentos realizados) (número total de entropía: )
Para calcular la probabilidad de un atacante de tener éxito, tenemos que asumir que se llevan a cabo intentos sin que se produzca una interrupción entremedias por parte de un SPI basado en firmas, un refuerzo legal o cualquier otro factor; en el caso de un ataque de fuerza bruta, el demonio no puede reiniciarse. También tenemos que descubrir cuántos bits son relevantes y a cuántos se está atacando en cada intento, dejando a un lado los bits que el atacante tiene que derrotar.
Las siguientes fórmulas representan la probabilidad de éxito para un grupo dado de intentos de bits de entropía.
(suposición aislada; tras cada intento, vuelve a aplicarse aleatoriedad al espacio de direcciones) (ataque sistemático de fuerza bruta sobre copias del programa con el mismo espacio de direcciones)
En muchos sistemas, puede ser un valor de miles de millones; en los sistemas modernos de 64 bits, lo habitual es que estas cifras alcancen como mínimo millones. Héctor Marco-Gisbert e Ismael Ripoll mostraron en 2014 cómo saltarse el ASLR en sistemas de 64 bits en menos de un segundo bajo ciertas circunstancias. En el caso de sistemas de 32 bits a velocidades de 2004, y disponiendo de 16 bits para la aleatoriedad de las direcciones, Schacham y compañía aseguraron que "... 16 bits de aleatoriedad en las direcciones es algo que puede romperse con un ataque de fuerza bruta en cuestión de minutos". Conviene apuntar que esta afirmación por parte de su autor depende de la capacidad par atacar a la misma aplicación múltiples veces sin retraso alguno. Una implementación correcta de ASLR como la incluida en grsecurity proporciona varios métodos para hacer inviables tales ataques de fuerza bruta. Uno de los métodos consiste en impedir que un ejecutable se ejecute durante un determinado período de tiempo en caso de haberse colgado antes cierto número de veces.
Android y posiblemente otros sistemas implementan Aleatoriedad en el Orden de Carga de Librerías, una forma de ASLR que hace que el orden en el que se cargan las librerías sea aleatorio. Esto aporta muy poca entropía. Abajo se indica una aproximación del número de bits de entropía aportados por cada librería necesaria; esto no tiene en cuenta todavía los diferentes tamaños de las librerías, con lo cual la entropía obtenida en realidad es un poco mayor. Téngase en cuenta que los atacantes normalmente necesitan únicamente una librería; los cálculos son más complejos cuando entran en juego varias librerías, y también se muestran a continuación. Téngase también en cuenta que el caso de un atacante que emplea una única librería es una simplificación de la fórmula más compleja de .
(número de librerías cargadas) (número de librerías usadas por el atacante)
Estos valores tienden a ser bajos aun con valores grandes de , lo que resulta importante dado que los atacantes normalmente pueden usar únicamente la librería estándar de C y por tanto uno puede suponer que . Resulta interesante, sin embargo, el hecho de que incluso con un pequeño número de librerías se ganan aquí unos pocos bits de entropía; por lo tanto, resulta potencialmente interesante combinar la aleatoriedad en el orden de carga de las librerías con la aleatoriedad de las direcciones de memoria virtual para ganar así unos bits extra de entropía. Téngase en cuenta que estos bits extra de entropía no se aplicarán a otros segmentos de mmap(), sino únicamente a librerías.
Reducción de la entropía
Un atacante puede utilizar varios métodos para reducir la entropía presente en un espacio de direcciones al que se ha aplicado aleatoriedad, que pueden ir desde simples fugas de información a atacar múltiples bits de entropía en cada ataque (como la técnica de pulverización del heap). Poco puede hacerse a este respecto.
Es posible obtener información sobre la disposición de la memoria empleando vulnerabilidades en el formateo de cadenas. Las funciones de formateo de cadenas tales como printf utilizan una lista de argumentos variables para hacer su trabajo; los especificadores de formato describen el aspecto de la lista de argumentos. Debido a la manera en que se suelen pasar los argumentos, cada especificador de formato se acerca cada vez más al tope superior del marco de la pila. Llegado a cierto punto pueden extraerse el puntero de retorno y el puntero del marco de la pila, revelando así las direcciones de una librería vulnerable y la dirección de un marco de pila conocido; esto puede eliminar por completo la aleatoriedad de la pila y de las librerías como un obstáculo para el atacante.
Uno puede también reducir la entropía en la pila o en el heap. Lo habitual es que la pila tenga que alinearse a 16 bytes, con lo cual este sería el intervalo de aleatoriedad más pequeño posible, mientras que el heap debe alinearse a página, normalmente 4096 bytes. Al intentar llevar a cabo un ataque, es posible alinear ataques duplicados con estos intervalos; una cadena de instrucciones NOP puede utilizarse con inyección de código shell, y la cadena '/bin/sh' puede sustituirse con '////////bin/sh' empleando un número arbitrario de barras inclinadas al intentar retornar al sistema. El número de bits eliminado es exactamente para intervalos atacados.
Tales reducciones están limitadas debido a la cantidad de información presente en la pila o en el heap. La pila, por ejemplo, suele estar limitada a 8 MBs y crece para ser mucho más pequeña; esto permite como mucho 19 bits, aunque una estimación más conservadora sería de entre 8 y 10 bits correspondientes a 4-16 KBs de ataques a la pila. El heap, por otra parte, está limitado por el comportamiento del adjudicador de memoria; en el caso de glibc, las reservas por encima de los 128KB se crean con mmap, limitando los atacantes a 5 bits de reducción. Esto es un factor también limitante en el caso de ataques de fuerza bruta; aunque puede reducirse el número de ataques que es necesario realizar, el tamaño de los ataques aumenta lo suficiente como para que en determinadas circunstancias esto llame la atención de un sistema de prevención de intrusos.
Implementaciones
Varios sistemas operativos populares de propósito general implementan ASLR.
Android
Android 4.0 Ice Cream Sandwich proporciona aleatoriedad en la disposición del espacio de direcciones (ASLR) para ayudar a proteger el sistema y las aplicaciones de terceros frente a vulnerabilidades relacionadas con la gestión de la memoria. Android 4.1 añadió soporte para ejecutables independientes de posición (PIE), mientras que Android 5.0 abandonó el soporte para ejecutables sin PIE y exige que todos los binarios enlazados dinámicamente sean independientes de posición. La aleatoriedad en el orden de carga de las librerías se aceptó en el proyecto de código abierto Android el 26 de octubre de 2015, y fue incluido a partir de Android 7.0.
DragonFly BSD
DragonFly BSD dispone de una implementación de ASLR basada en el modelo de OpenBSD, añadido en 2010.mmap - add mmap offset randomization, DragonFly Gitweb, 25 de noviembre de 2010. Está desactivada por defecto, y puede activarse poniendo a 1 el valor de vm.randomize_mmap con sysctl.
iOS (iPhone, iPod Touch, iPad)
Apple introdujo ASLR en iOS 4.3, lanzado en marzo de 2011.Pwn2Own day 2: iPhone, BlackBerry beaten; Chrome, Firefox no-shows, Ars Technica, 11 de marzo de 2011
Base del kernel KASLR una vez aplicada la aleatoriedad = 0x01000000 + ((1+0xRR) * 0x00200000)iOS Kernel ASLR
donde 0xRR = un byte aleatorio de SHA1(información alatoria) generado por iBoot (el cargador de arranque de segunda etapa).
Linux
El núcleo Linux activó una forma débil de ASLR por defecto desde su versión 2.6.12, lanzada en junio de 2005.The NX Bit And ASLR, Tom's Hardware, 25 de marzo de 2009. Los juegos de parches PaX y Exec Shield aplicados al núcleo Linux proporcionan implementaciones más completas. El parche Exec Shield para Linux proporciona 19 bits de entropía de la pila en un período de 16 bytes, así como 8 bits de aleatoriedad de la base de mmap en un período de 1 página de 4096 bytes. Esto sitúa a la base de la pila en un área de una anchura de 8 MB, conteniendo 524.288 posiciones posibles, y la base de mmap en un área de 1 MB de anchura, conteniendo 256 posiciones posibles. Varias distribuciones de Linux —incluyendo Adamantix, Alpine Linux, Gentoo Hardened y Hardened Linux From Scratch— vienen por defecto con la implantación PaX de ASLR.