Домен-фронтинг на база TLS 1.3. Част 2

Въведение

В първата част статии дадохме кратко описание на механизма encrypted SNI (eSNI). Показахме как на базата на него може да се избягва откритие от съвременни DPI системи (на примера на DPI на Билайн и забранения РКН рутрекер), както и разгледахме нов вариант на домейн фронтинг на базата на този механизъм.

Във втората част на статията ще преминем към по-практически неща, които ще бъдат полезни за специалистите от RedTeam в тяхната нелека работа. В крайна сметка нашата цел не е да получим достъп до блокирани ресурси (за такива банални неща имаме стария добър VPN). Добре, че VPN доставчиците са многобройни, както казват, на всеки вкус, цвят и бюджет.

Ще се постараем да приложим механизма на домейн фронтинга за съвременните инструменти на RedTeam, например, такива като Cobalt Strike, Empire и т.н., и да им предоставим допълнителни възможности за мимикриране и избягване на съвременните системи за филтриране на съдържание.

В миналия път внедрихме механизма eSNI в библиотеката OpenSSL и успешно го използвахме в познатата на всички утилита curl. Но само с curl, както се казва, човек не може да се нахрани. Разбира се, искаме да реализираме нещо подобно и в езици с високо ниво. Но, за съжаление, беглият търсене из мрежата ни разочарова, тъй като поддръжката на механизма eSNI е пълноценно реализирана само в GOLANG. Така че, изборът ни не е много голям: или пишем на чист C или C++ с използване на пропатчена библиотека OpenSSL, или използваме отделен форк на GOLANG от CloudFlare и се опитваме да портнем нашите инструменти там. В принципе, има и още един вариант, по-класически, но едновременно с това и трудоемък – това е да реализираме поддръжка на eSNI за Python. В крайна сметка Python също използва OpenSSL за работа с https. Но този вариант ще оставим за разработка на някой друг, а ние ще се задоволим с реализацията на голанга, особено след като нашият любим Cobalt Strike отлично работи с канала за връзка, построен от трети страни (External C2 channel) – за това ще разкажем в края на статията.

Изпробвайте по-усилено…

Един от реализираните на Go инструменти – нашето решение за пивотиране вътре в мрежата – тунелера rsockstun, която, между другото, в момента се открива от софтуер на компанията Microsoft и Symantec, като изключително злоупотребяваща програма, насочена към нарушаване на световната стабилност…

Домен-фронтинг на база TLS 1.3. Част 2

Беше чудесно да използваме предишната разработка и в този случай. Но тук възниква малък проблем. Работата е там, че първоначално rsockstun предвижда използването на синхронен SSL канал за комуникация със сървъра. Това означава, че свързването се установява веднъж и съществува през цялото време на работа на тунела. Както разбирате, протоколът https малко не е предназначен за такъв режим на работа – той работи в режим запитване-отговор, където всяко ново http запитване съществува в рамките на ново tcp свързване.

Основният недостатък на такава схема е, че сървърът не може да предаде данни на клиента, докато клиентът не изпрати ново http запитване. Но, за щастие, съществуват множество варианти за решаване на този проблем – потокова предаване на данни чрез http протокол (в крайна сметка успяваме да гледаме любимите си сериали и да слушаме музика от портали, работещи на https, а предаването на видео и аудио не е нищо повече от потокова предаване на данни). Една от технологиите за емилиране на работата на напълно tcp свързване върху http протокола е технологията на уеб сокетите (WebSockets), която основно се състои в организиране на пълноценна мрежова връзка между клиента и уеб сървъра.

На наше късмет (ура! ура!!!), тази технология е включена по подразбиране във всички тарифни планове на CloudFlare и работи прекрасно в комбинация с eSNI. Именно нея ще използваме, за да научим нашия тунел да използва домейн-фронтиране и да се скрие от съвременните DPI.

Няколко неща за WebSockets

На първо място, накратко и с прости думи ще разкажем за уебсокетите, за да имат всички представа с какво ще работим.

Технологията на уеб сокетите позволява временно превключване от http свързване на стандартно потоково предаване на данни чрез мрежов сокет, без да се прекъсва установеното tcp свързване. Когато клиентът иска да превключи на уеб сокет, в своето http запитване задава няколко http заглавия. Два задължителни заглавия – Connection: Upgrade и Upgrade: websocket. Освен това клиентът може да зададе принудително версията на протокола на websocket (Sec-Websockset-Version: 13) и нещо подобно на base64 идентификатор на уеб сокет (Sec-WebSocket-Key: DAGDJSiREI3+KjDfwxm1FA==). Сървърът отговаря с http-код 101 Switching Protocols и също така задава заглавките Connection, Upgrade и Sec-WebSocket-Accept. Процесът на превключване е илюстриран на изображението по-долу:

Домен-фронтинг на база TLS 1.3. Част 2

След това установяването на WebSocket връзката може да се счита за завършено. Всички данни, както от клиента, така и от сървъра, сега ще бъдат снабдени не с http, а с WebSocket заглавки (те започват с байта 0x82). Сега сървърът няма нужда да чака заявка от клиента, за да предаде данни, тъй като tcp връзката не се разкъсва.

В Go за работа с уеб сокети има няколко библиотеки. Най-популярните от тях са Gorilla WebSocket и стандартната WebSocket. Ние ще използваме последната, тъй като е по-проста, по-малка и работи, казват, малко по-бързо.

В кода на клиента rsockstun трябва да заменим извикванията на net.dial или tls.dial с съответните извиквания на WebSocket:

Домен-фронтинг на база TLS 1.3. Част 2

Домен-фронтинг на база TLS 1.3. Част 2

Искаме клиентската част на нашия тунел да бъде универсална и да може да работи както през директно ssl връзка, така и през протокола WebSocket. За целта ще създадем отделна функция func connectForWsSocks(address string, proxy string) error {…} по аналогия с connectForSocks() и ще я използваме за работа с уеб сокети в случай, че адресът на сървъра, зададен при стартиране на клиента, започва с ws: или wss: (в случай на Secure WebSocket).

За сървърната част на тунела също ще направим отделна функция за работа с уеб сокети. В нея ще бъде създаден екземпляр на класа http и ще се зададе обработчик на http връзката (функцията wsHandler):

Домен-фронтинг на база TLS 1.3. Част 2

А цялата логика за обработка на свързването (идентификация на клиента с парола, установяване и приключване на yamux сесия) ще поставим в обработчика на WebSocket свързването:

Домен-фронтинг на база TLS 1.3. Част 2

Компилираме проекта, стартираме сървърната част:

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

И след това клиентската част:

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

И проверяваме работата на локалния хост:

Домен-фронтинг на база TLS 1.3. Част 2

Домен-фронтинг на база TLS 1.3. Част 2

Преминаваме към домейн-фронтиране

С уеб сокетите изглежда сме се разбрали. Сега нека преминем директно към eSNI и домейн-фронтиране. Както вече споменахме, за работа с DoH и eSNI е необходимо да вземем специален клон на Go от компанията CloudFlare. Нужен ни е клон с поддръжка за eSNI (pwu/esni).

Клонираме го на локалната си машина или сваляме и разархивираме съответния zip:

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

След това трябва да копираме каталога GOROOT, да заменим съответните файлове от клонираната версия и да го установим като основен. За да освободят разработчиците от това главоболие, хората от CloudFlare подготвиха специален скрипт – _dev/go.sh. Просто го стартираме. Скриптът заедно с makefile ще направят всичко сами. За интерес можете да погледнете вътре в makefile за подробности.

След изпълнението на скрипта, при компилиране на проекта, трябва да посочим локалния каталог, подготвен от скрипта, като GOROOT. В нашия случай това изглежда така:

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

Следва да реализираме в тунела функционалността за запитване и парсинг на публични eSNI ключове за необходимия домейн. В нашия случай, това ще бъдат публични eSNI ключове от фронтенд-сървърите на CloudFlare. За това ще създадем три функции:

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

Наименованията на функциите, в принцип, говорят сами за себе си. Запълването ще вземем от файла esni_query.go, който е част от tls-tris. Първата функция създава мрежов пакет с запитване към DNS сървера на CloudFlare, използвайки протокола DoH (DNS-over-HTTPS), втората – парсира резултатите от запитването и получава стойностите на публичните ключове на домейна, а третата е контейнер за първите две.

След това ще добавим в нашата новосъздадена функция за свързване на уебсокетите connectForWsSocks функционалността за запитване на eSNI ключове за домейна. Където функционира сървърната част, задаваме параметри за TLS и определяме името на фалшивия «домейн за прикритие»:

Домен-фронтинг на база TLS 1.3. Част 2

Тук следва да се отбележи, че първоначално, версията tls-tris не е предвидена за използване на домейн-фронтиране. Следователно, в нея не е обърнато внимание на фалшивото име на сървъра (в пакета client-hello се предава празно поле serverName). За да поправим това, трябва да добавим в структурата TlsConfig съответното поле FakeServerName. Стандартното поле ServerName на структурата не можем да използваме, защото го използват вътрешни механизми на tls и ако то се различава от оригиналното, tls хендшейкът ще завърши с грешка. Описанието на структурата TlsConfig се съдържа в файла tls/common.go – именно него ще трябва да поправим:

Домен-фронтинг на база TLS 1.3. Част 2

Домен-фронтинг на база TLS 1.3. Част 2

Допълнително ще трябва да внесем промени в файла tls/handshake_client.go, за да използвате нашето поле FakeServerName при формирането на TLS handshake:

Домен-фронтинг на база TLS 1.3. Част 2

Това е всичко! Можете да компилирате проекта и да проверите работата. Но преди да стартирате проверката, трябва да настроите профила си в CloudFlare. Ами как да кажем, да настроите - просто създайте профил в CloudFlare и свържете домейна си с него. Всички функции, свързани с DoH, WebSocket и ESNI, са включени в CloudFlare по подразбиране. След като DNS записите се обновят - можете да проверите работата на домейна, като изпълните запитване за eSNI ключове:

