Cobalt Strike sous les couleurs de Microsoft et Google : une chasse avec ONYPHE et Claude Code

Écrit le 2026-10-23

Lors de notre webcast consacré à ctiscan l’an dernier (la rediffusion est sur YouTube), nous avions montré une requête qui recherche les listeners Cobalt Strike se faisant passer pour légitime. Sur une semaine de données, elle remontait sept documents répartis sur trois hôtes, tous arborant un nom Microsoft ou Google.

Trois hôtes, c’est un point de départ, pas un résultat. Nous avons donc confié la requête à Claude Code, avec notre plugin onyphe-ai-skills installé, en lui demandant de chasser à partir de là. À l’arrivée : onze hôtes, dont deux partagent une clé privée, et pas un seul honeypot dans le lot.

Voici comment cela s’est déroulé, avec quelques conseils à reprendre pour vos propres chasses. Le plugin est gratuit, sous licence BSD 3-Clause, et son seul rôle est d’apprendre à Claude Code à se servir d’ONYPHE comme le ferait un analyste expérimenté.

La requête d’origine

onyphe -search 'category:ctiscan http.header.data.sha256:"aa182c6f2cdfa5aed16b6d2dfe68c54fcc9656d9477e5a7db41785d92545f07b"   http.header.contentlength:0 app.tls:true ( -orregexp:cert.domain,".*microsoft.*" -orregexp:cert.domain,".*google.*" ) 
-since:1w  | uniq cert.domain,ip.dest,ip.country,ip.asn'

(À exécuter sur une seule ligne : le retour à la ligne ci-dessus n’est là que pour tenir dans la page.)

Décortiquons-la :

  • http.header.data.sha256 est le hash de l’ensemble du bloc d’en-têtes de la réponse HTTP. Celui-ci correspond au 404 vide qu’un listener Cobalt Strike renvoie à tout ce qui n’est pas un beacon. ONYPHE conserve également le MD5 du même bloc d’en-têtes, 5293315563ba2448348295a4e1571a82, et c’est celui que vous verrez à partir de l’étape 1. Même en-tête, hash plus court.
  • http.header.contentlength:0 et app.tls:true demandent un corps de réponse vide servi en HTTPS, c’est-à-dire le mode de déploiement habituel du listener ; au passage, le certificat TLS nous donne de quoi pivoter.
  • Le -orregexp: sur cert.domain ne retient que les certificats dont le domaine contient microsoft ou google. C’est le filtre d’usurpation, et c’est lui qui fait le travail intéressant.
  • | uniq … est une étape d’OPP, l’ONYPHE Processing Pipeline, qui réduit les documents à une ligne par domaine et par hôte.

Tout cela tient en une seule requête parce que ctiscan range les en-têtes HTTP, le certificat TLS et le contexte réseau dans le même document. Aucune corrélation à faire après coup.

On voit les candidats potentiels s’effondrer à mesure que les filtres s’ajoutent, sur la même semaine :

RequêteDocuments
Hash d’en-tête seul443
+ corps vide401
+ TLS198
+ certificat Microsoft/Google7

C’est la dernière ligne qui fait basculer la statistique en piste. 198 listeners Cobalt Strike en HTTPS sur une semaine, c’est une foule ; sept documents qui se réclament de Microsoft ou de Google, c’est une piste. Trois hôtes, pour être précis :

googleapi2[.]com         107.172.43[.]189   US   AS36352
microsoft-server[.]top   192.3.139[.]18     US   AS36352
mailmicrosoft[.]com      193.235.207[.]69   CZ   AS174

Deux des trois sont chez le même hébergeur, AS36352, qu’ONYPHE étiquette HostPapa et que le whois appelle encore ColoCrossing. C’est à noter, mais cela ne va pas bien loin en soi. Le certificat, lui, est autrement plus parlant : un opérateur qui prend la peine de baptiser son listener du nom de Microsoft ou de Google fait un choix délibéré, et ce sont les choix délibérés qui méritent qu’on pivote dessus. C’est ce fil que nous avons tiré.

On passe la main à Claude Code

Le plugin s’installe directement depuis Claude Code :

/plugin install onyphe --marketplace onyphe/onyphe-ai-skills

Ou bien clonez-le et lancez d’abord la vérification des prérequis :

git clone https://github.com/onyphe/onyphe-ai-skills.git
cd onyphe-ai-skills
./prerequisites.sh
claude plugin marketplace add ./
claude plugin install onyphe

Votre clé d’API reste dans ~/.onyphe.ini, là où le CLI va déjà la chercher.
Le plugin se contente d’interroger les données qu’ONYPHE possède déjà : il ne scanne jamais rien par lui-même.

Collez ensuite la requête et demandez :

Exécute cette requête onyphe, puis chasse les hôtes qu’elle renvoie. Trouve l’infrastructure associée.

La skill onyphe-hunt fait valider le périmètre avec vous avant de lancer la moindre requête, puis déroule une séquence fixe : vérifier ce que votre licence autorise réellement, prendre une capture de référence de chaque hôte, classer les attributs de cet hôte par rareté, soumettre chaque indicateur candidat au contrôle honeypot, pivoter, puis construire une chronologie. Tout atterrit dans un répertoire de chasse daté (le NDJSON brut, les comptages et un rapport de conclusions), de sorte que vous pouvez rejouer n’importe quelle étape que vous auriez envie de contester.

La chasse décrite ci-dessous a coûté environ 90 requêtes d’API.

Étape 1 : laisser la rareté choisir le pivot

Avec trois hôtes suspects sous les yeux, la tentation est d’attraper l’élément qui paraît le plus distinctif et de le rechercher tel quel. L’agent ne procède pas ainsi. Pour chaque hôte, il commence par compter combien d’autres documents partagent chacun de ses attributs. Voici une partie de la table pour le faux Google :

3          cert.fingerprint.md5     a28b6cefc38065d88d322da4e2fd8503
473        http.header.data.md5     5293315563ba2448348295a4e1571a82
18125      hhhash.fingerprint.md5   81e4f0fa6bb0edb65367494e6c364c9a
1255418    cert.subject.cn          CloudFlare Origin Certificate
166932904  ja3s.fingerprint.md5     15af977ce25de452b96affa2addb1036

Ce qui tranche assez vite la question. L’empreinte JA3S est partagée par 167 millions de documents, parce qu’elle identifie une bibliothèque TLS et rien d’autre. Le hash d’en-tête, à 473, identifie l’outil et non l’opérateur qui s’en sert. À l’autre extrémité, l’empreinte du certificat n’apparaît que sur trois documents, tous rattachés à ce même hôte : parfait pour le suivre, inutile pour trouver ses camarades.

(Si vous vous demandez pourquoi 473 ici et 443 dans l’entonnoir : la requête de départ compte sur sept jours glissants, -since:1w, alors que l’agent compte sur la dernière semaine calendaire, -weekago:1. Tous les comptages qui suivent sont en semaine calendaire.)

La ligne intéressante, c’est le sujet du certificat. Il s’agit d’un certificat Cloudflare Origin : ce listener est donc placé derrière Cloudflare, et de fait googleapi2[.]com ne résout que vers des adresses de bordure Cloudflare. Prise isolément, cette ligne ne vaut rien, 1,25 million de documents représentant à peu près toute la clientèle de Cloudflare. Mise à côté du hash d’en-tête, en revanche, elle décrit quelque chose de très précis : un listener Cobalt Strike que quelqu’un a pris la peine de dissimuler derrière Cloudflare.

Les deux faux Microsoft n’ont rien donné d’équivalent. Leurs tables de rareté sont dominées par des certificats auto-signés que personne d’autre ne porte, ce qui est commode pour suivre ces deux hôtes mais d’aucun secours pour en trouver de nouveaux ; en dessous, on retrouve le même en-tête Cobalt Strike et la même pile TLS que tout le monde. Ils attendront donc la chronologie, et nous tirons sur le fil Google.

Nous tenons donc un pivot : l’en-tête Cobalt Strike et un certificat Cloudflare Origin, ensemble.

Étape 2 : le pivot

onyphe-count.sh 'category:ctiscan
  http.header.data.md5:5293315563ba2448348295a4e1571a82
  cert.subject.cn:"CloudFlare Origin Certificate" -weekago:1'

Vingt documents, huit hôtes. Tous font tourner un listener Cobalt Strike derrière Cloudflare, et chaque certificat origin nomme le domaine de l’opérateur lui-même :

HôtePortHébergeurCertificat origin pour
107.172.43[.]189443HostPapa, USgoogleapi2[.]com
192.210.206[.]196443HostPapa, USwinboxtoday[.]com
198.46.217[.]168443HostPapa, USviclian[.]com
198.46.226[.]210443HostPapa, USviclian[.]com
119.45.198[.]2502096, 44445, 55555Tencent, CNun domaine en .xyz (nom omis)
154.198.162[.]928443Scloud, HKprompti[.]top
165.154.225[.]2398443Scloud, HKzhimawithyou[.]top
2602:fa59:10:409::1445RouterHosting, UStwnic[.]top

En y regardant de plus près, 198.46.217[.]168 et 198.46.226[.]210 présentent le même certificat origin, numéro de série compris, et qui dit même certificat dit même clé privée. Deux machines, deux adresses IP, une clé que seul leur opérateur devrait détenir. Ce n’est pas une preuve en soi (un reverse proxy mutualisé ou une clé ayant fuité donneraient exactement la même image vue de l’extérieur), mais les deux hôtes répondent aussi avec le même en-tête Cobalt Strike, et deux indicateurs indépendants qui pointent dans la même direction, c’est à peu près le mieux qu’on puisse obtenir depuis l’extérieur.

Le premier des deux expose également un service TLS sur le port 30999, avec un certificat auto-signé *.google.com dont le sujet est O=Google, L=LA, ST=WA (quelqu’un était pressé). Aucun autre hôte dans ONYPHE ne porte ce certificat ce mois-ci : voilà un identifiant de suivi bien propre pour cet opérateur précis.

Étape 3 : et si c’étaient des honeypots ?

Avant que tout cela ne devienne une conclusion, chaque indicateur passe par onyphe-hpcheck.sh. À chaque chasse, nous y faisons aussi passer un témoin : une bannière SSH que les honeypots aiment beaucoup imiter. La raison est simple : un contrôle qui répond toujours « ce n’est pas un honeypot » ressemble exactement à un contrôle qui ne fonctionne pas.

IndicateurDocumentsHoneypot
En-tête Cobalt Strike, corps vide, TLS2110 %
En-tête + certificat Cloudflare Origin200 %
Certificat *.googleapi2[.]com30 %
Témoin : bannière SSH-2.0-Paramiko42299,8 %

(La première ligne affiche 211 et non les 198 de l’entonnoir, pour la raison déjà évoquée : semaine calendaire et non sept jours glissants.)

Cette dernière ligne justifie à elle seule l’existence du témoin. Sur ces 422 documents Paramiko, 222 seulement portent le tag honeypot d’ONYPHE : en filtrant sur le tag seul, il vous en resterait 200 qui ressemblent à d’honnêtes serveurs SSH. Le contrôle du plugin, qui rattrape aussi les non tagués grâce à leur signe distinctif (exposer exactement 199 services), en signale 421. Le contrôle fonctionne donc, et nos trois indicateurs Cobalt Strike en ressortent intacts. L’agent le fait pour chaque indicateur, à chaque chasse, que vous pensiez à le demander ou non.

Étape 4 : depuis combien de temps sont-ils là ?

L’agent cherche la date de première observation de chaque hôte et, quand la fenêtre de ctiscan s’épuise, il poursuit dans l’historique de datascan :

HôtePremière observationDernière observation
192.3.139[.]182026-09-232026-10-21
198.46.226[.]2102026-09-242026-10-22
192.210.206[.]1962026-09-252026-10-20
107.172.43[.]1892026-09-272026-10-21
193.235.207[.]692026-09-292026-10-20
198.46.217[.]1682026-09-302026-10-20

Il s’agit des trois hôtes de départ et des hôtes HostPapa issus du pivot ; nous n’avons pas remonté l’historique des quatre machines situées en Asie et en IPv6 cette fois-ci. ONYPHE les a tous découverts dans un intervalle de huit jours, et tous les six répondaient encore cette semaine. Les certificats, eux, sont nettement plus anciens que les hôtes, et c’est en général la moitié la plus instructive de l’histoire : le certificat origin de googleapi2[.]com date de mai 2025, et celui de viclian[.]com du 2026-09-03, soit trois semaines avant que l’un ou l’autre de ses deux hôtes n’apparaisse.

Élargissez la requête de départ à un mois complet et un quatrième imitateur apparaît : 2.59.217[.]108, sur le port 1443, avec un certificat google.com. Celui-là s’est tu depuis.

Quelques conseils pour vos propres chasses

  • Partez de l’outil, puis resserrez sur l’intention. Un hash d’en-tête vous trouvera l’outil, mais c’est le -orregexp: sur cert.domain qui met la main sur les opérateurs cherchant à se faire passer pour quelqu’un d’autre. Remplacez par .*apple.*, .*okta.*, ou par votre propre marque, et voyez qui porte votre nom cette semaine.
  • Demandez des hôtes, pas des documents. Chaque hôte est scanné plusieurs fois par semaine : un nombre de documents sera toujours supérieur à ce que vous voulez réellement mettre dans un rapport. Terminez la requête par | uniq ip.dest, ou demandez simplement à l’agent combien d’hôtes distincts il a trouvés.
  • Laissez la table de rareté choisir le pivot plutôt que de le choisir vous-même. Posez la question : « qu’est-ce qui est rare sur cet hôte ? » La table compte des documents et non des hôtes, alors convertissez le chiffre en hôtes avant de vous enthousiasmer ; mais tout ce qui retombe entre deux et vingt-cinq hôtes mérite en général qu’on pivote dessus. Ce qui est partagé par des milliers de documents désigne une bibliothèque ou un hébergeur et ne vous apprendra rien sur un opérateur, même si, comme l’a montré le certificat Cloudflare, cela peut encore gagner sa place en deuxième terme d’une requête.
  • Regardez le certificat avant toute chose. Domaines sosies, champs de sujet remplis à la va-vite, certificats origin réutilisés, sujets *.google.com recopiés : chacun de ces éléments est un choix humain, exactement ce qu’on attend d’un pivot. Le logiciel serveur, lui, vous dit surtout quel est le logiciel serveur.
  • Confirmez sur deux indicateurs. Un hash d’en-tête partagé place deux hôtes dans le même outillage ; un numéro de série de certificat partagé les place dans les mêmes mains. Ce ne sont pas les mêmes affirmations : demandez à l’agent de confirmer chaque membre d’un cluster sur deux indicateurs indépendants avant d’écrire quoi que ce soit.
  • Demandez la chronologie. « Quand chacun de ces hôtes a-t-il été vu pour la première fois ? » L’agent remonte l’historique dans datascan dès que la fenêtre de ctiscan est épuisée, et les dates de certificat précèdent souvent les hôtes de plusieurs semaines.
  • Transformez une bonne requête en alerte. Une fois qu’elle est assez serrée pour qu’on puisse lui faire confiance, la skill onyphe-alert l’enregistre et vous envoie un courriel dès qu’un nouvel hôte correspond.
  • Profitez-en pour le pointer vers votre propre périmètre. Le même plugin gère la découverte et la gestion de surface d’attaque : onyphe-asd construit un inventaire à partir de quelques domaines de départ, et onyphe-asm confronte cet inventaire à riskscan et vulnscan.
onyphe -alert-add -alert-name "CS behind Cloudflare" -alert-email "you@example.org" \
  'category:ctiscan http.header.data.md5:5293315563ba2448348295a4e1571a82 cert.subject.cn:"CloudFlare Origin Certificate"'

Indicateurs

IndicateurTypeRemarque
192.3.139[.]18IPv4microsoft-server[.]top, auto-signé
193.235.207[.]69IPv4mailmicrosoft[.]com, auto-signé O=Microsoft, OU=Digicert
107.172.43[.]189IPv4googleapi2[.]com derrière Cloudflare
198.46.217[.]168IPv4viclian[.]com derrière Cloudflare ; faux *.google.com sur le port 30999
198.46.226[.]210IPv4viclian[.]com derrière Cloudflare (même certificat)
192.210.206[.]196IPv4winboxtoday[.]com derrière Cloudflare
119.45.198[.]250IPv4domaine en .xyz derrière Cloudflare
154.198.162[.]92IPv4prompti[.]top derrière Cloudflare
165.154.225[.]239IPv4zhimawithyou[.]top derrière Cloudflare
2602:fa59:10:409::1IPv6twnic[.]top derrière Cloudflare
2.59.217[.]108IPv4certificat google[.]com, port 1443, vu le mois dernier
aa182c6f2cdfa5aed16b6d2dfe68c54fcc
9656d9477e5a7db41785d92545f07b
SHA-256 d’en-tête404 vide de Cobalt Strike
5293315563ba2448348295a4e1571a82MD5 d’en-tête404 vide de Cobalt Strike (même en-tête)
26:55:ba:70:66:71:93:d0:23:d3:17:06:38:c7:ea:99:91:15:25:bcnuméro de série de certificatcertificat origin de viclian[.]com
739919d043fa817fe6174487c632e729MD5 de certificatfaux *.google.com, port 30999

Tous observés dans ctiscan et datascan d’ONYPHE entre le 2026-09-23 et le 2026-10-23.

Pour l’essayer

/plugin install onyphe --marketplace onyphe/onyphe-ai-skills

Le plugin est gratuit et open source (BSD 3-Clause), et il fonctionne avec votre propre clé d’API ONYPHE. Apportez une requête en laquelle vous avez déjà confiance, et demandez à Claude Code de chasser à partir de là.

Défiler vers le haut