Domain Fronting sur la base de TLS 1.3. Partie 2

Introduction

Dans la première partie article nous avons donné une brève description du mécanisme de SNI chiffré (eSNI). Nous avons montré comment il est possible d'échapper à la détection par des systèmes DPI modernes (à l'aide de l'exemple du DPI de Beeline et du tracker interdit par le RKN), et avons également exploré une nouvelle variante de domain fronting basée sur ce mécanisme.

Dans la deuxième partie de l'article, nous passerons à des aspects plus pratiques qui seront utiles aux spécialistes de RedTeam dans leur travail difficile. Après tout, notre objectif n'est pas d'accéder à des ressources bloquées (pour de telles choses banales, nous avons le vieux bon VPN). Heureusement, il existe de nombreux fournisseurs de VPN, comme on dit, pour tous les goûts, couleurs et budgets.

Nous essaierons d'appliquer le mécanisme de domain fronting à des outils modernes de RedTeam, tels que Cobalt Strike, Empire, etc., pour leur donner des capacités supplémentaires en matière de mimétisme et d'évasion des systèmes de filtrage de contenu modernes.

La dernière fois, nous avons intégré le mécanisme eSNI dans la bibliothèque OpenSSL et l'avons utilisé avec succès dans l'outil bien connu curl. Mais le simple curl, comme on dit, ne suffit pas. Bien sûr, nous aimerions réaliser quelque chose de similaire dans des langages de haut niveau. Cependant, une recherche rapide sur le web nous déçoit, car le support du mécanisme eSNI est pleinement réalisé uniquement dans GOLANG. Ainsi, nous n'avons pas beaucoup de choix : soit nous écrivons en pur C ou C++ en utilisant une bibliothèque OpenSSL patchée, soit nous utilisons un fork séparé de GOLANG par CloudFlare et essayons de porter nos outils là-bas. En principe, il y a une autre option, plus classique, mais en même temps laborieuse - mettre en œuvre le support de l'eSNI pour Python. Après tout, Python utilise également OpenSSL pour fonctionner avec https. Mais nous laisserons cette option à un autre développeur, et nous nous contenterons de la mise en œuvre en golang, d'autant plus que notre cher Cobalt Strike sait parfaitement travailler avec un canal de communication construit par des moyens tiers (External C2 channel) - nous en parlerons à la fin de l'article.

Try Harder…

Un des outils réalisés en Go - notre développement pour le pivotement à l'intérieur du réseau - un tunnel rsockstun, qui, soit dit en passant, est actuellement détecté par les outils de Microsoft et Symantec comme un logiciel malveillant très dangereux, visant à perturber la stabilité mondiale…

Domain Fronting sur la base de TLS 1.3. Partie 2

Il serait formidable d'utiliser le développement précédent dans ce cas. Mais ici, une petite problème se pose. En effet, rsockstun suppose à l'origine l'utilisation d'un canal SSL synchrone de communication avec le serveur. Cela signifie que la connexion est établie une fois et existe pendant toute la durée de fonctionnement du tunnel. Comme vous le comprenez, le protocole https n'est pas vraiment conçu pour ce mode de fonctionnement – il fonctionne en mode requête-réponse, où chaque nouvelle requête http existe dans le cadre d'une nouvelle connexion tcp.

Le principal inconvénient de ce schéma est que le serveur ne peut pas transmettre de données au client tant que le client n'envoie pas une nouvelle requête http. Mais heureusement, il existe de nombreuses solutions à ce problème – la transmission en continu de données via le protocole http (après tout, nous parvenons à regarder nos séries préférées et à écouter de la musique sur des portails fonctionnant sous https, et la transmission vidéo et audio n'est rien d'autre qu'une transmission de données en continu). L'une des technologies permettant d'émuler le fonctionnement d'une connexion tcp complète au-dessus du protocole http est la technologie des web-sockets (WebSockets), dont l'essence réside dans l'établissement d'une connexion réseau complète entre le client et le serveur web.

Par chance (hourra!!!), cette technologie est activée par défaut dans tous les plans tarifaires de CloudFlare et fonctionne très bien en combinaison avec eSNI. C'est précisément celle-ci que nous allons utiliser pour enseigner à notre tunnelier comment utiliser le domain fronting et se cacher des DPI modernes.

