Decifrare il file con i messaggi della nuova versione di WhatsApp

Nota: questo articolo non è più aggiornato e non è più possibile decifrare i messaggi seguendo queste indicazioni

Volete accedere a tutti i messaggi WhatsApp salvati sul vostro telefono o tablet Android ma non sapete come fare?
Vi occorrono:

  • Un telefono/tablet/phablet/qualsiasicosa Android con WhatsApp, nelle versioni da 2.11.152 a 2.11.186
  • L’indirizzo di posta elettronica con il quale avete attivato il telefono android
  • Python (ActivePython se usate Windows)
  • Il modulo python aggiuntivo: M2Crypto (con ActivePython è sufficiente dare pypm install m2crypto)
  • se usate Ubuntu potete installare direttamente il pacchetto python-m2crypto
  • Un programma che legga i database in formato SQLite 3
  • Il programma pwncrypt5 che trovate su GitHub lo metto anche qui sotto, si sa mai..

Prima di dirvi quali sono i passaggi per decifrare il file, vediamo di capire più in dettaglio come
funziona la cifratura del database con le conversazioni di WhatsApp:

Per decifrare il contenuto delle conversazioni servono tre informazioni
fondamentali:
La chiave o password, che, sorpresa, è uguale per tutti gli utenti WhatsApp del mondo!
Il vettore d’inizializzazione, anche questo è uguale e non dovrebbe affatto esserlo
Il vostro indirizzo email di android
Come si è riusciti ad ottenere ognuna di queste informazioni?
La chiave
WhatsApp Statistics
è un’aplicazione che vi mostra una serie di statistiche sulle vostre
conversazioni passate. Per poter funzionare ha bisogno di leggere l’archivio
con le vostre conversazioni. E per riuscirci l’autore di questa app era a
conoscenza della chiave universale. Sia pure per uno scopo lecito.
Estrapolare la chiave in questione e il famoso vettore di inizializzazione dal whatsapp statistics non dev’essere stato
semplice, ma due hacker spagnoli sono riusciti e nell’impresa e lo hanno scritto sul loro
blog
Qui potete vedere l’immagine il codice disassemblato di whatsapp statistics
e con annotati di fianco i byte esadecimali che contengono LA chiave.

Chiave che corrisponde a quella contenuta nel sorgente del programma pwncrypt5. E’ possibile
verificarlo in maniera molto rapida usando python e convertendo il contenuto
della variabile key in una stringa di caratteri esadecimali.

>>> ''.join('%x' % byte for byte in [141, 75, 21, 92, 201, 255, 129, 229, 203, 246, 250, 120, 25, 54, 106, 62, 198, 33, 166, 86, 65, 108, 215, 147]) '8d4b155cc9ff81e5cbf6fa7819366a3ec621a656416cd793'

 

Come vedete la chiave è esattamente la stessa visibile in verticale nell’immagine, all’interno del riquadro centrale. E’ scritta in verde: 8Dh; 4Bh; .. e così via,
la h finale indica che si tratta di cifre esadecimali.
Mi soffermo un momento su questo punto, perché mi sembra sia questo il nocciolo
fondamentale dalla questione:
il fatto che sia possibile decifrare il file utilizzando una chiave identica per tutte le installazioni su tutti i telefoni,
sia pure in aggiunta all’account utente, dimostra che contrariamente a quello che dichiara, WhatsApp NON ha a cuore la vostra privacy!
Se davvero fosse il caso, la chiave per decifrare il file verrebbe generata in maniera
casuale ad ogni installazione del programma e idealmente una parte di essa sarebbe legata sia all’hardware del dispositivo sul quale
gira l’app che ad una qualche informazione conosciuta solo dall’utente, come ad esempio un PIN, in modo che non sia
possibile in alcun modo decifrare il file senza conoscere due ulteriori informazioni che non possono essere ottenute in
maniera automatizzata.
Naturalmente questo renderebbe più difficoltoso spostare le vecchie
conversazioni da un dispositivo all’altro, ad esempio quando si cambia
telefono, perché sarebbe prima necessario esportarle dal vecchio e reimportarle sul nuovo
telefono. Ma si tratta di un piccolo fastidio in confronto
alla concreta possibilità di essere derubati delle proprie conversazioni
private da parte di perfetti sconosciuti.
Nel caso di WhatsApp, ad oggi, è invece concretamente possibile rubare
l’archivio di tutte le vostre conversazioni private, sotto i vostri occhi
e senza che voi ve ne rendiate conto! Questo perché la chiave per decifrare
tale archivio è unica per tutti gli utenti, sia pure in aggiunta all’indirizzo
email con il quale avete attivato al telefono, un’informazione che però è alla
portata di chiunque sappia scrivere un’applicazione android o trovi il modo di
venirne a conoscenza.
Il vettore d’inizializzazione
o Initialization Vector abbreviato IV sembra una parolona ma in realtà è
solo una sequenza di byte casuali, con una lunghezza prestabilita, che servirebbe a rendere più robusta la cifratura.
Se solo fosse usato nel modo giusto.. come abbiamo visto, invece, anche questa
“seconda chiave” è sempre uguale e si trovava all’interno di WhatsApp
statistics. Se volete saperne di più vi rimando a Wikipedia
Il vostro account su Android
Ottenere l’indirizzo email con il quale avete attivato Android è semplicissimo,
basta che un’altra applicazione sul vostro telefono abbia richiesto il permesso chiamato GET_ACCOUNTS
quando l’avete installata. Ma.. Sono certo che fate sempre caso a quanti e quali permessi chiede ogni
applicazione che installate sul telefono, vero? Vero???
Quali sono i passaggi fatti dal programma per decriptare il file?
A questo punto devo scendere un pò più sul tecnico..
Per prima cosa legge il contenuto del file msgstore.db.crypt5
Poi fa un hash dell’indirizzo email con cui avete attivato android sul
telefono, usando l’algoritmo MD5
Dopodiché inizia il vero processo di decifratura:
La chiave è lunga 192 bit e l’algoritmo di cifratura utilizzato è AES.
192 bit corrispondono a 24 byte e per ogni byte della chiave il programma,
tramite il ciclo for i in xrange(24) farà un’operazione booleana di disgiunzione eslusiva meglio nota come XOR, tra il byte della chiave e l’hash del vostro account android. Di fatto
fondendo queste due informazioni nella chiave vera e propria.
Questo per ovviare al vano tentativo, da parte degli sviluppatori di WhatsApp, di evitare
che con una singola chiave si potessero decifrare tutte le conversazioni di
ogni telefono del pianeta. Purtroppo è un goffo tentativo, perché vi ho appena
spiegato quanto sia banale per un’altra applicazione sapere qual’è il vostro
account Android. Anche realizzare un’app fasulla che finga di fare
qualcos’altro mentre invece carica le vostre conversazioni da qualche parte su
internet è talmente semplice che il blogger olandese Bas Bosschert lo ha
fatto notare pubblicamente creando
un vero e proprio esempio pratico sul suo blog. Ma andiamo avanti..
Una volta fatto lo XOR tra la chiave e l’hash dell’indirizzo email e inserito il vettore di inizializzazione, tutti i pezzi
necessari per decifrare il file con l’algoritmo AES, che è uno standard mondiale ed è pubblico, sono al loro posto e
il file può essere comodamente decifrato. Per farlo, il programma si avvale delle funzioni del modulo M2Crypto.
Voilà, il file cifrato è ora diventato un normale database SQLite 3
Riassumendo I passaggi da fare sono:

 

Collegate il vostro telefono android al PC
Accedete tramite il vostro PC alla cartella WhatsApp del telefono
Copiate il file che si chiama msgstore.db.crypt5 in una cartella sul vostro computer
Lanciate questo comando:
python pwncrypt5.py msgstore.db.crypt5 QUI_METTETE_IL_VOSTRO_ACCOUNT_GOOGLE(es:blablabla@gmail.com) > msgstore.db
Aprite il file msgstore.db con un programma che legga i database SQLite3

Per comodità potete anche convertire il file in un simpatico foglio Excel
Qui c’è il codice sorgente del programma

#!/usr/bin/python
"""
48bits presents:
8===============================================D~~~
WhatsApp msgstore crypt5 decryptor by grbnz0 and nullsub
8===============================================D~~~

"""

import sys
import hashlib
import StringIO
from M2Crypto import EVP

key = bytearray([141, 75, 21, 92, 201, 255, 129, 229, 203, 246, 250, 120, 25, 54, 106, 62, 198, 33, 166, 86, 65, 108, 215, 147])
iv = bytearray([0x1E,0x39,0xF3,0x69,0xE9,0xD,0xB3,0x3A,0xA7,0x3B,0x44,0x2B,0xBB,0xB6,0xB0,0xB9])

def decrypt(db,acc):
   fh = file(db,'rb')
   edb = fh.read()
   fh.close()
   m = hashlib.md5()
   m.update(acc)
   md5 = bytearray(m.digest())
   for i in xrange(24):
      key[i] ^= md5[i&0xF]
      cipher = EVP.Cipher('aes_192_cbc', key=key, iv=iv, op=0)
      sys.stdout.write(cipher.update(edb))
   sys.stdout.write(cipher.final())

if __name__ == '__main__':
   if len(sys.argv) != 3:
      print 'usage %s > decrypted.db' % sys.argv[0]
   else:
      decrypt(sys.argv[1],sys.argv[2])