
C2Bridges permiten a los desarrolladores crear nuevos protocolos de comunicación personalizados y utilizarlos rápidamente dentro de Covenant.
Los C2Bridges permiten a los desarrolladores crear nuevos protocolos de comunicación personalizados y utilizarlos rápidamente dentro de Covenant.
Los C2Bridges se utilizan para desarrollar un protocolo de comando y control saliente sin editar ningún código de Covenant. Para los desarrolladores que se sienten cómodos integrando nuevos listeners, un nuevo protocolo C2 debe añadirse como un nuevo tipo de listener de primera clase completamente integrado en la interfaz. Sin embargo, puede ser más rápido en algunas situaciones crear un C2Bridge fuera de Covenant y conectarlo con un BridgeListener para pruebas de concepto o probar nuevos protocolos.
Los desarrolladores pueden usar el proyecto C2Bridge como plantilla para crear nuevos C2Bridges. Dentro del proyecto C2Bridge, hay una clase abstracta C2Bridge. Un desarrollador puede heredar de esta clase e implementar las funciones necesarias para leer y escribir desde implants hacia el BridgeListener usando el nuevo protocolo C2 elegido.
using System.Threading;
using System.Threading.Tasks;
namespace C2Bridge
{
/// <summary>
/// IC2Bridge is an interface implemented by the C2Bridge class.
/// </summary>
public interface IC2Bridge
{
Task RunAsync(CancellationToken token);
}
/// <summary>
/// C2Bridge is an abstract class that new C2Bridges should inherit from.
/// </summary>
public abstract class C2Bridge : IC2Bridge
{
// The BridgeConnector handles communication between the Covenant server and the C2Bridge
protected BridgeConnector BridgeConnector { get; set; }
// The BridgeProfile handles parsing and formatting data passed between the implant and Covenant
protected BridgeProfile BridgeProfile { get; set; }
/// <summary>
/// The constructor for the C2Bridge. New C2Bridges should use their own constructor that accepts
/// any command line arguments needed for the C2Bridge to function.
/// </summary>
/// <param name="Connector">The BridgeConnector that handles communication with the Covenant server.</param>
/// <param name="Profile">The BridgeProfile that handles the parsing and formatting of data.</param>
protected C2Bridge(BridgeConnector Connector, BridgeProfile Profile)
{
this.BridgeConnector = Connector;
this.BridgeProfile = Profile;
BridgeConnector.OnReadBridge += OnReadBridge;
}
/// <summary>
/// The RunAsync function is the main function that should start the C2Bridge and continue to run until you
/// are done with your operation. C2Bridge developers should implement the logic to start and run the listener
/// within this function.
/// </summary>
/// <param name="Token">The CancellationToken that will cancel the C2Bridge if the source of the token is cancelled.</param>
/// <returns></returns>
public abstract Task RunAsync(CancellationToken Token);
/// <summary>
/// The OnReadBridge function is called each time data is read from the Covenant server meant for an implant.
/// C2Bridge developers should implement the logic to determine which implant this data is meant for and write
/// this data to the implant.
/// </summary>
/// <param name="sender">
/// Sender is the object that called the OnReadBridge function. C2Bridge developers can safely ignore this parameter.
/// </param>
/// <param name="args">Args contains the data that should be written from the Covenant server to the implant.</param>
protected abstract void OnReadBridge(object sender, BridgeConnector.ReadBridgeArgs args);
/// <summary>
/// The WriteToConnector function handles writing data from an implant to the Covenant server. This logic should be the
/// same for all C2Bridge types, but can be overloaded by the C2Bridge developer if custom logic is needed.
///
/// When calling this function, the returned GUID string should be used to track implant GUID values by the C2Bridge.
/// </summary>
/// <param name="Data">The data read from the implant that should be written to the Covenant server.</param>
/// <returns>
/// Returns the GUID value parsed out of the Data. This value should be used to track implant GUID values by the C2Bridge.
/// </returns>
protected virtual string WriteToConnector(string Data)
{
var parsed = this.BridgeProfile.ParseWrite(Data);
if (parsed != null)
{
_ = this.BridgeConnector.Write(this.BridgeProfile.FormatRead(parsed));
return parsed.Guid;
}
return null;
}
/// <summary>
/// The GetBridgeMessengerCode function should contain the code to be embedded in the implant for communication with
/// the C2Bridge. This function is not actually used anywhere within the project, but is here so that the necessary
/// implant code can be found along with the C2Bridge. C2Bridge developers should place the code here for use within
/// a BridgeProfile's BridgeMessengerCode property.
/// </summary>
/// <returns></returns>
protected abstract string GetBridgeMessengerCode();
}
}
El proyecto C2Bridge contiene una clase TCPC2Bridge de ejemplo que hereda de esta interfaz y proporciona un ejemplo de cómo implementar una.

