Domain fronting based on TLS 1.3

Introduction

Domain fronting based on TLS 1.3
Modern corporate content filtering systems from such eminent manufacturers as Cisco, BlueCoat, FireEye have quite a lot in common with their more powerful counterparts - DPI systems, which are being heavily implemented at the national level. The essence of the work of both is to inspect incoming and outgoing Internet traffic and, based on black / white lists, make a decision to ban the Internet connection. And since both of them rely on similar principles in the basics of their work, the ways to bypass them will also have much in common.

One of the technologies that can quite effectively bypass both DPI and corporate systems is domain-fronting technology. Its essence is that we go to a blocked resource, hiding behind another, public domain, with a good reputation, which will certainly not be blocked by any system, such as google.com.

A lot of articles have already been written about this technology and many examples have been given. However, the DNS-over-HTTPS and encrypted-SNI technologies that have been popular and discussed recently, as well as the new version of the TLS 1.3 protocol, provide an opportunity to consider another domain-fronting option.

Getting to grips with technology

First, let's define a little the basic concepts so that everyone has an understanding of who is who and why all this is needed. We have mentioned the eSNI mechanism, the operation of which will be discussed further. The eSNI (encrypted Server Name Indication) mechanism is a secure version of SNI available only for the TLS 1.3 protocol. The main point is to encrypt, among other things, information about which domain the request is sent to.

Now let's look at how the eSNI mechanism works in practice.

Let's say we have an Internet resource that is blocked by a modern DPI solution (let's take, for example, the famous torrent tracker - rutracker.nl). When trying to access the site of a torrent tracker, we see a standard provider stub stating that the resource is being blocked:

Domain fronting based on TLS 1.3

On the RKN website, this domain is indeed listed in the stop lists:

Domain fronting based on TLS 1.3

When requesting whois, it is clear that the domain itself is β€œhidden” behind the Cloudflare cloud provider.

Domain fronting based on TLS 1.3

But unlike the β€œspecialists” from the RKN, the more technically savvy employees from Beeline (or taught by the bitter experience of our famous regulator) did not stupidly ban the site by IP address, but put the domain name on the stop list. This is easy to verify if you look at what other domains are hiding behind the same IP address, visit one of them and see that access is not blocked:

Domain fronting based on TLS 1.3

But how does it happen? How does the provider's DPI know which domain my browser is going to, because all communications take place over the https protocol, and we haven't noticed the substitution of https certificates from the beeline yet? Is he a clairvoyant, or am I being followed?

Let's try to answer this question by looking at the traffic through wireshark

Domain fronting based on TLS 1.3

The screenshot shows that first the browser gets the server's IP address via DNS, then there is a standard TCP handshake with the destination server, and then the browser tries to establish an ssl connection with the server. To do this, it sends an SSL Client Hello packet that contains the name of the source domain in clear text. This field is required by the cloudflare frontend server in order to correctly route the connection. This is where the provider's DPI catches us, breaking our connection. At the same time, we do not receive any stub from the provider, and we see a standard browser error as if the site is disabled or simply does not work:

Domain fronting based on TLS 1.3

Now let's enable the eSNI mechanism in the browser, as it is written in the instructions for Firefox :
To do this, we open the Firefox configuration page about: config and activate the following settings:

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

After that, we will check the correct operation of the settings on the cloudflare website by link and try the trick with our torrent tracker again.

Domain fronting based on TLS 1.3

Voila. Our favorite tracker opened up, without any VPN or proxy servers. Let's now look at the traffic dump in wireshark, what happened.

Domain fronting based on TLS 1.3

This time, the ssl client hello package does not explicitly contain the destination domain, but instead, a new field appeared in the package - encrypted_server_name - this is where the rutracker.nl value is contained, and only the cloudflare front-end server can decrypt this field. And if so, then the DPI provider has no choice but to wash their hands and allow such traffic. And there are no other options with encryption.

