Fronting de dominio basado en TLS 1.3. Parte 2

introducción

En la primera parte Artículo Hemos dado una breve descripción del mecanismo SNI cifrado (eSNI). Mostraron cómo, basándose en esto, es posible evadir la detección de los sistemas DPI modernos (usando el ejemplo de Beeline DPI y el rastreador de raíz RKN prohibido), y también exploraron una nueva versión de fronting de dominio basada en este mecanismo.

En la segunda parte del artículo pasaremos a cosas más prácticas que serán de utilidad para los especialistas de RedTeam en su difícil trabajo. Al final, nuestro objetivo no es obtener acceso a recursos bloqueados (para cosas tan triviales tenemos la vieja VPN). Afortunadamente, existe una gran variedad de proveedores de VPN, como dicen, para todos los gustos, colores y presupuestos.

Intentaremos aplicar el mecanismo de dominio de dominio a herramientas modernas de RedTeam, por ejemplo, como Cobalt Strike, Empire, etc., y darles capacidades adicionales para imitar y evadir los sistemas de filtrado de contenido modernos.

La última vez implementamos el mecanismo eSNI en la biblioteca OpenSSL y lo utilizamos con éxito en la conocida utilidad curl. Pero, como suele decirse, no te contentarás con un solo pollo. Por supuesto, me gustaría implementar algo similar en lenguajes de alto nivel. Pero, desafortunadamente, una búsqueda rápida en Internet nos decepciona, porque el soporte para el mecanismo eSNI está completamente implementado solo en GOLANG. Por lo tanto, no tenemos muchas opciones: o escribimos en C puro o C++ usando la biblioteca OpenSSL parcheada, o usamos una bifurcación GOLANG separada de CloudFlare e intentamos migrar nuestras herramientas allí. En principio, existe otra opción, más clásica, pero que requiere mucho tiempo: implementar el soporte eSNI para Python. Después de todo, Python también usa OpenSSL para manejar https. Pero dejaremos esta opción para que la desarrolle otra persona, y nosotros mismos estaremos contentos con la implementación en Golang, especialmente porque nuestro querido Cobalt Strike es perfectamente capaz de trabajar con un canal de comunicación creado por herramientas de terceros (canal C2 externo). - Hablaremos de esto al final del artículo.

Esforzarse más...

Una de las herramientas implementadas en Go es nuestro desarrollo para pivotar en la red: un tunelizador. rsockstun, que, por cierto, ahora es detectado por herramientas de Microsoft y Symantec como software muy malicioso destinado a alterar la estabilidad global...

Fronting de dominio basado en TLS 1.3. Parte 2

Sería genial utilizar el desarrollo anterior también en este caso. Pero aquí surge un pequeño problema. El hecho es que inicialmente rsockstun implica el uso de un canal de comunicación SSL síncrono con el servidor. Esto significa que la conexión se establece una vez y existe durante toda la operación del túnel. Y, como comprenderá, el protocolo https no está diseñado para este modo de operación: funciona en modo solicitud-respuesta, donde cada nueva solicitud http existe dentro de una nueva conexión tcp.

La principal desventaja de este esquema es que el servidor no puede transferir datos al cliente hasta que el cliente envíe una nueva solicitud http. Pero, afortunadamente, hay muchas opciones para resolver este problema: transmitir datos a través del protocolo http (después de todo, de alguna manera logramos ver nuestros programas de televisión favoritos y escuchar música desde portales que funcionan en https, pero transmitir video y audio no es otra cosa. que la transmisión de datos). Una de las tecnologías para emular el funcionamiento de una conexión TCP completa a través del protocolo HTTP es la tecnología WebSockets, cuya esencia principal es organizar una conexión de red completa entre el cliente y el servidor web.

Por suerte para nosotros (¡¡¡hurra!!!), esta tecnología está incluida por defecto en todos los planes tarifarios de CloudFlare y funciona muy bien en combinación con eSNI. Esto es exactamente lo que usaremos para enseñarle a nuestro tunelizador a usar el dominio frontal y esconderse de los DPI modernos.

Un poco sobre WebSockets

En primer lugar, explicaremos de forma breve y sencilla los websockets para que todos tengan una idea de con qué trabajaremos.

