Cómo crear un sistema de plugins (dll) en C# sin pisar disco - BoomerNiX

martes, 9 de junio de 2020

Cómo crear un sistema de plugins (dll) en C# sin pisar disco

Hace un tiempo atrás estuve haciendo un código para una PoC de un C&C en C# (código en mi GitHub), para ver qué tal se manejaba el lenguaje, por ello en esta ocasión voy a hablar sobre cómo montar un sistema de plugins en C# de manera muy rápida y sin que pise disco, por si a alguien le sirve. El código es del todo mejorable, ya que no se buscaba algo robusto, simplemente ver su comportamiento y poder tener una funcionalidad mínima en la máquina objetivo y que según se necesite se vaya cargando en memoria. El código de carga de plugins es el que se puede ver en la figura 1.

Figura 1: código de la carga de plugins (DLLs)

El servidor pedirá al agente ejecuta la funcionalidad X, y el agente comenzará a obtener el plugin, para ello abrimos la URL deseada en una variable de tipo Stream, que se la pasaremos a la función BinaryReader que nos permitirá leer los bytes y obtener el array de bytes que necesitamos para cargar el código, que se hará con Assembly.Load

Obtenemos la clase del plugin y creamos la instancia, a partir de aquí podemos invocar a nuestro método Run (que puede o no tener argumentos, está funcionalidad se puede mejorar para evitar comprobaciones innecesarias).

Un ejemplo de plugin rápido (el primer valor es el resultado, y el segundo si se produce algún error, aquí lo ignoro):

namespace CurrentDirectory { 
    class Plugin { 
        public void Run() { 
    return (Directory.GetCurrentDirectory(), “”); 
        } 
    }
}


El plugin en el servidor estará guardado como CurrentDirectory.dll. La función de carga de módulo recibe un tipo  llamado ServerData, que es el que se observa en la figura 2.
    
Figura 2: clase para almacenar los datos

Los datos que vienen desde el servidor son varios, puede servir para ejecutar comandos, o ejecutar funciones por defecto dentro del C&C, y que no necesitan ser cargados:

  • id: identifica la tarea
  • command: el comando a ejecutar
  • args: argumentos del comandos
  • type: tipo de comando
  • pluginargs: los argumentos que necesite el plugin

La información se trata como se observa en la figura 3, al finalizar la respuesta se manda a través de una petición POST al servidor.

Figura 3: código para tratar los datos enviados desde el servidor

Si el servidor pide ejecutar un comando, va sin más, si pide una función, buscará el método command en las funciones definidas (aquí se encuentra nuestra función LoadPlugin). Luego obtenemos la respuesta y se la devolvemos al servidor (sin olvidar el identificador de la tarea). Existe ya funcionalidad en el core del agente, por ejemplo, la subida de ficheros, por lo que no se carga como plugin, se puede ver en la figura 4 (observar que recibe y devuelve lo mismo que la carga de plugins).

Figura 4: función de ejemplo para subir ficheros

Y queda ver una pequeña captura del C&C funcionando y cargando los plugins o dlls, que se muestra en la figura 5.

Figura 5: ejemplo del C&C corriendo

En este ejemplo ServerData será:
  • id: xxxx
  • command: “LoadPlugin”
  • args: “http://lhost:lport/simple/ CheckAdmin”
  • type: “function”
  • pluginargs: “”

Por lo tanto en la función treatServerData entrará por “function”, ejecutará LoadPlugin, que llevará a la función de la figura 1 y se producirá la carga del plugin o dll en memoria, se ejecutará y se devolverá el resultado al servidor.

Muy sencillo de implementar, aquí no se ha enseñado todo el código, ni se muestra la parte del servidor, lo interesante es la carga de plugins en memoria. La carga de DLLs y la subida de ficheros es mejor hacerlo directamente desde el mismo servidor y puerto, un cambio mínimo que para el ejemplo no me he molestado.

El código completo del C&C y más capturas se puede consultar en mi GitHub. Solo he buscado montar una PoC y ver el comportamiento de C#, ya que hasta esta prueba para mi era un lenguaje totalmente desconocido. Me ha gustado bastante, pero no llegará a se mi lenguaje preferido :D.

¡Hasta pronto!

No hay comentarios:

Publicar un comentario