SPID e Google Authenticator
Quando l'interoperabilità viene ostacolata di proposito

9 marzo 2021 • Modificato il 26 ottobre 2024English version

La maggior parte dei provider SPID supporta l’autenticazione a due fattori tramite un’app che genera codici OTP. Ogni provider ha la propria app, incompatibile con le app degli altri provider e con quelle “universali” come Google Authenticator. Peccato che, dietro le quinte, tutte le app usino lo stesso algoritmo e che l’incompatibilità sia puramente artificiale.

In questo post analizzo le app per Android di alcuni provider SPID. Con del reverse engineering ottengo i parametri necessari per la generazione dei codici OTP, e li uso per configurare un generatore di codici universale come Google Authenticator, Yubico Authenticator o Authy.

Motivazioni

  • Flessibilità: persone diverse hanno esigenze diverse. C’è chi ha uno smartphone vecchio, chi preferisce non installare i Google Play Services, chi ha il root o il jailbreak1. In tutti questi casi potrebbe non essere possibile usare le app fornite dai provider.
  • Sicurezza: qualcuno potrebbe voler utilizzare un dispositivo offline ad alta sicurezza come una YubiKey2 piuttosto che il proprio smartphone, soprattutto nel caso in cui non sia dotato di sistemi di sicurezza hardware3 per memorizzare le credenziali in modo sicuro.
  • FOSS: ad oggi non esistono provider che utilizzino un’app rilasciata come software libero open source. Esistono invece decine di app FOSS universali per generare codici OTP.

A queste motivazioni ne aggiungo una soggettiva: la comodità. Se ogni sito web a cui siamo registrati avesse una sua app per l’autenticazione a due fattori, avremmo i telefoni inutilmente intasati di app tutte simili ma incompatibili tra loro. Avere tutto in un unico posto è meglio.

Background: cenni sull’algoritmo TOTP

Sugli app store di iOS e Android è possibile trovare decine o centinaia di applicazioni che generano codici OTP per l’autenticazione a due fattori. Certamente Google Authenticator è la più popolare, ma è solo una delle tante: ce n’è per tutti i gusti. Ciò che accomuna tutti questi autenticatori universali è l’algoritmo su cui si basano, TOTP (Time-based One-Time Password)4, estensione del più generico HOTP (HMAC-based One-Time Password)5.

Non mi dilungherò a spiegare il funzionamento dell’algoritmo, dato che per comprendere il resto del post basta sapere che esso prevede quattro “ingredienti”:

  1. un segreto;
  2. una funzione hash (di default SHA-1);
  3. l’intervallo di validità di ogni codice (di default 30 secondi);
  4. il numero di cifre dei codici (di default 6).

Tutti questi elementi devono essere condivisi tra server e applicazione. Solitamente sono stabiliti dal server, che li comunica all’app tramite un codice QR. In alternativa l’utente può trascrivere il segreto manualmente, ma in tal caso alcune app (come Google Authenticator) non consentono di impostare il resto dei parametri a valori diversi da quelli di default.

Di fatto il codice QR contiene soltanto un URI con la seguente struttura:

otpauth://totp/?secret=SEGRETO&algorithm=HASH&period=INTERVALLO&digits=CIFRE

in cui sono ben riconoscibili i quattro parametri appena descritti. Eventualmente possono essere inclusi anche ulteriori parametri come il nome del servizio e l’username. Segnalo questa pagina web che permette di generare un codice QR a partire dai parametri TOTP e che ho trovato utilissima nel corso delle mie analisi.

Un’ultima osservazione riguarda la codifica del segreto (che solitamente è una sequenza casuale di byte): si usa la rappresentazione in Base32, meno comune di Base64 ma ottimizzata per essere letta dagli umani. Comprende le 26 lettere dell’alfabeto (solo maiuscolo) e i numeri da 2 a 7 (mancano 0 e 1 perché potrebbero essere confusi con le lettere O e I).

Casi di studio

Ora che abbiamo ripassato i concetti fondamentali dell’algoritmo TOTP, possiamo entrare nel merito delle app dei provider SPID. Mi permetto di anticipare il succo di ciò che segue: tutti i provider usano l’algoritmo TOTP per la generazione dei codici, ma adottano misure più o meno complesse per impedire che venga usato con app diverse dalla loro.

InfoCert ID

L’app di InfoCert ID6 per Android si attiva semplicemente effettuando il login con le proprie credenziali. È ragionevole dedurre che il segreto dell’algoritmo TOTP sia inviato dal server all’applicazione durante questa fase, e che quindi si possa ricavare intercettando le comunicazioni tra app e server.

Un primo ostacolo emerge dal fatto che l’app non trasmette il traffico attraverso eventuali proxy impostati a livello di sistema (cioè dalle impostazioni di Android). Per fare un MITM7 si deve quindi usare una soluzione basata su VPN, come l’app Packet Capture8. Per catturare il traffico HTTPS è necessario configurare il sistema affinché consideri attendibile l’autorità di certificazione di Packet Capture, cosa che a sua volta richiede di avere i privilegi di root.

L’app di InfoCert ID rifiuta di avviarsi sui dispositivi con root. Inoltre effettua certificate pinning, ovvero rifiuta di connettersi se il server le presenta un certificato emesso da un’autorità di certificazione diversa da quelle previste in fase di sviluppo. Per superare questi due problemi si rende necessario patchare l’app.

Una rapida occhiata al contenuto estratto del file .apk rende evidente che l’app sia stata scritta in C++ usando Qt9 invece che direttamente in Java; l’intera logica dell’applicazione si trova nella libreria libinfocertID.so. Questo rende molto più difficile procedere con una patch a runtime, usando strumenti come Frida10. Fortunatamente, però, modificare la libreria è semplice e per farlo basta un hex editor.

Il controllo anti-root è implementato in modo che a chiudere l’app sia il front-end, scritto in QML11. Siccome il codice QML si trova “in chiaro” all’interno della libreria, dopo aver identificato la parte rilevante possiamo semplicemente eliminare la chiamata a Qt.quit().

Patching del controllo anti-root con un hex editorPatching del controllo anti-root con un hex editor

Per bypassare il certificate pinning, invece, possiamo esportare il certificato di Packet Capture in formato PEM e sostituirlo all’interno della libreria al posto di uno dei certificati originali. In questo modo l’applicazione considererà il certificato di Packet Capture tra quelli autorizzati e non rifiuterà la connessione.

Patching del certificate pinning con un hex editorPatching del certificate pinning con un hex editor

A questo punto possiamo sostituire la nostra libreria patchata all’interno del file .apk. Una volta firmato e installato ci consentirà di usare l’applicazione e di catturarne il traffico senza problemi. L’analisi del traffico conferma la deduzione iniziale: dopo il login il server invia all’app il segreto per l’algoritmo TOTP sotto forma di stringa esadecimale.

Per usare il segreto in app diverse da quella ufficiale, basta convertirne la codifica in Base32. Inoltre bisogna impostare il numero di cifre dei codici OTP a 8 e la funzione hash a SHA-512 (scoperta semplicemente andando per tentativi).

È interessante notare il fatto che il segreto sembra indissolubilmente legato al proprio account e che non cambi mai. Non è possibile revocarlo dalla propria area personale sul sito di InfoCert, e non cambia a seguito del cambiamento della password. Ciò significa che attivando l’applicazione su più dispositivi, tutti genereranno gli stessi codici OTP. Significa anche che se il segreto viene compromesso, non esiste rimedio.

Le funzionalità di sicurezza che abbiamo visto contribuiscono a rendere improbabile il fatto che il segreto possa essere rubato durante il normale utilizzo del servizio. Bisogna invece prestare particolare attenzione se si decide di sperimentare seguendo le mie orme, e conviene evitare se non si è ben consci dei rischi a cui si va incontro.

Aruba ID

L’app di Aruba ID12 segue un processo molto simile per la fase di attivazione. Richiede l’inserimento di un “codice di attivazione” invece delle proprie credenziali, ma anche in questo caso possiamo supporre che il segreto sia trasmesso dal server e che lo si possa intercettare durante la comunicazione.

Fortunatamente l’app di Aruba è strutturata in modo più convenzionale e scritta in Java. Non effettua controlli anti-root, ma fa uso di certificate pinning. In questo caso possiamo ricorrere a Frida e patchare l’app a runtime con uno script open source, come ad esempio masbog/frida-android-unpinning-ssl13.

L’analisi del traffico e una successiva decompilazione dell’app con JD14 rivelano un meccanismo di protezione insolito: i dati scambiati tra client e server sono criptati a livello applicativo con AES-256. Considerando che (come vedremo tra un attimo) la chiave è fissa e che durante il normale utilizzo dell’app il traffico è già protetto dalla connessione SSL (con certificate pinning!), questa misura sembra superflua ed è probabile che sia più un meccanismo per scoraggiare il reverse engineering piuttosto che una protezione per gli utenti.

Ho accettato la sfida e ho ricostruito il funzionamento della cifratura con l’analisi statica del codice. La chiave di cifratura principale, usata per criptare il traffico, si trova in un file binario tra le risorse del file .apk. Questo file è a sua volta criptato con un’altra chiave che l’app deriva a runtime usando l’algoritmo PBKDF215 (implementato dagli sviluppatori senza usare librerie pre-esistenti) e partendo da parametri in parte hard-codati e in parte salvati nei file di configurazione dell’app.

Ovviamente vale la considerazione che finché i parametri iniziali sono fissi, la chiave risultante è sempre la stessa, e a conti fatti la si può estrarre facilmente con Frida mettendo un hook sul metodo che esegue la decifratura. Procedendo in quel modo avrei potuto anche ignorare i dettagli su come sia derivata la chiave, ma mi sarei perso parte del divertimento.

Una volta ottenuta la chiave principale, ancora una volta possiamo recuperare il segreto inviato dal server e convertirne la codifica in Base32 per usarlo nell’app che preferiamo. Anche in questo caso bisogna impostare il numero di cifre dei codici OTP a 8, mentre la funzione hash è SHA-256. A differenza di InfoCert, Aruba consente di cambiare il segreto associato al proprio account dall’area personale accessibile sul sito.

Codici OTP di Aruba ID su Google Authenticator e Yubico AuthenticatorCodici OTP di Aruba ID su Google Authenticator e Yubico Authenticator

Aggiornamento 11 marzo 2021

Un lettore di questo post, che ringrazio, mi ha segnalato di aver scritto del codice in Python per recuperare il segreto TOTP dall’app ArubaOTP. Il codice è disponibile presso questo repository su GitHub.

Mi è stato fatto anche notare che Google Authenticator per Android, a differenza della versione per iOS, non supporta la generazione di codici con un numero di cifre diverso da 6 o con funzione hash diversa da SHA-1. Suggerisco quindi di provare una delle numerose app alternative.

LepidaID

L’app di LepidaID16 adotta un approccio diverso dalle precedenti per la procedura di attivazione. Funziona in modo molto simile a Google Authenticator: completamente offline, richiede che il segreto venga inserito a mano o scansionato tramite un codice QR. Notando che per l’inserimento manuale il segreto viene fornito già in Base32, mi sono quasi illuso che fosse direttamente utilizzabile con altre app di autenticazione.

Il codice QR non rispetta il formato standard; poco male. Provando a digitare il segreto in Google Authenticator ci si accorge che esso viene sì accettato, ma risulta nella generazione di codici OTP errati.

Una rapida occhiata al codice decompilato dell’applicazione svela il motivo (abbastanza comico). Il segreto che ci viene fornito è “criptato” con un cifrario a sostituzione monoalfabetica. In pratica ogni carattere X dell’alfabeto in Base32 è sostituito con un carattere Y dello stesso alfabeto; l’app si limita ad eseguire la sostituzione inversa.

Di tutte le tecniche che abbiamo visto fin’ora, questa è sicuramente quella più efficiente in termini di sforzo per creare un’incompatibilità tra due sistemi perfettamente interoperabili.

Per utilizzare il segreto con app diverse da quelle di Lepida è sufficiente effettuare la stessa sostituzione che viene fatta dall’app, usando la tabella che si trova facilmente nel codice decompilato. Gli altri parametri, a differenza dei casi precedenti, rimangono quelli più comuni: codici OTP di 6 cifre e algoritmo SHA-1.

Per l’analisi di quest’app ringrazio Fred.

Aggiornamento 26 ottobre 2024

Un lettore di questo post, che ringrazio, mi ha segnalato di aver scritto del codice in Python per convertire automaticamente il segreto di LepidaID e il relativo codice QR in formato standard. Il codice è disponibile presso questo repository su GitHub.

Altri provider

Non ho avuto modo di analizzare nel dettaglio Namirial ID e SielteID, che lascio per occasioni future. Mi giungono però notizie da colleghi che l’hanno fatto e riferiscono che i concetti sono sempre gli stessi: algoritmo TOTP, segreto ricavabile dall’analisi del traffico e utilizzabile su altre app. Potrebbe essere un ottimo passatempo per chiunque voglia mettersi alla prova.

I seguenti provider, al momento della scrittura, non utilizzano generatori di codici offline; inviano i codici OTP di volta in volta tramite SMS.

  • IntesaID17
  • SpidItalia18
  • TIM ID19
  • PosteID20

(PosteID consente anche di effettuare il login scansionando un codice QR dall’applicazione o rispondendo a una notifica push).

Aggiornamento 10 ottobre 2022

Dopo la pubblicazione di questo post, diversi lettori mi hanno segnalato che l’applicazione di PosteID è stata aggiornata introducendo un generatore di codici OTP analogo a quello delle altre app analizzate. Non ho avuto, tuttavia, il tempo da dedicare a un reverse engineering dell’app per approfondirne il funzionamento.

Segnalo che Lorenzo, uno dei lettori di questo post, ha prodotto un’implementazione open source delle funzionalità dell’app e l’ha resa disponibile al seguente indirizzo: https://projects.lilik.it/zolfa/pyjod. Le funzionalità implementate includono la generazione di codici OTP, l’accesso tramite codici QR e notifiche push.

Il lavoro di Lorenzo rivela che anche PosteID, dietro le quinte, utilizza il protocollo TOTP, come tutte le altre app studiate in questo post.

Ringrazio Lorenzo per aver condiviso il suo lavoro e per avermi tenuto informato durante il processo di analisi.

Conclusioni

I provider SPID usano l’algoritmo standard TOTP per la generazione dei codici OTP, ma tentano di impedire che si usino app diverse dalla loro distruggendo l’interoperabilità che lo standard garantisce, e probabilmente limitando anche l’esperienza d’uso degli utenti.

Spero che questo post possa essere di aiuto agli smanettoni che, come me, hanno intenzione di superare quest’inutile restrizione e a chi, più in generale, abbia semplicemente voglia di smontare un’app per vedere come funziona.

spidappreverse engineering
Condividi post:

Analisi dei biglietti magnetici usati per i trasporti in Lombardia

È vero che Apple traccia ogni app che apri? Uno sguardo tecnico