Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2022-0778 — Preuve de concept d'exploitation pour CVE-2022-0778, démontrant une boucle infinie dans BN_mod_sqrt d'OpenSSL via un certificat X.509 conçu avec des paramètres de courbe non premiers, permettant des attaques par déni de service. | Kitploit
Outils/GitHubGitHub/drago-96/cve-2022-0778
Analyse des VulnérabilitésExploitationCryptographieAnalyse de BinairesArticles et RechercheApprentissage et Éducation
GitHubdrago-96/cve-2022-0778

CVE-2022-0778

Preuve de concept d'exploitation pour CVE-2022-0778, démontrant une boucle infinie dans BN_mod_sqrt d'OpenSSL via un certificat X.509 conçu avec des paramètres de courbe non premiers, permettant des attaques par déni de service.

Voir le dépôt
1814610il y a 4 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2022-0778

La vulnérabilité découverte déclenche une boucle infinie dans la fonction BN_mod_sqrt() d'OpenSSL lors de l'analyse d'une clé de courbe elliptique. Cela signifie qu'un certificat X.509 malveillant peut provoquer un déni de service sur tout serveur non corrigé.

Le cœur de la vulnérabilité se situe dans l'analyse des clés EC dont les points sont au format compressé : lors de l'analyse de ce type de clés, OpenSSL tente de décompresser le point compressé, en essayant de calculer une racine carrée modulo le nombre premier p sur lequel la courbe est définie. Cependant, la primalité de p n'est vérifiée nulle part, pas même dans BN_mod_sqrt() pour laquelle c'est pourtant une exigence ; ainsi, un bogue dans l'implémentation provoque une boucle infinie parce que p n'est pas premier comme attendu.

Une explication en chinois est disponible sur mon blog OpenSSL CVE-2022-0778漏洞问题复现与非法证书构造

Crédits

  • Tavis Ormandy pour avoir découvert et divulgué la vulnérabilité
  • Drago pour avoir publié le test contre BN_mod_sqrt()
  • catbro666 pour avoir réellement fabriqué un certificat X.509 qui fait se bloquer le serveur
  • wllm-rbnt pour l'outil utile asn1template

Comment tester

Le prérequis est d'avoir installé gcc et une version vulnérable d'OpenSSL.

Pour le bogue dans BN_mod_sqrt() : compilez avec gcc -o my_bad_sqrt my_bad_sqrt.c -lcrypto, exécutez ./my_bad_sqrt et regardez-le se bloquer pour toujours ! :D

Avec un certificat : exécutez openssl x509 -in certs/cert.der.new -inform DER -text -noout en ligne de commande ; cela se bloque également.

Déclencher la boucle

La fonction BN_mod_sqrt() implémente l'algorithme de Tonelli-Shanks pour trouver une racine carrée modulaire, c'est-à-dire que, étant donné un entier a et un nombre premier p, elle retourne une valeur r telle que r^2 == a (mod p).

En analysant le commit qui corrige la vulnérabilité, on voit que le coupable est la boucle qui trouve le plus petit indice i tel que b^(2^i)==1 (mod p), où b est défini plus haut dans l'algorithme.

La boucle passe de

i = 1;
if (!BN_mod_sqr(t, b, p, ctx))
    goto end;
while (!BN_is_one(t)) {
    i++;
    if (i == e) {
        ERR_raise(ERR_LIB_BN, BN_R_NOT_A_SQUARE);
        goto end;
    }
    if (!BN_mod_mul(t, t, t, p, ctx))
        goto end;
}

à

for (i = 1; i < e; i++) {
    if (i == 1) {
        if (!BN_mod_sqr(t, b, p, ctx))
            goto end;
    } else {
        if (!BN_mod_mul(t, t, t, p, ctx))
            goto end;
    }
    if (BN_is_one(t))
        break;
}

Dans le second cas, il y a une boucle for limitée par la variable e ; dans le code d'origine, il n'y a cependant qu'une vérification du cas i==e à l'intérieur d'une boucle while.

Comme ces boucles sont à l'intérieur d'une boucle plus grande qui, à chaque itération, définit la nouvelle valeur de e comme étant la valeur courante de i, nous essayons la stratégie d'attaque suivante :

  1. lors de la première exécution de la boucle externe, faites en sorte que i=1 à la fin ; pour cela, nous avons besoin que b^2=1 (mod p).
  2. de cette façon, lors de la seconde exécution nous aurons e=1, et si nous pouvons entrer dans la boucle interne, la vérification i==e échouera toujours
  3. si nous parvenons à avoir toujours t != 1 (mod p), nous resterons alors dans la boucle pour toujours

Notez que les deux premières étapes peuvent en réalité se produire lors d'une exécution « normale », c'est-à-dire avec un nombre premier p. Cependant, si p est composé, nous pouvons également satisfaire la troisième étape !

Un peu de mathématiques

L'algorithme de Tonelli-Shanks fonctionne en écrivant p - 1 = 2^e * q, avec q impair. C'est aussi l'ordre du groupe multiplicatif des entiers modulo p, et les valeurs e et q seront utilisées de nombreuses fois pendant l'exécution ; cependant, si p n'est pas premier, l'ordre du groupe multiplicatif ne sera pas p-1, ce qui nous aidera à entrer dans la boucle infinie.

En particulier, b est initialisé comme b = a^q (mod p), ce qui signifie que si p était premier, alors b aurait pour ordre une puissance de 2, que nous trouverons ensuite en utilisant la boucle.

Mais si nous posons p = r * s, l'ordre du groupe multiplicatif est (r-1)*(s-1) = r*s - r - s + 1 au lieu de r*s-1. L'algorithme utilise la valeur q pour obtenir un élément y d'ordre exactement 2^e ; cependant, lorsque p n'est pas premier, la valeur q n'aura pas de signification particulière pour l'ordre, donc l'élément y n'aura pas un ordre qui soit une puissance de deux modulo p=r*s.

Comme à la fin de la première boucle externe b est défini comme b = b*y^(e-i) (mod p), à sa seconde itération la boucle interne essaiera de trouver une valeur i telle que b^(2^i) == 1 (mod p), mais échouera étant donné que y n'est plus garanti d'avoir un ordre qui soit une puissance de deux.

L'exploit

Les nombres dans l'exploit sont très simples : nous prenons r=17,s=41, ce qui donne p=r*s=697. Cela signifie que les valeurs calculées de e et q seront p-1 = 2^3 * 87.

Nous choisissons ensuite a=696, ce qui signifie que a == -1 (mod p) et aussi b == -1 (mod p) lors de l'initialisation. Cela satisfera l'étape 1 en définissant e=1 pour la boucle externe suivante.

Ensuite, b sera défini comme un élément dont l'ordre n'est pas une puissance de 2, et la boucle interne restera bloquée à essayer de trouver un i tel que b^(2^i)==1 (mod p).

Créer un certificat dangereux

OK, maintenant fabriquons un certificat dangereux qui contient des paramètres de courbe explicites invalides avec un point de base encodé sous forme compressée.

Les fichiers de cette section se trouvent dans le dossier certs.

Créer un certificat normal avec des paramètres de courbe explicites

Tout d'abord, nous devons créer une clé privée EC. Comme nous voulons un certificat cible avec des paramètres de courbe explicites, la clé doit également contenir des paramètres de courbe explicites.

$ openssl ecparam -out ec.key -name prime256v1 -genkey -noout -param_enc explicit -conv_form compressed

Ensuite, pour plus de commodité, nous avons auto-signé un certificat et l'avons sorti au format DER.

$ openssl req -new -x509 -key ec.key -out cert.der -outform DER -days 360 -subj "/CN=TEST/"

Vérifions les informations du certificat. Il contient des paramètres de courbe explicites comme prévu.

$ openssl x509 -in cert.der -text -noout -inform DER
...
                Field Type: prime-field
                Prime:
                    00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00:
                    00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:
                    ff:ff:ff
                A:
                    00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00:
                    00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:
                    ff:ff:fc
                B:
                    5a:c6:35:d8:aa:3a:93:e7:b3:eb:bd:55:76:98:86:
                    bc:65:1d:06:b0:cc:53:b0:f6:3b:ce:3c:3e:27:d2:
                    60:4b
                Generator (compressed):
                    03:6b:17:d1:f2:e1:2c:42:47:f8:bc:e6:e5:63:a4:
                    40:f2:77:03:7d:81:2d:eb:33:a0:f4:a1:39:45:d8:
                    98:c2:96
                Order:
                    00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:ff:ff:
                    ff:ff:bc:e6:fa:ad:a7:17:9e:84:f3:b9:ca:c2:fc:
                    63:25:51
...

Fabriquer un certificat invalide

Télécharger l’outil