Front-End-Domain basierend auf TLS 1.3. Teil 2

Einleitung


Im ersten Teil des Artikels haben wir den verschlüsselten SNI-Mechanismus (eSNI) kurz beschrieben. Sie zeigten, wie es auf dieser Basis möglich ist, die Erkennung durch moderne DPI-Systeme (am Beispiel von Beeline DPI und verbotenem ILV-Rutracker) zu umgehen und eine neue Version des Domain-Frontends zu untersuchen, die auf diesem Mechanismus basiert.

Im zweiten Teil des Artikels werden wir uns weiteren praktischen Dingen zuwenden, die RedTeam für Spezialisten bei ihrer schwierigen Arbeit von Nutzen sein werden. Letztendlich ist es unser Ziel, keinen Zugriff auf blockierte Ressourcen zu erhalten (für solche alltäglichen Dinge haben wir ein gutes altes VPN). Glücklicherweise gibt es sehr viele VPN-Anbieter für jeden Geschmack, jede Farbe und jedes Budget.

Wir werden versuchen, den Domain-Fronting-Mechanismus auf moderne RedTeam-Tools wie Cobalt Strike, Empire usw. anzuwenden und ihnen zusätzliche Möglichkeiten zur Nachahmung und Umgehung moderner Inhaltsfiltersysteme zu bieten.

Beim letzten Mal haben wir den eSNI-Mechanismus in der OpenSSL-Bibliothek implementiert und ihn erfolgreich im bekannten Dienstprogramm curl verwendet. Aber eine Locke, wie sie sagen, wird nicht voll sein. Natürlich möchte ich etwas Ähnliches in Hochsprachen implementieren. Leider enttäuscht uns eine flüchtige Suche nach der Weite des Netzwerks, da die Unterstützung des eSNI-Mechanismus nur in GOLANG vollständig implementiert ist. Daher ist unsere Auswahl nicht sehr groß: Entweder schreiben wir in reinem C oder C ++ mit der gepatchten OpenSSL-Bibliothek, oder wir verwenden eine separate GOLANG-Verzweigung von CloudFlare und versuchen, unser Toolkit dort zu portieren. Grundsätzlich gibt es eine andere Option, die klassischer, aber auch zeitaufwändiger ist - die Implementierung der eSNI-Unterstützung für Python. Schließlich verwendet Python auch OpenSSL, um mit https zu arbeiten. Aber wir werden diese Option für die Entwicklung jemand anderem überlassen und uns mit der Implementierung auf dem Golang begnügen, zumal unser geliebter Cobalt Strike perfekt mit einem Kommunikationskanal arbeiten kann, der von Tools von Drittanbietern (externer C2-Kanal) erstellt wurde - wir werden am Ende des Artikels darüber sprechen.

Versuchen Sie es noch einmal ...


Eines der auf Go implementierten Tools ist unsere Entwicklung für das Pivoting innerhalb des Netzwerks - der rsockstun- Tuner , der von Microsoft- und Symantec-Tools jetzt übrigens als sehr bösartige Software erkannt wird, die die Stabilität der Welt verletzen soll ...



Es wäre großartig, die vorherige Entwicklung in diesem Fall zu verwenden. Aber hier tritt ein kleines Problem auf. Tatsache ist, dass rsockstun zunächst die Verwendung eines synchronen SSL-Kommunikationskanals mit dem Server impliziert. Dies bedeutet, dass die Verbindung einmal hergestellt wird und für die gesamte Dauer des Tunnelbetriebs besteht. Und wie Sie verstehen, ist das https-Protokoll nicht für diesen Betriebsmodus ausgelegt - es funktioniert im Anforderungs-Antwort-Modus, in dem jede neue http-Anforderung im Rahmen einer neuen TCP-Verbindung vorhanden ist.

Der Hauptnachteil dieses Schemas besteht darin, dass der Server keine Daten an den Client übertragen kann, bis der Client eine neue http-Anforderung sendet. Aber zum Glück gibt es viele Möglichkeiten, dieses Problem zu lösen - das Streaming von Daten über das http-Protokoll (am Ende schaffen wir es irgendwie, unsere Lieblingssendungen im Fernsehen zu sehen und Musik von Portalen zu hören, die auf https laufen, und die Video- und Audioübertragung ist das nicht andere als Streaming-Daten). Eine der Technologien zur Emulation des Betriebs einer vollwertigen TCP-Verbindung über das HTTP-Protokoll ist die WebSockets-Technologie, deren Hauptbestandteil die Organisation einer vollwertigen Netzwerkverbindung zwischen dem Client und dem Webserver ist.

