Introducción

Los sistemas modernos de filtrado de contenido empresarial, de reconocidos fabricantes como Cisco, BlueCoat y FireEye, tienen mucho en común con sus poderosos parientes: los sistemas DPI, que se están implementando a nivel nacional. La esencia del funcionamiento de ambos radica en inspeccionar el tráfico de Internet entrante y saliente y, basándose en listas negras/blancas, decidir sobre la prohibición de conexiones a Internet. Dado que tanto uno como otro se fundamentan en principios similares, los métodos para eludirlos también compartirán muchas similitudes.
Una de las tecnologías que permite eludir de manera bastante efectiva tanto DPI como sistemas empresariales, es la tecnología de fronting de dominio. Su esencia consiste en acceder a un recurso bloqueado cubriéndonos con otro dominio público de buena reputación que no será bloqueado por ningún sistema, por ejemplo, google.com.
Ya se han escrito bastantes artículos sobre esta tecnología y se han proporcionado muchos ejemplos. Sin embargo, las tecnologías populares y debatidas recientemente como DNS-over-HTTPS y encrypted-SNI, así como la nueva versión del protocolo TLS 1.3, ofrecen la posibilidad de considerar un nuevo enfoque para el fronting de dominio.
Analizando la tecnología
Primero, aclaremos algunos conceptos básicos para que todos tengan claro quién es quién y para qué sirve todo esto. Hemos mencionado el mecanismo eSNI, cuya operación se describirá más adelante. El mecanismo eSNI (Encrypted Server Name Indication) es una versión protegida de SNI, disponible solo para el protocolo TLS 1.3. Su esencia principal es cifrar, entre otras cosas, la información sobre a qué dominio se envía la solicitud.
Ahora, examinemos la operación del mecanismo eSNI en la práctica.
Supongamos que tenemos un recurso en internet que está bloqueado por una moderna solución DPI (tomaremos como ejemplo el famoso tracker de torrents — rutracker.nl). Al intentar acceder al sitio del tracker de torrents, vemos el mensaje estándar del proveedor de que el recurso está bloqueado:

En el sitio de la RKN, este dominio realmente aparece en las listas de bloqueo:

Al realizar una solicitud whois, se puede ver que el dominio está "escondido" detrás del proveedor de la nube Cloudflare.

Pero a diferencia de los «especialistas» del RKN, los empleados más técnicamente capacitados de Beeline (o los que han aprendido de la amarga experiencia de nuestro famoso regulador) no se limitaron a bloquear el sitio por dirección IP, sino que incluyeron en la lista de prohibidos precisamente el nombre de dominio. Esto se puede comprobar fácilmente si se observa qué otros dominios se ocultan detrás de este mismo dirección IP, visitar uno de ellos y ver que el acceso no está bloqueado:

¿Cómo es posible esto? ¿Cómo sabe el DPI del proveedor a cuál de los dominios se dirige mi navegador, dado que todas las comunicaciones se realizan mediante el protocolo https, y parece que no hemos detectado sustituciones de certificados https por parte de Beeline? ¿Acaso tiene visión de rayos X o hay vigilancia sobre mí?
Intentemos responder a esta pregunta observando el tráfico a través de Wireshark

En la captura de pantalla se puede ver que primero el navegador obtiene la dirección IP del servidor a través de DNS, luego ocurre el apretón de manos TCP estándar con el servidor de destino, y después el navegador intenta establecer una conexión ssl con el servidor. Para ello, envía el paquete SSL Client Hello, que contiene el nombre del dominio de origen en texto claro. Este campo es necesario para que el servidor frontal de Cloudflare pueda enrutar correctamente la conexión. Aquí es donde nos atrapa el DPI del proveedor, rompiendo nuestra conexión. Al mismo tiempo, no recibimos ningún mensaje del proveedor, y vemos el error estándar del navegador como si el sitio estuviera apagado o simplemente no funcionara:

Ahora activemos el mecanismo eSNI en el navegador, como se indica en las instrucciones para Firefox :
Para ello, abrimos la página de configuración de Firefox about:config y activamos las siguientes configuraciones:
network.trr.mode = 2;
network.trr.uri = https://mozilla.cloudflare-dns.com/dns-query
network.security.esni.enabled = true
Después de esto, verificaremos la correcta aplicación de las configuraciones en el sitio de Cloudflare a través de el enlace y probaremos el truco con nuestro tracker de torrents una vez más.

Voilà. Nuestro querido tracker se abrió, sin necesidad de VPN ni servidores proxy. Ahora veamos el volcado de tráfico en Wireshark, ¿qué ocurrió?

Esta vez, el paquete ssl client hello no contiene explícitamente el dominio de destino, y en su lugar aparece un nuevo campo en el paquete: encrypted_server_name — ahí se encuentra el valor rutracker.nl, y solo el servidor frontal de Cloudflare puede descifrar este campo. Así que, el DPI del proveedor no tiene más opción que lavarse las manos y permitir dicho tráfico. No hay otras alternativas para el cifrado.
Entonces, hemos visto cómo funciona la tecnología en el navegador. Ahora intentemos aplicarla a cosas más específicas e interesantes. Para empezar, vamos a enseñarle a curl a usar eSNI para trabajar con TLS 1.3, y al mismo tiempo, examinaremos cómo funciona el domain fronting basado en eSNI.
Domain Fronting con eSNI
Dado que curl utiliza la biblioteca estándar openssl para conexiones HTTPS, primero debemos asegurar el soporte de eSNI en ella. Actualmente, las ramas master de openssl no tienen soporte para eSNI, por lo que necesitamos descargar una rama especial de openssl, compilarla e instalarla.
Clonamos el repositorio de GitHub y compilamos como de costumbre:
$ git clone https://github.com/sftcd/openssl
$ cd openssl
$ ./config
$ make
$ cd esnistuff
$ make
A continuación, clonamos el repositorio de curl y configuramos su compilación utilizando nuestra 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
Es importante especificar correctamente todos los directorios donde se encuentra openssl (en nuestro caso, es /opt/openssl/) y asegurarse de que el proceso de configuración se complete sin errores.
En caso de que la configuración sea exitosa, veremos la línea:
WARNING: esni ESNI enabled but marked EXPERIMENTAL. Use with caution!
$ makeDespués de construir el paquete con éxito, utilizaremos un archivo bash especial de la biblioteca openssl para configurar y ejecutar curl. Lo copiaremos al directorio de curl para mayor comodidad:
cp /opt/openssl/esnistuff/curl-esni y realizaremos una solicitud HTTPS de prueba al servidor de Cloudflare, registrando simultáneamente los paquetes DNS y TLS en Wireshark.
$ ESNI_COVER="www.hello-rkn.ru" ./curl-esni https://cloudflare.com/En la respuesta del servidor, además de una gran cantidad de información de depuración de openssl y curl, obtendremos una respuesta HTTP con código 301 de 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/
lo que indica que nuestra solicitud se entregó con éxito al servidor de destino, fue escuchada y procesada.
Ahora veamos el volcado de tráfico en Wireshark, es decir, lo que en este caso vio el DPI del proveedor.

Se puede ver que primero curl se dirigió al servidor DNS en busca de la clave pública eSNI para el servidor cloudflare — solicitud DNS TXT a _esni.cloudflare.com (paquete n.º 13). Luego, utilizando la biblioteca openssl, curl envió una solicitud TLS 1.3 al servidor cloudflare en la cual el campo SNI fue cifrado con la clave pública obtenida en el paso anterior (paquete n.º 22). Sin embargo, además del campo eSNI, en el paquete SSL-hello también se insertó un campo con el SNI común — abierto, que podemos especificar en un orden arbitrario (en este caso — www.hello-rkn.ru).
Este campo de SNI abierto no fue considerado al ser procesado por los servidores de cloudflare y solo servía como una máscara para el DPI del proveedor. El servidor cloudflare aceptó nuestro paquete ssl-hello, descifró el eSNI, extrajo el SNI original y lo procesó sin ningún problema (hizo todo exactamente como se planeó durante el desarrollo de eSNI).
Lo único por lo que en este caso se puede cuestionar desde el punto de vista del DPI es la solicitud DNS inicial a _esni.cloudflare.com. Pero hicimos la solicitud DNS abierta solo para mostrar cómo funciona este mecanismo desde adentro.
Para eliminar completamente el suelo bajo los pies del DPI, utilizamos el mecanismo mencionado de DNS-over-HTTPS. Una pequeña aclaración: DOH es un protocolo que permite protegerse contra ataques de "hombre en medio" al enviar la solicitud DNS a través del protocolo HTTPS.
Realizamos la solicitud nuevamente, pero esta vez obtendremos las claves públicas eSNI a través del protocolo https, y no DNS:
ESNI_COVER="www.hello-rkn.ru" DOH_URL=https://mozilla.cloudflare-dns.com/dns-query ./curl-esni https://cloudflare.com/El volcado del tráfico de la solicitud se presenta en la captura de pantalla a continuación:

Se puede observar que primero curl se dirige al servidor mozilla.cloudflare-dns.com a través del protocolo DoH (conexión https al servidor 104.16.249.249), para obtener de ellos los valores de las claves públicas para cifrar el SNI, y luego se dirige al servidor de destino, ocultándose detrás del dominio www.hello-rkn.ru.
Además del resolutor DoH mencionado anteriormente, mozilla.cloudflare-dns.com, también podemos utilizar otros servicios populares de DoH, como el de la famosa corporación del mal.
Realizaremos tal solicitud:
ESNI_COVER="www.kremlin.ru" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/Y recibiremos la respuesta:
< 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

En este caso, nos dirigimos al servidor bloqueado rutracker.nl, utilizando el resolvedor DoH dns.google (no hay error tipográfico, ahora la famosa corporación tiene su propio dominio de nivel superior) y nos ocultamos detrás de otro dominio, que está estrictamente prohibido a todos los DPI bajo la pena de muerte. A partir de la respuesta obtenida, se puede entender que nuestra solicitud fue procesada correctamente.
Como una verificación adicional de que el DPI del proveedor responde al SNI abierto que enviamos como cubierta, podemos hacer una solicitud a rutracker.nl ocultándonos detrás de algún otro recurso prohibido, por ejemplo, otro "buen" tracker de torrents:
$ ESNI_COVER="rutor.info" DOH_URL=https://dns.google/dns-query ./curl-esni https://rutracker.nl/No recibiremos respuesta del servidor, ya que nuestra solicitud será bloqueada por el sistema DPI.
Una breve conclusión para la primera parte
Así que hemos logrado demostrar la funcionalidad de eSNI utilizando openssl y curl, y verificar el funcionamiento del domain fronting basado en eSNI. De la misma manera, podemos adaptar nuestras herramientas favoritas que utilizan la biblioteca openssl para trabajar "bajo la cubierta" de otros dominios. Más sobre esto en nuestros próximos artículos.
Fuente: habr.com
