if ( !emtpy($headline_subheadline ) ) : ?>
J’ai procédé à l’ingénierie inverse d’un implant qui exécute C2 via un vrai compte OneDrive et peut remplacer à distance chaque identifiant volé. La révocation n’est pas un confinement.
endif; ?>
Chaque runbook de compromission d’identité que j’ai écrit, lu ou hérité comporte la même étape en haut : révoquer les jetons. Réinitialisez le mot de passe, tuez les sessions, invalidez les jetons d’actualisation, puis partez à la chasse. C’est le bon instinct. Contre le phishing par adversaire du milieu, où l’intégralité du prix est un cookie de session volé, la révocation est la mesure qui met fin à l’incident.
Ensuite, j’ai passé quelques jours à démonter une porte dérobée où cette étape ne vous rapporte rien du tout. La raison réside dans une seule fonction, et c’est le dernier endroit où la plupart d’entre nous penseraient à chercher.
L’échantillon est GraphWorm, un implant personnalisé lié au groupe APT chinois Webworm. Une chose que j’y ai trouvée réécrit une ligne de ma propre procédure de réponse aux incidents, et je pense qu’elle appartient à la vôtre.
La chaîne C2 est le OneDrive de quelqu’un
GraphWorm n’a pas de domaine C2, pas de balise vers un VPS loué, pas d’adresse codée en dur à bloquer. Il s’authentifie auprès de Microsoft Graph en tant qu’application OAuth et utilise un compte OneDrive comme point mort.
La mise en page est assez simple à dessiner sur une serviette. L’opérateur écrit un fichier de tâche crypté dans un dossier de tâches. L’implant interroge ce dossier, exécute la tâche, puis télécharge le résultat chiffré dans un dossier de résultats. Un fichier de battement de cœur reçoit un nouvel horodatage à chaque intervalle et un fichier d’empreintes digitales contient les détails du système de la victime. L’ensemble de commandes couvre l’exécution du shell, le téléchargement et le téléchargement de fichiers, la mise en veille, la suppression et une paire d’échange de clés qui met à niveau la clé de déploiement en clés par session.
Tout cela passe par graph.microsoft.com via TLS, à partir d’un hôte qui parle déjà à Microsoft 365 toute la journée. Il n’y a pas de destination inhabituelle à signaler par un pare-feu, pas de domaine fraîchement enregistré à pénaliser par un moteur de réputation, pas de port étrange. La couche réseau n’a rien à dire. C’est l’objectif de conception, et c’est le même changement dont j’ai déjà parlé, où les opérateurs cessent de construire leur propre infrastructure et commencent à fonctionner sur celle de quelqu’un d’autre.
Les informations d’identification se trouvent toutes dans le binaire en texte clair : un identifiant client, un secret client, un identifiant locataire et un jeton d’actualisation de plus de 1 300 caractères. L’opérateur a également livré une version de débogage avec le chemin PDB complet intact.
Un détail supplémentaire compte pour quiconque planifie une réponse. L’implant n’identifie pas ses victimes par nom d’hôte ou adresse. Il crée un identifiant en hachant l’adresse matérielle de la carte réseau avec les numéros de série du processeur et du disque extraits via WMI. Renommez la machine, déplacez-la vers un autre sous-réseau ou placez-la derrière une nouvelle adresse de sortie, et l’opérateur la reconnaît toujours comme la même boîte. Tout plan de confinement reposant sur la modification de l’identité réseau de la victime résout un problème que cet implant n’a pas.
Jusqu’à présent, c’est une bonne histoire mais familière. C2 hébergé dans le cloud n’est pas nouveau. La partie à laquelle je ne m’attendais pas était celle du gestionnaire de tâches.
La fonction qui casse le runbook
Parmi les commandes acceptées par l’implant, il y en a une appelée mise à niveau. Le flux est court et cela vaut la peine de le parcourir.
Le gestionnaire analyse un blob de configuration à partir de la tâche entrante. Il détruit ensuite les cinq chaînes d’informations d’identification contenues dans l’objet balise, en copie cinq nouvelles, reconstruit la structure de portée OAuth, teste une connexion avec le nouveau compte OneDrive, écrit la configuration de remplacement sur le disque et échange l’instance d’API en direct.
Une tâche. Identité entière remplacée.
Asseyez-vous avec les conséquences pendant une seconde. Votre enquête atteint le point où vous avez identifié l’application, vous déposez auprès de la plateforme et les jetons sont révoqués. Le prochain sondage de l’implant échoue. Si l’opérateur surveille et qu’un opérateur écrivant un fichier de battement de cœur à chaque intervalle surveille, il met en file d’attente une tâche de mise à niveau pointant vers un deuxième compte OneDrive qu’il a enregistré il y a des mois. L’implant le récupère, tourne et reprend. Rien sur le point final n’a changé. Pas de nouveau binaire, pas de nouveau mécanisme de persistance, pas de nouveau processus. Même fichier sur le disque, identité différente derrière.
La révocation a supprimé un identifiant. Cela n’a pas supprimé l’accès.
Cela n’apparaît pas dans les reportages publics sur la famille, ce qui ne constitue pas une critique. Les articles des fournisseurs sont limités à la campagne qu’ils ont observée, et c’est le genre de détail que vous ne voyez qu’avec le décompilateur ouvert sur une fonction que personne n’avait de raison de prioriser. Je l’ai confirmé deux fois avant de vouloir l’écrire, une fois à partir des chaînes extraites et une fois à partir de la fonction décompilée elle-même. Les décalages des champs d’informations d’identification que j’ai récupérés à partir des chaînes devaient s’aligner sur les décalages à partir desquels le constructeur lit réellement, et ils l’ont fait, ce qui fait la différence entre une découverte et une supposition.
Ce que j’ai changé par la suite
Il en est ressorti trois choses que je mettrais demain dans une procédure de réponse d’identité.
- Traitez la révocation comme un retard plutôt que comme une expulsion chaque fois que le C2 utilise une identité d’application. L’objet durable est l’enregistrement et non les jetons qu’il délivre. Les jetons sont des feuilles, l’enregistrement est la racine, et le confinement qui s’arrête à la révocation a déclenché un chronomètre plutôt que fermé une porte. Si l’enregistrement réside chez un locataire que vous ne contrôlez pas, la suspension signifie déposer un rapport et attendre dans la file d’attente de quelqu’un d’autre, alors déposez tôt plutôt que comme dernière étape.
- Supposons que l’opérateur possède une pièce de rechange. La rotation des informations d’identification ne coûte presque rien à un attaquant et vous coûte tout un cycle de réponse. Cette asymétrie devrait conduire au séquençage : supprimer la capacité du point final à atteindre le canal au moment même où vous gravez les informations d’identification, pas après. Isoler l’hôte ou empêcher cette application spécifique de s’authentifier auprès de votre propre locataire sont deux mesures qui ne dépendent pas de la coopération de quelqu’un d’autre.
- Chasse sur le plan de l’identité, parce que le plan du réseau est ici aveugle. Les détections qui se déclenchent réellement sur cette famille ne sont pas du tout des signatures réseau. Il s’agit de requêtes de télémétrie cloud : l’ID d’application de l’opérateur apparaissant dans vos événements de connexion, l’authentification auprès d’un locataire inconnu, un agent utilisateur de bibliothèque HTTP non-navigateur frappant OneDrive, les noms de fichiers de balise et d’empreintes digitales apparaissant dans la télémétrie de fichiers. L’ID de l’application est une chaîne fixe ; il n’appartient à personne légitime, et une seule requête sur votre télémétrie de connexion répond s’il a déjà demandé un jeton à votre locataire.
Rien de tout cela n’a besoin de nouveaux outils. Il faut que l’enregistrement de la demande soit traité comme la chose que vous essayez de tuer.
Le modèle le plus large est ce qui m’est resté. Nous avons passé une décennie à apprendre à chasser les infrastructures, et les adversaires ont répondu en n’en possédant pas. Lorsque le canal est un dossier dans un locataire cloud et que l’identité derrière ce dossier peut être échangée par commande à distance, les artefacts que nous sommes formés à rechercher sont précisément ceux qu’un opérateur peut remplacer à moindre coût. Ce qu’ils ne peuvent pas remplacer à moindre coût, c’est le code situé sur le point final et le comportement de ce code dans votre télémétrie.
Donc, je vérifie l’hypothèse maintenant. Avant de qualifier un incident d’identité de contenu, je demande ce que j’ai tué spécifiquement et si l’adversaire peut se procurer un remplaçant sans jamais toucher la machine de la victime. Dans cet exemple, la réponse était oui, et il fallait une fonction pour le prouver.
Le contenu complet du démontage et de la détection de cette analyse est publié sur GitHub.



