18 ene 2018

DLL Hijacking: Aprendiendo los conceptos básicos

Hace un tiempo estuve leyendo el libro Gray Hat Python de Justin Seitz, recomendable, así que dejo el enlace al libro en Amazon. En él se explican cosas bastante interesantes, entre otras se puede ver cómo crear un debugger básico para Windows o cómo hacer una inyección de shellcode o DLL en un proceso.

Esta última tarea, la inyección de DLL en un proceso es de la que voy a hablar en este post. Os dejo una definición de la Wikipedia:

DLL injection es una técnica utilizada para ejecutar lenguaje de máquina dentro del espacio de direcciones de otro proceso forzándolo a cargar una biblioteca de enlace dinámico.”
Antes de empezar hay que tener en cuenta lo siguiente:

·       Se hace uso de Python 3 (usar versión de 32 bits para inyecciones de 32 y la de 64 para la correspondiente)
·       DLL de 32 bits para aplicaciones de 32 bits
·       DLL de 64 bits para aplicaciones de 64 bits
·       Uso de Process Hacker para ver información del proceso objetivo
·       Yo uso Windows 10

Se muestra a continuación el código por partes. Empecemos:


La primera parte no tiene mucho que explicar. Vemos que se comprueba la versión de Python que está corriendo (para saber si es de 32 bits o 64 bits), se hace uso de argparse par los 2 argumentos que necesitamos, PID del proceso y ruta de la DLL. Al final se ve la definición de 3 constantes:
·       PAGE_READWRITE: sirve para establecer un acceso de lectura y escritura.
·       PROCESS_ALL_ACCESS: todos los accesos posibles al proceso.
·       COMMIT_RESERVE: para reservar espacio en las direcciones virtuales, asegurándonos de que al acceder el contenido esté en 0.

Continuamos con más código:



Vemos como cargamos un “envoltorio” a través del objeto windll, que nos permitirá acceder a las funciones de la librería kernel32, acto seguido manejamos los parámetros recibidos al llamar al script y comprobamos si la dll existe con la función isfile. Vemos que se obtiene la longitud de la ruta de la dll, es necesario para reservar la memoria en los siguientes pasos.
Se llama a la función OpenProcess, que si va bien, nos devolverá un manejador al proceso, si no tendremos un NULL y salimos. El prototipo de la función es el siguiente:


Se procede a llamar a VirtualAllocEx, si se procesa con éxito, se devolverá la región de memoria asignada, si no NULL y salimos. El prototipo a continuación:


Ya estamos llegando al final, penúltima parte del código:


Se hace la llamada a WriteProcessMemory, si falla devolverá 0, y si no un valor distinto a 0. Y su prototipo es:


Se obtiene la dirección de memoria de la función “LoadLibraryA”, si todo va bien seguimos, si no salimos, no tiene sentido seguir. Y pasamos a la última parte del código:


Aquí lo primero que hacemos es crear un tipo de datos que se va a necesitar para definir los tipos de argumentos de la función, LPSECURITY_ATTRIBUTES, se trata de una estructura de C, y que tiene 3 campos. Acto seguido, se definen los tipos que se le van a pasar a la función CreateRemoteThread (podemos ver la estructura, aunque la dejaremos como None), si no hacemos esto, en la versión de 64 bits fracasaremos , y finalmente se llama a la función, y si va como esperamos, devolverá un manejador al nuevo hilo, si no devolverá NULL. El prototipo de la función es como sigue:


Para hacer la primera prueba, yo tengo un XAMPP de 32 bits corriendo, voy a utilizar la herramienta Process Hacker para obtener el PID, aquí también se podría hacer uso del administrador de tareas:


Ahora ejecutamos el script, en mi PC tengo instalada tanto la versión de 32 bits, como la de 64 bits (en la PATH).


Vemos que se ha podido inyectar la DLL en el proceso con PID 5128, si ahora hacemos uso de Process Hacker, click derecho del ratón en nuestro proceso objetivo, y damos en Properties, ahí vamos a la pestaña Modules, y buscamos la DLL inyectada. (Nota: en esta prueba se utilizo una versión antigua del script, que solo corría en 32 bits).
La segunda prueba es para 64 bits, y hago uso de Android Studio:


Si se mira en Process Hacker, se ve la DLL de Python inyectada, se deja a continuación una captura, ya que en la otra prueba no se mostró:



Para jugar puedes crear tu propia DLL, consulta la siguiente página de Microsoft, por ejemplo, en el caso de DLL_PROCESS_ATTACH, puedes escribir:
            MessageBox(0, "Flu-project!", "DLL Injected…", 0);
            break;

Es posible que en algunos procesos no se tengan los permisos suficientes y falle la inyección, además, si intentas inyectar una DLL de 64 bits en algún proceso de 32 bits no habrá errores, pero la inyección no se realizará (y viceversa).
El código se puede consultar en mi GitHub en este link: DLL injection. Hasta la próxima.

Autor: Josué Encinar García (@JosueEncinar). Ingeniero de Software por la Universidad Rey Juan Carlos, estudiante del Máster Universitario en Seguridad de Tecnologías de la Información y de las Comunicaciones en la Universidad Europea de Madrid. Analista de Seguridad en Accenture. Co-Fundador de @_ciberbyte_.

No hay comentarios:

Publicar un comentario