
C2Bridges allow developers to create new custom communication protocols and quickly utilize them within Covenant.
C2Bridges ermöglichen es Entwicklern, neue benutzerdefinierte Kommunikationsprotokolle zu erstellen und diese schnell in Covenant zu nutzen.
C2Bridges werden verwendet, um ein ausgehendes Command-and-Control-Protokoll zu entwickeln, ohne Covenant-Code zu bearbeiten. Für Entwickler, die sich mit der Integration neuer Listener wohlfühlen, sollte ein neues C2-Protokoll als erstklassiger neuer Listener-Typ hinzugefügt werden, der vollständig in die Oberfläche integriert ist. In manchen Situationen kann es jedoch schneller sein, eine C2Bridge außerhalb von Covenant zu erstellen und sie für Proof-of-Concepts oder zum Testen neuer Protokolle mit einem BridgeListener zu verbinden.
Entwickler können das C2Bridge-Projekt als Vorlage für die Erstellung neuer C2Bridges verwenden. Innerhalb des C2Bridge-Projekts gibt es eine abstrakte C2Bridge-Klasse. Ein Entwickler kann von dieser Klasse erben und die benötigten Funktionen implementieren, um von Implantaten zum BridgeListener unter Verwendung des neuen gewählten C2-Protokolls zu lesen und zu schreiben.
using System.Threading;
using System.Threading.Tasks;
namespace C2Bridge
{
/// <summary>
/// IC2Bridge ist ein Interface, das von der C2Bridge-Klasse implementiert wird.
/// </summary>
public interface IC2Bridge
{
Task RunAsync(CancellationToken token);
}
/// <summary>
/// C2Bridge ist eine abstrakte Klasse, von der neue C2Bridges erben sollten.
/// </summary>
public abstract class C2Bridge : IC2Bridge
{
// Der BridgeConnector verwaltet die Kommunikation zwischen dem Covenant-Server und der C2Bridge
protected BridgeConnector BridgeConnector { get; set; }
// Das BridgeProfile verwaltet das Parsen und Formatieren von Daten, die zwischen dem Implantat und Covenant ausgetauscht werden
protected BridgeProfile BridgeProfile { get; set; }
/// <summary>
/// Der Konstruktor für die C2Bridge. Neue C2Bridges sollten ihren eigenen Konstruktor verwenden, der
/// alle für die Funktion der C2Bridge benötigten Befehlszeilenargumente akzeptiert.
/// </summary>
/// <param name="Connector">Der BridgeConnector, der die Kommunikation mit dem Covenant-Server verwaltet.</param>
/// <param name="Profile">Das BridgeProfile, das das Parsen und Formatieren von Daten verwaltet.</param>
protected C2Bridge(BridgeConnector Connector, BridgeProfile Profile)
{
this.BridgeConnector = Connector;
this.BridgeProfile = Profile;
BridgeConnector.OnReadBridge += OnReadBridge;
}
/// <summary>
/// Die RunAsync-Funktion ist die Hauptfunktion, die die C2Bridge starten und so lange laufen lassen sollte, bis Sie
/// mit Ihrem Vorgang fertig sind. C2Bridge-Entwickler sollten die Logik zum Starten und Betreiben des Listeners
/// innerhalb dieser Funktion implementieren.
/// </summary>
/// <param name="Token">Das CancellationToken, das die C2Bridge abbricht, wenn die Quelle des Tokens abgebrochen wird.</param>
/// <returns></returns>
public abstract Task RunAsync(CancellationToken Token);
/// <summary>
/// Die OnReadBridge-Funktion wird jedes Mal aufgerufen, wenn Daten vom Covenant-Server gelesen werden, die für ein Implantat bestimmt sind.
/// C2Bridge-Entwickler sollten die Logik implementieren, um zu bestimmen, für welches Implantat diese Daten bestimmt sind, und diese
/// Daten an das Implantat schreiben.
/// </summary>
/// <param name="sender">
/// Sender ist das Objekt, das die OnReadBridge-Funktion aufgerufen hat. C2Bridge-Entwickler können diesen Parameter getrost ignorieren.
/// </param>
/// <param name="args">Args enthält die Daten, die vom Covenant-Server zum Implantat geschrieben werden sollen.</param>
protected abstract void OnReadBridge(object sender, BridgeConnector.ReadBridgeArgs args);
/// <summary>
/// Die WriteToConnector-Funktion verwaltet das Schreiben von Daten von einem Implantat zum Covenant-Server. Diese Logik sollte für
/// alle C2Bridge-Typen gleich sein, kann aber von einem C2Bridge-Entwickler überschrieben werden, wenn eine benutzerdefinierte Logik erforderlich ist.
///
/// Beim Aufrufen dieser Funktion sollte die zurückgegebene GUID-Zeichenfolge verwendet werden, um Implantat-GUID-Werte durch die C2Bridge zu verfolgen.
/// </summary>
/// <param name="Data">Die vom Implantat gelesenen Daten, die zum Covenant-Server geschrieben werden sollen.</param>
/// <returns>
/// Gibt den aus den Daten geparsten GUID-Wert zurück. Dieser Wert sollte verwendet werden, um Implantat-GUID-Werte durch die C2Bridge zu verfolgen.
/// </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>
/// Die GetBridgeMessengerCode-Funktion sollte den Code enthalten, der für die Kommunikation mit der C2Bridge in das Implantat eingebettet werden soll.
/// Diese Funktion wird im Projekt tatsächlich nirgendwo verwendet, ist aber hier, damit der notwendige Implantat-Code
/// zusammen mit der C2Bridge gefunden werden kann. C2Bridge-Entwickler sollten den Code hier zur Verwendung in der
/// BridgeMessengerCode-Eigenschaft eines BridgeProfile platzieren.
/// </summary>
/// <returns></returns>
protected abstract string GetBridgeMessengerCode();
}
}
Das C2Bridge-Projekt enthält eine Beispielklasse TCPC2Bridge, die von diesem Interface erbt und ein Beispiel zeigt, wie eine Implementierung aussehen kann.