Quelques mots sur les WebSockets

Tout d'abord, nous allons brièvement et simplement expliquer ce qu'est un web-socket, afin que tout le monde ait une idée de ce avec quoi nous allons travailler.

La technologie des web-sockets permet de basculer temporairement d'une connexion http à une transmission de données standard via un socket réseau, sans rompre la connexion tcp établie. Lorsque le client souhaite passer au web-socket, il définit plusieurs en-têtes http dans sa requête http. Deux en-têtes obligatoires sont Connection: Upgrade et Upgrade: websocket. Il peut également spécifier de manière forcée la version du protocole websocket (Sec-Websockset-Version: 13) et quelque chose comme un identifiant base64 de WebSocket (Sec-WebSocket-Key: DAGDJSiREI3+KjDfwxm1FA==). Le serveur répond par le code HTTP 101 Switching Protocols et en établissant également les en-têtes Connection, Upgrade et Sec-WebSocket-Accept. Le processus de commutation est illustré sur l'image ci-dessous :

Domain Fronting sur la base de TLS 1.3. Partie 2

Après cela, l'établissement de la connexion WebSocket peut être considéré comme terminé. Toutes les données, qu'elles proviennent du client ou du serveur, seront désormais accompagnées non pas d'en-têtes HTTP, mais d'en-têtes WebSocket (commençant par le byte 0x82). Le serveur n'a plus besoin d'attendre une demande du client pour transmettre des données, car la connexion TCP ne se coupe pas.

En Go, il existe plusieurs bibliothèques pour travailler avec les WebSockets. Les plus populaires sont Gorilla WebSocket et la standard WebSocket. Nous utiliserons la dernière, car elle est plus simple, plus légère et, dit-on, un peu plus rapide.

Dans le code du client rsockstun, nous devons remplacer les appels à net.dial ou tls.dial par les appels WebSocket correspondants :

Domain Fronting sur la base de TLS 1.3. Partie 2

Domain Fronting sur la base de TLS 1.3. Partie 2

Nous voulons rendre la partie client de notre tunnel universelle et capable de fonctionner aussi bien via une connexion SSL directe que via le protocole WebSocket. Pour cela, nous créerons une fonction distincte func connectForWsSocks(address string, proxy string) error {…} par analogie avec connectForSocks() et nous l'utiliserons pour travailler avec les WebSockets si l'adresse du serveur spécifiée au lancement du client commence par ws: ou wss: (dans le cas de WebSocket sécurisé).

Pour la partie serveur du tunnel, nous ferons également une fonction distincte pour travailler avec les WebSockets. Dans celle-ci, une instance de la classe http sera créée et un gestionnaire de connexion http sera défini (la fonction wsHandler) :

Domain Fronting sur la base de TLS 1.3. Partie 2

Et toute la logique de traitement de la connexion (authentification du client par mot de passe, établissement et terminaison de la session yamux) sera placée dans le gestionnaire de la connexion WebSocket :

Domain Fronting sur la base de TLS 1.3. Partie 2

Nous compilons le projet, démarrons la partie serveur :

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

Et ensuite la partie client :

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

Et nous vérifions le fonctionnement sur l'hôte local :

Domain Fronting sur la base de TLS 1.3. Partie 2

Domain Fronting sur la base de TLS 1.3. Partie 2

Passons au domaine fronting

Nous semblons avoir compris les WebSockets. Maintenant, passons directement à eSNI et au domaine fronting. Comme mentionné précédemment, pour travailler avec DoH et eSNI, nous devons prendre une branche spéciale de Go de la société CloudFlare. Nous avons besoin d'une branche avec le support eSNI (pwu/esni).

Clonez-la localement ou téléchargez et dézippez le zip correspondant :

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

Ensuite, nous devons copier le répertoire GOROOT, remplacer les fichiers appropriés de la branche clonée et le définir comme principal. Pour soulager les développeurs de cette tâche pénible, les gars de CloudFlare ont préparé un script spécial – _dev/go.sh. Il suffit de l'exécuter. Le script fera tout seul avec le makefile. Par curiosité, vous pouvez jeter un œil à l'intérieur du makefile pour plus de détails.

