Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
WEASEL — Implante de canal encubierto DNS para Equipos Rojos. | Kitploit
Herramientas/GitHubGitHub/facebookarchive/weasel
Herramientas de Cifrado/DescifradoMecanismos de PersistenciaPost-ExplotaciónPruebas de PenetraciónComando y ControlRed TeamingDesarrollo de PayloadsAnálisis de DNSArchived
GitHubfacebookarchive/weasel

WEASEL

Implante de canal encubierto DNS para Equipos Rojos.

7316615hace 6 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
Ver Repositorio

WEASEL: Un Beacon DNS Sigiloso

WEASEL es un pequeño implante en memoria que utiliza Python 3 sin dependencias. El cliente baliza envía una pequeña cantidad de información identificativa sobre su host a una zona DNS que usted controla. El servidor WEASEL puede asignar a los clientes la ejecución de comandos predefinidos o arbitrarios.

WEASEL es un payload de etapa 1, diseñado para ser difícil de detectar y útil para recuperar el acceso cuando sus ruidosas etapas completas son detectadas.

Estado

  • Ha sido utilizado con éxito en una operación y ha evadido detecciones.
  • El cliente puede iniciar una sesión con el servidor y establecer comunicación bidireccional.
  • El servidor tiene una CLI completamente funcional.
  • El cliente admite varias funciones que el servidor puede asignar.
  • El cliente tiene 5.2KB cuando está minificado y ofuscado.
  • La ofuscación automática es deficiente y necesita corrección manual (consulte Limitaciones en el README del cliente).
  • El servidor no tiene soporte multijugador (múltiples operadores simultáneos).

Ejemplos

Consulte el uso en el README del cliente y el README del servidor para instrucciones específicas.

Para iniciar el servidor o el cliente, ejecute los scripts directamente o pásalos al intérprete de Python.

Asegúrese de que cada dominio C2 tenga un registro NS con la dirección IP del host que ejecuta server.py.

Requisitos

WEASEL requiere Python 3.6+.

El cliente es autónomo y solo utiliza bibliotecas estándar, por lo tanto, puede ejecutarse en macOS, Linux, etc.

El servidor tiene algunas dependencias de pip, incluidas en requirements.txt del servidor. El servidor debe ejecutarse en Linux, pero nada impide que se ejecute en macOS u otros *nix.

Pruebas / Ejecución en Desarrollo

No es necesario ofuscar y minimizar la baliza en este caso. Las declaraciones de impresión se conservan. Al igual que en el Uso anterior, asegúrese de que los registros NS del dominio(s) en servidores en beacon.py apunten a la dirección IP de server.py.

En el host del servidor:

sudo python3 server.py

En el host de la víctima (puede ser el mismo que el servidor):

python3 beacon.py

Arquitectura

No necesita entender nada de esto para usar WEASEL.

La baliza se comunica a través de DNS utilizando consultas y respuestas AAAA. No utiliza registros TXT debido a que son conocidos por ser utilizados por malware y túneles DNS. Los equipos azules suelen tener detecciones de túneles DNS que alertan sobre consultas TXT grandes.

El lado del cliente no necesita root para funcionar, no utiliza sockets sin procesar y no crea paquetes DNS malformados. Utiliza interfaces regulares del sistema y del lenguaje para realizar solicitudes DNS. La información está codificada y cifrada en los propios registros.

  • Un solo registro A (dirección IPv4) puede contener 4 bytes de información.
  • Un solo registro AAAA (dirección IPv6) puede contener 16 bytes de información.
  • Los registros CNAME y los nombres de host utilizados en las consultas pueden contener hasta 64 bytes por subdominio y no deben tener más de 255 bytes en total según RFC. Sin embargo, las pautas de detección de DNS de SANS dicen que los subdominios de más de 52 caracteres son sospechosos. Por esta razón, limitamos los subdominios a 52 caracteres (configurable en el código) e intentamos usar no más subdominios y solicitudes de los que necesitamos.
  • Una respuesta puede contener múltiples registros, hasta el límite de tamaño de un datagrama UDP (65,507 bytes).

Esta baliza está diseñada para ser lenta y discreta, con poco ancho de banda. Debe decirnos en qué hosts se encuentra y darnos una manera de lanzar más etapas según sea necesario, y nada más. Aunque tiene soporte para comandos arbitrarios, no está destinada a usarse como un shell interactivo regular o canal de comunicaciones.

WEASEL es una etapa 1 que dejas ejecutando, asegurando acceso continuo mientras tus etapas completas (y por lo tanto más ruidosas) son detectadas.

Persistencia

WEASEL fue inicialmente dirigido a servidores de alta disponibilidad donde teníamos un vector de punto de apoyo/explotación confiable. Evadir el análisis forense era una alta prioridad. Como resultado, no tiene características de persistencia nativas.

Puedes hacerlo persistente agregando su ejecución a tu técnica de persistencia favorita, lo cual se deja como ejercicio para el lector :)

Protocolo y Formato de Mensajes

Solicitud del Cliente

Una solicitud (del cliente) es una única consulta AAAA para un nombre formateado como:

<preamble><data>.<stream>.<session>.domain.tld

El preámbulo tiene 2 bytes. Preámbulo[0] es el número de secuencia de ese paquete. Preámbulo[1] es el número total de paquetes en esa secuencia.

Los datos están limitados a 50 bytes (configurable) y contienen la carga útil. La carga útil está codificada en base32 con un alfabeto personalizado.

Codificación de la Carga Útil

Primero, todos los caracteres 'w' se intercambian por '-'.

Luego, el carácter de relleno se intercambia de '=' a 'w' para ajustarse al conjunto de caracteres DNS: [a-z0-9] y [-].

No intercambiamos '=' con '-' directamente porque el relleno siempre estará al final de la cadena, y terminar un nombre de host con '---' es sospechoso y va en contra de la RFC de DNS. De esta manera, cuando una cadena tiene relleno, terminará en 'www', lo cual es menos sospechoso y cumple con la RFC.

Respuesta del Servidor

Una respuesta (del servidor) está compuesta por una o más respuestas AAAA.

Cada respuesta AAAA es una carga útil cifrada de 16 bytes representada como una dirección IPv6 usando socket.inet_ntop. Las respuestas en una respuesta DNS no mantienen su orden en tránsito, por lo que se secuencian y reensamblan como las solicitudes del cliente.

La carga útil de transporte es una cadena de elementos de datos separados por un carácter ^.

Formato de Transporte

Las solicitudes y respuestas siguen este formato:

<type>|<data>

Sesiones

Las sesiones son de larga duración: un cliente inicia una sesión cuando la baliza se ejecuta por primera vez y esa sesión debe durar todo el tiempo que la baliza esté activa en ese cliente. Tenga en cuenta que, dado que la baliza está en memoria y no es persistente, los datos de la sesión se almacenan en la memoria de ese proceso de Python. Cualquier nueva invocación de la baliza iniciará una nueva sesión.

Iniciar una sesión implica que el cliente elabore un mensaje con un preámbulo no de datos que identifique de manera única (para señalar al servidor que esta es una nueva sesión): la concatenación de una clave pública Diffie-Hellman de 32 bytes y un IV AES aleatorio de 16 bytes.

El servidor recibe esto y responde con su propia clave pública de 32 bytes. En este punto, el cliente y el servidor han establecido una clave de sesión compartida que se utilizará durante toda la vida de esta sesión para cifrar las cargas útiles de datos usando AES-128 en modo CTR. El intercambio Diffie-Hellman Efímero asegura que cada conexión cliente-servidor use una clave de sesión única con secreto hacia adelante.

Maldad del Cifrado

El cifrado es deliberadamente malo por varias razones:

  • Estamos emulando a atacantes reales que generalmente tienen poca idea de cómo construir sistemas criptográficos robustos y son fanáticos de hacer los suyos propios
  • El ancho de banda de la baliza es lo más bajo posible, lo que significa que nuestro intercambio DHE debe mantenerse muy pequeño
  • La no atribución es importante, no autenticamos el servidor
  • Es menos divertido para los respondedores si usamos criptografía de última generación que no pueden esperar romper

