Une CVE n'est pas un exploit

Le sigle est partout, souvent mal compris. Une entrée CVE (Common Vulnerabilities and Exposures) est un identifiant, CVE-AAAA-NNNNN, attribué à une vulnérabilité précise dans un produit précis. Ce n'est ni un exploit, ni un correctif, ni un score : c'est un nom commun, pour que tout le monde parle de la même faille. L'identifiant est attribué, dans le cadre du programme CVE, par une CNA (CVE Numbering Authority) : un éditeur, un projet ou un coordinateur comme un CERT, chacun numérotant les failles de son propre périmètre.

Le chemin de l'anomalie à cet identifiant est méthodique, et il ressemble peu à l'image d'Épinal. L'essentiel du travail n'est pas de déclencher la faille, mais de la comprendre et de la faire corriger sans nuire à personne. C'est ce chemin qu'on décrit ici, sur un exemple volontairement générique.

Trouver : par où les failles apparaissent

Une vulnérabilité est un écart entre ce qu'un programme est censé faire et ce qu'il fait vraiment aux limites. On la débusque de plusieurs façons, complémentaires.

La revue de code lit les endroits sensibles : analyse d'entrées, gestion de mémoire, frontières de confiance, contrôles d'accès. Le fuzzing envoie au programme des masses d'entrées malformées et guette les plantages ; il est particulièrement efficace sur le code qui analyse des entrées (formats de fichiers, protocoles) et sur les cibles écrites en langages non sûrs pour la mémoire.

python
import subprocess

def campagne_fuzz(binaire: str, graines: list[bytes]):
    # Idée du fuzzing : muter des entrées valides et repérer celles qui
    # font sortir le programme de son comportement normal. Un fuzzer réel
    # (AFL++, libFuzzer) guide les mutations par la couverture de code.
    for graine in graines:
        for entree in muter(graine, n=200):
            code = subprocess.run(binaire, input=entree,
                                  capture_output=True).returncode
            if code < 0:                    # terminé par un signal
                consigner_plantage(entree, code)

L'analyse différentielle compare deux versions ou deux implémentations d'une même spécification : un écart de comportement trahit souvent un bogue. Peu importe la porte d'entrée, la sortie est la même : un cas d'entrée qui met le programme dans un état qu'il n'aurait pas dû atteindre.

Comprendre : de l'anomalie à la cause racine

C'est ici que se fait le vrai travail. Un plantage n'est qu'un symptôme ; la CVE décrit la cause. Il faut donc réduire le cas fautif à son essence, puis remonter la pile jusqu'à l'instruction qui, la première, s'écarte de l'intention du code.

Prenons un exemple générique : un analyseur qui lit une longueur annoncée dans un en-tête, puis copie autant d'octets depuis le corps du message.

c
/* Défaut classique de logique : la longueur annoncée n'est jamais
   confrontée à la taille réellement disponible. Exemple illustratif. */
void lire_champ(const uint8_t *entree, size_t taille_entree) {
    uint16_t longueur = lire_u16(entree);      /* longueur annoncée */
    uint8_t  tampon[256];
    /* La faille est ici : rien ne vérifie que `longueur` tient dans le
       tampon ni qu'elle n'excède pas ce qui reste réellement en entrée. */
    memcpy(tampon, entree + 2, longueur);
}

La cause racine se formule en une phrase : une valeur contrôlée par l'attaquant est utilisée comme taille de copie sans être bornée. C'est cette phrase, pas le plantage, qui a de la valeur : c'est elle qui dicte le correctif, et elle range la faille dans une classe connue (ici, un dépassement de tampon, CWE-120). Le référentiel CWE nomme ces classes ; le rapport s'y adosse.

Une preuve de concept minimale

Une preuve de concept (PoC) sert à démontrer que la faille existe, et rien de plus. La bonne PoC est la plus petite possible : une entrée qui déclenche le comportement anormal de façon fiable et reproductible. Pour la faille ci-dessus, c'est un message dont l'en-tête annonce une longueur supérieure à la taille du tampon.

Une PoC de recherche n'est pas une arme. Elle vise un plantage démontrable, de quoi prouver et diagnostiquer, pas la transformation en exécution de code sur des systèmes en production. Cette retenue est à la fois éthique et pratique : elle suffit au correctif, et elle limite la casse si la PoC fuite. On la teste dans un environnement isolé, sur une instance qu'on possède ou qu'on est autorisé à tester, jamais sur l'infrastructure d'autrui.

Évaluer l'impact : CVSS

Une fois la faille comprise, on en mesure la gravité avec le CVSS (Common Vulnerability Scoring System). Le score se compose à partir de facteurs : le vecteur d'attaque (réseau, local), la complexité, les privilèges requis, l'interaction nécessaire d'un utilisateur, et l'atteinte à la confidentialité, à l'intégrité, à la disponibilité. Il produit une note de 0 à 10 et un vecteur lisible, par exemple AV:N/AC:L/PR:N/UI:N, qui dit en clair « exploitable à distance, sans privilège ni interaction ».

Il faut garder en tête ce que ce score mesure : une gravité technique, pas le risque réel. Une faille au CVSS élevé peut être peu exposée dans une organisation donnée, tandis qu'une faille techniquement mineure peut être critique pour une activité précise. Le CVSS aide à prioriser et situe la faille par rapport aux autres ; il ne remplace pas l'analyse de risque, qui tient compte du contexte réel de déploiement.

Divulgation responsable

C'est l'étape qui distingue la recherche de la nuisance. La divulgation coordonnée suit un ordre : on prévient d'abord l'éditeur, en privé, avec le rapport et la PoC minimale ; on convient d'un délai raisonnable pour le correctif (90 jours est une durée fréquemment retenue) ; on aide, si besoin, à reproduire et à corriger ; puis on publie une fois le correctif disponible, ou à l'échéance convenue.

L'ordre protège les utilisateurs : publier avant le correctif, c'est armer les attaquants contre des systèmes sans défense. Beaucoup d'organisations facilitent ce contact par un fichier security.txt ou un programme de divulgation ; le standard ISO/IEC 29147 en décrit les bonnes pratiques.

De l'identifiant au correctif

Au terme, une CNA attribue l'identifiant, l'entrée CVE est publiée avec sa description, ses versions affectées et ses références, puis reprise dans les bases de vulnérabilités que consultent les défenseurs. Le chercheur est crédité ; l'éditeur diffuse un correctif ; les équipes de sécurité peuvent enfin nommer, mesurer et corriger.

La boucle est vertueuse quand chacun tient son rôle : le chercheur comprend et prévient, l'éditeur corrige, la communauté apprend d'une classe de faille de plus. Une CVE bien menée n'est pas le récit d'une intrusion : c'est celui d'un défaut rendu public, proprement, pour que d'autres ne le répètent pas.

À retenir

  1. 01

    Une CVE identifie une faille, pas un moyen de l'exploiter.

  2. 02

    Le cœur du travail est l'analyse de cause racine, pas le déclenchement.

  3. 03

    Une preuve de concept démontre l'existence : minimale, elle n'a pas à être une arme.

  4. 04

    La divulgation coordonnée protège les utilisateurs avant de créditer le chercheur.