Zu unserem Glück (hurra hurra !!!) ist diese Technologie standardmäßig in allen CloudFlare-Tarifplänen enthalten und funktioniert hervorragend in Kombination mit eSNI. Dies ist genau das, was wir verwenden werden, um unserem Tunnel beizubringen, Domain-Fronts zu verwenden und sich vor modernen DPIs zu verstecken.

Ein bisschen über WebSockets


Zunächst werden wir kurz und in einfachen Worten über Web-Sockets berichten, damit jeder eine Vorstellung davon hat, womit wir arbeiten werden.

Mithilfe der Web-Socket-Technologie können Sie vorübergehend von einer HTTP-Verbindung zu Standard-Streaming-Daten über ein Netzwerk-Socket wechseln, ohne die hergestellte TCP-Verbindung zu unterbrechen. Wenn ein Client zu einem Web-Socket wechseln möchte, legt er in seiner http-Anforderung mehrere http-Header fest. Zwei erforderliche Header sind Connection: Upgrade und Upgrade: Websocket . Es kann auch die Version des Websocket- Protokolls ( Sec-Websockset-Version: 13 ) und so etwas wie die Base64-Web-Socket -ID ( Sec-WebSocket-Key: DAGDJSiREI3 + KjDfwxm1FA == ) erzwingen . Der Server antwortet mit dem HTTP-Code 101 Switching Protocols und setzt auch die Header Connection, Upgrade und Sec-WebSocket-Accept . Der Umschaltvorgang ist im folgenden Screenshot dargestellt:



Danach kann die WebSocket-Verbindung als abgeschlossen betrachtet werden. Alle Daten sowohl vom Client als auch vom Server werden jetzt nicht mehr mit http, sondern mit WebSocket-Headern versorgt (sie beginnen mit Byte 0x82). Jetzt muss der Server nicht mehr auf eine Anfrage vom Client warten, um Daten zu übertragen, wie TCP-Verbindung ist nicht unterbrochen.

Es gibt mehrere Bibliotheken in der Gruppe der Web-Sockets. Die beliebtesten davon sind Gorilla WebSocket und Standard WebSocket . Wir werden letztere verwenden, weil es ist einfacher, kleiner und arbeitet, wie man sagt, etwas schneller.

Im rsockstun-Clientcode müssen die Aufrufe von net.dial oder tls.dial durch die entsprechenden WebSocket-Aufrufe ersetzt werden:





Wir möchten, dass der Client Teil unseres Tunnels wird und sowohl über eine direkte SSL-Verbindung als auch über das WebSockset-Protokoll funktioniert. Dazu erstellen wir analog zu connectForSocks () eine separate Funktion func connectForWsSocks (Adresszeichenfolge, Proxy-Zeichenfolge) error {...} und verwenden sie für die Arbeit mit Web-Sockets, wenn die beim Start des Clients angegebene Serveradresse mit beginnt ws: oder wss: (im Fall von Secure WebSocket).

Für die Serverseite des Tunnels werden wir auch eine separate Funktion für die Arbeit mit Web-Sockets erstellen. Darin wird eine Instanz der http-Klasse erstellt und ein http-Verbindungshandler (wsHandler-Funktion) festgelegt:



Die gesamte Logik für die Verarbeitung der Verbindung (Autorisierung des Clients mit einem Kennwort, Installation und Beendigung der Yamux-Sitzung) wird im WebSocket-Verbindungshandler abgelegt:



Wir kompilieren das Projekt, starten den Serverteil:

./rsockstun –listen ws:127.0.0.1:8080 –pass P@ssw0rd 

Und dann der Client-Teil:

 ./rsockstun -connect ws:127.0.0.1:8080 –pass P@ssw0rd 

Und wir überprüfen die Arbeit auf dem lokalen Host:





Wir gehen zum Domain-Fronting über


Wir scheinen die Web-Sockets geklärt zu haben. Gehen wir jetzt direkt zu eSNI und Domain-Fronts. Wie bereits erwähnt, müssen wir, um mit DoH und eSNI arbeiten zu können, einen speziellen Zweig des Golangs von CloudFlare übernehmen . Wir brauchen eine Filiale mit eSNI-Unterstützung (pwu / esni).

Wir klonen es lokal für uns oder laden die entsprechende Zip herunter und erweitern sie:

 git clone -b pwu/esni https://github.com/cloudflare/tls-tris.git 

Dann müssen wir das GOROOT-Verzeichnis kopieren, die entsprechenden Dateien aus dem geklonten Zweig ersetzen und als Hauptverzeichnis festlegen. Um dem Entwickler diese Kopfschmerzen zu ersparen, haben die Leute von CloudFlare ein spezielles Skript vorbereitet - _dev / go.sh. Lass es einfach laufen. Das Skript zusammen mit dem Makefile erledigt alles selbst. Zum Spaß - Sie können im Makefile nach Details suchen.

