Hacking Fastweb: Responsible Disclosure

Introduzione

Fastweb S.p.A. è un’azienda italiana di telecomunicazioni specializzata nella telefonia terrestre e nelle connessioni a banda larga. Nel 2018 ha introdotto una responsible disclosure, dove i ricercatori di sicurezza vengono invitati a segnalare vulnerabilità nei sistemi mobile, hardware e web dell’azienda: https://www.fastweb.it/corporate/responsible-disclosure/

Il security team di Fastweb è stato molto cordiale e veloce sia nel rispondere alle e-mail e sia nel porre rimedio alle vulnerabilità segnalate.

Di seguito vengono riportate due vulnerabilità considerate “critiche”: una SQL Injection e una implementazione errata dei token di accesso JWT che consente l’accesso a qualsiasi account conoscendo l’username.

SQL Injection

L’SQL è un linguaggio che consente di interagire con i database ovvero di creare, modificare, eliminare ed estrarre dati salvati in esso. Queste operazioni vengono effettuate attraverso dei costrutti di programmazione chiamati query. La pagina vulnerabile, presente sul dominio https://www.fastweb.it/, è stata scritta in PHP, un linguaggio di programmazione pensato per costruire siti web dinamici, che consente di interagire con un database attraverso le query SQL. Un esempio può essere una query che estrae le informazioni di un utente loggato in un portale, oppure una query che estrae l’indirizzo di tutti i negozi presenti in una città e così via.

Durante la fase di ricerca delle varie pagine appartenenti al dominio https://www.fastweb.it/ è stato individuato un portale interno ovvero non riservato al pubblico:

Portale

Solitamente, in questi casi o si inseriscono credenziali di default (come ad esempio admin:admin o test:test o amministratore:amministratore e così via) oppure caratteri di escape (per semplicità verranno chiamati speciali) per verificare le presenza di una SQL injection. Inserendo così le 100 combinazioni di credenziali di default più comuni, il portale non restituisce alcun risultato, inserendo invece caratteri speciali, genera un errore del database:

Errore

Abbiamo una SQL injection: i dati immessi dall’utente (nel campo username) vengono inseriti “direttamente” in una query SQL e poi eseguiti; per “direttamente” si intende che alcuni caratteri speciali (che hanno un significato ben preciso nel linguaggio SQL) non vengono filtrati prima di essere inseriti in una query. Per dimostrare la vulnerabilità è stato inserito un carattere che indica la fine di una query: il database genera un errore relativo alla sintassi del costrutto non corretta.

Per confermare la vulnerabilità è stato impiegato sqlmap configurato in modo tale da non estrarre informazioni confidenziali dal server:

SQLMap

Un malintenzionato potrebbe sfruttare questa vulnerabilità in diversi modi:

Implementazione errata dei token di accesso JWT permette l’accesso a qualsiasi account conoscendo l’username

Il JSON WEB TOKEN (JWT) è uno standard definito in formato JSON che consente di scambiare informazioni fra diversi servizi o parti.

Quando viene eseguito un login, tradizionalmente, viene creata una sessione fra il server e il client, all’interno della quale viene memorizzato l’identificatore dell’utente; questa operazione ha come obiettivo principale quello di recuperare le informazioni di autenticazione nelle successive chiamate.

In circostanze simili cosa accadrebbe se utilizzassimo più server per bilanciare il carico del sito in questione? Se creassimo la sessione sul server A e successivamente il bilanciatore di risorse ci portasse sul server B, la sessione creata sul server A verrebbe persa (anche se si potrebbero creare altri meccanismi per condividere le sessioni).

Oggi i JWT sono utilizzati principalmente per autenticare le richieste nelle applicazioni web/mobile, in particolare quando queste si allacciano ad API, dove il client (l’utente) invia una richiesta di autenticazione al server, il quale genera un token firmato e lo restituisce al client che, da quel momento in poi, lo utilizzerà per autenticare le successive richieste.