Sobald Sie Ihre neue C2Bridge geschrieben haben, kann der Konstruktoraufruf für TCPC2Bridge innerhalb der Main()-Funktion durch den neuen Konstruktor ersetzt werden:

Die abstrakte Methode GetBridgeMessengerCode() wird im C2Bridge-Projekt nirgendwo tatsächlich verwendet, dient aber dazu, eine C2Bridge mit einem Implantat zu verknüpfen. Ein Implantat benötigt Code, der in der Lage ist, zur und von der ausgehenden C2Bridge zu lesen und zu schreiben. Dieser Code ist für eine bestimmte C2Bridge spezifisch und sollte in der geerbten Methode GetBridgeMessengerCode() platziert werden. Ein Covenant-Benutzer, der eine C2Bridge verwendet, nimmt den BridgeMessengerCode aus dieser Methode und verwendet ihn in einem BridgeProfile.
Covenant-Benutzer, die eine C2Bridge verwenden, müssen ein BridgeProfile konfigurieren, das für die C2Bridge spezifisch ist. Die Grunt-Implantate müssen wissen, wie sie zur und von der ausgehenden C2Bridge lesen und schreiben. Die Eigenschaft BridgeProfile.BridgeMessengerCode repräsentiert den Code, der im Implantat platziert wird und für das Lesen und Schreiben zur ausgehenden C2Bridge verantwortlich ist. Dieser Code sollte in der Methode GetBridgeMessengerCode() einer C2Bridge zu finden sein.
Benutzer können ein völlig neues BridgeProfile erstellen oder das DefaultBridgeProfile mit dem korrekten BridgeMessengerCode bearbeiten. Navigieren Sie dazu zur Listener-Navigationsseite und wählen Sie den Reiter "Profiles":

