Domaine frontal basé sur TLS 1.3. 2e partie

Présentation


Dans la première partie de l' article, nous avons donné une brève description du mécanisme SNI chiffré (eSNI). Ils ont montré comment, sur sa base, il est possible d'échapper à la détection par les systèmes DPI modernes (en utilisant le DPI Beeline et le rutracker ILV interdit comme exemple), ainsi qu'en explorant une nouvelle version du front-end de domaine basé sur ce mécanisme.

Dans la deuxième partie de l'article, nous allons passer à des choses plus pratiques que RedTeam sera utile aux spécialistes dans leur travail difficile. En fin de compte, notre objectif n'est pas d'accéder aux ressources bloquées (pour de telles choses courantes, nous avons un bon vieux 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 gestion de domaine aux outils RedTeam modernes, tels que Cobalt Strike, Empire, etc., et leur donnerons des opportunités supplémentaires pour imiter et échapper aux systèmes de filtrage de contenu modernes.

La dernière fois, nous avons implémenté le mécanisme eSNI dans la bibliothèque OpenSSL et l'avons utilisé avec succès dans l'utilitaire curl familier. Mais une boucle, comme on dit, ne sera pas pleine. Bien sûr, je veux implémenter quelque chose de similaire dans les langages de haut niveau. Mais, malheureusement, une recherche rapide de l'immensité du réseau nous déçoit, car la prise en charge du mécanisme eSNI n'est pleinement implémentée que dans GOLANG. Ainsi, notre choix n'est pas très large: soit nous écrivons en C ou C ++ pur en utilisant la bibliothèque OpenSSL patché, soit nous utilisons un fork GOLANG distinct de CloudFlare et essayons d'y porter nos outils. En principe, il existe une autre option, plus classique, mais qui prend également beaucoup de temps - est d'implémenter le support eSNI pour python. Après tout, Python utilise également OpenSSL pour fonctionner avec https. Mais nous laisserons cette option de développement à quelqu'un d'autre, et nous nous contenterons de la mise en œuvre sur le Golang, d'autant plus que notre bien-aimé Cobalt Strike est parfaitement capable de travailler avec un canal de communication construit par des outils tiers (canal C2 externe) - nous en parlerons à la fin de l'article.

Essayez plus fort ...


L'un des outils mis en œuvre sur Go est notre développement pour pivoter à l'intérieur du réseau - le tuner rsockstun, qui, incidemment, est maintenant détecté par les outils Microsoft et Symantec comme un logiciel très malveillant visant à violer la stabilité mondiale ...



