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