Introduzione

I moderni sistemi aziendali di filtraggio dei contenuti, prodotti da noti produttori come Cisco, BlueCoat e FireEye, hanno molto in comune con le loro controparti più potenti: i sistemi DPI, che vengono ampiamente implementati a livello nazionale. La loro funzione è quella di esaminare il traffico internet in entrata e in uscita e, sulla base di liste nere/bianche, prendere decisioni sul divieto di connessione internet. Poiché entrambi i tipi di sistemi si basano su principi simili, anche i metodi per aggirarli presentano molte somiglianze.
Una delle tecnologie che consente di aggirare in modo efficace sia i DPI che i sistemi aziendali è la tecnologia del domain fronting. Essa consiste nel visitare una risorsa bloccata, nascondendosi dietro un altro dominio pubblico con buona reputazione, che sicuramente non sarà bloccato da nessun sistema, ad esempio google.com.
Sono stati scritti già molti articoli su questa tecnologia e sono stati forniti numerosi esempi. Tuttavia, le tecnologie recentemente popolari e discusse, come DNS-over-HTTPS ed encrypted-SNI, così come la nuova versione del protocollo TLS 1.3, permettono di considerare un ulteriore variante di domain fronting.
Esaminiamo la tecnologia
Iniziamo a definire alcune nozioni fondamentali, affinché tutti abbiano chiaro chi è chi e a cosa serve tutto questo. Abbiamo menzionato il meccanismo eSNI, il cui funzionamento sarà esaminato in seguito. Il meccanismo eSNI (encrypted Server Name Indication) è una variante protetta di SNI, disponibile solo per il protocollo TLS 1.3. La sua essenza principale è quella di crittografare, tra l'altro, le informazioni su quale dominio viene inviata la richiesta.
Ora esaminiamo l'operato del meccanismo eSNI nella pratica.
Supponiamo di avere una risorsa internet che viene bloccata da una moderna soluzione DPI (prendiamo per esempio il famoso tracker torrent — rutracker.nl). Cercando di accedere al sito del tracker torrent, vediamo un tipico messaggio di avviso del provider che informa che la risorsa è bloccata:

Sul sito del RKN questo dominio è effettivamente presente nelle liste di blocco:

Richiedendo un whois si può vedere che il dominio stesso è 'nascosto' dietro al provider Cloudflare.

Ma a differenza dei «professionisti» del RKN, i dipendenti più tecnicamente preparati di Beeline (o quelli istruiti dall'amara esperienza del nostro famoso regolatore) non hanno semplicemente bloccato il sito per indirizzo IP, ma hanno inserito nella lista nera precisamente il nome di dominio. È facile verificarlo, basta guardare quali altri domini si nascondono dietro questo stesso indirizzo IP, visitare uno di essi e vedere che l'accesso non è bloccato:

E come può succedere? In che modo il DPI del provider sa a quale dominio si sta rivolgendo il mio browser, dato che tutte le comunicazioni avvengono tramite il protocollo https, e non abbiamo notato sostituzioni dei certificati https da parte di Beeline? È forse un veggente o sono sotto sorveglianza?
Proviamo a rispondere a questa domanda esaminando il traffico attraverso Wireshark

Nello screenshot si vede che inizialmente il browser riceve l'indirizzo IP del server tramite DNS, poi avviene il consueto handshake TCP con il server di destinazione, e infine il browser tenta di stabilire una connessione ssl con il server. Per fare questo, invia un pacchetto SSL Client Hello, che contiene il nome del dominio di origine in chiaro. Questo campo è necessario al server frontend di Cloudflare per instradare correttamente la connessione. È proprio qui che ci coglie il DPI del provider, interrompendo la nostra connessione. Non riceviamo alcun messaggio di errore dal provider e vediamo un errore standard del browser come se il sito fosse offline o non funzionasse:

Ora attiviamo il meccanismo eSNI nel browser, come indicato nelle istruzioni per Firefox :
Per fare questo, apriamo la pagina di configurazione di Firefox about:config e attiviamo le seguenti impostazioni:
network.trr.mode = 2;
network.trr.uri = https://mozilla.cloudflare-dns.com/dns-query
network.security.esni.enabled = true
Dopo di che verificheremo il corretto funzionamento delle impostazioni sul sito di Cloudflare tramite link e proveremo di nuovo il trucco con il nostro tracker Torrent.

Voilà. Il nostro tracker preferito si è aperto, senza alcun VPN o server proxy. Ora diamo un'occhiata al dump del traffico in Wireshark, che cosa è successo.

Questa volta il pacchetto ssl client hello non contiene esplicitamente il dominio di destinazione, ma invece è comparso un nuovo campo nel pacchetto — encrypted_server_name — dove è contenuto il valore rutracker.nl, e questo campo può essere decrittato solo dal server frontend di Cloudflare. E così, il DPI del provider non ha altra scelta che alzare le mani e consentire tale traffico. Non ci sono altre opzioni per la crittografia.
Quindi, abbiamo esaminato come funziona la tecnologia nel browser. Ora proviamo ad applicarla a cose più specifiche e interessanti. Per iniziare, insegneremo al nostro curl a utilizzare eSNI per funzionare con TLS 1.3, e vedremo anche come funziona il domain fronting basato su eSNI.
Domain fronting con eSNI
Poiché curl utilizza la libreria standard openssl per la connessione tramite il protocollo https, dobbiamo prima garantire il supporto per eSNI proprio lì. Attualmente, le branch master di openssl non supportano eSNI, quindi dobbiamo scaricare una branch speciale di openssl, compilarla e installarla.
Cloniamo il repository da GitHub e compiliamo come al solito:
$ git clone https://github.com/sftcd/openssl
$ cd openssl
$ ./config
$ make
$ cd esnistuff
$ make
Successivamente, cloniamo il repository di curl e configuriamo la sua compilazione utilizzando la nostra libreria openssl assemblata:
$ 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 specificare correttamente tutte le directory dove si trova openssl (nel nostro caso, è /opt/openssl/) e assicurarsi che il processo di configurazione sia completato senza errori.
In caso di configurazione riuscita, vedremo la seguente riga:
ATTENZIONE: esni ESNI abilitato ma contrassegnato come ESPERIMENTALE. Usare con cautela!
$ makeDopo una compilazione riuscita del pacchetto, utilizzeremo un file bash speciale fornito con openssl per configurare e avviare curl. Copiamolo nella cartella di curl per comodità:
cp /opt/openssl/esnistuff/curl-esni e faremo una richiesta https di prova al server cloudflare, registrando contemporaneamente i pacchetti DNS e TLS in Wireshark.
$ ESNI_COVER="www.hello-rkn.ru" ./curl-esni https://cloudflare.com/Nella risposta del server, oltre a molte informazioni di debug da openssl e curl, riceveremo una risposta HTTP con codice 301 da 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/
ciò indica che la nostra richiesta è stata consegnata con successo al server di destinazione, ascoltata e elaborata.
Ora diamo un'occhiata al dump del traffico in Wireshark, ossia a cosa ha visto in questo caso il DPI del provider.

È evidente che inizialmente curl si è rivolto al server DNS per ottenere la chiave eSNI pubblica per il server cloudflare — richiesta DNS TXT su _esni.cloudflare.com (pacchetto n. 13). Poi, utilizzando la libreria openssl, curl ha inviato una richiesta TLS 1.3 al server cloudflare in cui il campo SNI era criptato con la chiave pubblica ottenuta nella fase precedente (pacchetto n. 22). Tuttavia, oltre al campo eSNI, nel pacchetto SSL-hello è stato inserito anche un campo con il normale SNI — aperto, che possiamo specificare in un ordine arbitrario (in questo caso — www.hello-rkn.ru).
Questo campo SNI aperto non è stato preso in considerazione dai server cloudflare e serviva solo come maschera per il DPI del provider. Il server cloudflare ha accettato il nostro pacchetto ssl-hello, ha decriptato l'eSNI, ha estratto l'SNI originale e lo ha elaborato come se nulla fosse (ha fatto tutto esattamente come previsto durante lo sviluppo dell'eSNI).
L'unica cosa su cui in questo caso il DPI potrebbe agganciarsi è la richiesta DNS primaria su _esni.cloudflare.com. Ma abbiamo reso la richiesta DNS aperta solo per mostrare come funziona questo meccanismo dall'interno.
Per far crollare definitivamente il terreno sotto i piedi del DPI, utilizziamo il già menzionato meccanismo DNS-over-HTTPS. Una breve spiegazione – DOH – è un protocollo che consente di proteggersi dagli attacchi «uomo nel mezzo» inviando una richiesta DNS tramite il protocollo HTTPS.
Eseguiamo nuovamente la richiesta, ma questa volta otteniamo le chiavi eSNI pubbliche tramite il protocollo https, e non DNS:
ESNI_COVER="www.hello-rkn.ru" DOH_URL=https://mozilla.cloudflare-dns.com/dns-query ./curl-esni https://cloudflare.com/Il dump del traffico della richiesta è mostrato nello screenshot qui sotto:

È evidente che inizialmente curl si rivolge al server mozilla.cloudflare-dns.com tramite il protocollo DoH (connessione https al server 104.16.249.249) per ricevere i valori delle chiavi pubbliche per la crittografia dell'SNI e poi al server di destinazione, coprendosi con il dominio www.hello-rkn.ru.
Oltre al resolver DoH menzionato sopra, mozilla.cloudflare-dns.com, possiamo utilizzare anche altri servizi DoH popolari, ad esempio quelli della famosa corporazione del male.
Eseguiamo una richiesta del genere:
ESNI_COVER="www.kremlin.ru" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/E otteniamo una risposta:
< 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

In questo caso abbiamo contattato il server bloccato rutracker.nl, utilizzando come risolutore DoH dns.google (non si tratta di un errore, ora la famosa corporazione ha il proprio dominio di primo livello) e ci siamo coperti con un altro dominio, il cui blocco è severamente vietato a tutti i DPI sotto minaccia di pena di morte. Dalla risposta ricevuta si può capire che la nostra richiesta è stata elaborata con successo.
Come ulteriore verifica che il DPI del provider risponde all'SNI aperto che stiamo utilizzando come copertura — possiamo fare una richiesta a rutracker.nl coprendoci con qualche altro sito vietato, ad esempio un altro "buon" tracker torrent:
$ ESNI_COVER="rutor.info" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/Non riceveremo risposta dal server, poiché la nostra richiesta sarà bloccata dal sistema DPI.
Una breve conclusione alla prima parte
Quindi, siamo riusciti a dimostrare il funzionamento dell'eSNI utilizzando openssl e curl e a verificare il funzionamento del domain fronting basato sull'eSNI. Possiamo adattare i nostri strumenti preferiti che utilizzano la libreria openssl per funzionare "sotto copertura" di altri domini. Maggiori informazioni su questo — nei nostri prossimi articoli.
Fonte: habr.com