Una vez que haya escrito su nuevo C2Bridge, la llamada al constructor de TCPC2Bridge dentro de la función Main() puede ser reemplazada por el nuevo constructor:

El método abstracto GetBridgeMessengerCode() no se utiliza realmente en ningún lugar dentro del proyecto C2Bridge, pero se usa para vincular un C2Bridge con un implant. Un implant necesita código que pueda leer y escribir en el C2Bridge saliente. Este código es específico de un C2Bridge dado, y debe colocarse dentro del método heredado GetBridgeMessengerCode(). Un usuario de Covenant que utilice un C2Bridge tomará el BridgeMessengerCode de este método y lo usará dentro de un BridgeProfile.
Los usuarios de Covenant que utilicen un C2Bridge necesitarán configurar un BridgeProfile específico para el C2Bridge. Los implants Grunt necesitan saber cómo leer y escribir en el C2Bridge saliente. La propiedad BridgeProfile.BridgeMessengerCode representa el código que se colocará en el implant y es responsable de leer y escribir en el C2Bridge saliente. Este código debe encontrarse en el método GetBridgeMessengerCode() de un C2Bridge.
Los usuarios pueden crear un BridgeProfile completamente nuevo o editar el DefaultBridgeProfile con el BridgeMessengerCode correcto. Para hacerlo, navegará a la página de navegación de listeners y seleccionará la pestaña "Profiles":

Para crear un nuevo perfil, haga clic en el botón "Create". Para editar un perfil en particular, haga clic en el nombre del perfil. Tenga en cuenta que no puede editar perfiles que estén asociados con listeners activos.
Después de hacer clic en "Create", seleccione la pestaña "BridgeProfile":

Las siguientes opciones deberán configurarse al editar o crear un perfil:
Name del perfil que se usará en toda la interfaz. ¡Elija algo reconocible!Description del perfil. Esta debe ser una descripción completa del perfil que los operadores puedan leer y comprender fácilmente cómo funciona el perfil y los casos de uso para los que sería apropiado usar el perfil.MessageTransform es una forma única de especificar cómo se transformarán los datos de comunicación antes de colocarlos en los formatos especificados en ReadFormat y WriteFormat. Un MessageTransform debe ser una clase estática de C# llamada MessageTransform que incluya una función pública Transform y una función pública Invert. La clase puede transformar los datos de cualquier forma que desee, siempre que las funciones Transform e Invert se reflejen entre sí (es decir, data == MessageTransform.Invert(MessageTransform.Transform(data))). La clase MessageTransform debe ser compatible con múltiples plataformas y compilar en , y .Al configurar estas opciones, el usuario de Covenant tiene total libertad para configurar cualquiera de estos valores de la manera que desee, excepto la propiedad BridgeMessengerCode. La propiedad BridgeMessengerCode debe tomarse del C2Bridge.
Si un usuario de Covenant edita las propiedades ReadFormat y/o WriteFormat, el C2Bridge debe ser informado de este cambio al iniciar el C2Bridge. El proyecto C2Bridge acepta un parámetro --profile <profile.yaml> que acepta un archivo YAML de perfil, que puede usarse opcionalmente cuando estas propiedades están personalizadas.
El proceso general para desarrollar y utilizar un C2Bridge es el siguiente:
C2Bridge del proyecto C2Bridge. Consulte la clase TCPC2Bridge como ejemplo.BridgeProfile que use el BridgeMessengerCode encontrado en el método GetBridgeMessengerCode() del C2Bridge.BridgeProfile creado.ReadFormat y/o WriteFormat del BridgeProfile, use el parámetro CLI opcional --profile <profile.yaml> para informar al C2Bridge de estas personalizaciones.GruntBridge y el BridgeListener que inició.Net40Net35NetCore21ReadFormat es el formato de un mensaje cuando un Grunt lee datos de un C2Bridge. El formato debe incluir una ubicación para los datos y el GUID del Grunt. Incluya la cadena "{DATA}" para indicar la ubicación donde deben colocarse los datos y la cadena "{GUID}" para indicar la ubicación donde debe colocarse el GUID.WriteFormat es el formato de un mensaje cuando un Grunt escribe datos en un C2Bridge. El formato debe incluir una ubicación para los datos y el GUID del Grunt. Incluya la cadena "{DATA}" para indicar la ubicación donde deben colocarse los datos y la cadena "{GUID}" para indicar la ubicación donde debe colocarse el GUID.BridgeMessengerCode es el código que se colocará en el implant y es responsable de leer y escribir en el C2Bridge saliente. Este código debe encontrarse en el método GetBridgeMessengerCode() de un C2Bridge.