Análisis de Comunicación de Comando y Control
Cuándo Usarlo
- Al realizar ingeniería inversa de una muestra de malware y se ha descubierto comunicación de red que necesita análisis de protocolo.
- Al construir firmas de detección a nivel de red para un marco C2 específico (Cobalt Strike, Metasploit, Sliver).
- Al mapear infraestructura C2, incluidos servidores primarios, dominios de respaldo y puntos muertos (dead drops).
- Al analizar tráfico C2 cifrado o codificado para comprender el conjunto de comandos y el formato de datos.
- Al atribuir malware a un actor de amenaza basándose en patrones de infraestructura C2 y herramientas.
No usar para detección general de anomalías de red; esto es específicamente para comprender protocolos C2 conocidos o sospechosos a partir de análisis de malware.
Requisitos Previos
- Captura PCAP del tráfico de red del malware (desde sandbox, captura de red o captura completa de paquetes).
- Wireshark/tshark para análisis a nivel de paquete.
- Herramientas de ingeniería inversa (Ghidra, dnSpy) para comprender el código C2 en el binario del malware.
- Python 3.8+ con
scapy,dpktyrequestspara análisis y reproducción de protocolos. - Bases de datos de inteligencia de amenazas para correlación de infraestructura C2 (VirusTotal, Shodan, Censys).
- Bases de datos de huellas digitales JA3/JA3S para identificación de C2 basado en TLS.
Flujo de Trabajo
Paso 1: Identificar el Canal C2
Determinar el protocolo y transporte utilizado para la comunicación C2:
Canales de Comunicación C2:
━━━━━━━━━━━━━━━━━━━━━━━━━━━
HTTP/HTTPS: Más común; utiliza tráfico web estándar para pasar desapercibido
Indicadores: Solicitudes POST/GET regulares, patrones URI específicos, cabeceras personalizadas
DNS: Tunelización de datos a través de consultas y respuestas DNS
Indicadores: Consultas TXT de alto volumen, nombres de subdominio largos, alta entropía
TCP/UDP personalizado: Protocolo binario propietario en puerto no estándar
Indicadores: Tráfico no HTTP en puertos altos, protocolo desconocido
ICMP: Datos codificados en cargas útiles de echo/reply ICMP
Indicadores: Paquetes ICMP con cargas útiles grandes o no estándar
WebSocket: Conexión bidireccional persistente para C2 en tiempo real
Indicadores: Actualización WebSocket seguida de tramas binarias
Servicios en la Nube: Uso de API legítimas (Telegram, Discord, Slack, GitHub)
Indicadores: Llamadas API a servicios en la nube desde procesos inesperados
Correo Electrónico: SMTP/IMAP para comandos C2 y exfiltración de datos
Indicadores: Operaciones de correo automatizadas desde procesos no relacionados con correo
Paso 2: Analizar el Patrón de Beacon
Caracterizar el patrón de comunicación periódica:
from scapy.all import rdpcap, IP, TCP
from collections import defaultdict
import statistics
import json
packets = rdpcap("c2_traffic.pcap")
# Agrupar paquetes TCP SYN por destino
connections = defaultdict(list)
for pkt in packets:
if IP in pkt and TCP in pkt and (pkt[TCP].flags & 0x02):
key = f"{pkt[IP].dst}:{pkt[TCP].dport}"
connections[key].append(float(pkt.time))
# Analizar cada destino en busca de beaconing
for dst, times in sorted(connections.items()):
if len(times) < 3:
continue
intervals = [times[i+1] - times[i] for i in range(len(times)-1)]
avg_interval = statistics.mean(intervals)
stdev = statistics.stdev(intervals) if len(intervals) > 1 else 0
jitter_pct = (stdev / avg_interval * 100) if avg_interval > 0 else 0
duration = times[-1] - times[0]
beacon_data = {
"destination": dst,
"connections": len(times),
"duration_seconds": round(duration, 1),
"avg_interval_seconds": round(avg_interval, 1),
"stdev_seconds": round(stdev, 1),
"jitter_percent": round(jitter_pct, 1),
"is_beacon": 5 < avg_interval < 7200 and jitter_pct < 25,
}
if beacon_data["is_beacon"]:
print(f"[!] BEACON DETECTADO: {dst}")
print(f" Intervalo: {avg_interval:.0f}s +/- {stdev:.0f}s ({jitter_pct:.0f}% jitter)")
print(f" Sesiones: {len(times)} en {duration:.0f}s")
Paso 3: Decodificar la Estructura del Protocolo C2
Realizar ingeniería inversa del formato del mensaje a partir del tráfico capturado:
# Análisis de protocolo C2 basado en HTTP
import dpkt
import base64
with open("c2_traffic.pcap", "rb") as f:
pcap = dpkt.pcap.Reader(f)
for ts, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf)
if not isinstance(eth.data, dpkt.ip.IP):
continue
ip = eth.data
if not isinstance(ip.data, dpkt.tcp.TCP):
continue
tcp = ip.data
if tcp.dport == 80 or tcp.dport == 443:
if len(tcp.data) > 0:
try:
http = dpkt.http.Request(tcp.data)
print(f"\n--- SOLICITUD C2 ---")
print(f"Método: {http.method}")
print(f"URI: {http.uri}")
print(f"Cabeceras: {dict(http.headers)}")
if http.body:
print(f"Cuerpo ({len(http.body)} bytes):")
# Intentar decodificación Base64
try:
decoded = base64.b64decode(http.body)
print(f" Decodificado: {decoded[:200]}")
except:
print(f" Crudo: {http.body[:200]}")
except:
pass
Paso 4: Identificar el Marco C2
Comparar patrones observados con marcos C2 conocidos:
Firmas de Marcos C2 Conocidos:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cobalt Strike:
- URI predeterminados: /pixel, /submit.php, /___utm.gif, /ca, /dpixel
- Los perfiles Malleable C2 personalizan todas las características del tráfico
- JA3: varía según el perfil, catálogo en ja3er.com
- Marca de agua en la configuración del beacon (única por licencia)
- Extracción de configuración: usar CobaltStrikeParser o 1768.py
Metasploit/Meterpreter:
- Patrones URI de staging predeterminados: checksum aleatorio de 4 caracteres
- Patrones del manejador Reverse HTTP(S)
- Estructura del protocolo TLV (Type-Length-Value) de Meterpreter
Sliver:
- Opciones de transporte: mTLS, HTTP, DNS, WireGuard
- Mensajes codificados en Protobuf
- ID de implante único en la comunicación
Covenant:
- Marco C2 basado en .NET
- HTTP con perfiles personalizables
- Ejecución de comandos basada en tareas
PoshC2:
- Basado en PowerShell/C#
- HTTP con cargas útiles cifradas
- Gestión de sesiones basada en cookies
# Extraer configuración del beacon de Cobalt Strike desde PCAP o muestra
python3 << 'PYEOF'
# Usando CobaltStrikeParser (pip install cobalt-strike-parser)
from cobalt_strike_parser import BeaconConfig
try:
config = BeaconConfig.from_file("suspect.exe")
print("Configuración del Beacon de Cobalt Strike:")
for key, value in config.items():
print(f" {key}: {value}")
except Exception as e:
print(f"No es un beacon de Cobalt Strike o error de análisis: {e}")
PYEOF
Paso 5: Mapear Infraestructura C2
Documentar la infraestructura C2 completa y los mecanismos de conmutación por error:
# Mapeo de infraestructura
import requests
import json
c2_indicators = {
"primary_c2": "185.220.101.42",
"domains": ["update.malicious.com", "backup.evil.net"],
"ports": [443, 8443],
"failover_dns": ["ns1.malicious-dns.com"],
}
# Enriquecer con Shodan
def shodan_lookup(ip, api_key):
resp = requests.get(f"https://api.shodan.io/shodan/host/{ip}?key={api_key}")
if resp.status_code == 200:
data = resp.json()
return {
"ip": ip,
"ports": data.get("ports", []),
"os": data.get("os"),
"org": data.get("org"),
"asn": data.get("asn"),
"country": data.get("country_code"),
"hostnames": data.get("hostnames", []),
"last_update": data.get("last_update"),
}
return None
# Enriquecer con DNS pasivo
def pdns_lookup(domain):
# Usando DNS pasivo de VirusTotal
resp = requests.get(
f"https://www.virustotal.com/api/v3/domains/{domain}/resolutions",
headers={"x-apikey": VT_API_KEY}
)
if resp.status_code == 200:
data = resp.json()
resolutions = []
for r in data.get("data", []):
resolutions.append({
"ip": r["attributes"]["ip_address"],
"date": r["attributes"]["date"],
})
return resolutions
return []
Paso 6: Crear Firmas de Detección de Red
Construir reglas de detección basadas en las características C2 analizadas:
# Reglas de Suricata para el C2 analizado
cat << 'EOF' > c2_detection.rules
# Patrón de beacon HTTP
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"MALWARE MalwareX C2 HTTP Beacon";
flow:established,to_server;
http.method; content:"POST";
http.uri; content:"/gate.php"; startswith;
http.header; content:"User-Agent: Mozilla/5.0 (compatible; MSIE 10.0)";
threshold:type threshold, track by_src, count 5, seconds 600;
sid:9000010; rev:1;
)
# Coincidencia de huella digital JA3
alert tls $HOME_NET any -> $EXTERNAL_NET any (
msg:"MALWARE MalwareX TLS JA3 Fingerprint";
ja3.hash; content:"a0e9f5d64349fb13191bc781f81f42e1";
sid:9000011; rev:1;
)
# Detección de beacon DNS (subdominio de alta entropía)
alert dns $HOME_NET any -> any any (
msg:"MALWARE Sospecha de tunelización C2 por DNS";
dns.query; pcre:"/^[a-z0-9]{20,}\./";
threshold:type threshold, track by_src, count 10, seconds 60;
sid:9000012; rev:1;
)
# Detección basada en certificado
alert tls $HOME_NET any -> $EXTERNAL_NET any (
msg:"MALWARE MalwareX Certificado C2 Autofirmado";
tls.cert_subject; content:"CN=update.malicious.com";
sid:9000013; rev:1;
)
EOF
Conceptos Clave
| Término | Definición |
|---|---|
| Beaconing | Comunicación periódica de verificación del malware con el servidor C2 a intervalos regulares, a menudo con jitter para evitar la detección de patrones |
| Jitter | Aleatorización aplicada al intervalo de beacon (ej., 60s +/- 15%) para que el patrón de tiempo sea menos predecible y más difícil de detectar |
| Malleable C2 | Característica de Cobalt Strike que permite a los operadores personalizar todos los aspectos del tráfico C2 (URI, cabeceras, codificación) para imitar servicios legítimos |
| Dead Drop | Ubicación intermedia (sitio de paste, almacenamiento en la nube, redes sociales) donde se publican comandos C2 para que el malware los recupere |
| Domain Fronting | Uso de un dominio CDN de confianza en el SNI de TLS mientras se enruta a un backend diferente, haciendo que el tráfico C2 parezca dirigido a un servicio legítimo |
| Fast Flux | Cambio rápido de registros DNS para dominios C2, distribuyéndolos a través de muchas IPs para resistir esfuerzos de eliminación |
| Marco C2 | Conjunto de herramientas de software que proporciona servidor C2, generador de implantes e interfaz de operador (Cobalt Strike, Metasploit, Sliver, Covenant) |
Herramientas y Sistemas
- Wireshark: Analizador de paquetes para análisis detallado de protocolos C2 a nivel de paquete.
- RITA (Real Intelligence Threat Analytics): Herramienta de código abierto que analiza registros de Zeek para detección de beacons y tunelización DNS.
- CobaltStrikeParser: Herramienta que extrae la configuración del beacon de Cobalt Strike a partir de muestras y volcados de memoria.
- JA3/JA3S: Método de huellas digitales TLS para identificar marcos C2 por las características de su implementación TLS.
- Shodan/Censys: Plataformas de escaneo de Internet para mapear infraestructura C2 e identificar servidores relacionados.
Escenarios Comunes
Escenario: Ingeniería Inversa de un Protocolo C2 Personalizado
Contexto: Una muestra de malware se comunica con su servidor C2 mediante un protocolo binario desconocido a través del puerto TCP 8443. El protocolo debe ser decodificado para comprender el conjunto de comandos y construir firmas de detección.
Enfoque:
- Filtrar el PCAP para conversaciones en el puerto TCP 8443 y extraer los flujos TCP.
- Analizar los primeros intercambios para identificar el mecanismo de handshake/autenticación.
- Mapear la estructura del mensaje (prefijo de longitud, campo de tipo, codificación de carga útil).
- Cruzar referencias con el desensamblado en Ghidra de las funciones de envío/recepción en el malware.
- Identificar el despachador de comandos y documentar la función de cada código de comando.
- Construir un decodificador de protocolo en Python para el análisis continuo del tráfico.
- Crear reglas de Suricata que coincidan con el handshake del protocolo o bytes de cabecera estáticos.
Errores Comunes:
- Asumir que el protocolo es estático; algunos marcos C2 negocian cifrado durante el handshake.
- No capturar suficiente tráfico para ver todos los tipos de comandos (algunos comandos son raros).
- Omitir canales C2 de respaldo (DNS, ICMP) que se activan cuando el canal principal falla.
- Confundir datos de carga útil cifrados con la estructura de enmarcado del protocolo.
Formato de Salida
INFORME DE ANÁLISIS DE COMUNICACIÓN C2
===========================================
Muestra: malware.exe (SHA-256: e3b0c44...)
Marco C2: Cobalt Strike 4.9
CONFIGURACIÓN DEL BEACON
Servidor C2: hxxps://185.220.101[.]42/updates
Tipo de Beacon: HTTPS (inverso)
Intervalo: 60 segundos
Jitter: 15%
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
URI (GET): /dpixel
URI (POST): /submit.php
Marca de Agua: 1234567890
ANÁLISIS DE PROTOCOLO
Transporte: HTTPS (TLS 1.2)
Hash JA3: a0e9f5d64349fb13191bc781f81f42e1
Certificado: CN=Microsoft Update (autofirmado)
Codificación: Base64 con clave XOR 0x69
Formato Comando: [4B longitud][4B id_comando][carga_útil]
CONJUNTO DE COMANDOS
0x01 - Sleep Cambiar intervalo del beacon
0x02 - Shell Ejecutar comando de cmd.exe
0x03 - Download Transferir archivo desde C2
0x04 - Upload Exfiltrar archivo a C2
0x05 - Inject Inyección de procesos
0x06 - Keylog Iniciar keylogger
0x07 - Screenshot Capturar pantalla
INFRAESTRUCTURA
Primario: 185.220.101[.]42 (AS12345, Hosting Co, NL)
Respaldo: 91.215.85[.]17 (AS67890, VPS Provider, RU)
DNS: update.malicious[.]com -> 185.220.101[.]42
Registrador: NameCheap
Registro: 2025-09-01
FIRMAS DE DETECCIÓN
SID 9000010: Patrón de beacon HTTP
SID 9000011: Huella digital TLS JA3
SID 9000013: Coincidencia de certificado C2