Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
dsa — Analisi di CVE-2016-3959 e un attacco proof of concept contro un server SSH Go. | Kitploit
Strumenti/GitHubGitHub/alexmullins/dsa
Analisi delle VulnerabilitàExploitCrittografiaPenetration TestingApprendimento e Formazione
GitHubalexmullins/dsa

dsa

Analisi di CVE-2016-3959 e un attacco proof of concept contro un server SSH Go.

Vedi Repository
11710 anni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

Un riepilogo della vulnerabilità crypto/dsa di Go (CVE-2016-3959)

Alex Mullins

9 aprile 2016


Introduzione

Recentemente è stato scoperto un bug nella libreria crittografica Digital Signature Algorithm (DSA) per il linguaggio di programmazione Go. In questo articolo esamineremo i dettagli del bug e come un attaccante potrebbe sfruttarlo per avviare un attacco denial of service contro un server SSH Go standard che utilizza la libreria DSA sottostante per autenticare i client.

La prima menzione di questa vulnerabilità è apparsa in un post sulla mailing list Open Source Security (oss-sec) all'indirizzo http://seclists.org/oss-sec/2016/q2/11.

Go ha un ciclo infinito in diverse routine per interi grandi che rende i programmi Go vulnerabili ad attacchi denial of service remoti. I programmi che utilizzano l'autenticazione client HTTPS o le librerie server SSH di Go sono entrambi esposti a questa vulnerabilità. Il problema è in fase di risoluzione nella seguente CL: https://golang.org/cl/21533

-- Jason Buberel

In sintesi, se questa vulnerabilità venisse sfruttata, potrebbe portare a un ciclo infinito nel codice sottostante della libreria BigNum. Ciò consumerà risorse di sistema in termini di CPU e memoria e potrebbe eventualmente rendere il programma o il sistema stesso non reattivo.

La dichiarazione sopra dice che SSH insieme all'autenticazione client HTTPS sono interessati, ma dopo aver esaminato i pacchetti crypto/tls e net/http di Go questo sembra essere errato. L'autenticazione client HTTPS può utilizzare schemi di firma RSA o ECDSA, ma non DSA. Vedi sotto. Se sbaglio su questo, per favore fatemelo sapere.

https://golang.org/pkg/crypto/tls/#Certificate

type Certificate struct {
        Certificate [][]byte
        // PrivateKey contains the private key corresponding to the public key
        // in Leaf. For a server, this must implement crypto.Signer and/or
        // crypto.Decrypter, with an RSA or ECDSA PublicKey. For a client
        // (performing client authentication), this must be a crypto.Signer
        // with an RSA or ECDSA PublicKey.
        PrivateKey crypto.PrivateKey

        ... other fields
}

Non molto dopo quel post apparso sulla mailing list oss-sec, è stato emesso un numero CVE: CVE-2016-3959. I manutentori di Go hanno una correzione pronta e apparirà nelle versioni 1.5.4 e 1.6.1 che saranno rilasciate mercoledì 13 aprile 2016; https://groups.google.com/forum/#!topic/golang-nuts/MmSbFHLPo8g.

Per seguire gli esempi di codice in questo articolo avrai bisogno di Go versione 1.6 installato. Segui le istruzioni su https://golang.org/doc/install. Se vuoi scaricare questo documento e gli esempi di codice, avrai bisogno anche di Git installato. Segui le istruzioni su https://git-scm.com/book/en/v2/Getting-Started-Installing-Git. Per clonare il repository esegui il seguente comando in un terminale:

$ go get github.com/alexmullins/dsa

Questo clonerà il repository nel tuo workspace di Go.

La prossima sezione illustrerà i dettagli della vulnerabilità.

Il Difetto

Allora, cosa c'è esattamente che non va? Per rispondere, bisogna tornare all'annuncio originale sulla mailing list oss-sec. Non ci sono molte informazioni lì oltre a una spiegazione generale del problema e un collegamento alla correzione del codice su https://golang.org/cl/21533. Il messaggio di commit per quella modifica contiene quanto segue:

crypto/dsa: elimina la PublicKey non valida all'inizio

Per PublicKey.P == 0, Verify fallirà. Non provare nemmeno.

--- Robert Griesemer

e il codice corretto:

https://github.com/golang/go/blob/master/src/crypto/dsa/dsa.go#L247

