
Un semplice generatore di exploit PoC per CVE-2022-39299 per bypassare l'autenticazione nelle integrazioni SAML SSO che utilizzano versioni vulnerabili di passport-saml
Avviso: https://github.com/node-saml/passport-saml/security/advisories/GHSA-m974-647v-whv7 Patch: https://github.com/node-saml/passport-saml/commit/8b7e3f5a91c8e5ac7e890a0c90bc7491ce33155e Esempio di payload base estratto dai casi di test di node-saml: https://github.com/node-saml/node-saml/blob/c1f275c289c01921e58f5c70ce0fdbc5287e5fbe/test/static/signatures/invalid/response.root-signed.multiple-root-elements.xml
Autore del bug: felixwilhelm Autore del generatore di exploit (la parte facile): Francesco Lacerenza
Un attaccante remoto può bypassare l'autenticazione SAML SSO su una piattaforma sfruttando CVE-2022-39299 che colpisce la libreria passport-saml.
Un exploit pubblico non era disponibile (al momento della scrittura), e l'avviso è stato pubblicato il 10/12/2022 con poche o nessuna informazione. Doyensec ha sviluppato un generatore di Proof Of Concept (PoC) funzionante per verificare il problema su piattaforme multi-tenant in cui l'amministratore del tenant è in grado di configurare SAML SSO con un IdP personalizzato.
Come affermato nell'avviso:
Un attacco riuscito richiede che l'attaccante sia in possesso di un elemento XML firmato da un IdP arbitrario. A seconda dell'IdP utilizzato, potrebbero essere possibili anche attacchi completamente non autenticati (cioè senza accesso a un utente valido) se è possibile innescare la generazione di un messaggio firmato.
Il controllo vulnerabile si trova all'interno della funzione validatePostResponse in passport-saml-2.0.0/src/passport-saml/saml.ts:775
// Check if this document has a valid top-level signature
let validSignature = false;
if (this.options.cert && this.validateSignature(xml, doc.documentElement, certs!)) {
validSignature = true;
}
In particolare, validateSignature verifica che il doc.documentElement nel documento XML completo contenga una firma valida. Poiché la proprietà documentElement restituisce il primo nodo radice del documento, verificherà la firma solo sul primo elemento radice.
La funzione continua verificando che nell'XML ci sia una sola asserzione:
const assertions = xmlCrypto.xpath(doc, "/*[local-name()='Response']/*[local-name()='Assertion']") as HTMLElement[];
const encryptedAssertions = xmlCrypto.xpath(doc,
"/*[local-name()='Response']/*[local-name()='EncryptedAssertion']");
if (assertions.length + encryptedAssertions.length > 1) {
// There's no reason I know of that we want to handle multiple assertions, and it seems like a
// potential risk vector for signature scope issues, so treat this as an invalid signature
throw new Error('Invalid signature: multiple assertions');
}
Di conseguenza, il parser XML analizzerà un documento XML con radici multiple. Mentre una firma può applicarsi a un solo nodo radice, XPath può attraversare più nodi radice per trovare elementi di autenticazione e autorizzazione.
In conclusione, un nodo radice può essere firmato (ad es. un messaggio di errore SAML generico) e poi un altro nodo, non firmato, potrebbe contenere informazioni di autenticazione e autorizzazione modificabili. In questo modo l'attaccante è in grado di alterare le informazioni di autenticazione e ottenere l'accesso a qualsiasi account all'interno del tenant.
NOTA: Il successo dello sfruttamento dipende completamente dalla logica di autenticazione interna relativa all'uso della libreria passport. Se la logica di autenticazione si fida completamente dell'oggetto della sessione autenticata risultante da passport.authenticate(...PASSPORT-SAML_OPTIONS...), allora è probabile che sia vulnerabile.
openssl nella cartella del generatore PoC:openssl req -x509 -new -newkey rsa:2048 -nodes -subj '/C=US/ST=California/L=San Francisco/O=JankyCo/CN=Test Identity Provider' -keyout key.pem -out cert.pem -days 7300
In alternativa, utilizza quelli presenti in questo repository.
Sulla piattaforma target, naviga come amministratore al pannello di integrazione SAML SSO. Quindi, imposta il certificato utilizzato per convalidare le firme dall'IdP come quello presente in questa cartella.
Configura il file payload_appendix.xml con gli elementi di autenticazione e autorizzazione necessari alla piattaforma per autenticare gli utenti SAML SSO. Puoi trovare queste informazioni nella documentazione o creando un'integrazione SSO funzionante per apprendere gli elementi di autenticazione validi.
Esegui il seguente comando per generare una risposta SAML con elementi radice multipli firmati contenente i tuoi dati alterati.
python3 payloadGenerator.py
La risposta SAML con elementi radice multipli ha la seguente struttura:
<!— BEGINNING OF THE SIGNED ERROR MESSAGE —>
<samlp:Response xmlns="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="IDVALUE" Version="2.0" IssueInstant="2022-28-08T14:38:05Z">
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:NoPassive">
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:PartialLogout">
</samlp:StatusCode>
</samlp:StatusCode>
</samlp:StatusCode>
<samlp:StatusMessage>Random Error</samlp:StatusMessage>
</samlp:Status>
</samlp:Response>
<!— END OF THE SIGNED ERROR MESSAGE. BEGINNING OF THE UNSIGNED AUTHENTICATION INFO—>
<Response>
<saml:Assertion ID="whatever" IssueInstant="2022-10-30T18:00:00+00:00" Version="2.0">
<!— TAMPERED AUTHN & AUTHZ INFO —>
</saml:Assertion>
</Response>
NOTA: Se desideri sfruttare questo problema quando non hai accesso alla configurazione dell'IdP, modifica semplicemente payloadGenerator.py sostituendo la variabile signed_base_payload_unicode utilizzata per costruire il payload finale. Per funzionare, devi sostituirla con una risposta SAML firmata che non contenga asserzioni. Buona fortuna nel trovare un modo per ottenerla dall'IdP del target (la logica varia caso per caso e non esiste documentazione al riguardo).
Nelle organizzazioni con integrazione SAML SSO abilitata, gli attaccanti potrebbero bypassare l'autenticazione e accedere come qualsiasi utente nel tenant.
Nonostante l'avviso affermi che l'attaccante potrebbe utilizzare "un elemento XML firmato da un IdP arbitrario", la libreria passport-saml impedisce qualsiasi messaggio XML contenente asserzioni multiple (vedi snippet di codice nella sezione descrizione). La limitazione richiede all'attaccante di ottenere un messaggio SAML firmato che non contenga un'asserzione, come un messaggio di errore. La presenza di tali messaggi dipende dall'implementazione dell'IdP.
Ad esempio, le risposte SAML senza asserzioni sono direttamente supportate dalla libreria node-samlp di Auth0. Vedi https://github.com/auth0/node-samlp/blob/master/lib/samlp.js