
C2Bridges permettent aux développeurs de créer de nouveaux protocoles de communication personnalisés et de les utiliser rapidement au sein de Covenant.
Les C2Bridges permettent aux développeurs de créer de nouveaux protocoles de communication personnalisés et de les utiliser rapidement dans Covenant.
Les C2Bridges sont utilisés pour développer un protocole de commande et de contrôle sortant sans modifier le code de Covenant. Pour les développeurs qui souhaitent intégrer de nouveaux écouteurs, un nouveau protocole C2 devrait être ajouté comme nouveau type d'écouteur de première classe, entièrement intégré à l'interface. Cependant, il peut être plus rapide dans certaines situations de créer un C2Bridge en dehors de Covenant et de le connecter avec un BridgeListener pour des preuves de concept ou le test de nouveaux protocoles.
Les développeurs peuvent utiliser le projet C2Bridge comme modèle pour créer de nouveaux C2Bridges. Dans le projet C2Bridge, il y a une classe abstraite C2Bridge. Un développeur peut hériter de cette classe et implémenter les fonctions nécessaires pour lire et écrire depuis les implants vers le BridgeListener en utilisant le nouveau protocole C2 choisi.
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();
}
}
Le projet C2Bridge contient un exemple de classe TCPC2Bridge qui hérite de cette interface et fournit un exemple d'implémentation.

Une fois que vous avez écrit votre nouveau C2Bridge, l'appel constructeur de TCPC2Bridge dans la fonction Main() peut être remplacé par le nouveau constructeur :

La méthode abstraite GetBridgeMessengerCode() n'est pas réellement utilisée dans le projet C2Bridge, mais sert à relier un C2Bridge à un implant. Un implant a besoin d'un code capable de lire et d'écrire sur le C2Bridge sortant. Ce code est spécifique à un C2Bridge donné et doit être placé dans la méthode héritée GetBridgeMessengerCode(). Un utilisateur de Covenant qui utilise un C2Bridge prendra le BridgeMessengerCode de cette méthode et l'utilisera dans un BridgeProfile.
Les utilisateurs de Covenant qui utilisent un C2Bridge devront configurer un BridgeProfile spécifique au C2Bridge. Les implants Grunt ont besoin de savoir comment lire et écrire sur le C2Bridge sortant. La propriété BridgeProfile.BridgeMessengerCode représente le code qui sera placé dans l'implant et est responsable de la lecture et de l'écriture sur le C2Bridge sortant. Ce code doit se trouver dans la méthode GetBridgeMessengerCode() d'un C2Bridge.
Les utilisateurs peuvent créer un tout nouveau BridgeProfile ou modifier le DefaultBridgeProfile avec le BridgeMessengerCode correct. Pour ce faire, naviguez vers la page de navigation des écouteurs et sélectionnez l'onglet « Profils » :

Pour créer un nouveau profil, cliquez sur le bouton « Créer ». Pour modifier un profil particulier, cliquez sur son nom. Gardez à l'esprit que vous ne pouvez pas modifier les profils associés à des écouteurs actifs.
Après avoir cliqué sur « Créer », sélectionnez l'onglet « BridgeProfile » :