So, we have seen how the technology works in the browser. Now let's try to apply it to more specific and interesting things. And to begin with, we will teach the same curl to use eSNI to work with TLS 1.3, and at the same time we will see how the eSNI-based fronting domain itself works.

Domain fronting with eSNI

In view of the fact that curl uses the standard openssl library to connect via the https protocol, first of all we need to provide eSNI support there. There is no eSNI support in the openssl master branches yet, so we need to download a special openssl branch, compile and install it.

We clone the repository from the github and compile as usual:

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

$ make
$ cd esnistuff
$ make

Next, we clone the repository with curl and configure its compilation using our built openssl library:

$ 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

Here it is important to correctly specify all the directories where openssl is located (in our case, this is /opt/openssl/) and make sure that the configuration process goes without errors.

In case of successful configuration, we will see the line:

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

$ make

After successfully building the package, we will use a special bash file from openssl to configure and run curl. Copy it to the directory with curl for convenience:

cp /opt/openssl/esnistuff/curl-esni 

and execute a test https request to the cloudflare server, simultaneously writing DNS and TLS packets to Wireshark.

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

In the server response, in addition to a lot of debug-information from openssl and curl, we will receive an HTTP response with a 301 code from 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/

which indicates that our request was successfully delivered to the destination server, heard and processed.

Now let's look at the traffic dump in wireshark, i.e. what the provider's DPI saw in this case.

Domain fronting based on TLS 1.3

It can be seen that at first curl turned to the DNS server for a public eSNI key for the cloudflare server - a TXT DNS request to _esni.cloudflare.com (package No. 13). Then, using the openssl library, curl sent a TLS 1.3 request to the cloudflare server in which the SNI field was encrypted with the public key obtained in the previous step (packet #22). But, in addition to the eSNI field, the SSL-hello package also included a field with the usual - open SNI, which we can specify in any order (in this case - www.hello-rkn.ru).

This open SNI field was not taken into account in any way when processed by cloudflare servers and was only a camouflage for the provider's DPI. The cloudflare server received our ssl-hello packet, decrypted the eSNI, extracted the original SNI from there and processed it as if nothing had happened (did everything exactly as it was planned during the development of eSNI).

The only thing that can be hooked on in this case in terms of DPI is the primary DNS request to _esni.cloudflare.com. But we have made the DNS query open only to show how this mechanism works from the inside.

To finally knock the ground out from under DPI, we use the already mentioned DNS-over-HTTPS mechanism. A little explanation - DOH is a protocol that allows you to protect yourself from a man-in-the-middle attack by sending a DNS request over HTTPS.

Let's execute the request again, but this time we will receive public eSNI keys using the https protocol, and not DNS:

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

The request traffic dump is shown in the screenshot below:

Domain fronting based on TLS 1.3

It can be seen that curl first accesses the mozilla.cloudflare-dns.com server using the DoH protocol (https connection to the server 104.16.249.249) in order to get the public key values ​​for SNI encryption from them, and then to the destination server, hiding behind the domain www.hello-rkn.ru.

In addition to the mozilla.cloudflare-dns.com DoH resolver mentioned above, we can use other popular DoH services, for example, from the famous evil corporation.
Let's execute the following query:

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

And we get the answer:

< 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 based on TLS 1.3

In this case, we turned to the blocked rutracker.nl server, using the dns.google DoH resolver (there is no typo here, now the famous corporation has its own first-level domain) and covered ourselves with another domain, which is strictly forbidden to be blocked by all DPI under pain of death. From the received response, we can understand that our request was successfully processed.

As an additional check that the provider's DPI responds to the open SNI that we pass as a cover, we can make a request to rutracker.nl behind some other forbidden resource, for example, another "good" torrent tracker:

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

We will not receive a response from the server, because our request will be blocked by the DPI system.

A little conclusion to the first part

So, we were able to demonstrate the performance of eSNI using openssl and curl and test the operation of eSNI-based domain fronting. In the same way, we can adapt our favorite tools that use the openssl library to work "under the guise" of other domains. More on this in our next articles.

Source: habr.com

Add a comment