Skip to content
KitploitKITPLOIT
HerramientasBlog
Log in
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2022-0778 — Exploit de prueba de concepto para CVE-2022-0778, que demuestra un bucle infinito en BN_mod_sqrt de OpenSSL mediante un certificado X.509 manipulado con parámetros de curva no primos, lo que permite ataques de denegación de servicio. | Kitploit
Herramientas/GitHubGitHub/drago-96/cve-2022-0778
Análisis de VulnerabilidadesExplotaciónCriptografíaAnálisis de BinariosPapers e InvestigaciónAprendizaje y Educación
GitHubdrago-96/cve-2022-0778

CVE-2022-0778

Exploit de prueba de concepto para CVE-2022-0778, que demuestra un bucle infinito en BN_mod_sqrt de OpenSSL mediante un certificado X.509 manipulado con parámetros de curva no primos, lo que permite ataques de denegación de servicio.

Ver Repositorio
1814610hace 4 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2022-0778

La vulnerabilidad descubierta provoca un bucle infinito en la función BN_mod_sqrt() de OpenSSL al analizar una clave de curva elíptica. Esto significa que un certificado X.509 manipulado de forma maliciosa puede provocar un DoS en cualquier servidor sin parchear.

El núcleo de la vulnerabilidad está en el análisis de claves EC con puntos en formato comprimido: al analizar este tipo de claves, OpenSSL intentará expandir el punto comprimido, tratando de calcular una raíz cuadrada módulo el primo p sobre el que está definida la curva. Sin embargo, la primalidad de p no se comprueba en ningún sitio, ni siquiera en BN_mod_sqrt(), para la cual es un requisito; por lo tanto, un error en la implementación provocará un bucle infinito debido a que p no es primo como se esperaba.

La explicación en chino está disponible en mi blog OpenSSL CVE-2022-0778: reproducción del problema y construcción de certificados no válidos

Créditos

  • Tavis Ormandy por descubrir y divulgar la vulnerabilidad
  • Drago por publicar la prueba contra BN_mod_sqrt()
  • catbro666 por construir realmente un certificado X.509 que hace que el servidor se cuelgue
  • wllm-rbnt por la útil herramienta asn1template

Cómo probarlo

El requisito previo es tener instalados gcc y una versión vulnerable de OpenSSL.

Para el error en BN_mod_sqrt(): compila con gcc -o my_bad_sqrt my_bad_sqrt.c -lcrypto, ejecuta ./my_bad_sqrt y observa cómo se cuelga para siempre. :D

Con un certificado: ejecuta openssl x509 -in certs/cert.der.new -inform DER -text -noout en la línea de comandos; esto también se cuelga.

Entrando en el bucle

La función BN_mod_sqrt() implementa el algoritmo de Tonelli-Shanks para encontrar una raíz cuadrada modular, es decir, dado un entero a y un número primo p, devuelve un valor r tal que r^2 == a (mod p).

Al analizar el commit que parchea la vulnerabilidad, vemos que el culpable es el bucle que encuentra el índice más pequeño i para el cual b^(2^i)==1 (mod p), donde b se define antes en el algoritmo.

El bucle se cambia 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;
}

a

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;
}

En el segundo caso, hay un bucle for limitado por la variable e; en el código original, sin embargo, solo hay una comprobación del caso i==e dentro de un bucle while.

Dado que estos bucles están dentro de un bucle mayor que en cada iteración establece el nuevo valor de e al valor actual de i, probamos la siguiente estrategia de ataque:

  1. en la primera ejecución del bucle externo, hacer que i=1 al final; para ello, necesitamos que b^2=1 (mod p).
  2. de esta manera, durante la segunda ejecución tendremos e=1, y si podemos entrar en el bucle interno, la comprobación i==e siempre fallará
  3. si conseguimos tener siempre t != 1 (mod p), entonces permaneceremos en el bucle para siempre

Observa que los dos primeros pasos pueden ocurrir en una ejecución "normal", es decir, con un primo p. Sin embargo, si p es compuesto, ¡también podemos satisfacer el tercer paso!

Un poco de matemáticas

El algoritmo de Tonelli-Shanks funciona escribiendo p - 1 = 2^e * q, con q impar. Este es también el orden del grupo multiplicativo de los enteros módulo p, y los valores e y q se usarán muchas veces durante la ejecución; sin embargo, si p no es primo, el orden del grupo multiplicativo no será p-1, y esto nos ayudará a entrar en el bucle infinito.

En particular, b se inicializa como b = a^q (mod p), lo que significa que si p fuera primo, entonces b tendría orden una potencia de 2, que luego encontraremos usando el bucle.

Pero si establecemos p = r * s, el orden del grupo multiplicativo es (r-1)*(s-1) = r*s - r - s + 1 en lugar de r*s-1. El algoritmo usa el valor de q para obtener un elemento y de orden exactamente 2^e; sin embargo, cuando p no es primo, el valor de q no tendrá un significado especial para el orden, por lo que el elemento y no tendrá orden una potencia de dos módulo p=r*s.

Dado que al final del primer bucle externo b se establece como b = b*y^(e-i) (mod p), en su segunda iteración el bucle interno intentará encontrar un valor i para el cual b^(2^i) == 1 (mod p), pero fallará dado que y ya no está garantizado que tenga orden una potencia de dos.

El exploit

Los números en el exploit son muy simples: tomamos r=17,s=41, lo que da p=r*s=697. Esto significa que los valores calculados de e y q serán p-1 = 2^3 * 87.

Luego elegimos a=696, lo que significa que a == -1 (mod p) y también b == -1 (mod p) cuando se inicializa. Esto satisfará el paso 1 estableciendo e=1 para el siguiente bucle externo.

Entonces b se establecerá como un elemento con orden que no es una potencia de 2, y el bucle interno se quedará atascado tratando de encontrar un i para el cual b^(2^i)==1 (mod p).

Creando un certificado peligroso

Bien, ahora vamos a construir un certificado peligroso que contenga parámetros de curva explícitos no válidos con un punto base codificado en formato comprimido.

Los archivos de esta sección están en la carpeta certs.

Creando un certificado normal con parámetros de curva explícitos

Primero, necesitamos crear una clave privada EC. Como queremos un certificado objetivo con parámetros de curva explícitos, la clave también debe contener parámetros de curva explícitos.

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

Luego, por conveniencia, firmamos automáticamente un certificado y lo generamos en formato DER.

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

Veamos la información del certificado. Contiene parámetros de curva explícitos como se esperaba.

$ 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
...

Construyendo un certificado no válido

Ahora necesitamos modificar los valores de estos parámetros: Prime, A, B, Generator. Satisfacen la ecuación siguiente

Descargar herramienta