Strano caso in bug bounty, $17K per due vulnerabilities chained insieme

Ogni tanto posto su cose che trovo in bug bounties perche’ mi e’ sembrato che alcuni sono interessati a questo topic.

Mi e’ stato appena approvato un report per cui ho dovuto aspettare 4 mesi, ma ne vale la pena perche’ la reward e’ 17K :smiley:

Come spesso accade, in questo caso la applicazione principale dell’azienda e’ fatta molto bene dal punto di vista della sicurezza, ma purtroppo per loro ho trovato un’altra applicazione, vecchia, che e’ connessa allo stesso database, e li’ ho trovato due vulnerabilita’ che mi hanno consentito di accedere a PII come financial data, social security numbers e persino dati medici :danceperv: Per questo motivo spendo sempre parecchio tempo con recon prima di attaccare la applicazione principale.

Spiegazione: parto dalla applicazione principale sulla quale non sono riuscito a trovare niente perche’ e’ moderna e fatta bene.

L’applicazione principale e’ fatta bene e tiene conto di tutte le migliori pratiche di sicurezza, che e’ aspettato per una applicazione che gestisce dati sensitivi come quelli che ho trovato. Ho speso settimane su questa senza trovare niente tipico di OWASP e altri comuni problemi. Quindi non ero riuscito a trovare niente la’.

Durante un primo recon non avevo notato un subdomain che punta ad una applicazione vecchia e brutta per uso interno e che gira su una porta non comune, e addirittura con self-signed certificate. Segni che e’ stata praticamente dimenticata o che comunque dovrebbero rimuoverla.

Questa applicazione vecchia accetta le mie credenziali per l’accesso, e a prima vista sembra che il mio accesso e’ molto limitato probabilmente perche’ non sono dello staff e quindi non ho permessi.

Purtroppo per loro, ho trovato nel giro di alcune settimane due vulnerabilita’ in questa applicazione vecchia; la prima e’ una UNION SQL injection (in una sezione dove posso aggiungere note ad un calendario per appuntamenti) con cui ho exfiltrato i dati di alcune tabelle, incuse accounts e la interessante encryption_keys. In un primo momento mi e’ sembrato che non posso fare molto perche’ stacked queries non sono possibili, quindi non posso modificare o rimuovere dati, e anche perche’ quasi tutto nel database e’ criptato. La encryption_keys table mostra dati che normalmente sono un brutto segno per un bug bounty hunter, perche’ ha tre colonne: ID, hashed_kek, e encrypted_dek. Questa e’ la seconda volta in meno di un anno che trovo una applicazione che usa KEK/DEK encryption.

Spiegazione per chi non e’ familiare con questo metodo:

Nella implementazione piu’ semplice di encryption at rest in un database, di solito si usa una singola key per symmetric encryption; il problem con molti devs usano una singola key per tutti gli accounts, che e’ una pratica molto brutta e poco sicura. Pero’ se usi una key diversa per ogni account, e usi qualcosa come la password (di solito) per generare quella key, e’ un problema perche’ quando l’utente cambia la password o altra informazione usata per generare la key, bisogna fare re-encryption di tutti i dati di quell’utente, che e’ lento. Inoltre se - come e’ buona pratica - viene fatta la rotation delle keys, avere una singola key per account significa fare re-encryption dell’intero database, che non e’ ottimale e puo’ essere molto lento se il database e’ grande.

Per evitare la re-encryption dei dati, un methodo usato spesso da applicazioni fatte meglio della media e’ l’uso del combo KEK/DEK, dove KEK sta per “key encryption key” e DEK sta per “data encryption key”. Praticamente hai due keys, o chiavi, mi devo abituare a piu’ termini in italiano :slight_smile:

La KEK viene usata per criptare la DEK, e la DEK per criptare i dati sensitivi. In questo modo, quando l’utente cambia la password oppure quando gli amministratori fanno rotazione delle chiavi, bisogna soltanto 1) aggiornare la hashed KEK generata con la nuova password, 2) re-criptare la DEK. Quindi la DEK rimane la stessa (unencrypted), e dunque non bisogna re-criptare i dati sensitivi.

Il database di questa applicazione su cui ho lavorato usa proprio questo sistema; dopo alcuni test, ho potuto confermare che la KEK e’ generata dalla password come e’ spesso il caso (di solito si usa la password perche’ non e’ conservata nel database in cleartext).

Quindi finora, con la SQL injection ho potuto exfiltrare dati criptati che sono inutili senza le password di altri utenti. Ma anche se trovo le password di altri utenti, non posso usarle per authenticarmi come loro perche’ 2FA e’ obbligatorio con SMS/email o OTP.

