
plantilla para desarrollar canales C2 personalizados para Cobalt Strike usando ganchos IAT aplicados por un cargador reflectivo.
Esta es una PoC simple y una plantilla para desarrollar canales C2 personalizados para Cobalt Strike usando hooks de IAT aplicados por un cargador reflectante.
Publicación del blog: https://codex-7.gitbook.io/codexs-terminal-window/red-team/cobalt-strike/building-custom-c2-channels-by-hooking-wininet
Gif de demostración del canal TCP

Los archivos customCallback.h, hook.c, hash.h y hook.h son plantillas preliminares, pero pueden colocarse en Crystal kit para usarse tal cual como PoC. Colóquelos en la carpeta udrl/src, reemplazando las copias existentes. tcg.h no ha sido modificado (del jardín de trucos de Raphael Mudge).
Los ejemplos en la carpeta examples/ pueden usarse tal cual, pero son ejemplos y no se tuvieron en cuenta consideraciones operativas al escribirlos. Úselos con precaución.
Los ejemplos actuales son:
Tenga en cuenta que las capacidades de evasión originales en Crystal kit, como la implementación de Draugr y el enmascaramiento de sueño, se han eliminado de hook.c para mantener este código limpio y portátil. Si desea conservar esas funcionalidades, puede agregarlas nuevamente desde las copias originales en Crystal kit.
Debe seleccionar la biblioteca HTTP adecuada (winhttp/wininet) como biblioteca HTTP a usar al generar el DLL del beacon.
El perfil malleable con el que se probó esto se proporciona en el repositorio; en teoría, (la mayoría de) otros perfiles malleable deberían funcionar, pero esta plantilla se probó usando este perfil (tomado de GraphStrike).
La interfaz oficial ExternalC2 es difícil de usar: requiere el staging de un beacon SMB SOBRE el canal externalc2, y (hasta 4.10) no soportaba la comunicación con un beacon SMB previamente creado sin staging a través del agente externalc2 primero. Incluso en su estado actual, sigue ligada a la arquitectura:
smb beacon --tubería con nombre--> agente externalc2 --canal personalizado--> manejador externalc2 --> teamserver
Sí, sé que se agregó UDC2 en Cobalt Strike 4.12. De todos modos, esto es solo un experimento divertido para replicar esa capacidad en el UDRL.
El concepto es simple: si puedes hacer hook de las WinAPI utilizadas para el callback, ya tienes todos los datos necesarios para un callback. Este método de implementar canales C2 personalizados ya se ha hecho antes, como se ve en GraphStrike.
Sin embargo, la implementación de GraphStrike sigue estando bastante ligada al propio protocolo HTTP. El objetivo de este repositorio es proporcionar una plantilla fácil de usar, modificar y extender para implementar cualquier canal personalizado, HTTP o de otro tipo, con poca modificación del código circundante.
Obviamente, esta plantilla no está pensada para usarse en su estado predeterminado, por lo que para implementar el canal C2 de su elección, debe modificar lo siguiente:
La función customCallback para que realice las siguientes tareas:
Puede usar el host y puerto originales de la solicitud HTTP (que configura desde cobalt) a través de los argumentos:
const char *host
INTERNET_PORT port
y modificar la función handleCallback() en broker.py para que haga lo siguiente:
Eso es todo.
Como ejemplo, la PoC en la función customCallback() en customCallback.h actualmente hace lo siguiente:
La PoC en la función handleCallback en broker.py actualmente hace lo siguiente:
process_encoded_request(encoded_request)usage: broker.py [-h] --host HOST --port PORT
donde el host y el puerto apuntan al listener HTTP en su teamserver. El broker analiza la solicitud HTTP y la envía al listener real.
Esta es probablemente la forma "más vaga" de hacerlo, pero también una de las más estables. Básicamente, envuelve toda la solicitud HTTP y la envía al broker como quieras, que luego la envía al teamserver de verdad, para que funcione como un beacon HTTP, totalmente transparente para el teamserver.
Hay una implementación (técnicamente) más limpia que intenté que implicaba usar un perfil Malleable C2 mínimo (usé el de graphstrike, de hecho) y analizar los diferentes componentes de los datos del beacon según la especificación malleable dentro de los propios hooks de wininet (id, metadatos, salida, etc.). Esto habría hecho que los tamaños de los blobs de callback fueran ligeramente más pequeños, pero esa implementación fue abandonada porque el código se volvió innecesariamente desordenado debido al análisis de la solicitud y también requería el uso de ese perfil específico (que no es gran cosa, pero es un poco chapucero).
Sentí que esta implementación era mejor porque depende menos del perfil malleable chapucero (técnicamente, todavía requiere que la salida de respuesta del beacon se envíe en el cuerpo de la respuesta, pero ese es el único requisito) y el código era 10 veces más fácil de leer.
También vale la pena señalar que no hay ofuscación ni cifrado en el JSON de la solicitud HTTP aparte de la codificación base64: eres libre de agregar el tuyo propio, pero dado que los callbacks de Beacon ya están cifrados, técnicamente ningún dato corre el riesgo de ser descifrado. Lo peor que podría pasar es que el blob base64, si se recupera, podría identificarse como una solicitud HTTP. Haga con esa información lo que quiera.
Sí, usé un LLM para escribir parte del código y los comentarios; a nadie le gusta escribir documentación o escribir análisis JSON estándar en C desde cero. Denúncienme.
El descargo de responsabilidad habitual: no soy responsable de ningún crimen contra la humanidad que puedan cometer o de la guerra nuclear que puedan causar usando este código mal escrito.