Domain fronting oparty na TLS 1.3

Wprowadzenie

Domain fronting oparty na TLS 1.3
Nowoczesne korporacyjne systemy filtracji treści, takie jak Cisco, BlueCoat, FireEye, mają wiele wspólnego z bardziej zaawansowanymi rozwiązaniami — systemami DPI, które są intensywnie wdrażane na poziomie krajowym. Ich działanie polega na monitorowaniu przychodzącego i wychodzącego ruchu internetowego oraz, na podstawie czarnych/białych list, podejmowaniu decyzji o zablokowaniu połączenia internetowego. Ponieważ zarówno jedne, jak i drugie polegają na podobnych zasadach, metody ich omijania również mają wiele wspólnego.

Jedną z technologii, która pozwala dość skutecznie omijać zarówno systemy DPI, jak i korporacyjne, jest technologia domain fronting. Polega ona na tym, że kierujemy się do zablokowanego zasobu, ukrywając się za inną, publiczną domeną o dobrej reputacji, która z pewnością nie będzie zablokowana przez żaden system, na przykład google.com.

Na temat tej technologii napisano już wiele artykułów i podano liczne przykłady. Jednak popularne ostatnio technologie DNS-over-HTTPS i encrypted-SNI, a także nowa wersja protokołu TLS 1.3, dają możliwość rozważenia kolejnej opcji domain fronting.

Zagłębiamy się w technologię

Najpierw ustalmy podstawowe pojęcia, aby każdy miał jasność, kto jest kim i po co to wszystko. Wspomnieliśmy o mechanizmie eSNI, którego działanie omówimy później. Mechanizm eSNI (encrypted Server Name Indication) to zabezpieczona wersja SNI, dostępna tylko dla protokołu TLS 1.3. Główna idea polega na szyfrowaniu również informacji o tym, do jakiej domeny wysyłane jest zapytanie.

A teraz przyjrzyjmy się, jak działa mechanizm eSNI w praktyce.

Załóżmy, że mamy zasób internetowy, który jest blokowany przez nowoczesne rozwiązanie DPI (weźmy na przykład znany tracker torrentów — rutracker.nl). Przy próbie dostępu do strony trackera torrentów widzimy standardowy komunikat dostawcy, informujący o tym, że zasób jest zablokowany:

Domain fronting oparty na TLS 1.3

Na stronie RKN domena faktycznie widnieje na czarnej liście:

Domain fronting oparty na TLS 1.3

Przy zapytaniu whois widać, że sama domena jest "schowana" za chmurowym dostawcą Cloudflare.

Domain fronting oparty na TLS 1.3

Jednak w przeciwieństwie do "specjalistów" z RKN, bardziej technicznie zaawansowani pracownicy z Beeline (lub nauczeni gorzkim doświadczeniem naszego słynnego regulatora) nie po prostu zablokowali strony po adresie IP, lecz wpisali na czarną listę właśnie nazwę domeny. Łatwo to potwierdzić, jeśli zobaczysz, jakie inne domeny są ukryte za tym samym adresem IP, odwiedzisz jedną z nich i zobaczysz, że dostęp nie jest zablokowany:

Domain fronting oparty na TLS 1.3

Jak to możliwe? W jaki sposób dostawca wykrywa, na którą domenę kieruje się moja przeglądarka, skoro wszystkie komunikacje odbywają się za pomocą protokołu https, a zjawiska podmiany certyfikatów https ze strony Beeline wydają się na razie nie zauważone? Czy może ma jakieś zdolności parapsychiczne, czy też ktoś mnie śledzi?

Spróbujemy odpowiedzieć na to pytanie, analizując ruch za pomocą Wiresharka

Domain fronting oparty na TLS 1.3

Na zrzucie ekranu widać, że najpierw przeglądarka uzyskuje adres IP serwera przez DNS, potem następuje standardowe nawiązanie połączenia TCP z docelowym serwerem, a następnie przeglądarka próbuje nawiązać połączenie ssl z serwerem. W tym celu przesyła pakiet SSL Client Hello, w którym znajduje się nazwa źródłowej domeny w otwartej formie. To pole jest potrzebne serwerowi frontendowemu Cloudflare, aby poprawnie kierować połączenie. I to jest moment, w którym dopada nas dostawca DPI, zrywając nasze połączenie. Przy tym nie otrzymujemy od dostawcy żadnego komunikatu o błędzie, a widzimy standardowy błąd przeglądarki, jakby strona była wyłączona lub po prostu nie działała:

Domain fronting oparty na TLS 1.3