Ma… c’e sempre un ma :D Ho trovato un’altra vulnerabilita’ sempre nella vecchia applicazione. L’applicazione principale ha implementato correttamente l’uso di tokens per evitare attacchi come CSRF (Cross Site Request Forgery); ma quella vecchia non controlla il CSRF token :asd:

Potete indovinare cosa significa prima di leggere la fine? :smiley:

Con l’applicazione vecchia, anche se trovo la password di un altro utente non posso fare log in come loro a causa del 2FA. Ma dal momento che questa applicazione non controlla il CSRF token, posso cambiare la password di altri utenti con un CSRF exploit, e ovviamente con la SQL injection menzionata prima posso vedere le email di altri utenti.

Quando cambio la password in un utente, per il motivo spiegato prima viene aggiornata la KEK, e questo significa che posso controllare la KEK, e dunque la DEK, di altri utenti, e quindi posso usare la DEK per decryptare i dati sensitivi di altri utenti. :asdsad:

Questo e’ un esempio in cui 2 cose sono importanti quando si fanno bug bounties:

1 - mai fermarsi alla applicazione principale; fare sempre recon e provare a trovare applicazioni secondarie o vecchie perche’ spesso non sono aggiornate e sicure come quella principale
2 - le due vulnerabilita’ che ho trovato, da sole, non hanno alcun impatto diretto e dunque e’ probabile che l’azienda non paga se riporti una sola. La SQL injection da sola non ha molto valore perche’ quasi tutto e’ criptato nel database, e la CSRF mi consente di cambiare la password di altri utenti ma non posso fare log in a causa del 2FA. Ma facendo chain delle due, ho potuto controllare le chiavi di encryption per altri utenti attraverso il cambio delle loro password, e bingo. pwned

Questo tipo di casi sono i miei favoriti. Spesso richiedono molto tempo e pazienza, ma di solito portano a vulnerabilita’ critiche che valgono $$$.

Se ci sono devs tra di voi, ricordate che encryption at rest puo’ comunque servire a nulla se ci sono delle falle :asd:

4 Likes

Interessante, ma ho una domanda.
Come si fa in un sistema del genere a permettere agli utenti di resettare la password se la dimenticano?
Perdono tutti i dati che sono stati encrypted con la vecchia password?

8 Likes

Pensa che è una settimana che - dall’alto della mia incredibile incapacità di programmare - sto smadonnando con un bug del mio semplicissimo gioco testuale :asdsad: E non ho nemmeno la consolazione che se lo trovo poi guadagno soldoni perché ho solo 24 persone che ce l’hanno in wishlist

interessante
come si fa a partecipare al programma?

io anni fa avevo trovato un bug su facebook con il quale si riusciva a vedere gli amici di qualcuno senza essere nella sua lista amici o anche se erano nascosti

avevo segnalato la cosa ma non mi avevano considerato
qualche mese dopo era uscita una news che una importante dev aveva segnalto il bug…
non ho mai capito perchè lei si ed io no

pensa che Namirial (spid) quando ti connettevi, se nel campo password digitavi la prima lettera autocompletava la password :asd: poi hanno sistemato

1 Like

E’ proprio il motivo per cui usi KEK/DEK combo invece di una singola chiave. Quando cambi la password la KEK viene aggiornata e la DEK re-criptata con la nuova KEK, che e’ molto veloce. I dati sono ancora criptati con la stessa DEK, che rimane statica. Quindi nessun problema :slight_smile:

Volevo dire sensibili :asdpunk:

Ogni inizio e’ modesto :smiley:

Questi sono programmi privati, puoi accedere solo dietro invito se hai buona reputazione etc. :slight_smile:
Quanto tempo fa avevi trovato quel bug e come lo avevi riportato?

Mai sentiti Namirial e spid prima e ho dovuto ricercare. Non ho capito come e’ possibile che la password veniva autocompletata. Mi stai dicendo che quandi digiti veniva fatta una richiesta server side per caricare le password che corrispondevano alla stringa? Questo mi sembra inverosimile… non penso ci siano devs stupidi a questi livelli. Ma forse ho frainteso, puoi elaborare?

Sorry forse non ho spiegato bene.
Il motivo mi è chiaro, se l’utente cambia la password tutto ok, perché inserisce prima quella vecchia, si verifica che l"hash della kek corrisponda, viene decriptata la dek con la vecchia, a quel punto si usa la nuova kek (derivata dalla nuova psw) per crittare la dek di nuovo e sono tutti contenti.

