Red Hot Cyber

La cybersecurity è condivisione.
Riconosci il rischio, combattilo, condividi le tue esperienze ed 
incentiva gli altri a fare meglio di te.

Cerca
Crowdstrike

Scopriamo la vulnerabilità Phishic Signatures di Java

Redazione RHC : 25 Aprile 2022 09:53

Un ricercatore di sicurezza di ForgeRock, Neil Madden, ha rivelato e segnalato una vulnerabilità in una funzione crittografica in Java. Alla vulnerabilità è stato assegnato un CVE ID CVE-2022-21449 con un punteggio CVSS di 7,5 di score.

Il difetto consente agli aggressori di falsificare facilmente alcuni tipi di certificati SSL e handshake TLS in una comunicazione protetta. Ciò consente agli aggressori di aggirare JWT firmati, asserzioni SAML o token IDOIDC e persino WebAuthn e intercettare o manomettere la comunicazione su un canale crittografato e protetto.

E’ molto importante correggere la vulnerabilità e Invitiamo tutti a fixare la CVE-2022-21449 all’interno delle proprie applicazioni Java e non dimenticare di contattare tutti i fornitori di applicazioni di terze parti per risolvere questo problema.

L’algoritmo ECDSA

L’algoritmo di firma digitale ECDSA si basa sull’algoritmo di crittografia a curva ellittica (ECC), utilizzato per generare chiavi pubbliche e private. Le firme ECDSA sono considerate più sicure delle tradizionali firme RSA e sono anche più brevi e veloci da generare. Ciò ha reso l’ECDSA prevalente dove velocità e dimensioni sono fattori decisivi.

Le firme ECDSA utilizzano chiavi più piccole, a parità di sicurezza, rispetto alle tradizionali firme RSA per cui essendo più brevi sono anche più veloci da generare. Sono basate sul problema del logaritmo discreto in curve ellittiche anziché sul problema della fattorizzazione di interi della firma RSA. In entrambi i casi non esistono algoritmi efficienti (che possano essere risolti in un tempo polinomiale) che permettano di calcolare:

  • i fattori primi di un numero risultante dal prodotto di numeri primi molto grandi (problema della fattorizzazione su cui si basa RSA: è facile calcolare il prodotto ma è estremamente complesso scomporre il prodotto nei suoi fattori);
  • nell’equazione esponenziale a**x = b, ovvero x = log (in base a) b, la soluzione è facile (tempo polinomiale) nel campo dei numeri reali ma se applicate al contesto di un campo finito (come quello definito dall’equazione di una curva ellittica) risultano un problema estremamente complesso.

Questo tipo di funzioni, calcolabili facilmente ma la cui inversa è invece di complessa risoluzione, sono dette “funzioni unidirezionali” proprio per questa loro peculiarità e sono fondamentali per la crittografia moderna a chiave pubblica e privata e quindi per il mondo tecnologico attuale, così come lo conosciamo.

Oggi, ECDSA è emerso come standard globale per un’ampia gamma di algoritmi di firma, ad eccezione di alcuni algoritmi come Windows Hello, che utilizza l’algoritmo RSA per problemi di comparabilità TPM precedenti.

Per dirla in parole semplici, la firma ECDSA è composta da due valori chiamati r e s.

Per verificare una firma ECDSA, il verificatore confronta una formula con r, s, la chiave pubblica del firmatario e l’hash del messaggio. La firma è valida se entrambi i membri dell’equazione sono uguali, altrimenti è considerata non valida e verrà rifiutata.

Quindi è molto importante che sia r che s non debbano essere “0” per convalidare la firma.

È il primo controllo per verificare i valori di r e s. Il processo di verifica della firma ECDSA dovrebbe garantire che i valori di r e s siano entrambi >= 1.

Alcuni dettagli tecnici