Teraz włączmy mechanizm eSNI w przeglądarce, zgodnie z instrukcją dla Firefox :
W tym celu otwieramy stronę konfiguracji Firefox about:config i aktywujemy następujące ustawienia:

network.trr.mode = 2;
network.trr.uri = https://mozilla.cloudflare-dns.com/dns-query
network.security.esni.enabled = true

Po tym sprawdzimy poprawność ustawień na stronie Cloudflare za linkiem i spróbujemy jeszcze raz użyć naszego torrenta.

Domain fronting oparty na TLS 1.3

Voilà. Nasz ulubiony tracker otworzył się, bez jakichkolwiek VPN i serwerów proxy. Spójrzmy teraz na zrzut ruchu w Wiresharku, co się wydarzyło.

Domain fronting oparty na TLS 1.3

Tym razem pakiet ssl client hello nie zawiera jawnie docelowej domeny, a zamiast tego pojawiło się nowe pole w pakiecie — encrypted_server_name — to tam znajduje się wartość rutracker.nl, a pole to może odszyfrować tylko serwer frontendowy Cloudflare. W związku z tym dostawca DPI nie ma innego wyboru, jak tylko umyć ręce i zezwolić na taki ruch. Nie ma innych opcji z szyfrowaniem.

Przyjrzyjmy się, jak technologia działa w przeglądarkach — to już zobaczyliśmy. Teraz spróbujmy zastosować ją w bardziej specyficznych i interesujących rzeczach. Na początek nauczymy ten sam curl używać eSNI do pracy z TLS 1.3, a przy okazji zobaczymy, jak działa sam domain fronting na podstawie eSNI.

Domain fronting z eSNI

Biorąc pod uwagę, że curl do łączenia się przez protokół https używa standardowej biblioteki openssl, najpierw musimy zapewnić wsparcie eSNI tam. W głównych gałęziach openssl wsparcia eSNI na razie nie ma, więc musimy pobrać specjalną gałąź openssl, skompilować ją i zainstalować.

Klonujemy repozytorium z GitHuba i kompilujemy jak zazwyczaj:

$ git clone https://github.com/sftcd/openssl
$ cd openssl
$ ./config

$ make
$ cd esnistuff
$ make

Następnie klonujemy repozytorium z curl i konfigurujemy jego kompilację z wykorzystaniem naszej skompilowanej biblioteki openssl:

$ cd $HOME/code
$ git clone https://github.com/niallor/curl.git curl-esni
$ cd curl-esni

$ export LD_LIBRARY_PATH=/opt/openssl
$ ./buildconf
$ LDFLAGS="-L/opt/openssl" ./configure --with-ssl=/opt/openssl --enable-esni --enable-debug

Ważne jest, aby prawidłowo wskazać wszystkie katalogi, w których znajduje się openssl (w naszym przypadku — to /opt/openssl/) i upewnić się, że proces konfiguracji przebiegł bez błędów.

W przypadku pomyślnej konfiguracji zobaczymy linię:

WARNING: esni ESNI enabled but marked EXPERIMENTAL. Use with caution!

$ make

Po pomyślnej budowie pakietu skorzystamy ze specjalnego pliku bash z zestawu openssl do konfiguracji i uruchomienia curl. Skopiujemy go do katalogu z curl dla wygody:

cp /opt/openssl/esnistuff/curl-esni 

i przeprowadzimy testowe zapytanie https do serwera cloudflare, jednocześnie zapisując pakiety DNS i TLS w Wireshark.

$ ESNI_COVER="www.hello-rkn.ru" ./curl-esni https://cloudflare.com/

W odpowiedzi serwera, obok wielu informacji debugowych od openssl i curl, otrzymamy odpowiedź HTTP z kodem 301 od cloudflare.

HTTP/1.1 301 Moved Permanently
< Date: Sun, 03 Nov 2019 13:12:55 GMT
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: max-age=3600
< Expires: Sun, 03 Nov 2019 14:12:55 GMT
< Location: https://www.cloudflare.com/

co wskazuje, że nasza prośba została pomyślnie dostarczona do serwera docelowego, usłyszana i przetworzona.

Teraz przyjrzyjmy się zrzutowi ruchu w Wireshark, to znaczy, co w tej sytuacji zobaczył dostawca z DPI.

Domain fronting oparty na TLS 1.3