Questo token è formato da 3 parti principali separate tutte da un punto . e che sono:

Poichè il token contiene tutte le informazioni necessarie all’autenticazione (username o identificatore dell’utente), il server potrà evitare di passare ogni volta dal database per verificare a quale utente corrisponda quel token (ottimo per la scalabilità).

Senza bilanciamento del carico Senza bilanciamento del carico

Con bilanciamento del carico Con bilanciamento del carico

Ora verrà analizzata una versione semplificata della vulnerabilità per arrivare a quella presente su Fastweb.

Prendiamo come esempio il login effettuato da due utenti diversi, utente A e utente B, soffermandoci sui token generati:

Login effettuato dall’utente A -> Token utilizzato: xxxxx.yyutenteayy.zzzzz Login effettuato dall’utente A -> Token utilizzato:
xxxxx.yyutenteayy.zzzzz

Login effettuato dall’utente B -> Token utilizzato: xxxxx.yyutentebyy.ppppp Login effettuato dall’utente B -> Token utilizzato:
xxxxx.yyutentebyy.ppppp

L’utente A vuole accedere all’account dell’utente B per rubare i suoi dati, quindi l’utente A decodifica il payload del suo token e manomette i valori cambiando l’username dell’utente loggato da “yyutenteayy” a “yyutentebyy”; tuttavia questo non porterà a nessun risultato poichè l’utente A non conosce la firma dell’utente B:

L’utente A non può entrare nell’account dell’utente B cambiando semplicemente l’username -> Token utilizzato: xxxxx.yyutentebyy.zzzzz L’utente A non può entrare nell’account dell’utente B cambiando semplicemente l’username -> Token utilizzato:
xxxxx.yyutentebyy.zzzzz

L’utente A sa che l’unico ostacolo è il controllo sulla firma e quindi potrebbe o tentare di effettuare un bruteforce della firma, ma impiegherebbe anni; oppure potrebbe trovare una falla nell’implementazione dei token di accesso JWT in modo tale che la firma non venga presa in considerazione dal server.

L’utente A ipotizza che il server non faccia nessun controllo sull’header: ciò significa che il server accetta tutti quei token che hanno nell’header un algoritmo di criptazione configurato a null/none.

L’utente A cambia l’header da “xxxxx” (dove l’algoritmo di criptazione era impostato fra HS256, RS256 e ES512) a “rrrrr” (dove l’algoritmo di criptazione è impostato a null/none): in questo caso il server non effettua nessun controllo sull’header, che a sua volta impone al server di non controllare la firma; quindi tutti i tipi di token vengono accettati, siano essi con la firma o senza.

Login effettuato con l’algoritmo di criptazione impostato a none -> Token: rrrrr.yyutenteayy.zzzzz Login effettuato con l’algoritmo di criptazione impostato a none -> Token:
rrrrr.yyutenteayy.zzzzz

Login effettuato con l’algoritmo di criptazione impostato a none -> Token: rrrrr.yyutenteayy. Login effettuato con l’algoritmo di criptazione impostato a none -> Token:
rrrrr.yyutenteayy.

L’utente A cambia il payload da “yyutenteayy” a “”yyutentebyy”, invia la richiesta al server A e l’utente A riesce ad accedere ai dati dell’utente B:

Login effettuato con l’algoritmo di criptazione impostato a none -> Token: rrrrr.yyutenteayy. Login effettuato con l’algoritmo di criptazione impostato a none -> Token:
rrrrr.yyutenteayy.

Ora applichiamo il tutto a Fastweb. L’accesso diretto può essere effettuato in due modi diversi: attraverso il sito web (dove i token JWT non vengono utilizzati) oppure attraverso l’applicazione mobile MyFastweb (Versione 3.2.8 del 18 Aprile 2019) che vede l’implementazione dei token JWT.

Avviando l’applicazione e iniziando a intercettare le richieste (cioè la comunicazione che avviene fra l’applicazione e i server della Fastweb), in maniera predefinita, viene effettuato l’accesso diretto con una serie di operazioni:

Oltre al token JWT viene inviato anche l’username dell’account legato all’abbonamento Oltre al token JWT viene inviato anche l’username dell’account legato all’abbonamento

Il server restituisce l’OK e il parametro favBillingAccount Il server restituisce l’OK e il parametro favBillingAccount

Quando al server viene inviato un token non valido, cioè quando la firma non coincide con il payload, viene generato un messaggio di errore:

Token Errato

Utilizzerò, per dimostrare la vulnerabilità, il mio token JWT (ovviamente ho cambiato le mie informazioni personali con delle stringhe casuali, motivi di privacy):

eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9.eyJmdy5zc28uY2xhaW1zLmNsaWVudC5 pcGFkZHJlc3MiOiIxMTEuMTExLjEuMTExIiwiZncuc3NvLmNsYWltcy5jbGllbnQubG9jYXRpb24iOiJob21lIiw iaXNzIjoibG9nb24uZmFzdHdlYi5pdCIsIm9yYWNsZS5vaWMudG9rZW4udHlwZSI6IlVTRVJUT0tFTiIsImZ3LnN zby5jbGFpbXMudXNlci5ndWlkIjoic3VhaWFkaWpzZGlqYXNpamFzZCIsImlhdCI6OTk5OTk5OTk5OTk5OTk5OSw ib3JhY2xlLm9hdXRoLnBybi5pZF90eXBlIjoiTERBUF9VSUQiLCJvcmFjbGUub2F1dGgudGtfY29udGV4dCI6InV zZXJfYXNzZXJ0aW9uIiwiZXhwIjo5OTk5OTk5OTk5OTk5OTk5LCJhdWQiOiJsb2dvbi5mYXN0d2ViLml0IiwicHJ uIjoidXRlbnRlQSIsImp0aSI6Inh4eHh4LXl5eXl5eXl5LXp6enp6enp6enp6enotYWFhYWFhYWFhYWEiLCJmdy5 zc28uY2xhaW1zLnNlc3Npb24uYXV0aG5sZXZlbCI6IjEiLCJmdy5zc28uY2xhaW1zLnNlc3Npb24uc2NvcGUiOiJ mdWxsIiwib3JhY2xlLm9pYy50b2tlbi51c2VyX2RuIjoiY249MTExMTExMTExLG91PVJFUyxjbj1Vc2VycyxvdT1 GV0NTVCxkYz1mYXN0d2ViLGRjPWxvY2FsIn0=.VQPVFiEACnVzZXJfimoH_EVFiBojDUJDQIPwa9XJfYXNc0pdua HSTRC-CdSh_dsypZXNz a9oIPEVFi g2h8dndnVzZXs0G_EypZa9oIcaW9uFiPEcANs0soa-ba9oICBFen LmF1dGhuNbY7YYfLUXN

Come detto prima, l’header, il payload e la signature sono separati da un punto, quindi dividendo il token in tre parti si ottiene:

eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9 -> Header

eyJmdy5zc28uY2xhaW1zLmNsaWVudC5pcGFkZHJlc3MiOiIxMTEuMTExLjEuMTExIiwiZncuc3NvLmNsYWltcy5j bGllbnQubG9jYXRpb24iOiJob21lIiwiaXNzIjoibG9nb24uZmFzdHdlYi5pdCIsIm9yYWNsZS5vaWMudG9rZW4u dHlwZSI6IlVTRVJUT0tFTiIsImZ3LnNzby5jbGFpbXMudXNlci5ndWlkIjoic3VhaWFkaWpzZGlqYXNpamFzZCIs ImlhdCI6OTk5OTk5OTk5OTk5OTk5OSwib3JhY2xlLm9hdXRoLnBybi5pZF90eXBlIjoiTERBUF9VSUQiLCJvcmFj bGUub2F1dGgudGtfY29udGV4dCI6InVzZXJfYXNzZXJ0aW9uIiwiZXhwIjo5OTk5OTk5OTk5OTk5OTk5LCJhdWQi OiJsb2dvbi5mYXN0d2ViLml0IiwicHJuIjoidXRlbnRlQSIsImp0aSI6Inh4eHh4LXl5eXl5eXl5LXp6enp6enp6 enp6enotYWFhYWFhYWFhYWEiLCJmdy5zc28uY2xhaW1zLnNlc3Npb24uYXV0aG5sZXZlbCI6IjEiLCJmdy5zc28u Y2xhaW1zLnNlc3Npb24uc2NvcGUiOiJmdWxsIiwib3JhY2xlLm9pYy50b2tlbi51c2VyX2RuIjoiY249MTExMTEx MTExLG91PVJFUyxjbj1Vc2VycyxvdT1GV0NTVCxkYz1mYXN0d2ViLGRjPWxvY2FsIn0= -> Payload

VQPVFiEACnVzZXJfimoH_EVFiBojDUJDQIPwa9XJfYXNc0pduaHSTRC-CdSh_dsypZXNz a9oIPEVFi g2h8dndnVzZXs0G_EypZa9oIcaW9uFiPEcANs0soa-ba9oICBFen LmF1dGhuNbY7YYfLUXN -> Signature o firma

Decodificando da base64 l’header e il payload (la signature non può essere decodificata in quanto abbiamo bisogno della “password segreta”), otteniamo:

{“alg”:”RS512″,”typ”:”JWT”,”kid”:”orakey”} -> Header (da notare che qui viene utilizzato l’algoritmo di criptazione RS512, non null/none)

{“fw.sso.claims.client.ipaddress”:”111.111.1.111″,”fw.sso.claims.client.location”:”home” ,”iss”:”logon.fastweb.it”,”oracle.oic.token.type”:”USERTOKEN”,”fw.sso.claims.user.guid”: “suaiadijsdijasijasd”,”iat”:9999999999999999,”oracle.oauth.prn.id_type”:”LDAP_UID”,”orac le.oauth.tk_context”:”user_assertion”,”exp”:9999999999999999,”aud”:”logon.fastweb.it”,”p rn”:”utenteA”,”jti”:”xxxxx-yyyyyyyy-zzzzzzzzzzzzz- aaaaaaaaaaa”,”fw.sso.claims.session.authnlevel”:”1″,”fw.sso.claims.session.scope”:”full” ,”oracle.oic.token.user_dn”:”cn=111111111,ou=RES,cn=Users,ou=FWCST,dc=fastweb,dc=local”} -> Payload, modificato in modo tale da non esporre i miei dati personali. Il parametro su cui si basa l’individuazione dell’utente è prn.

Per poter sfruttare questa vulnerabilità occorre:

Per svolgere le operazioni di decodifica, modifica e codifica in maniera automatica ho creato uno script in Python:

Esecuzione dello script:

Script BASE64

Viene generato un nuovo token con l’username impostato a “admin” (che è inesistente, dato che gli username di Fastweb seguono uno schema determinato: nome.cognome.xxxx, dove xxxx parte da 0000 e arriva fino a 9999; la parte numerica viene usata per distinguere gli omonimi), questo è il risultato ottenuto:

Ricerca dell'utente nel database

Il sistema cerca il nostro username nel database. Ho utilizzato un account inesistente in quanto accedere ai dati di un altro utente è illegale. Consegno quello che ho trovato al security team, il giorno dopo arriva una mail dove la vulnerabilità è confermata ed è in attesa di un fix.

Ecco la comunicazione di Fastweb che avvisa la chiusura dell’accesso diretto (l’url della pagina è https://fastweb.it/myfastweb/comunicazioni/chiusura-accesso-diretto/?from=sms):

Comunicazione sito web

Ecco l’sms che è stato inviato, nel mese di Settembre del 2019, ai numeri di cellulare ai quali è intestato l’abbonamento Fastweb:

Comunicazione SMS

Alla prossima.