Nach dem Ausarbeiten des Skripts müssen wir beim Kompilieren des Projekts das vom Skript vorbereitete lokale Verzeichnis als GOROOT angeben. In unserem Fall sieht es so aus:

 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" go build …. 

Als nächstes müssen wir im Tunnel die Funktionalität implementieren, öffentliche eSNI-Schlüssel für die gewünschte Domain anzufordern und zu analysieren. In unserem Fall sind dies öffentliche eSNI-Schlüssel von CloudFlare-Front-End-Servern. Dazu erstellen wir drei Funktionen:

 func makeDoTQuery(dnsName string) ([]byte, error) func parseTXTResponse(buf []byte, wantName string) (string, error) func QueryESNIKeysForHost(hostname string) ([]byte, error) 

Die Namen der Funktionen sprechen grundsätzlich für sich. Wir werden die Füllung der Datei esni_query.go entnehmen, die Teil von tls-tris ist. Die erste Funktion erstellt ein Netzwerkpaket mit einer Anforderung an den CloudFlare-DNS-Server unter Verwendung des DoH-Protokolls (DNS-over-HTTPS), die zweite Funktion analysiert die Abfrageergebnisse und empfängt die Werte der öffentlichen Domänenschlüssel, und die dritte Funktion ist ein Container für die ersten beiden.

Als Nächstes führen wir die Funktion zum Anfordern von eSNI-Schlüsseln für die Domäne in unsere neu erstellte Verbindungsfunktion für den Web-Socket connectForWsSocks ein . Wenn der Serverteil funktioniert, legen Sie die TLS-Parameter und den Namen der gefälschten "Cover-Domain" fest:



Hierbei ist zu beachten, dass der tls-tris-Zweig zunächst nicht für die Verwendung von Domain-Fronting ausgelegt war. Daher wird der falsche Name des Servers nicht berücksichtigt (ein leeres Feld serverName wird als Teil des Client-Hallo-Pakets übertragen). Um dies zu beheben, müssen wir der TlsConfig-Struktur das entsprechende FakeServerName-Feld hinzufügen. Wir können das Standardfeld ServerName der Struktur nicht verwenden, weil es wird von internen tls-mechanismen verwendet und wenn es vom original abweicht, endet der tls-handshake mit einem fehler. Die Beschreibung der TlsConfig-Struktur ist in der Datei tls / common.go enthalten - wir müssen sie korrigieren :





Außerdem müssen wir Änderungen an der Datei tls / handshake_client.go vornehmen , um unser Feld FakeServerName beim Generieren des TLS-Handshakes zu verwenden:



Das ist alles! Sie können das Projekt kompilieren und die Arbeit überprüfen. Bevor Sie den Test ausführen, müssen Sie jedoch Ihr CloudFlare-Konto konfigurieren. Nun, wie sagen Sie zum Einrichten - erstellen Sie einfach ein Cloudflare-Konto und binden Sie Ihre Domain daran. Alle mit DoH, WebSocket und ESNI verbundenen Chips sind standardmäßig in CloudFlare enthalten. Nachdem die DNS-Einträge aktualisiert wurden, können Sie die Domäne überprüfen, indem Sie die eSNI-Schlüsselanforderung ausführen:

 dig +short txt _esni.df13tester.info 



Wenn Sie für Ihre Domain etwas Ähnliches sehen, funktioniert alles für Sie und Sie können mit dem Testen fortfahren.

Starten Sie Ubuntu VPS beispielsweise auf DigitalOcean. PS In unserem Fall stand die gerade vom Provider vergebene VPS-IP-Adresse auf der ILV-Sperrliste. Wundern Sie sich also nicht, wenn Ihnen etwas Ähnliches passiert. Ich musste ein VPN verwenden, um zu meinem VPS zu gelangen.

Wir kopieren das kompilierte rsockstun nach VPS (das ist übrigens ein weiterer Reiz des Golangs - Sie können das Projekt selbst kompilieren und es unter jedem Linux ausführen, wobei Sie nur die Bitkapazität des Systems beachten) und starten den Serverteil:



Und dann der Client-Teil:



Wie wir sehen können, hat der Client über den CloudFlare-Front-End-Server über einen Web-Socket erfolgreich eine Verbindung zum Server hergestellt. Um zu überprüfen, ob der Tunnel genau wie ein Tunnel funktioniert, können Sie über die auf dem Server geöffneten lokalen Socks5 eine Aufrollanforderung stellen:



Nun wollen wir sehen, was DPI im Kommunikationskanal sieht:



Zunächst greift der Tunnel-Tuner mithilfe des DoH-Mechanismus auf den Cloudflare-DNS-Server für eSNI-Schlüssel für die Zieldomäne (Pakete Nr. 1-19) zu, greift dann auf den Front-End-Server zu und stellt eine TLS-Verbindung her, die sich unter der Domain www.google.com (dieser Wert) versteckt Standardmäßig, wenn beim Client-Start keine gefälschte Domäne festgelegt wurde. Um Ihre gefälschte Domain anzugeben, müssen Sie den Parameter -fronfDomain verwenden:





Nun noch eine Sache. Standardmäßig sind die Kontoeinstellungen von CloudFalre auf Flexible SSL eingestellt. Dies bedeutet, dass https-Anforderungen von Clients an Cloudflare-Front-End-Server unverschlüsselt (http) an unseren Server umgeleitet werden. Aus diesem Grund haben wir den Serverteil des Tunnels im Nicht-SSL-Modus gestartet (-listen ws: 0.0.0.0) und nicht (-listen wss: 0.0.0.0).



Um in den vollständigen Verschlüsselungsmodus zu wechseln, müssen Sie Vollständig oder Vollständig (streng) auswählen, wenn dieses Zertifikat auf dem Server vorhanden ist. Nach dem Umschalten des Modus können wir Verbindungen von CloudFlare über das https-Protokoll akzeptieren. Denken Sie daran, ein selbstsigniertes Zertifikat für die Serverseite des Tunnels zu generieren.



Ein nerviger Leser fragt: „Was ist mit dem Kundenkonto unter Windows? In der Tat besteht die Hauptanwendung des Tunnels darin, die Verbindung von Unternehmenscomputern und -servern aus wiederherzustellen. In der Regel handelt es sich dabei immer um Windows. Wie kann ich einen Tunnel für Windows und sogar mit einem bestimmten TLS-Stack kompilieren? “Und jetzt werden wir einen weiteren Chip vorstellen, der zeigt, wie praktisch der Golang ist. Wir kompilieren Fenster direkt aus Kali, indem wir einfach den Parameter GOOS = windows hinzufügen:

 GOARCH=amd64 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows go build -ldflags="-s -w" 

Oder eine 32-Bit-Option:

 GOARCH=386 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows go build -ldflags="-s -w" 

Das ist alles! Und es sind keine Probleme mehr nötig. Das funktioniert wirklich!



Die Compiler-Flags –w und –s werden benötigt, um überschüssigen Datenmüll aus der ausführbaren Datei zu entfernen und um einige Megabyte zu reduzieren. Außerdem kann es dann mit UPX verpackt werden, um die Größe weiter zu verringern.

Anstelle einer Schlussfolgerung


In dem Artikel haben wir anhand eines auf einem Golang geschriebenen Tuner-Beispiels die Verwendung der neuen Technologie des Domain-Fronting demonstriert, die auf einem ziemlich interessanten Merkmal des TLS 1.3-Protokolls implementiert ist. In ähnlicher Weise können Sie das vorhandene Toolkit, das auf dem Golang geschrieben ist, so anpassen, dass es über den CloudFlare-Server funktioniert, z. B. Merlin , das bekannte C2, oder CobaltStrike Beacon zur Verwendung von eSNI-Domänenfronten zwingen, wenn Sie mit Teamserver über den auf dem Golang implementierten externen C2-Kanal oder unter Verwendung von Standard C ++ arbeiten die gepatchte Version von OpenSSL, über die wir im letzten Teil des Artikels gesprochen haben. Der Fantasie sind im Allgemeinen keine Grenzen gesetzt.

Das Beispiel des Tunnels und von CloudFlare wird in Form eines Konzepts dargestellt, und es ist immer noch schwer zu sagen, wie weit die Aussichten für diese Art von Domain-Front-Facing sind. Derzeit ist die Unterstützung für eSNI nur bei CloudFlare verfügbar. Grundsätzlich hindert sie nichts daran, diese Art von Front-End zu deaktivieren und z. B. die tls-Verbindungen zu trennen, wenn SNI und eSNI nicht übereinstimmen. Im Allgemeinen wird die Zukunft zeigen. Aber im Moment scheint die Aussicht, unter dem Deckmantel von kremlin.ru zu arbeiten, ziemlich attraktiv zu sein. Oder?

Der aktualisierte Tunnelcode sowie kompilierte ausführbare EXE-Dateien befinden sich in einem separaten Projektzweig auf Github . Es ist besser, ein Problem mit allen möglichen Tunnelproblemen auf der Projektseite von GitHub zu schreiben.

Source: https://habr.com/ru/post/de477696/


All Articles