Après l'exécution du script, lors de la compilation du projet, nous devrons indiquer comme GOROOT le répertoire local préparé par le script. Dans notre cas, cela ressemble à :

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

Ensuite, nous devons implémenter dans le tunnel la fonctionnalité de requête et de parsing des clés eSNI publiques pour le domaine souhaité. Dans notre cas, ce seront les clés eSNI publiques des serveurs frontaux CloudFlare. Pour cela, nous allons créer trois fonctions :

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

Les noms des fonctions parlent d'eux-mêmes. Nous allons remplir cela à partir du fichier esni_query.go, qui fait partie de tls-tris. La première fonction crée un paquet réseau avec une requête vers le serveur DNS de CloudFlare, en utilisant le protocole DoH (DNS-over-HTTPS), la seconde analyse les résultats de la requête et obtient les valeurs des clés publiques du domaine, et la troisième est un conteneur pour les deux premières.

Ensuite, nous intégrons dans notre fonction nouvellement créée pour la connexion WebSocket connectForWsSocks la fonctionnalité de requête des clés eSNI pour le domaine. Là où fonctionne la partie serveur, nous définissons les paramètres TLS et spécifions le nom du « domaine de couverture » fictif :

Domain Fronting sur la base de TLS 1.3. Partie 2

Il convient de noter que, à l'origine, la branche tls-tris n'est pas conçue pour l'utilisation de domain fronting. Par conséquent, aucune attention n'est accordée au nom de serveur fictif (un champ vide serverName est transmis dans le paquet client-hello). Pour corriger cela, nous devrons ajouter dans la structure TlsConfig le champ correspondant FakeServerName. Nous ne pouvons pas utiliser le champ standard ServerName de la structure, car il est utilisé par les mécanismes internes de tls et s'il diffère de l'original, le tls-handshake échouera avec une erreur. La description de la structure TlsConfig se trouve dans le fichier tls/common.go – et nous devrons le corriger :

Domain Fronting sur la base de TLS 1.3. Partie 2

Domain Fronting sur la base de TLS 1.3. Partie 2

De plus, nous devrons apporter des modifications au fichier tls/handshake_client.go, pour utiliser notre champ FakeServerName lors de la formation du handshake TLS :

Domain Fronting sur la base de TLS 1.3. Partie 2

C'est tout ! Vous pouvez compiler le projet et vérifier son fonctionnement. Mais avant de lancer le test, il est nécessaire de configurer le compte CloudFlare. Comment dire, configurer – il suffit de créer un compte sur CloudFlare et de lier votre domaine à celui-ci. Toutes les fonctionnalités liées à DoH, WebSocket et ESNI sont activées par défaut dans CloudFlare. Après que les enregistrements DNS aient été mis à jour, vous pouvez vérifier le fonctionnement du domaine en exécutant une requête pour les clés eSNI :

dig +short txt _esni.df13tester.info 

Domain Fronting sur la base de TLS 1.3. Partie 2

Si vous voyez quelque chose de similaire pour votre domaine, cela signifie que tout fonctionne et que vous pouvez passer aux tests.

Démarrons un VPS Ubuntu, par exemple, sur DigitalOcean. P.S. Dans notre cas, l'adresse IP fournie par le fournisseur s'est retrouvée sur des listes noires RKN. Donc, ne soyez pas surpris si vous vivez quelque chose de similaire. J'ai dû utiliser un VPN pour accéder à mon VPS.

Nous copions rsockstun déjà compilé sur le VPS (c'est d'ailleurs un autre atout de Golang – vous pouvez compiler le projet chez vous et le lancer sur n'importe quel Linux, en respectant simplement l'architecture du système) et démarrons la partie serveur :

Domain Fronting sur la base de TLS 1.3. Partie 2

Et ensuite, la partie client :

Domain Fronting sur la base de TLS 1.3. Partie 2

Comme nous le voyons, le client s'est connecté avec succès au serveur via le serveur frontal CloudFlare en utilisant WebSocket. Pour vérifier que le tunnel fonctionne vraiment comme un tunnel, vous pouvez faire une requête curl à travers le proxy socks5 local ouvert sur le serveur :

Domain Fronting sur la base de TLS 1.3. Partie 2