La tecnología Websocket le permite cambiar temporalmente de una conexión http a una transmisión de socket de red estándar sin interrumpir la conexión TCP establecida. Cuando un cliente quiere cambiar a un websocket, establece varios encabezados http en su solicitud http. Dos encabezados requeridos - Conexión: actualización и Actualización: websocket. También puede especificar con fuerza la versión del protocolo websocket (Sec-Websockset-Versión: 13) y algo así como un identificador de websocket base64 (Sec-WebSocket-Clave: DAGDJSiREI3+KjDfwxm1FA==). El servidor le responde con el código http 101 Protocolos de conmutación y también establece los encabezados. Conexión, actualización и Sec-WebSocket-Aceptar. El proceso de cambio se demuestra claramente en la siguiente captura de pantalla:

Fronting de dominio basado en TLS 1.3. Parte 2

Después de esto, la instalación de la conexión WebSocket se puede considerar completa. Todos los datos tanto del cliente como del servidor ahora no se proporcionarán con http, sino con encabezados WebSocket (comienzan con el byte 0x82). Ahora el servidor no necesita esperar una solicitud del cliente para transferir datos, porque La conexión TCP no está rota.

Golang tiene varias bibliotecas para trabajar con websockets. Los más populares son Gorila WebSocket y estándar WebSocket. Usaremos este último, porque... es más sencillo, más pequeño y, como dicen, funciona un poco más rápido.

En el código del cliente rsockstun, necesitamos reemplazar las llamadas net.dial o tls.dial con las llamadas WebSocket correspondientes:

Fronting de dominio basado en TLS 1.3. Parte 2

Fronting de dominio basado en TLS 1.3. Parte 2

Queremos que el cliente forme parte de nuestro túnel de forma universal y capaz de funcionar tanto a través de una conexión SSL directa como a través del protocolo WebSockset. Para esto crearemos una función separada. error de func connectForWsSocks (cadena de dirección, cadena de proxy) {…} por analogía con conectarParaCalcetines() y lo usaremos para trabajar con web sockets si la dirección del servidor especificada al iniciar el cliente comienza con ws: o wss: (en el caso de Secure WebSocket).

Para el lado del servidor del túnel, también crearemos una función separada para trabajar con sockets web. Creará una instancia de la clase http y configurará el controlador de conexión http (función wsHandler):

Fronting de dominio basado en TLS 1.3. Parte 2

Y colocaremos toda la lógica de procesamiento de la conexión (autorización del cliente mediante contraseña, configuración y finalización de una sesión de yamux) en el controlador de conexión WebSocket:

Fronting de dominio basado en TLS 1.3. Parte 2

Compilamos el proyecto y lanzamos la parte del servidor:

./rsockstun –listen ws:127.0.0.1:8080 –pass P@ssw0rd

Y luego la parte del cliente:

./rsockstun -connect ws:127.0.0.1:8080 –pass P@ssw0rd

Y verificamos el trabajo en el host local:

Fronting de dominio basado en TLS 1.3. Parte 2

Fronting de dominio basado en TLS 1.3. Parte 2

Pasemos al frente de dominio

Parece que hemos descubierto los websockets. Ahora pasemos directamente al eSNI y al fronting de dominio. Como se mencionó anteriormente, para trabajar con DoH y eSNI necesitamos tomar una sucursal especial de golang de la empresa. CloudFlare. Necesitamos una sucursal con soporte eSNI (pwu/esni).

Lo clonamos localmente o descargamos y descomprimimos el zip correspondiente:

git clone -b pwu/esni https://github.com/cloudflare/tls-tris.git

Luego necesitamos copiar el directorio GOROOT, reemplazar los archivos correspondientes de la rama clonada y configurarlo como maestro. Para salvar al desarrollador de este dolor de cabeza, los chicos de CloudFlare han preparado un script especial: _dev/go.sh. Simplemente lo lanzamos. El script junto con el archivo MAKE harán todo por sí mismos. Sólo por diversión, puedes mirar dentro del archivo MAKE para obtener más detalles.

Después de ejecutar el script, al compilar el proyecto, necesitaremos especificar el directorio local preparado por el script como GOROOT. En nuestro caso se ve así:

GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" go build ….

A continuación, debemos implementar en el túnel la funcionalidad de solicitar y analizar claves públicas eSNI para el dominio deseado. En nuestro caso, serán claves eSNI públicas de los servidores frontend de CloudFlare. Para ello crearemos tres funciones:

func makeDoTQuery(dnsName string) ([]byte, error)
func parseTXTResponse(buf []byte, wantName string) (string, error)
func QueryESNIKeysForHost(hostname string) ([]byte, error)

Los nombres de las funciones, en principio, hablan por sí solos. Tomaremos el contenido del archivo esni_query.go, que forma parte de tls-tris. La primera función crea un paquete de red con una solicitud al servidor DNS de CloudFlare utilizando el protocolo DoH (DNS-over-HTTPS), la segunda analiza los resultados de la consulta y obtiene los valores de las claves públicas del dominio, y la tercera es una contenedor para los dos primeros.

A continuación, agregamos una conexión de socket web a nuestra función recién creada. conectarForWsSocks Funcionalidad para solicitar claves eSNI para un dominio. Donde opera la parte del servidor, configuramos los parámetros TLS y también configuramos el nombre del "dominio de cobertura" falso:

Fronting de dominio basado en TLS 1.3. Parte 2

Cabe señalar aquí que inicialmente la rama tls-tris no fue diseñada para el uso de fronting de dominio. Por lo tanto, no presta atención al nombre falso del servidor (se envía un campo serverName vacío como parte del paquete de saludo del cliente). Para solucionar este problema, tendremos que agregar el campo FakeServerName correspondiente a la estructura TlsConfig. No podemos utilizar el campo ServerName estándar de la estructura, porque es utilizado por los mecanismos internos de tls y si difiere del original, el protocolo de enlace de tls terminará con un error. Una descripción de la estructura TlsConfig está contenida en el archivo tls/common.go - tenemos que arreglarlo:

Fronting de dominio basado en TLS 1.3. Parte 2

Fronting de dominio basado en TLS 1.3. Parte 2

Además, tendremos que realizar cambios en el archivo. tls/handshake_client.gopara utilizar nuestro campo FakeServerName al formar un protocolo de enlace TLS:

Fronting de dominio basado en TLS 1.3. Parte 2

¡Eso es todo! Puede compilar el proyecto y comprobar el trabajo. Pero antes de ejecutar el análisis, debe configurar una cuenta de CloudFlare. Bueno, ¿cómo puedo decir configurarlo? Simplemente cree una cuenta en Cloudflare y vincule su dominio a ella. Todas las funciones relacionadas con DoH, WebSocket y ESNI están incluidas en CloudFlare de forma predeterminada. Una vez actualizados los registros DNS, podrás comprobar el funcionamiento del dominio consultando las claves eSNI:

dig +short txt _esni.df13tester.info 

Fronting de dominio basado en TLS 1.3. Parte 2

Si ve algo similar para su dominio, significa que todo está funcionando para usted y puede continuar con la prueba.

Lanzamos Ubuntu Por ejemplo, un VPS en DigitalOcean. PD: En nuestro caso, la dirección IP del VPS que acabábamos de recibir de nuestro proveedor terminó en la lista negra de Roskomnadzor. Así que no te extrañes si te ocurre algo similar. Tuve que usar una VPN para acceder a mi VPS.

Copiamos el rsockstun ya compilado al VPS (esto, por cierto, es otra belleza de Golang: puedes compilar el proyecto tú mismo y ejecutarlo en cualquier Linux, observando solo la capacidad de bits del sistema) y ejecutamos la parte del servidor:

Fronting de dominio basado en TLS 1.3. Parte 2

Y luego la parte del cliente:

Fronting de dominio basado en TLS 1.3. Parte 2

Como podemos ver, el cliente se conectó exitosamente al servidor a través del servidor frontend de CloudFlare usando un websocket. Para comprobar que el túnel funciona exactamente como un túnel, puede realizar una solicitud curl a través de calcetines locales5, abiertos en el servidor:

Fronting de dominio basado en TLS 1.3. Parte 2

Ahora veamos qué ve DPI en el canal de comunicación:

Fronting de dominio basado en TLS 1.3. Parte 2

Primero, el tunelizador, utilizando el mecanismo DoH, se comunica con el servidor DNS de Cloudflare para obtener claves eSNI para el dominio de destino (paquetes n.° 1-19) y luego se comunica con el servidor frontend y establece una conexión TLS, escondiéndose detrás del dominio. www.google.com (Este es el valor predeterminado cuando no se especifica ningún dominio falso cuando se inicia el cliente). Para especificar su dominio falso, debe usar el parámetro -fronfDomain:

Fronting de dominio basado en TLS 1.3. Parte 2

Fronting de dominio basado en TLS 1.3. Parte 2

Ahora una cosa más. De forma predeterminada, la configuración de la cuenta de CloudFalre está configurada en SSL flexible. Esto significa que las solicitudes https a los servidores frontend de Cloudflare desde los clientes se reenviarán sin cifrar (http) a nuestro servidor. Es por eso que iniciamos la parte del servidor del túnel en modo no SSL ( -listen ws:0.0.0.0), y no ( -listen wss:0.0.0.0).

Fronting de dominio basado en TLS 1.3. Parte 2

Para cambiar al modo de cifrado completo, debe seleccionar PlenoO Completo (estricto) si hay un certificado real en el servidor. Después de cambiar de modo, podremos aceptar conexiones de CloudFlare utilizando el protocolo https. No olvide generar un certificado autofirmado para el lado del servidor del túnel.

Fronting de dominio basado en TLS 1.3. Parte 2

El lector curioso preguntará: "¿Qué pasa con el cliente bajo Windows"Al fin y al cabo, el uso principal de un tunelizador probablemente sea establecer una conexión de back-end desde máquinas y servidores corporativos, y estos suelen ser siempre Windows. ¿Cómo compilo un tunelizador para Windows, especialmente con una pila TLS específica?" Ahora presentaremos otra característica que demuestra lo conveniente que es Golang. Compilamos para Windows directamente desde Kali simplemente agregando el parámetro GOOS=windows:

GOARCH=amd64 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows  go build -ldflags="-s -w"

O la versión de 32 bits:

GOARCH=386 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows  go build -ldflags="-s -w"

¡Todo! Y no se necesitan más molestias. ¡Realmente funciona!

Fronting de dominio basado en TLS 1.3. Parte 2

Los indicadores del compilador –w y –s son necesarios para eliminar basura innecesaria del archivo ejecutable, haciéndolo un par de megabytes más pequeño. Además, se puede empaquetar usando UPX para reducir aún más el tamaño.

En lugar de una conclusión

En el artículo, utilizando el ejemplo de un túnel escrito en Golang, demostramos claramente el uso de la nueva tecnología de dominio frontal, implementada sobre una característica bastante interesante del protocolo TLS 1.3. De manera similar, puede adaptar las herramientas existentes escritas en Golang para que funcionen a través de servidores CloudFlare, por ejemplo. Esmerejón - famoso C2, o forzar a CobaltStrike Beacon a utilizar el dominio eSNI cuando se trabaja con Teamserver a través de Canal C2 externo, implementado en Golang, o en C++ estándar usando una versión parcheada de OpenSSL, de la que hablamos en la última parte del artículo. En general, la imaginación no tiene límites.

El ejemplo del tunelizador y CloudFlare se presenta en forma de concepto y todavía es difícil decir sobre las perspectivas a largo plazo de este tipo de dominio frontal. Por el momento, solo CloudFlare admite eSNI y, en teoría, nada les impide deshabilitar este tipo de fronting y, por ejemplo, romper las conexiones tls si SNI y eSNI no coinciden. En general, el futuro lo dirá. Pero por ahora, la perspectiva de trabajar bajo la “cubierta de kremlin.ru” parece bastante tentadora. ¿No es?

El código actualizado del tunelizador, así como los archivos ejecutables compilados, se encuentran en una rama separada del proyecto en gitHub. Es mejor escribir un número sobre todos los posibles problemas del tunelizador en la página del proyecto en GitHub.

Fuente: habr.com

Compre alojamiento confiable para sitios con protección DDoS, servidores VPS VDS 🔥 Compra alojamiento web fiable con protección DDoS, servidores VPS VDS | ProHoster