Um ein neues Profil zu erstellen, klicken Sie auf die Schaltfläche "Create". Um ein bestimmtes Profil zu bearbeiten, klicken Sie auf den Namen des Profils. Beachten Sie, dass Sie Profile, die mit aktiven Listenern verknüpft sind, nicht bearbeiten können.
Nachdem Sie auf "Create" geklickt haben, wählen Sie den Reiter "BridgeProfile":

Die folgenden Optionen müssen beim Bearbeiten oder Erstellen eines Profils konfiguriert werden:
Name des Profils, der in der gesamten Oberfläche verwendet wird. Wählen Sie einen erkennbaren Namen!Description des Profils. Dies sollte eine gründliche Beschreibung des Profils sein, die Betreiber lesen und leicht verstehen können, wie das Profil funktioniert und für welche Anwendungsfälle es geeignet ist.MessageTransform ist eine einzigartige Möglichkeit, um festzulegen, wie die Kommunikationsdaten transformiert werden, bevor sie in die in ReadFormat und WriteFormat angegebenen Formate eingefügt werden. Ein MessageTransform sollte eine statische C#-Klasse namens MessageTransform sein, die eine öffentliche Transform- und eine öffentliche Invert-Funktion enthält. Die Klasse kann die Daten auf jede gewünschte Weise transformieren, solange die Transform- und Invert-Funktionen spiegelbildlich sind (d. h. data == MessageTransform.Invert(MessageTransform.Transform(data))). Die Klasse MessageTransform muss plattformunabhängig sein und unter , und kompilieren.Bei der Konfiguration dieser Optionen hat der Covenant-Benutzer völlige Freiheit, jeden dieser Werte nach Belieben zu konfigurieren, mit Ausnahme der Eigenschaft BridgeMessengerCode. Die Eigenschaft BridgeMessengerCode muss von der C2Bridge übernommen werden.
Wenn ein Covenant-Benutzer die Eigenschaften ReadFormat und/oder WriteFormat bearbeitet, muss die C2Bridge beim Start über diese Änderung informiert werden. Das C2Bridge-Projekt akzeptiert einen Parameter --profile <profile.yaml>, der eine Profil-YAML-Datei akzeptiert, die optional verwendet werden kann, wenn diese Eigenschaften angepasst wurden.
Der gesamte Prozess zur Entwicklung und Nutzung einer C2Bridge ist wie folgt:
C2Bridge-Klasse aus dem C2Bridge-Projekt erbt. Verwenden Sie die Klasse TCPC2Bridge als Referenz.BridgeProfile, das den in der GetBridgeMessengerCode()-Methode der C2Bridge gefundenen BridgeMessengerCode verwendet.BridgeProfile verwendet.ReadFormat und/oder WriteFormat des BridgeProfile angepasst haben, verwenden Sie den optionalen CLI-Parameter --profile <profile.yaml>, um die C2Bridge über diese Anpassungen zu informieren.Net40Net35NetCore21ReadFormat ist das Format einer Nachricht, wenn ein Grunt Daten von einer C2Bridge liest. Das Format muss einen Platz für die Daten und die Grunt-GUID enthalten. Fügen Sie die Zeichenfolge "{DATA}" ein, um anzugeben, wo die Daten platziert werden sollen, und die Zeichenfolge "{GUID}", um anzugeben, wo die GUID platziert werden soll.WriteFormat ist das Format einer Nachricht, wenn ein Grunt Daten an eine C2Bridge schreibt. Das Format muss einen Platz für die Daten und die Grunt-GUID enthalten. Fügen Sie die Zeichenfolge "{DATA}" ein, um anzugeben, wo die Daten platziert werden sollen, und die Zeichenfolge "{GUID}", um anzugeben, wo die GUID platziert werden soll.BridgeMessengerCode ist der Code, der im Implantat platziert wird und für das Lesen und Schreiben zur ausgehenden C2Bridge verantwortlich ist. Dieser Code sollte in der Methode GetBridgeMessengerCode() einer C2Bridge zu finden sein.GruntBridge