Se vai a guardare i dettagli di ECDSA su wikipedia (Come riporta l’autore della ricerca), vedrai che il lato destro dell’equazione non è moltiplicato per s ma piuttosto per il suo inverso moltiplicativo: -1 . Se conosci un po’ di matematica, potresti pensare “calcolando questo inverso non risulterà in una divisione per zero?” Ma nella crittografia a curve ellittiche, questo inverso viene calcolato dal modulo di un numero grande, n , e per le curve tipicamente usate in ECDSA, n è un numero primo, quindi possiamo usare il Piccolo Teorema di Fermat per calcolare il modulo inverso:

n = x 1 = x (mod n)
(n-1) = x 0 = 1 (mod n)
(n-2) = x -1 (mod n)

Questo è molto efficiente ed è esattamente ciò che fa Java

valido solo per x diverso da 0″ oppure ” valido solo quando x non è 0

Tuttavia, è valido solo quando x non è zero, poiché zero non ha un inverso moltiplicativo. Quando x è zero, allora 0 (n-2) = 0: diventa spazzatura in entrata e spazzatura in uscita.

Il fatto che l’aritmetica venga eseguita nel modulo n è anche il motivo per cui è necessario verificare che anche r e s siano entrambi n , perché n = 0 (mod n) quindi impostare r o s su n avrebbe lo stesso effetto di impostarli su 0.

Un altro controllo che avrebbe dovuto fare Java è il controllo descritto nel passaggio 5 dell’algoritmo di verifica su Wikipedia: verificare che un punto calcolato da r e s non sia il “punto all’infinito”. 

Se r e s sono entrambi zero, il punto risultante sarà in effetti il ​​punto all’infinito e quindi questo controllo fallirà. Ma ancora una volta, Java non è riuscito a eseguire questo controllo.

Come funziona il bug

L’implementazione di Java del processo di verifica della firma ECDSA non è in grado di verificare se r o s è ‘0’. A causa di questo errore di verifica, Java accetterà la firma come firma valida anche se r e s sono ‘0’. Ciò consente a chiunque di produrre una firma con r e s ‘0’. 

Java la considererà una firma valida per qualsiasi messaggio e per qualsiasi chiave pubblica. Ciò significa che una carta d’identità vuota sarà accettata come carta d’identità valida.

Ecco il codice di implementazione vulnerabile della sessione jshell interattiva che accetta una firma vuota come firma valida per un messaggio arbitrario e una chiave pubblica:

|  Welcome to JShell -- Version 17.0.1 
|  For an introduction type: /help intro 
jshell> import java.security.* 
jshell> var keys = KeyPairGenerator.getInstance("EC").generateKeyPair() 
keys ==> java.security.KeyPair@626b2d4a 
jshell> var blankSignature = new byte[64] 
blankSignature ==> byte[64] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... , 0, 0, 0, 0, 0, 0, 0, 0 } 
jshell> var sig = Signature.getInstance("SHA256WithECDSAInP1363Format") 
sig ==> Signature object: SHA256WithECDSAInP1363Format 
jshell> sig.initVerify(keys.getPublic()) 
jshell> sig.update("Hello, World".getBytes()) 
jshell> sig.verify(blankSignature) 
$8 ==> true 
// Oops, that shouldn't have verified...

Concludendo

La vulnerabilità delle Psychic Signatures è una vulnerabilità di bypass della firma digitale in Java dovuta alla scarsa implementazione dell’algoritmo di firma digitale a curva ellittica in Java. 

Questa vulnerabilità di bypass della firma fa sì che Java accetti una firma vuota come firma valida. 

Quindi, come abbiamo anticipato all’inizio dell’articolo, gli aggressori potrebbero abusare di questa vulnerabilità per aggirare  JWT firmati ,  asserzioni SAML  o  token ID OIDC e persino  messaggi di autenticazione WebAuthn  e intercettare o addirittura manomettere la comunicazione su un canale crittografato protetto.

Redazione
La redazione di Red Hot Cyber è composta da un insieme di persone fisiche e fonti anonime che collaborano attivamente fornendo informazioni in anteprima e news sulla sicurezza informatica e sull'informatica in generale.