Desde hace un par de semanas estamos jugando con las técnicas de análisis forense y pentesting que tienen que ver con la memoria RAM y los trucos que rodean a este elemento volátil. En los artículos anteriores hemos visto “Cómo sacar la contraseña de Gmail de la memoria del proceso de Firefox usando Metasploit” o “Cómo volcar credenciales del proceso KeePass con Meterpreter”, lo que podría dar a un atacante datos jugosos o indicios que nos ayuden en una auditoría de seguridad. Puede que para muchos esto sea algo normal, pero lo cierto es que los sistemas aún podrían haber estado diseñados de forma mucho más robusta para garantizar la protección de la memoria contra este tipo de ataques, así que hemos hecho una prueba en Eleven Paths para mostraros "Cómo proteger tu password cuando esté en memoria RAM".
Figura 1: Cómo proteger tu password cuando esté en memoria RAM
Para hacer esta prueba vamos a hacer uso de los SecureString. Según indica Microsoft en su MSDN Library, el SecureString es un objeto similar al String - es decir, para almacenar cadenas de texto, pero que se almacena en memoria RAM con un mecanismo de cifrado ofrecido por el propio sistema operativo. Este tipo de objetos que protegen en el contenido en la memoria RAM por medio de cifrado se crearon en los sistemas operativos y lenguajes de programación para que la información sensible como contraseñas o datos personales, utilicen SecureString, mientras que el resto de información podría ser almacenada, sin más, en Strings.
Figura 2: ¿Cómo de seguros son los SecureString en .NET?
Hay que tener en cuenta que la memoria RAM de un proceso puede ser accesible no solo por medio de Metasploit como hemos visto en los casos anteriores, sino que un volcado de memoria producido por un fallo en el sistema operativo - como cuando se produce un BSOD - puede hacer que todos los datos que haya en la RAM terminen en un fichero de texto donde puede quedar toda la información expuesta. En el ejemplo que poníamos de Firefox, lo que quedaba no era directamente la contraseña, pero sí el usuario y la contraseña introducida por el usuario, que probablemente, si es un error de mecanografía, puede llevar a la password.
Un proceso con SecureString y otro con String
Para esta prueba de concepto se ha utilizado un código .NET escrito en C#, que permite ejemplificar dos situaciones: En la primera situación el programa utiliza SecureString para gestionar su clave en memoria RAM. La clave no se imprime por pantalla y si buscamos la información de la contraseña en RAM utilizando Metasploit no debemos encontrar nada. En la segunda situación el usuario gestiona su clave en un tipo de datos String. Cómo ya hemos visto en anteriores artículos, la información será mostrada cuando se haga un dump de memoria.
Figura 3: Funciones de protección de Strings con SecureString
El trozo de código anterior muestra dos funciones, una que permite convertir un String a SecureString y la otra realiza el proceso inverso. Una correcta gestión de los SecureString puede ayudarnos a solventar problemas de data leaks a través de información en la RAM.
Para realizar el volcado de memoria RAM del proceso .NET utilizado, en este caso el que solo gestiona la información con SecureString, se utiliza el script de Meterpreter llamado proc_memdump para obtener el volcado remoto.
Figura 4: Volcado de memoria de un proceso protegido con SecureString
Cómo puede verse en la imagen, si buscamos cadenas como “System.Security” se encuentra Password: System.Security.SecureString. En el caso de que se utilizará un String ya tendríamos el leak y el valor de la contraseña como veremos en la siguiente prueba, pero con esta configuración, nada de nada.
Figura 5: La cadena de la contraseña está protegida por SecureString
Conociendo la contraseña que hemos almacenado con SecureString realizamos una búsqueda sobre el volcado de memoria a ver si está en algún lugar almacenada la cadena de la password en texto plano. El resultado es el que se puede ver en la imagen, nada. No encontramos información sobre la contraseña en el volcado, se está gestionando de forma correcta y segura.
Figura 6: La cadena de la contraseña no está en volcado de memoria
Ahora vamos a ejecutar el proceso nuevamente pero haciendo que la contraseña se gestione a través de un String, algo muy común. Tal y como se puede ver en la imagen se ejecuta process_memdump y se obtiene el volcado en crudo del proceso.
Figura 7: Si no está protegida, la contraseña está accesible en el volcado
Realizando la búsqueda sobre la captura de la palabra “Pass” podemos encontrar la contraseña en texto plano en la memoria RAM. Esta información ha sido mostrada por pantalla, por lo que se está almacenando de manera insegura en la memoria del proceso.
Figura 8: GuardedString en Java
Cómo conclusión decir que una correcta gestión del uso de Strings sensibles y unas buenas pautas a la hora de programar nos ayudan a hacer nuestro desarrollo más seguro y que la fortificación de la aplicación sea mayor en cualquier entorno. En este ejemplo se ha visto con una aplicación en .NET, pero en otros lenguajes existen otras soluciones. En Java, por ejemplo, el tipo de datos para hacer algo similar a esto se llama GuardedString, y dependiendo de la plataforma de desarrollo que uses puedes buscar soluciones similares. Este tipo de protecciones, por supuesto, no son 100% seguras, pero si se accede al volcado de memoria sin poder utilizar las funciones criptográficas del sistema operativo con las claves de descifrado, obtener las cadenas protegidas es un trabajo de fuerza bruta.
Autor: Pablo González Pérez (@pablogonzalezpe)
No hay comentarios.:
Publicar un comentario