
API de Python para usar con la especificación External C2 de Cobalt Strike
Framework en Python para construir y utilizar interfaces que transfieran datos entre frameworks, con un enfoque específico en servir como extensión para frameworks de Comando y Control.
Actualmente, esto solo está pensado como una implementación de la especificación External C2 de Cobalt Strike, tal como se describe en este documento de especificación, pero está sujeto a cambios a medida que el proyecto madure.
Un enorme agradecimiento a xychix. Este proyecto no habría sido posible en absoluto sin sus valiosas contribuciones. Básicamente, este proyecto es una reconstrucción y extensión del proyecto External C2 de Outflank
Este proyecto consta de las siguientes partes principales:
El constructor lee un archivo de configuración y utiliza las opciones configuradas para generar una construcción reemplazando marcadores dentro de los esqueletos.
El constructor se puede usar con build_files.py. Se proporciona una configuración de constructor de ejemplo como sample_builder_config.config.sample.
Los esqueletos son los diferentes "esqueletos" de código que el constructor poblará dinámicamente para generar una construcción completamente utilizable. Los esqueletos contienen marcadores que serán reemplazados con valores utilizables por el constructor. Hay tres 'tipos' diferentes de esqueletos:
Un marcador se puede colocar dentro de cualquier archivo en un esqueleto, y será reemplazado con un valor especificado en la configuración del constructor. Como buena práctica, los marcadores nunca deben usarse para escribir directamente variables, y solo deben usarse para establecer valores. Si el valor de un marcador debe reutilizarse, se debe optar por almacenar el valor en una variable y referenciarlo de esa manera, en lugar de reutilizar el mismo marcador.
El formato del marcador es: ```[var:::identificador_del_marcador]```
Las cadenas se escribirán en un esqueleto directamente envueltas en comillas simples, y los números se escribirán tal cual.
En caso de que una cadena en la configuración esté envuelta en comillas dobles, la cadena se escribirá directamente en el archivo envuelta en comillas dobles, y las comillas simples envolventes se eliminarán.
Esta relación se puede demostrar como:
#################
# Código del esqueleto #
#################
# El esqueleto contiene la siguiente línea de código:
foo = ```[var:::bar]```
###########
# Resultado final #
###########
# Almacenado en la configuración como:
# foo = bar
# Escrito como:
foo = 'bar'
# Almacenado en la configuración como:
# foo = "bar"
# Escrito como:
foo = "bar"
# Almacenado en la configuración como:
# foo = 2
# Escrito como:
foo = 2
# Almacenado en la configuración como:
# foo = "2"
# Escrito como:
foo = "2"
Los frameworks son la aplicación base que determina qué datos están siendo utilizados por el transporte y el codificador, y cómo se utilizan esos datos. Lo que realmente haga un framework específico no importa, siempre que exista lógica para importar y usar el codificador y el transporte. La mayoría de las partes esenciales de un framework (principalmente la lógica del cliente) se almacenarán como un esqueleto, con una interfaz para interactuar con la parte del servidor almacenada como un objeto framework base.
Generalmente, un framework contiene un servidor y un cliente, y hace uso de codificadores y transportes para retransmitir datos entre ellos.
Hay algunos fundamentos a considerar al construir un framework:
framework es responsable de asegurar que el codificador esté disponible para que el transporte lo utilice.framework utiliza una relación cliente-servidor, deben organizarse apropiadamente como tal.cliente de un framework, por lo que si se desea que las cosas sean reconfigurables en el cliente, debe poder hacerlo durante la ejecución sin interacción directa.esqueleto de servidor porque el usuario final va a interactuar directamente con el servidor de un framework. En su lugar, se debe optar tanto por leer las opciones de una configuración como por dar al usuario final la capacidad de modificar opciones (como un temporizador de bloque o la verbosidad) durante la ejecución.esqueleto de framework será procesado por el constructor, iterando a través de cada archivo en él, por lo que si un argumento determinado necesita ser configurable en el momento de la construcción, se puede hacer fácilmente.servidor de framework debería poder ser interfazado por un gestor_de_framework común.El servidor es la aplicación que gestiona la comunicación entre el cliente y el servidor C2. La lógica del servidor es principalmente estática. La lógica del servidor para el framework cobalt_strike, denominado Controlador de Cliente de Terceros dentro de la especificación, se muestra a continuación:
codificadortransportetransportecodificadortransportetransportecodificadorUn servidor debe soportar la capacidad de manejar múltiples clientes (aún no implementado), y ser interfazado por un gestor_de_framework.
El cliente es esencialmente el payload que se ejecuta en el endpoint. La lógica del cliente para el framework cobalt_strike es principalmente estática y se muestra a continuación:
transportetransportetransporte en busca de nuevas tareastransporteEl cliente utiliza el codificador y el transporte especificados para retransmitir datos entre sí mismo y su servidor respectivo.
Los codificadores reciben datos, luego modifican esos datos para prepararlos para su uso al ser enviados a través del transporte, o decodifican datos recibidos a través del transporte de vuelta a su forma original para ser interpretados por el componente del framework que los esté utilizando.
Los codificadores deben esperar ser interfazados directamente por el transporte, y manejar los datos de manera independiente del framework y del componente.