Widać, że najpierw curl zwrócił się do serwera DNS o publiczne klucze eSNI dla serwera Cloudflare — zapytanie DNS TXT o _esni.cloudflare.com (pakiet nr 13). Następnie, używając biblioteki OpenSSL, curl wysłał zapytanie TLS 1.3 do serwera Cloudflare, w którym pole SNI zostało zaszyfrowane publicznym kluczem uzyskanym na wcześniejszym etapie (pakiet nr 22). Jednak oprócz pola eSNI w pakiecie SSL hello umieszczono również pole z normalnym — otwartym SNI, które możemy podać w dowolnej kolejności (w tym przypadku — www.hello-rkn.ru).

To pole otwartego SNI nie było brane pod uwagę podczas przetwarzania przez serwery Cloudflare i służyło jedynie jako maskowanie dla DPI dostawcy. Serwer Cloudflare przyjął nasz pakiet ssl-hello, odszyfrował eSNI, wyodrębnił z niego oryginalny SNI i przetworzył go tak, jakby nic się nie stało (zrobił wszystko tak, jak planowano podczas rozwoju eSNI).

Jedyną rzeczą, na którą można w tym przypadku zwrócić uwagę z punktu widzenia DPI, jest pierwotne zapytanie DNS o _esni.cloudflare.com. Ale zrobiliśmy zapytanie DNS otwarte jedynie po to, aby pokazać, jak ten mechanizm działa od środka.

Aby ostatecznie wyeliminować grunt pod nogami DPI, używamy już wspomnianego mechanizmu DNS-over-HTTPS. Krótkie wyjaśnienie – DOH to protokół, który pozwala chronić się przed atakiem „człowiek w środku” poprzez wysyłanie zapytania DNS za pomocą protokołu HTTPS.

Wykonamy żądanie ponownie, ale tym razem publiczne klucze eSNI uzyskamy za pomocą protokołu https, a nie DNS:

ESNI_COVER="www.hello-rkn.ru" DOH_URL=https://mozilla.cloudflare-dns.com/dns-query ./curl-esni https://cloudflare.com/

Zrzut ruchu zapytania jest przedstawiony na poniższym zrzucie ekranu:

Domain fronting oparty na TLS 1.3

Widać, że najpierw curl zwraca się do serwera mozilla.cloudflare-dns.com za pomocą protokołu DoH (połączenie https z serwerem 104.16.249.249), aby uzyskać od nich wartości publicznych kluczy do szyfrowania SNI, a następnie do serwera docelowego, ukrywając się pod tymczasowym domeną www.hello-rkn.ru.

Oprócz wspomnianego wcześniej resolvera DoH mozilla.cloudflare-dns.com możemy również używać innych popularnych usług DoH, na przykład od słynnej korporacji zła.
Wykonamy takie zapytanie:

ESNI_COVER="www.kremlin.ru" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/

I otrzymamy odpowiedź:

< HTTP/1.1 301 Moved Permanently
< Date: Sun, 03 Nov 2019 14:10:22 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=da0144d982437e77b0b37af7d00438b1a1572790222; expires=Mon, 02-Nov-20 14:10:22 GMT; path=/; domain=.rutracker.nl; HttpOnly; Secure
< Location: https://rutracker.nl/forum/index.php
< CF-Cache-Status: DYNAMIC
< Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
< Server: cloudflare
< CF-RAY: 52feee696f42d891-CPH

Domain fronting oparty na TLS 1.3

W tym przypadku skontaktowaliśmy się z zablokowanym serwerem rutracker.nl, używając przy tym rozwiązywacza DoH dns.google (tu nie ma literówki, teraz znana firma ma swoją własną domenę najwyższego poziomu) i przykryliśmy się inną domeną, blokowanie której jest surowo zabronione przez wszystkie systemy DPI pod groźbą kary śmierci. Z uzyskanej odpowiedzi można zrozumieć, że nasze zapytanie zostało pomyślnie przetworzone.

Jako dodatkowe sprawdzenie, że dostawca DPI reaguje na otwarte SNI, które przekazujemy jako osłonę — możemy złożyć zapytanie do rutracker.nl, przykrywając się jakimś innym zakazanym zasobem, na przykład innym 'dobrym' trackerem torrentów:

$ ESNI_COVER="rutor.info" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/

Nie otrzymamy odpowiedzi od serwera, ponieważ nasze zapytanie zostanie zablokowane przez system DPI.

Krótka konkluzja do pierwszej części

Zatem udało nam się pokazać działanie eSNI za pomocą openssl i curl oraz sprawdzić działanie frontingu domeny opartego na eSNI. W ten sam sposób możemy dostosować nasze ulubione narzędzia korzystające z biblioteki openssl do działania 'pod przykryciem' innych domen. Więcej na ten temat w naszych następnych artykułach.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster