Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2022-0778 — Prova de conceito de exploit para CVE-2022-0778, demonstrando um loop infinito no BN_mod_sqrt do OpenSSL por meio de um certificado X.509 malicioso com parâmetros de curva não primos, permitindo ataques de negação de serviço. | Kitploit
Ferramentas/GitHubGitHub/drago-96/cve-2022-0778
Análise de VulnerabilidadesExploraçãoCriptografiaAnálise de BináriosPapers e PesquisaAprendizado e Educação
GitHubdrago-96/cve-2022-0778

CVE-2022-0778

Prova de conceito de exploit para CVE-2022-0778, demonstrando um loop infinito no BN_mod_sqrt do OpenSSL por meio de um certificado X.509 malicioso com parâmetros de curva não primos, permitindo ataques de negação de serviço.

Ver Repositório
181468há 4 anosRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2022-0778

A vulnerabilidade descoberta desencadeia um loop infinito na função BN_mod_sqrt() do OpenSSL durante a análise de uma chave de curva elíptica. Isso significa que um certificado X.509 maliciosamente criado pode causar DoS em qualquer servidor não corrigido.

O cerne da vulnerabilidade está na análise de chaves EC com pontos em formato comprimido: ao analisar esse tipo de chave, o OpenSSL tentará expandir o ponto comprimido, tentando calcular uma raiz quadrada módulo o primo p sobre o qual a curva é definida. No entanto, a primalidade de p não é verificada em nenhum lugar, nem mesmo em BN_mod_sqrt(), para a qual é um requisito; assim, um bug na implementação causará um loop infinito devido a p não ser primo como esperado.

A explicação em chinês pode ser encontrada no meu blog Reprodução do OpenSSL CVE-2022-0778 e construção de certificado inválido

Créditos

  • Tavis Ormandy por descobrir e divulgar a vulnerabilidade
  • Drago por publicar o teste contra BN_mod_sqrt()
  • catbro666 por realmente criar um certificado X.509 que faz o servidor travar
  • wllm-rbnt pela útil ferramenta asn1template

Como testar

O pré-requisito é ter instalado gcc e uma versão vulnerável do OpenSSL.

Para o bug em BN_mod_sqrt(): compile com gcc -o my_bad_sqrt my_bad_sqrt.c -lcrypto, execute ./my_bad_sqrt e veja-o travar para sempre! :D

Com um certificado: execute openssl x509 -in certs/cert.der.new -inform DER -text -noout na linha de comando; isso também trava.

Acertando o loop

A função BN_mod_sqrt() implementa o algoritmo Tonelli-Shanks para encontrar uma raiz quadrada modular, ou seja, dado um inteiro a e um número primo p, retorna um valor r tal que r^2 == a (mod p).

Analisando o commit que corrige a vulnerabilidade, vemos que o culpado é o loop que encontra o menor índice i para o qual b^(2^i)==1 (mod p), onde b é definido anteriormente no algoritmo.

O loop foi alterado 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;
}

para

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

No segundo caso, há um loop for limitado pela variável e; no código original, no entanto, há apenas uma verificação para o caso i==e dentro de um loop while.

Como esses loops estão dentro de um loop maior que, a cada iteração, define o novo valor de e como o valor atual de i, tentamos a seguinte estratégia de ataque:

  1. na primeira execução do loop externo, fazer com que i=1 no final; para isso, precisamos que b^2=1 (mod p).
  2. dessa forma, durante a segunda execução teremos e=1, e se conseguirmos entrar no loop interno, a verificação i==e sempre falhará
  3. se conseguirmos sempre ter t != 1 (mod p), ficaremos presos no loop para sempre

Observe que as duas primeiras etapas podem realmente acontecer em uma execução "normal", ou seja, com um primo p. No entanto, se p for composto, também podemos satisfazer a terceira etapa!

Alguma matemática

O algoritmo Tonelli-Shanks funciona escrevendo p - 1 = 2^e * q, com um q ímpar. Esta é também a ordem do grupo multiplicativo de inteiros módulo p, e os valores e e q serão usados muitas vezes durante a execução; no entanto, se p não for primo, a ordem do grupo multiplicativo não será p-1, e isso nos ajudará a entrar no loop infinito.

Em particular, b é inicializado como b = a^q (mod p), o que significa que se p fosse primo, então b teria ordem alguma potência de 2, que então encontraríamos usando o loop.

Mas se definirmos p = r * s, a ordem do grupo multiplicativo é (r-1)*(s-1) = r*s - r - s + 1 em vez de r*s-1. O algoritmo usa o valor q para obter um elemento y de ordem exatamente 2^e; no entanto, quando p não é primo, o valor q não terá um significado especial para a ordem, então o elemento y não terá ordem uma potência de dois módulo p=r*s.

Como no final do primeiro loop externo b é definido como b = b*y^(e-i) (mod p), em sua segunda iteração o loop interno tentará encontrar um valor i para o qual b^(2^i) == 1 (mod p), mas falhará, dado que y não está mais garantido de ter ordem uma potência de dois.

O exploit

Os números no exploit são muito simples: pegamos r=17,s=41, o que dá p=r*s=697. Isso significa que os valores calculados de e e q serão p-1 = 2^3 * 87.

Em seguida, escolhemos a=696, o que significa que a == -1 (mod p) e também b == -1 (mod p) quando inicializado. Isso satisfará a etapa 1 definindo e=1 para o loop externo seguinte.

Então b será definido como um elemento com ordem não sendo uma potência de 2, e o loop interno ficará preso tentando encontrar um i para o qual b^(2^i)==1 (mod p).

Criando um certificado perigoso

OK, agora vamos criar um certificado perigoso que contém parâmetros de curva explícitos inválidos com um ponto base codificado em formato comprimido.

Os arquivos desta seção estão na pasta certs.

Criando um certificado normal com parâmetros de curva explícitos

Primeiro, precisamos criar uma chave privada EC. Como queremos um certificado alvo com parâmetros de curva explícitos, a chave também deve conter parâmetros de curva explícitos.

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

Então, por conveniência, auto-assinamos um certificado e o emitimos no formato DER.

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

Vamos verificar as informações do certificado. Ele contém parâmetros de curva explícitos como esperado.

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

Criando um certificado inválido

Agora precisamos modificar os valores desses parâmetros: Primo, A, B, Gerador. Eles satisfazem a equação abaixo

onde p é o Primo, a é o parâmetro A e b é o parâmetro B. p, a, b juntos determinam uma curva. Descomprimir um ponto significa calcular a coordenada Y a partir da coordenada X correspondente.

Obviamente, a operação de raiz quadrada modular deve ser usada, que chamará BN_mod_sqrt().

Baixar ferramenta