Introdução

Sistemas corporativos modernos de filtragem de conteúdo, de renomados fabricantes como Cisco, BlueCoat e FireEye, têm muito em comum com seus irmãos mais potentes — sistemas DPI, que estão sendo intensamente implementados em nível nacional. A essência do funcionamento de ambos é inspecionar o tráfego de internet de entrada e saída e, com base em listas negras/brancas, tomar decisões sobre a proibição de conexões. E como ambos se baseiam em princípios semelhantes, as formas de contorná-los também terão muito em comum.
Uma das tecnologias que permite contornar de forma bastante eficaz tanto o DPI quanto os sistemas corporativos é a tecnologia de domínio frontal. Seu princípio consiste em acessar um recurso bloqueado, escondendo-se atrás de outro domínio público, com boa reputação, que certamente não será bloqueado por nenhum sistema, como o google.com.
Já foram escritas muitas matérias sobre essa tecnologia e muitos exemplos foram fornecidos. No entanto, as tecnologias populares e debatidas recentemente, como DNS-over-HTTPS e encrypted-SNI, assim como a nova versão do protocolo TLS 1.3, permitem considerar mais uma variante de domínio frontal.
Vamos entender a tecnologia
Primeiro, vamos nos familiarizar com os principais conceitos, para que todos tenham uma compreensão de quem é quem e por que tudo isso é necessário. Mencionamos o mecanismo eSNI, cujo funcionamento será discutido a seguir. O mecanismo eSNI (encrypted Server Name Indication) – é uma versão protegida do SNI, disponível apenas para o protocolo TLS 1.3. O principal objetivo é criptografar, entre outras coisas, as informações sobre a qual domínio a solicitação está sendo enviada.
Agora vamos examinar o funcionamento do mecanismo eSNI na prática.
Suponha que temos um recurso na internet que está sendo bloqueado por uma solução DPI moderna (por exemplo, o famoso rastreador de torrents — rutracker.nl). Ao tentarmos acessar o site do rastreador de torrents, vemos a mensagem padrão do provedor informando que o recurso está bloqueado:

No site do RKN, este domínio realmente aparece nas listas de bloqueio:

Na consulta whois, é visível que o próprio domínio está "escondido" atrás do provedor de nuvem Cloudflare.

Mas, ao contrário dos "especialistas" da RKN, os funcionários mais tecnicamente preparados da Beeline (ou que aprenderam com a amarga experiência do nosso famoso regulador) não baniram o site pelo endereço IP, mas colocaram exatamente o nome de domínio. É fácil perceber isso ao olhar quais outros domínios estão escondidos por trás do mesmo endereço IP, visitar um deles e ver que o acesso não está bloqueado:

Como isso é possível? Como é que o DPI do provedor sabe a qual dos domínios meu navegador está se conectando, já que toda a comunicação ocorre via protocolo https, e até agora não notamos substituições de certificados https por parte da Beeline? Será que ele é um vidente ou estou sob vigilância?
Vamos tentar responder a essa pergunta analisando o tráfego com o Wireshark.

Na captura de tela, podemos ver que primeiro o navegador obtém o endereço IP do servidor através do DNS, depois ocorre o handshake TCP padrão com o servidor de destino, e então o navegador tenta estabelecer uma conexão SSL com o servidor. Para isso, ele envia o pacote SSL Client Hello, que contém o nome do domínio de origem em texto claro. Esse campo é necessário para que o servidor frontend da Cloudflare possa roteirizar a conexão corretamente. E é aqui que o DPI do provedor nos pega, rompendo a nossa conexão. Nesse processo, não recebemos nenhum aviso do provedor e vemos o erro padrão do navegador como se o site estivesse desligado ou simplesmente não funcionasse:

Agora vamos ativar o mecanismo eSNI no navegador, conforme descrito nas instruções para Firefox :
Para isso, abrimos a página de configurações do Firefox about:config e ativamos as seguintes configurações:
network.trr.mode = 2;
network.trr.uri = https://mozilla.cloudflare-dns.com/dns-query
network.security.esni.enabled = true
Depois disso, verificaremos a correção das configurações no site da Cloudflare em link e tentaremos o truque com nosso tracker de torrent mais uma vez.

Voilà. Nosso tracker favorito abriu, sem VPNs ou servidores proxy. Agora vamos dar uma olhada no dump de tráfego no Wireshark para ver o que aconteceu.

Desta vez, o pacote SSL Client Hello não contém explicitamente o domínio de destino; em vez disso, há um novo campo no pacote — encrypted_server_name — onde está o valor rutracker.nl, e apenas o servidor frontend da Cloudflare pode decifrar esse campo. Assim, o DPI do provedor não tem escolha a não ser lavar as mãos e permitir esse tráfego. E não existem outras opções para a criptografia.
Então, vimos como a tecnologia funciona no navegador. Agora, vamos tentar aplicá-la para coisas mais específicas e interessantes. Primeiro, vamos ensinar o mesmo curl a usar eSNI para trabalhar com TLS 1.3 e, ao mesmo tempo, ver como funciona o domain fronting baseado em eSNI.
Domain Fronting com eSNI
Uma vez que o curl usa a biblioteca padrão openssl para se conectar via https, precisamos garantir o suporte ao eSNI lá. Nas branches master do openssl, o suporte ao eSNI ainda não existe, portanto, precisamos baixar uma branch especial do openssl, compilá-la e instalá-la.
Clonamos o repositório do GitHub e compilamos como de costume:
$ git clone https://github.com/sftcd/openssl
$ cd openssl
$ ./config
$ make
$ cd esnistuff
$ make
Em seguida, clonamos o repositório do curl e configuramos sua compilação usando nossa biblioteca openssl compilada:
$ 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
É importante especificar corretamente todos os diretórios onde o openssl está localizado (neste caso, é /opt/openssl/) e garantir que o processo de configuração ocorra sem erros.
Em caso de configuração bem-sucedida, veremos a seguinte linha:
WARNING: esni ESNI enabled but marked EXPERIMENTAL. Use com cautela!
$ makeApós a construção bem-sucedida do pacote, usaremos um arquivo bash especial do conjunto do openssl para configurar e iniciar o curl. Vamos copiá-lo para o diretório do curl para conveniência:
cp /opt/openssl/esnistuff/curl-esni e faremos uma requisição https de teste ao servidor Cloudflare, gravando simultaneamente os pacotes DNS e TLS no Wireshark.
$ ESNI_COVER="www.hello-rkn.ru" ./curl-esni https://cloudflare.com/Na resposta do servidor, além de muitas informações de depuração do openssl e curl, receberemos uma resposta HTTP com código 301 do 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/
o que indica que nossa solicitação foi entregue com sucesso ao servidor de destino, ouvida e processada.
Agora, vamos analisar o tráfego no Wireshark, ou seja, o que o DPI do provedor viu neste caso.

É evidente que inicialmente o curl fez uma consulta ao servidor DNS para obter a chave pública eSNI do servidor Cloudflare — uma consulta DNS TXT para _esni.cloudflare.com (pacote nº 13). Em seguida, utilizando a biblioteca openssl, o curl enviou uma solicitação TLS 1.3 ao servidor Cloudflare, onde o campo SNI foi criptografado com a chave pública obtida na etapa anterior (pacote nº 22). No entanto, além do campo eSNI, o pacote SSL hello também continha um campo com o SNI padrão — aberto, que podemos especificar em qualquer ordem (neste caso — www.hello-rkn.ru).
Este campo SNI aberto não foi considerado na processamento pelos servidores Cloudflare e serviu apenas como uma camuflagem para o DPI do provedor. O servidor Cloudflare aceitou nosso pacote ssl-hello, decifrou o eSNI, extraiu o SNI original e o processou normalmente (fez tudo exatamente como planejado no desenvolvimento do eSNI).
A única coisa com que se pode argumentar do ponto de vista do DPI neste caso é a consulta DNS inicial para _esni.cloudflare.com. Mas fizemos a consulta DNS aberta apenas para mostrar como este mecanismo funciona por dentro.
Para eliminar definitivamente qualquer base para o DPI, usamos o já mencionado mecanismo DNS-over-HTTPS. Uma breve explicação – DOH é um protocolo que permite se proteger contra ataques de "homem no meio" ao enviar consultas DNS pelo protocolo HTTPS.
Vamos realizar a consulta novamente, mas desta vez nós obteremos as chaves públicas eSNI pelo protocolo https, e não pelo DNS:
ESNI_COVER="www.hello-rkn.ru" DOH_URL=https://mozilla.cloudflare-dns.com/dns-query ./curl-esni https://cloudflare.com/O tráfego da consulta é mostrado na captura de tela abaixo:

É visível que primeiro o curl se conecta ao servidor mozilla.cloudflare-dns.com pelo protocolo DoH (conexão https com o servidor 104.16.249.249) para obter os valores das chaves públicas para a criptografia do SNI, e só depois segue para o servidor de destino, disfarçando-se com o domínio. www.hello-rkn.ru.
Além do resolvedor DoH mencionado acima, mozilla.cloudflare-dns.com, também podemos usar outros serviços populares de DoH, como o da famosa corporação do mal.
Vamos fazer essa consulta:
ESNI_COVER="www.kremlin.ru" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/E obteremos a resposta:
< 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

Neste caso, acessamos o servidor bloqueado rutracker.nl, usando o resolver DoH dns.google (não há erro de digitação, agora a famosa corporação possui seu próprio domínio de nível superior) e nos camuflamos com outro domínio, cuja proibição de bloqueio é estritamente imposta a todos os DPI sob pena de morte. Pela resposta recebida, podemos entender que nossa solicitação foi processada com sucesso.
Como uma verificação adicional de que o DPI do provedor reage ao SNI aberto, que estamos usando como camuflagem — podemos fazer um pedido a rutracker.nl disfarçados de algum outro recurso proibido, como outro ‘bom’ rastreador de torrents:
$ ESNI_COVER="rutor.info" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/Não receberemos uma resposta do servidor, pois nossa solicitação será bloqueada pelo sistema DPI.
Um breve resumo da primeira parte
Assim, conseguimos demonstrar a funcionalidade do eSNI usando openssl e curl e verificar o funcionamento do domain fronting baseado em eSNI. Da mesma forma, podemos adaptar nossas ferramentas favoritas que usam a biblioteca openssl para operar ‘sob a camuflagem’ de outros domínios. Mais detalhes sobre isso — em nossos próximos artigos.
Fonte: habr.com