Ce serait formidable d'utiliser le développement précédent dans ce cas. Mais ici, un petit problème se pose. Le fait est que rsockstun implique initialement l'utilisation d'un canal de communication SSL synchrone avec le serveur. Cela signifie que la connexion est établie une fois et existe pour toute la durée de l'opération du tunnel. Et, comme vous le comprenez, le protocole https n'est pas conçu pour ce mode de fonctionnement - il fonctionne dans le 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 transférer de données au client jusqu'à ce que le client envoie une nouvelle requête http. Mais, heureusement, il existe de nombreuses options pour résoudre ce problème - la diffusion de données via le protocole http (à la fin, nous parvenons à regarder nos émissions de télévision préférées et à écouter de la musique à partir de portails fonctionnant sur https, et la transmission vidéo et audio n'est pas que autres que le streaming de données). L'une des technologies permettant d'émuler le fonctionnement d'une connexion TCP à part entière sur le protocole http est la technologie WebSockets, dont l'essence principale est l'organisation d'une connexion réseau à part entière entre le client et le serveur Web.

À notre chance (hourra hourra !!!), cette technologie est incluse par défaut dans tous les plans tarifaires CloudFlare et fonctionne très bien en combinaison avec eSNI. C'est exactement ce que nous allons utiliser pour apprendre à notre tunnel à utiliser les fronts de domaine et à se cacher des DPI modernes.

Un peu sur les WebSockets


Tout d'abord, nous parlerons brièvement et en termes simples des sockets Web afin que tout le monde ait une idée de ce avec quoi nous travaillerons.

La technologie de socket Web vous permet de passer temporairement d'une connexion http à des données de streaming standard sur une socket réseau sans interrompre la connexion TCP établie. Lorsqu'un client souhaite passer à une socket Web, il définit plusieurs en-têtes http dans sa requête http. Deux en-têtes requis sont Connection: Upgrade et Upgrade: websocket . Il peut également forcer la version du protocole websocket ( Sec-Websockset-Version: 13 ) et quelque chose comme l'identificateur de socket web base64 ( Sec-WebSocket-Key: DAGDJSiREI3 + KjDfwxm1FA == ). Le serveur répond avec des protocoles de commutation http-code 101 et définit également les en - têtes Connection, Upgrade et Sec-WebSocket-Accept . Le processus de commutation est illustré dans la capture d'écran ci-dessous:



Après cela, la connexion WebSocket peut être considérée comme terminée. Toutes les données du client et du serveur seront désormais fournies non pas avec http, mais avec les en-têtes WebSocket (ils commencent par l'octet 0x82). Maintenant, le serveur n'a pas besoin d'attendre une demande du client pour transférer des données, comme la connexion TCP n'est pas interrompue.

Il existe plusieurs bibliothèques dans le gang des sockets Web. Les plus populaires d'entre eux sont Gorilla WebSocket et WebSocket standard. Nous utiliserons ce dernier, car il est plus simple, plus petit et fonctionne, comme on dit, un peu plus vite.

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





Nous voulons rendre la partie client de notre tunnel universelle et capable de fonctionner à la fois via une connexion SSL directe et via le protocole WebSockset. Pour ce faire, nous allons créer une fonction distincte func connectForWsSocks (chaîne d'adresse, chaîne proxy) erreur {...} par analogie avec connectForSocks () et nous l'utiliserons pour travailler avec les sockets Web si l'adresse du serveur spécifiée au démarrage du client commence par ws: ou wss: (dans le cas de Secure WebSocket).

Pour le côté serveur du tunnel, nous allons également créer une fonction distincte pour travailler avec les sockets Web. Une instance de la classe http y sera créée et un gestionnaire de connexion http (fonction wsHandler) sera défini:



Et nous mettrons toute la logique de traitement de la connexion (autoriser le client avec un mot de passe, installer et terminer la session yamux) dans le gestionnaire de connexion WebSocket:



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

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

Et puis la partie client:

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

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





On passe au domaine-fronting


Nous semblons avoir réglé les sockets Web. Passons maintenant directement à l'eSNI et aux fronts de domaine. Comme mentionné précédemment, pour travailler avec DoH et eSNI, nous devons prendre une branche spéciale du golang de CloudFlare . Nous avons besoin d'une branche avec le support eSNI (pwu / esni).

Nous le clonons pour nous localement ou téléchargeons et développons 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 correspondants de la branche clonée et le définir comme principal. Pour sauver le développeur de ce mal de tête, les gars de CloudFlare ont préparé un script spécial - _dev / go.sh. Il suffit de l'exécuter. Le script et le makefile feront tout eux-mêmes. Pour le plaisir - vous pouvez regarder à l'intérieur du makefile pour plus de détails.

Après avoir élaboré le 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 à ceci:

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

Ensuite, nous devons implémenter dans le tunnel la fonctionnalité de demande et d'analyse des clés eSNI publiques pour le domaine souhaité. Dans notre cas, il s'agira de clés eSNI publiques des serveurs frontaux CloudFlare. Pour ce faire, 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 en principe d'eux-mêmes. Nous prendrons le remplissage du fichier esni_query.go, qui fait partie de tls-tris. La première fonction crée un paquet réseau avec une demande au serveur DNS CloudFlare en utilisant le protocole DoH (DNS-over-HTTPS), la seconde analyse les résultats de la requête et reçoit les valeurs des clés du domaine public, et la troisième est un conteneur pour les deux premières.

Ensuite, nous introduisons la fonction de demande de clés eSNI pour le domaine dans notre fonction de connexion nouvellement créée pour la socket Web connectForWsSocks . Lorsque la partie serveur fonctionne, définissez les paramètres TLS et définissez également le nom du faux "domaine de couverture":



Il convient de noter ici qu'au départ, la branche tls-tris n'a pas été conçue pour l'utilisation de la façade de domaine. Par conséquent, il ne fait pas attention au faux nom du serveur (un champ serverName vide est transmis dans le cadre du package client-hello). Afin de résoudre ce problème, nous devrons ajouter le champ FakeServerName correspondant à la structure TlsConfig. Nous ne pouvons pas utiliser le champ ServerName standard de la structure, car il est utilisé par les mécanismes internes tls et s'il diffère de l'original, la poignée de main tls se terminera par une erreur. La description de la structure TlsConfig est contenue dans le fichier tls / common.go - nous devons la corriger:





De plus, nous devrons apporter des modifications au fichier tls / handshake_client.go pour utiliser notre champ FakeServerName lors de la génération de la négociation TLS:



C’est tout! Vous pouvez compiler le projet et vérifier le travail. Mais avant d'exécuter le test, vous devez configurer votre compte CloudFlare. Eh bien, comment dites-vous de configurer - créez simplement un compte cloudflare et liez votre domaine à celui-ci. Toutes les puces liées à DoH, WebSocket et ESNI sont incluses dans CloudFlare par défaut. Une fois les enregistrements DNS mis à jour - vous pouvez vérifier le domaine en exécutant la demande de clé eSNI:

 dig +short txt _esni.df13tester.info 



Si vous voyez quelque chose de similaire pour votre domaine, alors tout fonctionne pour vous et vous pouvez procéder aux tests.

Lancez Ubuntu VPS, par exemple, sur DigitalOcean. PS Dans notre cas, l'adresse IP VPS qui vient d'être émise par le fournisseur figurait dans les listes noires ILV. Ne soyez donc pas surpris si quelque chose de similaire vous arrive. J'ai dû utiliser un VPN pour accéder à mon VPS.

Nous copions le rsockstun compilé sur VPS (c'est d'ailleurs un autre charme du golang - vous pouvez compiler le projet par vous-même et l'exécuter sur n'importe quel Linux, en observant uniquement la capacité en bits du système) et démarrer la partie serveur:



Et puis la partie client:



Comme nous pouvons le voir, le client s'est connecté avec succès au serveur via le serveur frontal CloudFlare à l'aide d'un socket Web. Pour vérifier que le tunnel fonctionne exactement comme un tunnel, vous pouvez faire une demande de boucle via les socks5 locaux ouverts sur le serveur:



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



Tout d'abord, le tuner tunnel, en utilisant le mécanisme DoH, accède au serveur DNS Cloudflare pour les clés eSNI pour le domaine de destination (packages n ° 1-19), puis accède au serveur frontal et établit une connexion TLS, se cachant sous le domaine www.google.com (cette valeur par défaut, lorsqu'un faux domaine n'est pas défini au démarrage du client). Pour spécifier votre faux domaine, vous devez utiliser le paramètre -fronfDomain:





Maintenant encore une chose. Par défaut, les paramètres de compte de CloudFalre sont définis sur SSL flexible. Cela signifie que les demandes https vers les serveurs frontaux Cloudflare des clients seront redirigées sous forme non chiffrée (http) vers notre serveur. C'est pourquoi nous avons lancé la partie serveur du tunnel en mode non ssl (-listen ws: 0.0.0.0), et non (-listen wss: 0.0.0.0).



Afin de passer en mode de cryptage complet, vous devez sélectionner Complet , ou Complet (strict) en cas de présence de ce certificat sur le serveur. Après avoir changé de mode, nous pourrons accepter les connexions de CloudFlare via le protocole https. N'oubliez pas de générer un certificat auto-signé pour le côté serveur du tunnel.



Un lecteur ennuyeux demandera: «Qu'en est-il du compte client sous Windows? En effet, à coup sûr, l'application principale du tunnel est de relancer la connexion à partir des machines et des serveurs d'entreprise, et là, en règle générale, c'est toujours Windows. Comment puis-je compiler un tunnel pour Windows, et même avec une pile TLS spécifique? »Et maintenant, nous allons présenter une autre puce qui montre à quel point le golang est pratique. Nous compilons pour les fenêtres directement à partir de 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 une option 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 problème n'est nécessaire. Ça marche vraiment!



Les indicateurs de compilateur –w et –s sont nécessaires pour supprimer les déchets excédentaires du fichier exécutable, ce qui le réduit de quelques mégaoctets. De plus, il peut ensuite être conditionné à l'aide d'UPX pour réduire davantage la taille.

Au lieu d'une conclusion


Dans l'article, nous, en utilisant un exemple de tuner écrit sur un golang, avons clairement démontré l'utilisation de la nouvelle technologie de fronting de domaine, implémentée sur une fonctionnalité plutôt intéressante du protocole TLS 1.3. De même, vous pouvez adapter la boîte à outils existante écrite sur le golang pour qu'elle fonctionne via le serveur CloudFlare, par exemple Merlin , le célèbre C2, ou forcer CobaltStrike Beacon à utiliser les fronts de domaine eSNI lorsque vous travaillez avec Teamserver via le canal C2 externe , implémenté sur le golang, ou sur le C ++ standard à l'aide de la version corrigée d'OpenSSL, dont nous avons parlé dans la dernière partie de l'article. En général, la fantaisie n'a pas de limites.

L'exemple du tunnel et de CloudFlare est présenté sous la forme d'un concept et il est encore difficile de dire sur les perspectives lointaines de ce type de front de domaine. Pour le moment, la prise en charge eSNI n'est disponible que sur CloudFlare et, en principe, rien ne les empêche de désactiver ce type de front-end et, par exemple, de rompre les connexions tls lorsque les SNI et eSNI ne correspondent pas. En général, l'avenir se montrera. Mais pour l'instant, la perspective de travailler sous le couvert de kremlin.ru semble assez attrayante. Non?

Le code tunnel mis à jour, ainsi que les fichiers exécutables exécutables compilés, sont situés dans une branche de projet distincte sur github . Il est préférable d'écrire un problème sur tous les problèmes de tunnel possibles sur la page du projet sur GitHub.

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


All Articles