Ma che succede se l’utente DIMENTICA la propria password? Non mi è chiaro come faccia a recuperarlo tramite i soliti meccanismi di “forgot you password?”.
Il sistema non salvando in chiaro la kek, ma solo l’hash, non ha la possibilità di decrittare la dek senza che l’utente la immetta (e non può visto che l’ha scordata), nè tantomeno i dati.
Come si fa in questo caso a generare una nuova psw senza perdere tutti i dati utenti crittati fino a quel momento?

Pics di un utente che perde la password, i vecchi capiranno

1 Like

sono passati almeno 10 anni ed avevo scritto direttamente alla mail di facebook per i bug

Oh vedo. Avevo capito male. La tua e’ una ottima domanda! In questo caso la password reset diretta non e’ disponibile e devi contattare supporto per fornire un ID e poi loro ti fanno fare il reset e non so 100% come funziona. Posso pero’ dirti come penso che funziona, in base a quello che viene di solito fatto in questi sistemi (l’ho usato io in un lavoro precedente dove ho architettato un sistema from scratch, e l’ho visto in bug bounties per pubblica amministrazione, banche e altre aziende con dati molto sensibili).

Nell’OP ho omesso una piccola parte del sistema nella spiegazione sopra giusto per limitarmi a quello che ho potuto fare come exploit per la bounty e mantenere la spiegazione semplice ad alto livello per chi non e’ familiare con cryptography, perche’ altrimenti e’ complicato da spiegare tutto in dettaglio.

La tua osservazione e’ corretta, nel senso che senza la password non si puo’ recuperare la KEK e dunque la DEK in quel modo.

Il dettaglio mancante che ho omesso e’ la *Recovery Key / RK. Questa e’ semplicemente una chiave conservata solo in memoria all’avvio del sistema con Secure Boot e non conservata sul filesystem. Per esempio, questa chiave viene letta da Hashicorp Vault or qualcosa di simile.

La DEK e’ in criptata con un mechanismo XOR che ha diversi nomi a seconda della persona a cui chiedi. Per simplicita’ lo chiamo XOR.

Il concetto e’ che la DEK viene criptata in un modo tale che puo essere decryptata sia con la KEK sia con la RK, e per questo tale methodo viene spesso chiamato “dual key encryption”.

Questo funziona, in breve, perche’ se fai XOR di A con B o di B con A ottieni lo stesso resultato.

Setup:

  • generi una random DEK (il “messaggio” da criptare in questo contesto)
  • generi una random KEK e una random RK della stessa lunghezza; la KEK e’ diversa per ogni user account, mentre la RK e’ generica ed esiste solo in memoria
  • generi pure un KEK_pad della stessa lunghezza delle altre
  • fai XOR della DEK con il KEK_pad, e poi fai XOR del risultato on KEK per ottenere il ciphertext della DEK
  • fai XOR del KEK_pad con RK per ottenere RK_pad
  • nel database conservi solo il ciphertext e RK_pad

Decryption:
1 - se hai la password e dunque puoi derivare la KEK: fai XOR del ciphertext con KEK, e poi XOR il risultato con RK_pad
2 - la password non e’ disponibile e dunque devi usare la RK: XOR RK_pad con RK per ottenere KEK_pad, e poi XOR il risultato con il ciphertext.

In entrambi i casi ottieni la DEK originale.

Capito? Queste cose diventano complicate abbastanza facilmente e fortunatamente la maggior parte delle applicazioni e’ piu’ semplice e usa basic encryption o piu’ spesso nessuna encryption.

Ok, immaginavo usassero una chiave di backup.
Thanks

E’ praticamente inevitabile in un sistema di questo tipo :slight_smile:

1 Like

Forse domanda stupidissima, ma come sei regolamentato con i dati che tu vedi quando trovi una vulnerabilità? Cioè entri in un db e trovi dati medici sensibili, tu li potresti vedere?

In pratica nella maggioranza dei casi potrei vedere molto o quasi tutto a seconda del caso e del bug o bugs.

Ma nelle rules of engagement o quello che sono in italiano e’ sempre proibito di accedere a dati di altri utenti. Quindi quando fai investigazione per vulnerabilita’ e prove di un exploit etc sei authorizzato ad usare soltanto account tuoi. Se si accorgono in qualche modo che hai avuto accesso a dati di altri utenti possono farti problemi. Normalmente devi anche aggiungere un header a tutte le tue richieste che ti idenfifica come hacker X cosi’ possono vedere che hai fatto.

Per essere sincero ogni tanto la curiosita’ di vedere in giro c’e’, ma rimane tra noi :asd:

capito grazie :lode: