Détecter le C2 chiffré avec le fingerprinting JA4+ dans Suricata
JA3 faiblit face à TLS 1.3. Configurez JA4 dans Suricata, écrivez une règle ja4.hash et corrélez avec le SNI pour détecter le C2 chiffré caché.
Un flux sortant en HTTPS, vers un domaine à la réputation neutre, sur le port 443 : rien dans les journaux de pare-feu ne le distingue d'un appel API légitime. C'est précisément le point aveugle que le C2 moderne exploite : le chiffrement masque le contenu, pas la manière dont le client a négocié la session TLS. Le fingerprinting JA4+ s'attaque à cet angle mort, et Suricata sait aujourd'hui l'exploiter nativement.
Pourquoi JA3 ne suffit plus face à TLS 1.3
JA3 a rendu un immense service pendant des années : hacher l'ordre des ciphers, des extensions et des courbes du ClientHello pour obtenir une empreinte du client TLS. Le problème : TLS 1.3 et les navigateurs modernes ont cassé les deux hypothèses sur lesquelles JA3 reposait.
D'abord, le GREASE : Chrome et les navigateurs Chromium injectent volontairement des valeurs aléatoires dans la liste des ciphers et des extensions, précisément pour déjouer le fingerprinting côté serveur. Résultat, un même navigateur génère des dizaines de hachages JA3 différents d'une connexion à l'autre. Ensuite, TLS 1.3 a réduit et réordonné les extensions par défaut, ce qui aplatit la diversité entre outils très différents : un beacon Cobalt Strike et un client légitime peuvent produire un JA3 quasi identique s'ils s'appuient sur la même bibliothèque TLS sous-jacente. JA3 identifie la bibliothèque, pas l'intention.
Ce que JA4+ apporte réellement
JA4+ (FoxIO) est une famille de fingerprints, pas une empreinte unique. Trois variantes comptent pour la détection réseau :
- JA4 (client TLS) : encode la version du protocole, la présence d'un SNI, le nombre de ciphers et d'extensions, l'ALPN négocié, puis hache séparément la liste triée des ciphers et celle des extensions. Le tri neutralise le GREASE, ce qui rend l'empreinte stable pour un même outil, contrairement à JA3.
- JA4S : l'équivalent côté serveur, utile pour repérer une infrastructure de commande et contrôle qui répond toujours avec la même configuration TLS, même derrière des domaines différents.
- JA4H : un fingerprint HTTP basé sur la méthode, l'ordre des en-têtes et le user-agent. Il complète JA4 quand le trafic malveillant repasse en clair avant le tunnel TLS.
Deux campagnes issues du même builder offensif partagent souvent le même JA4, alors que leur JA3 varie selon l'environnement de compilation : JA4 rapproche l'empreinte de l'outil, pas de la bibliothèque.
Activer JA4 dans Suricata
Suricata expose JA4 comme champ natif dans le moteur TLS depuis les versions récentes. Il faut l'activer explicitement dans la configuration :
# suricata.yaml
app-layer:
protocols:
tls:
enabled: yes
ja4-fingerprints: yes
outputs:
- eve-log:
enabled: yes
types:
- tls:
ja4: yes
extended: yes(Exemple illustratif : vérifiez la clé exacte selon votre version de Suricata ; le principe reste le même.) Une fois actif, chaque enregistrement tls dans eve.json porte un champ ja4 exploitable en recherche, en corrélation, et surtout en détection via le mot-clé ja4.hash.
Écrire une règle sur ja4.hash
Le mot-clé ja4.hash fonctionne comme un matcher de contenu classique, mais s'applique à la métadonnée TLS calculée par le moteur, pas au corps du paquet :
alert tls $HOME_NET any -> $EXTERNAL_NET any (msg:"JA4 correspond à un fingerprint C2 connu"; \
ja4.hash; content:"t13d1516h2_8daaf6152771_02713d6af862"; \
classtype:trojan-activity; sid:9010001; rev:1;)
Même principe côté serveur avec ja4s.hash, utile pour épingler une infrastructure qui recycle sa stack TLS sur plusieurs domaines de façade :
alert tls $HOME_NET any -> $EXTERNAL_NET any (msg:"JA4S correspond à une infrastructure C2 connue"; \
ja4s.hash; content:"t130200_1301_a56c5b993250"; \
classtype:command-and-control; sid:9010002; rev:1;)
Ces règles supposent que vous disposez déjà du hachage à surveiller, issu d'un rapport d'incident ou de votre propre corpus. C'est le cas d'usage "signature ciblée". L'autre, souvent plus rentable, est l'allowlist.
Constituer une allowlist de JA4 internes légitimes
Plutôt que de chasser des hachages malveillants connus, toujours en retard d'une variante, l'approche qui tient dans la durée inverse la logique : cataloguer les JA4 légitimes de votre parc, puis alerter sur tout ce qui sort de ce référentiel.
La démarche concrète :
- Sur une fenêtre de référence propre (une à deux semaines de trafic validé), extraire la distribution des
ja4observés danseve.json, par segment réseau si possible. - Regrouper par fréquence et par cohérence avec le SNI associé : un JA4 attaché systématiquement au même petit ensemble de domaines est un signal de légitimité probable.
- Documenter la liste retenue comme référentiel de base, avec une revue périodique (les mises à jour de navigateur ou de runtime changent parfois le JA4).
- Basculer la détection : au lieu de règles qui listent le mauvais, un tableau de suivi qui fait remonter tout JA4 vu pour la première fois, ou vu moins de N fois sur la période.
Un JA4 rare, associé à un SNI générique ou à un volume périodique, mérite un regard humain avant d'être classé bénin.
Corréler JA4, SNI et comportement pour distinguer un beacon d'un client normal
Le JA4 seul ne prouve rien : des outils légitimes (agents de supervision, bibliothèques HTTP internes) produisent eux aussi des empreintes rares. La détection fiable se construit sur un faisceau, pas sur un seul champ.
Trois axes à croiser systématiquement :
- JA4 x SNI : un même JA4 qui apparaît avec des SNI différents dans le temps, sans lien logique entre les domaines, est suspect. Un client légitime reste fidèle à un petit ensemble de destinations cohérentes.
- Régularité temporelle (beaconing) : un C2 rappelle sa base à intervalle quasi constant, avec un jitter faible. Mesurer l'écart-type des intervalles entre connexions pour un même couple JA4/SNI révèle ce motif bien mieux qu'un simple compteur de volume.
- Volume et taille des échanges : une exfiltration se traduit souvent par une asymétrie inhabituelle entre volume sortant et entrant, ou par des paquets de taille très stable sur une empreinte JA4 jamais vue avant.
Un JA4 inconnu isolé est une piste ; à intervalle régulier et ratio sortant/entrant anormal, c'est un incident à ouvrir.
Cas d'usage : l'agent IA interne qui exfiltre en HTTPS
Le déploiement d'un agent IA interne (assistant de code, automatisation de tickets, analyse de documents) ajoute une source de trafic sortant chiffré souvent mal cadrée : des appels à une API de modèle de langage, parfois via plusieurs relais applicatifs. Le RSSI se retrouve avec un flux HTTPS légitime sur le papier, mais dont le contenu réel (prompts, extraits de documents, résultats) échappe totalement à l'inspection classique.
La méthode JA4 s'applique directement :
- Identifier le JA4 propre au runtime de l'agent (le client HTTP ou le SDK appelant l'API du modèle) et le documenter dans l'allowlist, associé au SNI attendu de l'éditeur.
- Surveiller toute divergence : un JA4 qui change sans mise à jour connue, un SNI qui change sans configuration documentée, ou un volume sortant qui grimpe sans lien avec l'activité de l'agent.
- Poser une limite de volume par fenêtre glissante sur ce couple JA4/SNI : un agent bien cadré a un profil stable, un dépassement soutenu mérite une revue.
- Rester attentif à un JA4 identique à celui de l'agent mais associé à un SNI inattendu : le signe d'un composant qui réutilise la même bibliothèque cliente vers une destination non prévue.
L'idée n'est pas de bloquer l'agent, mais de lui donner le même traitement qu'à tout service sortant sensible : un profil réseau connu, documenté, et surveillé.
Les pièges à faux positifs
Trois sources de bruit reviennent quand on déploie du JA4 en production :
- La rotation de bibliothèques TLS. Une mise à jour de runtime (Node.js, Python, un navigateur) peut changer le JA4 sans rien changer au comportement de l'application. Une allowlist figée devient vite une source de faux positifs ; prévoir une revue à chaque changement de version documenté du parc.
- Les CDN et infrastructures partagées. Deux services distincts, hébergés derrière le même CDN ou la même passerelle API, peuvent produire un JA4S identique côté serveur : il doit toujours être croisé avec le SNI et, si possible, la plage IP de résolution.
- La dérive du corpus. Un référentiel de JA4 légitimes constitué une fois et jamais revisité devient obsolète en quelques mois. Le maintenir vivant demande un processus, pas un fichier statique.
En résumé
JA4+ change de nature par rapport à JA3 : en triant les listes de ciphers et d'extensions avant hachage, il neutralise le GREASE et rend l'empreinte représentative de l'outil plutôt que de la bibliothèque TLS. Activé dans Suricata via ja4-fingerprints, exploité en règle avec ja4.hash et ja4s.hash, et croisé avec le SNI et le comportement temporel, il permet de repérer un beacon C2 ou une exfiltration dans du trafic HTTPS qui ressemble, en apparence, à n'importe quel appel API, y compris celui d'un agent IA interne.
Construire et maintenir ce corpus de signatures JA4, valider chaque empreinte contre du trafic bénin réel pour éliminer les faux positifs, suivre la dérive des bibliothèques TLS au fil des versions : c'est exactement le travail continu que nous menons dans le flux de détection réseau ThreatClaw.
Articles liés
ET Open est gratuit, ET Pro et Talos sont payants, et les feeds curés se situent entre les deux. Comparaison pratique des rulesets Suricata et Snort pour la détection réseau, avec les critères qui comptent pour un SOC ou un MSSP.
Suricata vs Snort : comparatif architecture, compatibilité des règles, couverture ICS/OT et migration, pour arbitrer son moteur NIDS en connaissance de cause.
Détection intrusion réseau NIDS : où Suricata voit ce que l'EDR ne voit pas, anatomie d'une règle, et pourquoi un pack de règles curées bat un flux brut.
Comment écrire une règle Suricata : header, sticky buffers modernes, exemple CVE avant/après, test syntaxique sur pcap et piège anti-faux-positifs.