dig +short txt _esni.df13tester.info 

Домен-фронтинг на база TLS 1.3. Част 2

Ако виждате нещо подобно за вашия домейн - значи всичко работи и можете да преминете към тестването.

Стартираме Ubuntu VPS, например, на DigitalOcean. P.S. В нашия случай, току-що полученото IP-адрес от доставчика на VPS е попаднало в черните списъци на РКН. Така че не се учудвайте, ако ви се случи нещо подобно. Пришло се е да използвате VPN, за да получите достъп до вашия VPS.

Копираме на VPS вече скомпилираният rsockstun (в това, между другото, още едно предимство на голанга - можете да компилирате проекта си у дома и да го стартирате на всяка Linux система, спазвайки само разрядността на системата) и стартираме сървърната част:

Домен-фронтинг на база TLS 1.3. Част 2

А след това клиентската част:

Домен-фронтинг на база TLS 1.3. Част 2

Както виждаме, клиентът успешно се свърза със сървъра чрез фронтенд-сървъра CloudFlare, използвайки уеб-сокет. За да проверим, че тунелът работи точно като тунел, можем да направим curl-запитване през локалния socks5, отворен на сървъра:

Домен-фронтинг на база TLS 1.3. Част 2

Сега нека видим какво DPI вижда в канала на връзката:

Домен-фронтинг на база TLS 1.3. Част 2

Първо, тунелизаторът, използвайки механизма DoH, се свързва с DNS сървъра на Cloudflare за eSNI ключове за целевия домейн (пакети №1-19), а след това се свързва с фронтенд-сървъра и установява TLS свързване, прикривайки се с домейна www.google.com (това е стойността по подразбиране, когато при стартиране на клиента не е зададен фалшив домейн). За да посочите своя фалшив домейн, е необходимо да използвате параметъра -fronfDomain:

Домен-фронтинг на база TLS 1.3. Част 2

Домен-фронтинг на база TLS 1.3. Част 2

Сега още един момент. По подразбиране, в настройките на профила в CloudFlare е зададен режим на работа Flexible SSL. Това означава, че https запитванията към фронтенд-сървърите на Cloudflare от клиенти ще бъдат пренасочени в нешифрован вид (http) до нашия сървър. Именно затова стартирахме сървърната част на тунелизатора в non-ssl режим (-listen ws:0.0.0.0), а не (-listen wss:0.0.0.0).

Домен-фронтинг на база TLS 1.3. Част 2

За да превключите в режим на пълно шифроване, е необходимо да изберете Full, или Full (strict) в случай на наличието на този сертификат на сървъра. След смяната на режима, ще можем да приемаме свързвания от CloudFlare по протокол https. Не забравяйте да генерирате self-signed сертификат за сървърната част на тунелера.

Домен-фронтинг на база TLS 1.3. Част 2

Тревожният читател ще попита: "А какво ще кажете за клиента под Windows? Нали основното приложение на тунелера е да повдигне бек-конект с корпоративни компютри и сървъри, а там обикновено е винаги Windows. Как да компилирам тунелера под Windows, и то със специфичен стек TLS?" А сега да представим още една характеристика, която показва колко удобен е Golang. Компилираме под Windows директно от Kali, просто добавяйки параметъра GOOS=windows:

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

Или 32-битен вариант:

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

Всичко! И повече няма нужда от затруднения. Това наистина работи!

Домен-фронтинг на база TLS 1.3. Част 2

Флаговете на компилатора –w и –s са необходими, за да се отстранят излишните данни от изпълнимия файл, като го направят по-малък с няколко мегабайта. Допълнително може да бъде опакован с помощта на UPX, за да се намали още размерът.

Вместо заключение

В статията показахме на примера на тунелера, написан на Golang, приложението на новата технология домейн-фронтинг, реализирана на доста интересната особеност на протокол TLS 1.3. По подобен начин може да се адаптира съществуващият инструментариум, написан на Golang, за работа през сървърите на CloudFlare, например. Merlin — известен C2, или да накарате CobaltStrike Beacon да използва eSNI домейн-фронтинг при работа с Teamserver през External C2 Channel, реализиран на Golang, или на стандартен C++ с използване на модифицирана версия на OpenSSL, за която говорихме в предишната част на статията. В общи линии, фантазията няма край.

Примерът с тунелера и CloudFlare е представен в форма на концепция и в момента е трудно да се каже за далечни перспективи на подобен вид домейн-фронтинг. В момента поддръжката на eSNI е реализирана само от CloudFlare и, по принцип, нищо не пречи да спрат подобен фронтинг и, например, да разкъсат tls-съединенията при несъответствия между SNI и eSNI. В обобщение, бъдещето ще покаже. Но в момента перспективата за работа под "прикритие на kremlin.ru" изглежда доста примамливо. Не мислите ли?

Актуализираният код на тунелизатора, както и компилираните изпълними exe-файлове, са публикувани в отделен клон на проекта на github. За всички възможни проблеми с тунелизатора е най-добре да се пишат въпроси на страницата на проекта в GitHub.

Източник: habr.com

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster