Introduccion
En la primera parte del
artículo, proporcionamos una breve descripción del mecanismo de SNI encriptado (eSNI). Mostraron cómo, sobre la base, es posible evadir la detección por los sistemas DPI modernos (usando el Beeline DPI y el ILV rutracker prohibido como ejemplo), así como explorar una nueva versión del dominio front-end basado en este mecanismo.
En la segunda parte del artículo, pasaremos a cosas más prácticas que RedTeam será útil para los especialistas en su difícil trabajo. Al final, nuestro objetivo no es obtener acceso a recursos bloqueados (para cosas tan comunes, tenemos una buena VPN antigua). Afortunadamente, hay muchos proveedores de VPN, como dicen, para todos los gustos, colores y presupuestos.
Intentaremos aplicar el mecanismo de dominio de dominio para las herramientas modernas de RedTeam, por ejemplo, como Cobalt Strike, Empire, etc., y brindarles oportunidades adicionales para imitar y evadir los sistemas modernos de filtrado de contenido.
La última vez, implementamos el mecanismo eSNI en la biblioteca OpenSSL y lo utilizamos con éxito en la familiar utilidad curl. Pero un rizo, como dicen, no estará lleno. Por supuesto, quiero implementar algo similar en lenguajes de alto nivel. Pero, desafortunadamente, una búsqueda superficial de la inmensidad de la red nos decepciona, porque el soporte para el mecanismo eSNI se implementa completamente solo en GOLANG. Por lo tanto, nuestra elección no es muy grande: escribimos en C o C ++ puro usando la biblioteca parcheada de OpenSSL, o usamos una bifurcación GOLANG separada de CloudFlare e intentamos portar nuestras herramientas allí. En principio, hay otra opción, más clásica, pero que también requiere mucho tiempo: implementar el soporte eSNI para python. Después de todo, Python también usa OpenSSL para trabajar con https. Pero dejaremos esta opción para el desarrollo a otra persona, y nos contentaremos 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 externo C2). Hablaremos de esto al final del artículo.
Intenta más ...
Una de las herramientas implementadas en Go es nuestro desarrollo para pivotar dentro de la red: el
sintonizador rsockstun, que, por cierto, ahora es detectado por las herramientas de Microsoft y Symantec como un software muy malicioso destinado a violar la estabilidad mundial ...

Sería genial usar el desarrollo anterior en este caso. Pero aquí surge un pequeño problema. El hecho es que rsockstun inicialmente 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 el modo solicitud-respuesta, donde cada nueva solicitud http existe en el marco 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: la transmisión de datos a través del protocolo http (al final, de alguna manera logramos ver nuestros programas de TV favoritos y escuchar música desde portales que se ejecutan en https, y la transmisión de video y audio no es eso aparte de la transmisión de datos). Una de las tecnologías para emular el funcionamiento de una conexión TCP completa sobre el protocolo http es la tecnología WebSockets, cuya esencia principal es la organización de una conexión de red completa entre el cliente y el servidor web.
Para nuestra suerte (¡hurra!), Esta tecnología se incluye por defecto en todos los planes de tarifas de CloudFlare y funciona muy bien en combinación con eSNI. Esto es exactamente lo que usaremos para enseñarle a nuestro túnel a usar frentes de dominio y esconderse de los DPI modernos.
Un poco sobre WebSockets
En primer lugar, hablaremos brevemente y en palabras simples sobre los sockets web para que todos tengan una idea de con qué trabajaremos.
La tecnología de socket web le permite cambiar temporalmente de una conexión http a datos de transmisión estándar a través de un socket de red sin interrumpir la conexión tcp establecida. Cuando un cliente quiere cambiar a un socket web, establece varios encabezados http en su solicitud http. Dos encabezados necesarios son
Conexión: Actualización y
Actualización: websocket . También puede forzar la versión del protocolo websocket (
Sec-Websockset-Version: 13 ) y algo así como el identificador de socket web base64 (
Sec-WebSocket-Key: DAGDJSiREI3 + KjDfwxm1FA == ). El servidor responde con protocolos de conmutación de código http 101 y también establece los encabezados de
conexión, actualización y
aceptación de sec . Web. El proceso de cambio se ilustra en la siguiente captura de pantalla:

Después de eso, la conexión WebSocket se puede considerar completada. Todos los datos del cliente y del servidor ahora se proporcionarán no con http, sino con encabezados WebSocket (comienzan con el byte 0x82). Ahora el servidor no necesita esperar una solicitud del cliente para transferir datos, como La conexión TCP no está rota.
Hay varias bibliotecas en la pandilla de sockets web. Los más populares son
Gorilla WebSocket y
WebSocket estándar. Usaremos este último, porque Es más simple, más pequeño y funciona, como dicen, un poco más rápido.
En el código del cliente rsockstun, debemos reemplazar las llamadas net.dial o tls.dial con las llamadas WebSocket correspondientes:


Queremos que el cliente sea parte de nuestro túnel universal y capaz de funcionar tanto a través de una conexión SSL directa como a través del protocolo WebSockset. Para hacer esto, crearemos una función separada con el
error connectForWsSocks (cadena de dirección, cadena proxy) {...} por analogía con
connectForSocks () y la usaremos para trabajar con sockets web si la dirección del servidor especificada cuando se inicia el cliente comenzará con ws: o wss: (en el caso de Secure WebSocket).
Para el lado del servidor del túnel, también haremos una función separada para trabajar con sockets web. Se creará una instancia de la clase http y se establecerá un controlador de conexión http (función wsHandler):

Y pondremos toda la lógica para procesar la conexión (autorizando al cliente con una contraseña, instalando y finalizando la sesión de yamux) en el controlador de conexión WebSocket:

Compilamos el proyecto, iniciamos 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:


Pasamos al frente de dominio
Parece que hemos resuelto los enchufes web. Ahora vayamos directamente a eSNI y a los frentes de dominio. Como se mencionó anteriormente, para trabajar con DoH y eSNI, necesitamos tomar una rama especial del golang de
CloudFlare . Necesitamos una rama con soporte eSNI (pwu / esni).
Lo clonamos localmente o descargamos y expandimos el código postal correspondiente:
git clone -b pwu/esni https://github.com/cloudflare/tls-tris.git
Luego tenemos que copiar el directorio GOROOT, reemplazar los archivos correspondientes de la rama clonada y configurarlo como el principal. Para salvar al desarrollador de este dolor de cabeza, los chicos de CloudFlare prepararon un script especial: _dev / go.sh. Solo ejecútalo. El guión junto con el archivo MAKE harán todo por sí mismos. Para divertirse, puede buscar detalles en el interior del archivo MAKE.
Después de elaborar el script, al compilar el proyecto, necesitaremos indicar como GOROOT el directorio local preparado por el script. En nuestro caso, se ve así:
GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" go build ….
Luego, necesitamos 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 públicas eSNI de los servidores front-end de CloudFlare. Para hacer esto, 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í mismos. Tomaremos el relleno del archivo esni_query.go, que es parte de tls-tris. La primera función crea un paquete de red con una consulta al servidor DNS CloudFlare utilizando el protocolo DoH (DNS-over-HTTPS), la segunda analiza los resultados de la consulta y recibe los valores de las claves de dominio público, y la tercera es un contenedor para las dos primeras.
A continuación,
presentamos la función de solicitar claves eSNI para el dominio en nuestra función de conexión recién creada para el socket web
connectForWsSocks . Donde funciona la parte del servidor, establezca los parámetros TLS y también el nombre del "dominio de cobertura" falso:

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


Además, tendremos que hacer cambios en el archivo
tls / handshake_client.go para usar nuestro campo FakeServerName al generar el protocolo de enlace TLS:

Eso es todo! Puede compilar el proyecto y verificar el trabajo. Pero antes de ejecutar la prueba, debe configurar su cuenta de CloudFlare. Bueno, ¿cómo se dice configurar? Simplemente cree una cuenta de Cloudflare y vincule su dominio. Todos los chips relacionados con DoH, WebSocket y ESNI se incluyen en CloudFlare de forma predeterminada. Después de actualizar los registros DNS, puede verificar el dominio ejecutando la solicitud de clave eSNI:
dig +short txt _esni.df13tester.info

Si ve algo similar para su dominio, entonces todo funciona para usted y puede continuar con las pruebas.
Inicie Ubuntu VPS, por ejemplo, en DigitalOcean. PD En nuestro caso, la dirección IP de VPS que acaba de emitir el proveedor estaba en las listas negras de ILV. Así que no se sorprenda si le sucede algo similar. Tuve que usar una VPN para llegar a mi VPS.
Copiamos el rsockstun compilado a VPS (esto, por cierto, es otro encanto del golang: puede compilar el proyecto por su cuenta y ejecutarlo en cualquier Linux, observando solo la capacidad de bits del sistema) e iniciar la parte del servidor:

Y luego la parte del cliente:

Como podemos ver, el cliente se conectó con éxito al servidor a través del servidor front-end CloudFlare utilizando un socket web. Para verificar que el túnel funciona igual que un túnel, puede realizar una solicitud de curvatura a través de los calcetines locales5 abiertos en el servidor:

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

Primero, el sintonizador de túnel, usando el mecanismo DoH, accede al servidor DNS de Cloudflare para claves eSNI para el dominio de destino (paquetes No. 1-19), y luego accede al servidor front-end y establece una conexión TLS, escondiéndose bajo el dominio
www.google.com (este valor de forma predeterminada, cuando no se establece un dominio falso al inicio del cliente). Para especificar su dominio falso, debe usar el parámetro -fronfDomain:


Ahora una cosa más. De manera predeterminada, la configuración de la cuenta de CloudFalre está establecida en SSL flexible. Esto significa que las solicitudes https a los servidores front-end de Cloudflare de los clientes serán redirigidas en forma no cifrada (http) a nuestro servidor. Es por eso que lanzamos 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).

Para cambiar al modo de cifrado completo, debe seleccionar
Completo o
Completo (estricto) en el caso de la presencia de este certificado en el servidor. Después de cambiar el modo, podremos aceptar conexiones de CloudFlare a través del protocolo https. Recuerde generar un certificado autofirmado para el lado del servidor del túnel.

Un lector molesto preguntará: "¿Qué pasa con la cuenta del cliente en Windows? De hecho, seguro, la aplicación principal del túnel es elevar la conexión desde máquinas y servidores corporativos, y allí, como regla, siempre es Windows. ¿Cómo puedo compilar un túnel para Windows e incluso con una pila TLS específica? ”Y ahora presentaremos otro chip que muestra cuán conveniente es el 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 una opción de 32 bits:
GOARCH=386 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows go build -ldflags="-s -w"
Eso es todo! Y no se necesitan más problemas. ¡Realmente funciona!

Los indicadores del compilador –w y –s son necesarios para eliminar el exceso de basura del archivo ejecutable, haciéndolo menos por un par de megabytes. 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 que, usando un ejemplo de un sintonizador escrito en un golang, demostramos claramente el uso de la nueva tecnología de dominio de dominio, implementada en una característica bastante interesante del protocolo TLS 1.3. Del mismo modo, puede adaptar el kit de herramientas existente escrito en el golang para trabajar a través del servidor CloudFlare, por ejemplo
Merlin , el conocido C2, o forzar a CobaltStrike Beacon a usar frentes de dominio eSNI cuando trabaje con Teamserver a través del
canal externo C2 , implementado en el golang, o en C ++ estándar. la versión parcheada de OpenSSL, de la que hablamos en la última parte del artículo. En general, la fantasía no tiene límites.
El ejemplo del túnel y CloudFlare se presenta en forma de un concepto y aún es difícil decir sobre las perspectivas distantes de este tipo de dominio de frente. Por el momento, el soporte de eSNI solo está disponible en CloudFlare y, en principio, nada les impide deshabilitar este tipo de front-end y, por ejemplo, romper las conexiones de tls cuando SNI y eSNI no coinciden. En general, el futuro se mostrará. Pero por ahora, la posibilidad de trabajar bajo la cobertura de kremlin.ru parece bastante atractiva. Derecho?
El código de túnel actualizado, así como los archivos ejecutables compilados, se encuentran en una rama de proyecto separada en
github . Es mejor escribir un problema sobre todos los posibles problemas del túnel en la página del proyecto en GitHub.