Analyse des Communications de Commandement et de Contrôle (C2)
Quand l'utiliser
- Lorsque l'analyse d'un échantillon de malware a révélé une communication réseau nécessitant une analyse de protocole
- Pour construire des signatures de détection réseau pour un framework C2 spécifique (Cobalt Strike, Metasploit, Sliver)
- Pour cartographier l'infrastructure C2 incluant les serveurs primaires, les domaines de secours et les points de dépôt
- Pour analyser le trafic C2 chiffré ou encodé afin de comprendre l'ensemble des commandes et le format des données
- Pour attribuer un malware à un acteur de menace en se basant sur les patterns d'infrastructure et les outils C2
Ne pas utiliser pour la détection d'anomalies réseau générales ; cette compétence est spécifiquement destinée à la compréhension des protocoles C2 connus ou suspectés dans le cadre de l'analyse de malware.
Prérequis
- Capture PCAP du trafic réseau du malware (depuis un sandbox, une capture réseau ou une capture complète de paquets)
- Wireshark/tshark pour l'analyse au niveau paquet
- Outils de rétro-ingénierie (Ghidra, dnSpy) pour comprendre le code C2 dans le binaire du malware
- Python 3.8+ avec
scapy,dpktetrequestspour l'analyse et la relecture de protocole - Bases de données de renseignement sur les menaces pour la corrélation d'infrastructure C2 (VirusTotal, Shodan, Censys)
- Bases de données d'empreintes JA3/JA3S pour l'identification C2 basée sur TLS
Flux de travail
Étape 1 : Identifier le canal C2
Déterminez le protocole et le transport utilisés pour la communication C2 :
Canaux de Communication C2 :
━━━━━━━━━━━━━━━━━━━━━━━━━
HTTP/HTTPS : Le plus courant ; utilise le trafic web standard pour se fondre dans la masse
Indicateurs : Requêtes POST/GET régulières, motifs d'URI spécifiques, en-têtes personnalisés
DNS : Tunnelisation des données via des requêtes et réponses DNS
Indicateurs : Requêtes TXT à volume élevé, noms de sous-domaines longs, entropie élevée
TCP/UDP personnalisé : Protocole binaire propriétaire sur port non standard
Indicateurs : Trafic non-HTTP sur ports élevés, protocole inconnu
ICMP : Données encodées dans les charges utiles des échos/réponses ICMP
Indicateurs : Paquets ICMP avec des charges utiles volumineuses ou non standard
WebSocket : Connexion bidirectionnelle persistante pour C2 en temps réel
Indicateurs : Mise à niveau WebSocket suivie de trames binaires
Services Cloud : Utilisation d'API légitimes (Telegram, Discord, Slack, GitHub)
Indicateurs : Appels API vers des services cloud depuis des processus inattendus
Email : SMTP/IMAP pour les commandes C2 et l'exfiltration de données
Indicateurs : Opérations email automatisées depuis des processus non liés à l'email
Étape 2 : Analyser le motif de Beacon
Caractérisez le motif de communication périodique :
from scapy.all import rdpcap, IP, TCP
from collections import defaultdict
import statistics
import json
packets = rdpcap("c2_traffic.pcap")
# Grouper les paquets TCP SYN par destination
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))
# Analyser chaque destination pour le 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 DÉTECTÉ : {dst}")
print(f" Intervalle : {avg_interval:.0f}s +/- {stdev:.0f}s ({jitter_pct:.0f}% jitter)")
print(f" Sessions : {len(times)} sur {duration:.0f}s")
Étape 3 : Décoder la structure du protocole C2
Faites de la rétro-ingénierie sur le format des messages à partir du trafic capturé :
# Analyse de protocole C2 basé sur 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--- REQUÊTE C2 ---")
print(f"Méthode : {http.method}")
print(f"URI : {http.uri}")
print(f"En-têtes : {dict(http.headers)}")
if http.body:
print(f"Corps ({len(http.body)} octets) :")
# Tentative de décodage Base64
try:
decoded = base64.b64decode(http.body)
print(f" Décodé : {decoded[:200]}")
except:
print(f" Brut : {http.body[:200]}")
except:
pass
Étape 4 : Identifier le framework C2
Faites correspondre les patterns observés aux frameworks C2 connus :
Signatures des Frameworks C2 Connus :
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cobalt Strike :
- URI par défaut : /pixel, /submit.php, /___utm.gif, /ca, /dpixel
- Les profils C2 malléables personnalisent toutes les caractéristiques du trafic
- JA3 : varie selon le profil, catalogue sur ja3er.com
- Filigrane dans la configuration du beacon (unique par licence)
- Extraction de configuration : utiliser CobaltStrikeParser ou 1768.py
Metasploit/Meterpreter :
- Motifs d'URI de staging par défaut : somme de contrôle aléatoire de 4 caractères
- Patterns du gestionnaire HTTP(S) inverse
- Structure du protocole Meterpreter TLV (Type-Length-Value)
Sliver :
- Options de transport mTLS, HTTP, DNS, WireGuard
- Messages encodés en Protobuf
- Identifiant unique de l'implant dans la communication
Covenant :
- Framework C2 basé sur .NET
- HTTP avec profils personnalisables
- Exécution de commandes basée sur les tâches
PoshC2 :
- Basé sur PowerShell/C#
- HTTP avec charges utiles chiffrées
- Gestion de session basée sur les cookies
# Extraire la configuration du beacon Cobalt Strike depuis un PCAP ou un échantillon
python3 << 'PYEOF'
# En utilisant CobaltStrikeParser (pip install cobalt-strike-parser)
from cobalt_strike_parser import BeaconConfig
try:
config = BeaconConfig.from_file("suspect.exe")
print("Configuration du Beacon Cobalt Strike :")
for key, value in config.items():
print(f" {key}: {value}")
except Exception as e:
print(f"Ce n'est pas un beacon Cobalt Strike ou erreur d'analyse : {e}")
PYEOF
Étape 5 : Cartographier l'infrastructure C2
Documentez l'infrastructure C2 complète et les mécanismes de basculement :
# Cartographie de l'infrastructure
import requests
import json
c2_indicators = {
"c2_primaire": "185.220.101.42",
"domaines": ["update.malicious.com", "backup.evil.net"],
"ports": [443, 8443],
"dns_secours": ["ns1.malicious-dns.com"],
}
# Enrichir avec 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"),
"pays": data.get("country_code"),
"noms_hote": data.get("hostnames", []),
"derniere_maj": data.get("last_update"),
}
return None
# Enrichir avec DNS passif
def pdns_lookup(domain):
# En utilisant le DNS passif 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 []
Étape 6 : Créer des signatures de détection réseau
Construisez des règles de détection basées sur les caractéristiques C2 analysées :
# Règles Suricata pour le C2 analysé
cat << 'EOF' > c2_detection.rules
# Motif de beacon HTTP
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"MALWARE Beacon C2 MalwareX HTTP";
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;
)
# Correspondance d'empreinte JA3
alert tls $HOME_NET any -> $EXTERNAL_NET any (
msg:"MALWARE Empreinte JA3 TLS MalwareX";
ja3.hash; content:"a0e9f5d64349fb13191bc781f81f42e1";
sid:9000011; rev:1;
)
# Détection de beacon DNS (sous-domaine à haute entropie)
alert dns $HOME_NET any -> any any (
msg:"MALWARE Tunnel C2 DNS suspecté";
dns.query; pcre:"/^[a-z0-9]{20,}\./";
threshold:type threshold, track by_src, count 10, seconds 60;
sid:9000012; rev:1;
)
# Détection basée sur le certificat
alert tls $HOME_NET any -> $EXTERNAL_NET any (
msg:"MALWARE Certificat C2 auto-signé MalwareX";
tls.cert_subject; content:"CN=update.malicious.com";
sid:9000013; rev:1;
)
EOF
Concepts clés
| Terme | Définition |
|---|---|
| Beaconing | Communication périodique de check-in du malware vers le serveur C2 à intervalles réguliers, souvent avec du jitter pour éviter la détection de motifs |
| Jitter | Randomisation appliquée à l'intervalle de beacon (par exemple, 60s +/- 15%) pour rendre le motif temporel moins prévisible et plus difficile à détecter |
| C2 Malléable | Fonctionnalité de Cobalt Strike permettant aux opérateurs de personnaliser tous les aspects du trafic C2 (URI, en-têtes, encodage) pour imiter des services légitimes |
| Point de Dépôt | Emplacement intermédiaire (site de paste, stockage cloud, réseau social) où les commandes C2 sont publiées pour que le malware les récupère |
| Domain Fronting | Utilisation d'un nom de domaine CDN de confiance dans le SNI TLS tout en routant vers un backend différent, ce qui donne l'impression que le trafic C2 se dirige vers un service légitime |
| Fast Flux | Changement rapide des enregistrements DNS pour les domaines C2 afin de distribuer le trafic sur de nombreuses IP et de résister aux tentatives de démantèlement |
| Framework C2 | Ensemble d'outils logiciels fournissant un serveur C2, un générateur d'implant et une interface opérateur (Cobalt Strike, Metasploit, Sliver, Covenant) |
Outils et systèmes
- Wireshark : Analyseur de paquets pour une analyse détaillée du protocole C2 au niveau paquet
- RITA (Real Intelligence Threat Analytics) : Outil open source analysant les logs Zeek pour la détection de beacons et le tunneling DNS
- CobaltStrikeParser : Outil extrayant la configuration des beacons Cobalt Strike à partir d'échantillons et de dumps mémoire
- JA3/JA3S : Méthode d'empreinte TLS pour identifier les frameworks C2 par leurs caractéristiques d'implémentation TLS
- Shodan/Censys : Plateformes de scan Internet pour cartographier l'infrastructure C2 et identifier les serveurs associés
Scénarios courants
Scénario : Rétro-ingénierie d'un protocole C2 personnalisé
Contexte : Un échantillon de malware communique avec son serveur C2 en utilisant un protocole binaire inconnu sur le port TCP 8443. Le protocole doit être décodé pour comprendre l'ensemble des commandes et construire des signatures de détection.
Approche :
- Filtrer la PCAP pour les conversations sur le port TCP 8443 et extraire les flux TCP
- Analyser les premiers échanges pour identifier le mécanisme de handshake/authentification
- Cartographier la structure des messages (préfixe de longueur, champ de type, encodage de la charge utile)
- Recouper avec le désassemblage Ghidra des fonctions send/receive dans le malware
- Identifier le répartiteur de commandes et documenter la fonction de chaque code de commande
- Construire un décodeur de protocole en Python pour l'analyse continue du trafic
- Créer des règles Suricata correspondant au handshake du protocole ou aux octets d'en-tête statiques
Pièges à éviter :
- Supposer que le protocole est statique ; certains frameworks C2 négocient le chiffrement pendant le handshake
- Ne pas capturer suffisamment de trafic pour voir tous les types de commandes (certaines commandes sont rares)
- Manquer les canaux C2 de secours (DNS, ICMP) qui s'activent lorsque le canal principal échoue
- Confondre les données de charge utile chiffrées avec la structure de trame du protocole
Format de sortie
RAPPORT D'ANALYSE DE COMMUNICATION C2
=======================================
Échantillon : malware.exe (SHA-256 : e3b0c44...)
Framework C2 : Cobalt Strike 4.9
CONFIGURATION DU BEACON
Serveur C2 : hxxps://185.220.101[.]42/updates
Type de Beacon : HTTPS (inverse)
Intervalle : 60 secondes
Jitter : 15%
User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64)
URI (GET) : /dpixel
URI (POST) : /submit.php
Filigrane : 1234567890
ANALYSE DU PROTOCOLE
Transport : HTTPS (TLS 1.2)
Empreinte JA3 : a0e9f5d64349fb13191bc781f81f42e1
Certificat : CN=Microsoft Update (auto-signé)
Encodage : Base64 avec clé XOR 0x69
Format de commande : [4B longueur][4B id_commande][charge utile]
ENSEMBLE DE COMMANDES
0x01 - Dormir Changer l'intervalle du beacon
0x02 - Shell Exécuter une commande cmd.exe
0x03 - Télécharger Transférer un fichier depuis le C2
0x04 - Upload Exfiltrer un fichier vers le C2
0x05 - Injecter Injection de processus
0x06 - Keylog Démarrer le keylogger
0x07 - Capture Capturer l'écran
INFRASTRUCTURE
Primaire : 185.220.101[.]42 (AS12345, Hosting Co, NL)
Secours : 91.215.85[.]17 (AS67890, Fournisseur VPS, RU)
DNS : update.malicious[.]com -> 185.220.101[.]42
Registrar : NameCheap
Enregistrement : 2025-09-01
SIGNATURES DE DÉTECTION
SID 9000010 : Motif de beacon HTTP
SID 9000011 : Empreinte TLS JA3
SID 9000013 : Correspondance de certificat C2