// Verify verifies the signature in r, s of hash using the public key, pub. It
// reports whether the signature is valid.
//
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
// to the byte-length of the subgroup. This function does not perform that
// truncation itself.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
    // FIPS 186-3, section 4.7

    // Code fix added to check if the key parameters are sensible.
    if pub.P.Sign() == 0 {
        return false
    }

    if r.Sign() < 1 || r.Cmp(pub.Q) >= 0 {
        return false
    }
    if s.Sign() < 1 || s.Cmp(pub.Q) >= 0 {
        return false
    }

    w := new(big.Int).ModInverse(s, pub.Q)

    n := pub.Q.BitLen()
    if n&7 != 0 {
        return false
    }
    z := new(big.Int).SetBytes(hash)

    u1 := new(big.Int).Mul(z, w)
    u1.Mod(u1, pub.Q)
    u2 := w.Mul(r, w)
    u2.Mod(u2, pub.Q)
    v := u1.Exp(pub.G, u1, pub.P)
    u2.Exp(pub.Y, u2, pub.P)
    v.Mul(v, u2)
    v.Mod(v, pub.P)
    v.Mod(v, pub.Q)

    return v.Cmp(r) == 0
}

Per riassumere il messaggio di commit e la correzione del codice sopra: in Go 1.6 e versioni precedenti c'è un bug nella funzione Verify del pacchetto crypto/dsa. Se qualcuno chiama Verify con il parametro della chiave pubblica P impostato a 0, causerà un ciclo infinito in una delle istruzioni più avanti nella funzione Verify.

Una breve digressione per spiegare DSA. DSA è un algoritmo di firma digitale che utilizza la crittografia asimmetrica per firmare un messaggio che può successivamente essere usato per garantire che il messaggio sia stato effettivamente inviato dal mittente/detentore della chiave privata. Un semplice esempio: Alice invia un messaggio a Bob dicendogli dove e quando incontrarsi per pranzo. Bob, però, vuole essere sicuro che sia davvero Alice a inviargli il messaggio e non qualcun altro. Per far funzionare questo, Alice firmerà il messaggio con la sua chiave privata e Bob potrà verificare la firma di Alice con la sua chiave pubblica che Bob conosce. Nessuno diverso dal detentore della chiave privata può firmare un messaggio che possa poi essere verificato dalla corrispondente chiave pubblica (almeno in teoria).

Per funzionare, DSA ha bisogno di 5 numeri grandi. I primi 3 numeri sono noti come parametri DSA P, Q e G. Questi definiscono il gruppo sottostante e il generatore del gruppo. Questi numeri possono essere creati correttamente chiamando dsa.GenerateParameters().

type Parameters struct {
        P, Q, G *big.Int
}

Gli ultimi due numeri necessari per DSA sono la chiave privata X e la corrispondente chiave pubblica Y. Questi numeri possono essere creati anche chiamando dsa.GenerateKey().

type PrivateKey struct {
        PublicKey
        X *big.Int
}

type PublicKey struct {
        Parameters
        Y *big.Int
}

Questo è tutto ciò che serve sapere su DSA per seguire. Per maggiori informazioni, vedi lo standard NIST: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf o la pagina Wikipedia: https://en.wikipedia.org/wiki/Digital_Signature_Algorithm.

Tornando al tema; dove si trova il ciclo infinito nella funzione Verify? Con un po' più di approfondimento scoprirai che il codice si blocca su:

v := u1.Exp(pub.G, u1, pub.P)

Questo è il commento per il metodo Exp():

// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
// See Knuth, volume 2, section 4.6.3.
func (z *Int) Exp(x, y, m *Int) *Int {

Da quanto sopra, si può vedere che il commento specifica che quando m == 0, viene eseguita l'esponenziazione senza riduzione modulare. Quando prendi un numero grande e lo elevi a un altro numero grande, il risultato sarà anch'esso un numero ENORME. Non ho molta familiarità con come funziona math/big, ma penso che sia ciò che sta accadendo qui. Exp() sta lavorando su questa esponenziazione che richiederà molto, molto tempo per essere completata (praticamente infinita).

Ecco alcuni numeri di esempio utilizzati in una chiamata di dsa.Verify() a Exp() raccolti dal codice di test qui sotto:

Scarica lo strumento