Analyse d'un Groupe APT avec MITRE ATT&CK Navigator
Vue d'ensemble
MITRE ATT&CK Navigator est un outil web permettant d'annoter et d'explorer les matrices ATT&CK. Il offre aux analystes la possibilité de visualiser la couverture technique d'acteurs malveillants, de comparer plusieurs groupes APT, d'identifier les lacunes de détection et de construire des stratégies de défense basées sur la menace. Cette compétence couvre l'interrogation programmatique des données ATT&CK, la cartographie des TTPs des groupes APT en calques Navigator, la création de superpositions multi-calques pour l'analyse des lacunes, et la génération de rapports de renseignement exploitables pour les équipes d'ingénierie de détection.
Quand l'utiliser
- Lors de l'investigation d'incidents de sécurité nécessitant l'analyse d'un groupe APT avec le Navigateur MITRE
- Lors de la construction de règles de détection ou de requêtes de chasse aux menaces pour ce domaine
- Lorsque les analystes SOC ont besoin de procédures structurées pour ce type d'analyse
- Lors de la validation de la couverture de surveillance de sécurité pour les techniques d'attaque associées
Prérequis
- Python 3.9+ avec les bibliothèques
attackcti,mitreattack-python,stix2,requests - ATT&CK Navigator (https://mitre-attack.github.io/attack-navigator/) ou déploiement local
- Compréhension de la matrice ATT&CK Enterprise : 14 Tactiques, 200+ Techniques, Sous-techniques
- Accès à des rapports de renseignement sur les menaces ou à MISP/OpenCTI pour les données sur les acteurs
- Familiarité avec les objets STIX 2.1 Intrusion Set et Attack Pattern
Concepts clés
Calques ATT&CK Navigator
Les calques Navigator sont des fichiers JSON qui annotent les techniques ATT&CK avec des scores, couleurs, commentaires et métadonnées. Chaque calque peut représenter l'utilisation technique d'un seul groupe APT, une carte des capacités de détection, ou une superposition combinée. La version 4.5 des calques prend en charge les domaines enterprise-attack, mobile-attack et ics-attack avec filtrage par plateforme (Windows, Linux, macOS, Cloud, Azure AD, Office 365, SaaS).
Profils de groupes APT dans ATT&CK
ATT&CK répertorie plus de 140 groupes de menaces avec leur utilisation documentée de techniques. Chaque profil de groupe comprend des alias, des secteurs ciblés, des campagnes associées, les logiciels utilisés et les correspondances de techniques avec des détails de procédure. Les groupes sont identifiés par des codes G (par exemple, G0016 pour APT29, G0007 pour APT28, G0032 pour le groupe Lazarus).
Analyse multi-calques
Navigator permet de charger plusieurs calques simultanément, offrant aux analystes la possibilité de superposer les TTPs d'acteurs de menace par rapport à la couverture de détection pour identifier les lacunes, de comparer plusieurs groupes APT pour trouver les techniques communes à prioriser, et de suivre les changements de couverture technique dans le temps.
Flux de travail
Étape 1 : Interroger les données ATT&CK pour le groupe APT
from attackcti import attack_client
import json
lift = attack_client()
# Obtenir tous les groupes de menace
groups = lift.get_groups()
print(f"Nombre total de groupes ATT&CK : {len(groups)}")
# Trouver APT29 (Cozy Bear / Midnight Blizzard)
apt29 = next((g for g in groups if g.get('name') == 'APT29'), None)
if apt29:
print(f"Groupe : {apt29['name']}")
print(f"Alias : {apt29.get('aliases', [])}")
print(f"Description : {apt29.get('description', '')[:300]}")
# Obtenir les techniques utilisées par APT29 (G0016)
techniques = lift.get_techniques_used_by_group("G0016")
print(f"APT29 utilise {len(techniques)} techniques")
technique_map = {}
for tech in techniques:
tech_id = ""
for ref in tech.get("external_references", []):
if ref.get("source_name") == "mitre-attack":
tech_id = ref.get("external_id", "")
break
if tech_id:
tactics = [p.get("phase_name", "") for p in tech.get("kill_chain_phases", [])]
technique_map[tech_id] = {
"name": tech.get("name", ""),
"tactics": tactics,
"description": tech.get("description", "")[:500],
"platforms": tech.get("x_mitre_platforms", []),
"data_sources": tech.get("x_mitre_data_sources", []),
}
Étape 2 : Générer le JSON du calque Navigator
def create_navigator_layer(group_name, technique_map, color="#ff6666"):
techniques_list = []
for tech_id, info in technique_map.items():
for tactic in info["tactics"]:
techniques_list.append({
"techniqueID": tech_id,
"tactic": tactic,
"color": color,
"comment": info["name"],
"enabled": True,
"score": 100,
"metadata": [
{"name": "group", "value": group_name},
{"name": "platforms", "value": ", ".join(info["platforms"])},
],
})
layer = {
"name": f"{group_name} Couverture TTP",
"versions": {"attack": "16.1", "navigator": "5.1.0", "layer": "4.5"},
"domain": "enterprise-attack",
"description": f"Techniques attribuées à {group_name}",
"filters": {
"platforms": ["Linux", "macOS", "Windows", "Cloud",
"Azure AD", "Office 365", "SaaS", "Google Workspace"]
},
"sorting": 0,
"layout": {
"layout": "side", "aggregateFunction": "average",
"showID": True, "showName": True,
"showAggregateScores": False, "countUnscored": False,
},
"hideDisabled": False,
"techniques": techniques_list,
"gradient": {"colors": ["#ffffff", color], "minValue": 0, "maxValue": 100},
"legendItems": [
{"label": f"Utilisé par {group_name}", "color": color},
{"label": "Non observé", "color": "#ffffff"},
],
"showTacticRowBackground": True,
"tacticRowBackground": "#dddddd",
"selectTechniquesAcrossTactics": True,
"selectSubtechniquesWithParent": False,
"selectVisibleTechniques": False,
}
return layer
layer = create_navigator_layer("APT29", technique_map)
with open("apt29_layer.json", "w") as f:
json.dump(layer, f, indent=2)
print("[+] Calque sauvegardé : apt29_layer.json")
Étape 3 : Comparer plusieurs groupes APT
groups_to_compare = {"G0016": "APT29", "G0007": "APT28", "G0032": "Lazarus Group"}
group_techniques = {}
for gid, gname in groups_to_compare.items():
techs = lift.get_techniques_used_by_group(gid)
tech_ids = set()
for t in techs:
for ref in t.get("external_references", []):
if ref.get("source_name") == "mitre-attack":
tech_ids.add(ref.get("external_id", ""))
group_techniques[gname] = tech_ids
common_to_all = set.intersection(*group_techniques.values())
print(f"Techniques communes à tous les groupes : {len(common_to_all)}")
for tid in sorted(common_to_all):
print(f" {tid}")
for gname, techs in group_techniques.items():
others = set.union(*[t for n, t in group_techniques.items() if n != gname])
unique = techs - others
print(f"\nUniques à {gname} : {len(unique)} techniques")
Étape 4 : Analyse des lacunes de détection avec superposition de calques
# Définir vos capacités de détection actuelles
detected_techniques = {
"T1059", "T1059.001", "T1071", "T1071.001", "T1566", "T1566.001",
"T1547", "T1547.001", "T1053", "T1053.005", "T1078", "T1027",
}
actor_techniques = set(technique_map.keys())
covered = actor_techniques.intersection(detected_techniques)
gaps = actor_techniques - detected_techniques
print(f"=== Analyse des lacunes de détection pour APT29 ===")
print(f"Techniques de l'acteur : {len(actor_techniques)}")
print(f"Détectées : {len(covered)} ({len(covered)/len(actor_techniques)*100:.0f}%)")
print(f"Lacunes : {len(gaps)} ({len(gaps)/len(actor_techniques)*100:.0f}%)")
# Créer un calque des lacunes (rouge = non détecté, vert = détecté)
gap_techniques = []
for tech_id in actor_techniques:
info = technique_map.get(tech_id, {})
for tactic in info.get("tactics", [""]):
color = "#66ff66" if tech_id in detected_techniques else "#ff3333"
gap_techniques.append({
"techniqueID": tech_id,
"tactic": tactic,
"color": color,
"comment": f"{'DÉTECTÉ' if tech_id in detected_techniques else 'LACUNE'} : {info.get('name', '')}",
"enabled": True,
"score": 100 if tech_id in detected_techniques else 0,
})
gap_layer = {
"name": "Analyse des lacunes de détection APT29",
"versions": {"attack": "16.1", "navigator": "5.1.0", "layer": "4.5"},
"domain": "enterprise-attack",
"description": "Vert = détecté, Rouge = lacune",
"techniques": gap_techniques,
"gradient": {"colors": ["#ff3333", "#66ff66"], "minValue": 0, "maxValue": 100},
"legendItems": [
{"label": "Détecté", "color": "#66ff66"},
{"label": "Lacune de détection", "color": "#ff3333"},
],
}
with open("apt29_gap_layer.json", "w") as f:
json.dump(gap_layer, f, indent=2)
Étape 5 : Analyse par tactique
from collections import defaultdict
tactic_breakdown = defaultdict(list)
for tech_id, info in technique_map.items():
for tactic in info["tactics"]:
tactic_breakdown[tactic].append({"id": tech_id, "name": info["name"]})
tactic_order = [
"reconnaissance", "resource-development", "initial-access",
"execution", "persistence", "privilege-escalation",
"defense-evasion", "credential-access", "discovery",
"lateral-movement", "collection", "command-and-control",
"exfiltration", "impact",
]
print("\n=== Répartition par tactique APT29 ===")
for tactic in tactic_order:
techs = tactic_breakdown.get(tactic, [])
if techs:
print(f"\n{tactic.upper()} ({len(techs)} techniques) :")
for t in techs:
print(f" {t['id']} : {t['name']}")
Critères de validation
- Les données ATT&CK ont été interrogées avec succès via le serveur TAXII
- Le groupe APT a été cartographié avec toutes les techniques documentées et des exemples de procédures
- Le JSON du calque Navigator se valide et s'affiche correctement dans ATT&CK Navigator
- La superposition multi-calques montre la couverture de l'acteur par rapport à la couverture de détection
- L'analyse des lacunes de détection identifie les techniques non surveillées avec des recommandations de sources de données
- La comparaison inter-groupes révèle les TTPs partagées et uniques
- Le résultat est exploitable pour la priorisation de l'ingénierie de détection