Aquí hay algunos problemas conocidos con el esquema criptográfico:

  1. El módulo Diffie-Hellman p es RFC 3526 Grupo 5 truncado a los primeros 32 bytes. Esto no solo limita las claves públicas y privadas a 32 bytes, sino que el Grupo 5 ya está obsoleto y se recomienda no usarlo. Llamo a esta mala decisión "Grupo 1".
  2. Usamos random.randint() para el exponente a en lugar de un CSPRNG.
  3. Usamos una pequeña cantidad de datos de os.urandom() para la generación de ID de sesión e ID de flujo en lugar de un UUID, lo que significa que es probable que haya colisiones. Tenemos esto en cuenta reintentando hasta obtener un ID que no esté en uso.
  4. El cifrador AES-CTR se reinicia con el mismo IV (que tiene una larga vida como la clave de sesión) para cada flujo. Esto significa que el mismo texto plano en la misma posición entre flujos producirá el mismo texto cifrado.
  5. En AES-CTR, el IV se llama correctamente nonce, pero en nuestra implementación no estamos usando el número una vez, por lo que sería un poco grosero llamarlo así.

Flujos

Cada mensaje enviado entre un cliente y un servidor debe dividirse en paquetes de máximo 50 bytes, para mantenerse por debajo del límite de 52 bytes para detecciones comunes de canales encubiertos DNS. Todos los paquetes de un mensaje particular son parte del mismo flujo. Mensaje == Flujo.

Los flujos se identifican con un número hexadecimal aleatorio de 2 bytes. Recuerde que el formato de solicitud del cliente es: <preamble><data>.<stream>.<session>.domain.tld

El preámbulo de 2 bytes de cada paquete en el flujo tiene un número de secuencia y el número total de paquetes en ese flujo. Esto permite que el servidor sepa cuándo ha llegado todo.

Debido a que esto es DNS, lo hacemos todo sobre UDP, que no proporciona ninguna garantía sobre el orden en que llegarán los datagramas. Por eso WEASEL tiene que tener en cuenta la secuenciación, el reensamblaje y el seguimiento de múltiples flujos de muchas balizas.

Cada flujo reinicia un cifrador AES-128-CTR compartido globalmente para cifrar/descifrar cargas útiles.

La carga útil solo se puede descifrar una vez que el flujo está completo (todos los paquetes han llegado). Si no fuera por base32, podríamos descifrar lo que tenemos del mensaje incluso si nos faltaran paquetes (porque AES-CTR es un cifrador de flujo), pero no podemos decodificar base32 en flujos parciales. Bueno. Por la naturaleza de los clientes DNS, las solicitudes se realizan varias veces (generalmente 2 o 4 veces) hasta que se recibe una respuesta, por lo que tenemos una buena probabilidad de recibir todos los paquetes en un flujo, ya que cada paquete debe ser enviado por el cliente al menos dos veces. Si perdemos paquetes o flujos, no es un gran problema, la baliza se registrará nuevamente más tarde y probablemente tendrá mejor suerte entonces.

Únete a la comunidad WEASEL

Consulte el archivo CONTRIBUTING para saber cómo ayudar.

Licencia

WEASEL tiene licencia MIT, como se encuentra en el archivo LICENSE.

Descargar herramienta
TypeSignificado (remitente)AKADatos
0ReconocidoACKHex aleatorio
1Registrándose (cliente)PINGHex aleatorio
2Termínate a ti mismo (servidor), terminándome a mí mismo (cliente)FIN
3Mensaje de inicialización (cliente)SYN`version
4Reconectar (servidor)RST
5Establecer intervalo de devolución de llamada (servidor)segundos
6Obtener datos de interfaz de redeth0 1.2.3.4/24\neth1 fe80:::/64\n...
8Evaluar código Python3 arbitrario hasta 666 bytes (servidor), devolviendo los primeros 400 bytes de salida (cliente)EVALscript de una línea python3
9Ejecutar comando arbitrario hasta 666 bytes (servidor), devolviendo los primeros 400 bytes de salida (cliente)EXECcomando bash