Analyse des preuves d'attribution de campagne
Vue d'ensemble
L'analyse d'attribution de campagne consiste à évaluer systématiquement les preuves pour déterminer quel acteur malveillant ou groupe est responsable d'une opération cyber. Cette compétence couvre la collecte et la pondération des indicateurs d'attribution à l'aide du modèle Diamond et de l'ACH (Analyse des Hypothèses Concurrentes), l'analyse des chevauchements d'infrastructure, la cohérence des TTP, les similitudes de code malveillant, les schémas de timing opérationnel et les artefacts linguistiques pour construire des évaluations d'attribution pondérées par la confiance.
Quand l'utiliser
- Lors d'enquêtes sur des incidents de sécurité nécessitant l'analyse de preuves d'attribution de campagne
- 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,stix2,networkx - Accès aux plateformes de renseignement sur les menaces (MISP, OpenCTI)
- Compréhension du modèle Diamond d'analyse d'intrusion
- Familiarité avec les profils de groupes de menaces MITRE ATT&CK
- Connaissance de l'analyse de logiciels malveillants et des techniques de suivi d'infrastructure
Concepts clés
Catégories de preuves d'attribution
- Chevauchement d'infrastructure : Serveurs C2 partagés, domaines, plages IP, fournisseurs d'hébergement
- Cohérence des TTP : Correspondance des techniques et sous-techniques ATT&CK entre les campagnes
- Similarité du code malveillant : Bases de code partagées, compilateurs, chemins PDB, routines de chiffrement
- Schémas opérationnels : Timing (heures de travail, fuseaux horaires), schémas de ciblage, rythme opérationnel
- Artefacts linguistiques : Chaînes intégrées, noms de variables, messages d'erreur dans des langues spécifiques
- Victimologie : Secteur cible, géographie et cohérence du profil organisationnel
Niveaux de confiance
- Confiance élevée : Plusieurs catégories de preuves indépendantes convergent vers le même acteur
- Confiance modérée : Plusieurs catégories de preuves correspondent, une certaine ambiguïté demeure
- Confiance faible : Preuves limitées, possibilité de faux drapeaux ou d'outils partagés
Analyse des Hypothèses Concurrentes (ACH)
Méthode analytique structurée qui évalue les preuves par rapport à plusieurs hypothèses concurrentes. Chaque élément de preuve est noté comme cohérent, incohérent ou neutre par rapport à chaque hypothèse. L'hypothèse avec le moins de preuves incohérentes est privilégiée.
Flux de travail
Étape 1 : Collecter les preuves d'attribution
from stix2 import MemoryStore, Filter
from collections import defaultdict
class AnalyseAttribution :
def __init__(self) :
self.preuves = []
self.hypotheses = {}
def ajouter_preuve(self, categorie, description, valeur, confiance) :
self.preuves.append({
"categorie" : categorie,
"description" : description,
"valeur" : valeur,
"confiance" : confiance,
"horodatage" : None,
})
def ajouter_hypothese(self, nom_acteur, identifiant_acteur="") :
self.hypotheses[nom_acteur] = {
"identifiant_acteur" : identifiant_acteur,
"preuves_coherentes" : [],
"preuves_incoherentes" : [],
"preuves_neutres" : [],
"score" : 0,
}
def evaluer_preuve(self, indice_preuve, nom_acteur, evaluation) :
"""Évaluer une preuve par rapport à une hypothèse : coherente/incoherente/neutre."""
if evaluation == "coherente" :
self.hypotheses[nom_acteur]["preuves_coherentes"].append(indice_preuve)
self.hypotheses[nom_acteur]["score"] += self.preuves[indice_preuve]["confiance"]
elif evaluation == "incoherente" :
self.hypotheses[nom_acteur]["preuves_incoherentes"].append(indice_preuve)
self.hypotheses[nom_acteur]["score"] -= self.preuves[indice_preuve]["confiance"] * 2
else :
self.hypotheses[nom_acteur]["preuves_neutres"].append(indice_preuve)
def classer_hypotheses(self) :
"""Classer les hypothèses par score d'attribution."""
classes = sorted(
self.hypotheses.items(),
key=lambda x : x[1]["score"],
reverse=True,
)
return [
{
"acteur" : nom,
"score" : donnees["score"],
"coherentes" : len(donnees["preuves_coherentes"]),
"incoherentes" : len(donnees["preuves_incoherentes"]),
"confiance" : self._score_vers_confiance(donnees["score"]),
}
for nom, donnees in classes
]
def _score_vers_confiance(self, score) :
if score >= 80 :
return "ÉLEVÉE"
elif score >= 40 :
return "MODÉRÉE"
else :
return "FAIBLE"
Étape 2 : Analyse du chevauchement d'infrastructure
def analyser_chevauchement_infra(infra_campagne_a, infra_campagne_b) :
"""Comparer l'infrastructure entre deux campagnes pour l'attribution."""
chevauchement = {
"ips_partagees" : set(infra_campagne_a.get("ips", [])).intersection(
infra_campagne_b.get("ips", [])
),
"domaines_partages" : set(infra_campagne_a.get("domaines", [])).intersection(
infra_campagne_b.get("domaines", [])
),
"asns_partages" : set(infra_campagne_a.get("asns", [])).intersection(
infra_campagne_b.get("asns", [])
),
"registres_partages" : set(infra_campagne_a.get("registres", [])).intersection(
infra_campagne_b.get("registres", [])
),
}
score_chevauchement = 0
if chevauchement["ips_partagees"] :
score_chevauchement += 30
if chevauchement["domaines_partages"] :
score_chevauchement += 25
if chevauchement["asns_partages"] :
score_chevauchement += 15
if chevauchement["registres_partages"] :
score_chevauchement += 10
return {
"chevauchement" : {k : list(v) for k, v in chevauchement.items()},
"score_chevauchement" : score_chevauchement,
"evaluation" : "FORT" if score_chevauchement >= 40 else "MODÉRÉ" if score_chevauchement >= 20 else "FAIBLE",
}
Étape 3 : Comparaison des TTP entre campagnes
from attackcti import attack_client
def comparer_ttp_campagnes(techniques_campagne, techniques_acteur_connu) :
"""Comparer les TTP d'une campagne aux profils d'acteurs de menace connus."""
ensemble_campagne = set(techniques_campagne)
ensemble_acteur = set(techniques_acteur_connu)
communes = ensemble_campagne.intersection(ensemble_acteur)
uniques_campagne = ensemble_campagne - ensemble_acteur
uniques_acteur = ensemble_acteur - ensemble_campagne
jaccard = len(communes) / len(ensemble_campagne.union(ensemble_acteur)) if ensemble_campagne.union(ensemble_acteur) else 0
return {
"techniques_communes" : sorted(communes),
"nombre_communes" : len(communes),
"uniques_a_la_campagne" : sorted(uniques_campagne),
"uniques_a_l_acteur" : sorted(uniques_acteur),
"similarite_jaccard" : round(jaccard, 3),
"pourcentage_chevauchement" : round(len(communes) / len(ensemble_campagne) * 100, 1) if ensemble_campagne else 0,
}
Étape 4 : Générer le rapport d'attribution
def generer_rapport_attribution(analyseur) :
"""Générer un rapport structuré d'évaluation d'attribution."""
classements = analyseur.classer_hypotheses()
rapport = {
"date_evaluation" : "2026-02-23",
"nombre_preuves" : len(analyseur.preuves),
"hypotheses_evaluees" : len(analyseur.hypotheses),
"classements" : classements,
"attribution_principale" : classements[0] if classements else None,
"resume_preuves" : [
{
"indice" : i,
"categorie" : p["categorie"],
"description" : p["description"],
"confiance" : p["confiance"],
}
for i, p in enumerate(analyseur.preuves)
],
}
return rapport
Critères de validation
- La collecte de preuves couvre les six catégories d'attribution
- La matrice ACH évalue correctement les preuves par rapport aux hypothèses concurrentes
- L'analyse du chevauchement d'infrastructure identifie les indicateurs partagés
- La comparaison des TTP utilise les identifiants de technique ATT&CK pour la précision
- Les niveaux de confiance d'attribution sont correctement justifiés
- Le rapport inclut des hypothèses alternatives et des considérations de faux drapeaux