Voyons maintenant ce que DPI voit dans le canal de communication :

Domain Fronting sur la base de TLS 1.3. Partie 2

D'abord, le tunnelier, en utilisant le mécanisme DoH, se connecte au serveur DNS de Cloudflare pour obtenir les clés eSNI pour le domaine cible (paquets n°1-19), puis il se connecte au serveur frontal et établit une connexion TLS, se cachant ainsi derrière le domaine www.google.com (c'est la valeur par défaut lorsque le domaine factice n'est pas spécifié lors du lancement du client). Pour indiquer votre propre domaine factice, vous devez utiliser le paramètre -frontDomain :

Domain Fronting sur la base de TLS 1.3. Partie 2

Domain Fronting sur la base de TLS 1.3. Partie 2

Maintenant, un autre point. Par défaut, les paramètres du compte sur CloudFlare sont réglés sur le mode SSL Flexible. Cela signifie que les requêtes https aux serveurs frontaux Cloudflare des clients seront redirigées vers notre serveur sous forme non chiffrée (http). C'est pourquoi nous avons démarré la partie serveur du tunnel en mode non-ssl ( -listen ws:0.0.0.0), et non ( -listen wss:0.0.0.0).

Domain Fronting sur la base de TLS 1.3. Partie 2

Pour passer en mode de chiffrement complet, vous devez choisir Complet, ou Complet (strict) en cas de présence d'un certificat valide sur le serveur. Après le changement de mode, nous pourrons accepter des connexions de CloudFlare via le protocole https. N'oubliez pas de générer un certificat auto-signé pour la partie serveur du tunnel.

Domain Fronting sur la base de TLS 1.3. Partie 2

Un lecteur curieux demandera : « Et pour le client sous Windows ? Après tout, l'utilisation principale du tunnel est de mettre en place un back-connect avec des machines et serveurs d'entreprise, où il y a généralement du Windows. Comment puis-je compiler le tunnel pour Windows, avec une pile TLS spécifique ? » Maintenant, imaginons une autre caractéristique qui montre à quel point Golang est pratique. Nous allons compiler pour Windows directement depuis Kali, simplement en ajoutant le paramètre GOOS=windows :

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

Ou la version 32 bits :

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

C'est tout ! Et plus aucun tracas n'est nécessaire. Cela fonctionne réellement !

Domain Fronting sur la base de TLS 1.3. Partie 2

Les flags de compilation –w et –s sont nécessaires pour enlever les données inutiles du fichier exécutable, le rendant plus léger de quelques mégaoctets. De plus, il peut être empaqueté avec UPX, pour réduire encore davantage sa taille.

En conclusion

Dans cet article, nous avons illustré, à travers un exemple de tunnel écrit en Golang, l'application d'une nouvelle technologie de fronting de domaine, réalisée sur une caractéristique assez intéressante du protocole TLS 1.3. De manière similaire, il est possible d'adapter des outils existants écrits en Golang pour fonctionner via les serveurs CloudFlare, par exemple Merlin — un C2 bien connu, ou de forcer CobaltStrike Beacon à utiliser le fronting de domaine eSNI lors de l'interaction avec le Teamserver via External C2 Channel, réalisé en Golang, ou sur une version standard en C++ en utilisant une version patchée d'OpenSSL, dont nous avons parlé dans la première partie de l'article. En général, l'imagination n'a pas de limites.

L'exemple du tunnel et de CloudFlare est présenté sous forme de concept et il est encore difficile de dire quelles seront les perspectives futures de ce type de fronting de domaine. Actuellement, le support de l'eSNI n'est activé que sur CloudFlare et, a priori, rien ne les empêche de désactiver ce type de fronting et, par exemple, de rompre les connexions tls en cas de non-correspondance entre SNI et eSNI. En résumé, l'avenir le dira. Mais pour l'instant, la perspective de travailler sous "couvercle kremlin.ru" semble plutôt séduisante. N'est-ce pas ?

Le code mis à jour du tunnel ainsi que les fichiers exécutables exe compilés sont placés dans une branche distincte du projet sur github. Pour toute problème potentiel lié au tunnel, il est préférable de soumettre un problème sur la page du projet sur GitHub.

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster