This page looks best with JavaScript enabled

Forense automatizado a un whatsapp

 ·   ·   6 min read

Buenas a todos, ya hace un tiempo que no escribo algún que otro articulo y hoy aburrido hablando con unos amigos por whatsapp me quedo la duda de si whatsapp guardaba los logs de todo lo que hicíera y efectivamente whatsapp lo hacia.

Viendo la de cositas que se estaban guardando :
      - Conversaciones de tlfn a tlfn
      - Chats activos
      - Fotos de los perfiles que mire
      - Imágenes, audios, videos que me pasarón o que pase

      (Por ejemplo).

Pues me apetecio hacerle un forense y al tiempo que lo hago os haré una demo del forense a un whatsapp y vereís todos los datos que podemos sacar de utilidad.

Recrearemos un entorno en el que dispongo de acceso físico a un terminal.
El whatsapp es una buena forma de extraer información sobre el día día de la persona, se podría aplicar algo como “Dime con quien andas y te diré quien eres” pero convertido al método geek.

Empezamos con la DEMO :

Bueno, los ficheros de whatsapp se guardan por defecto en /storage/sdcard0/WhatsApp/ , y yo me enviaré los ficheros con Airdroid, una estupenda app para compartir archivos PC - Smartphone vía wifi.

Para pasar a estar conectados en “Modo de conexión remota” como ahí podeís ver solo hay que acceder a web.android.com y te logueas con tu cuenta.

Y tan solo te queda acceder al directorio y descargar los arhivos de los que extraeremos los metadatos.

Una vez descargados los ficheros voy a proceder a comentaros que podemos encontrar en cada uno de los directorios y cómo podríamos extraerles el jugo.

Tenemos “Databases”, “Media” y “Profile Pictures”, he hecho un script para que extraiga los metadatos de los db.crypt, tambien extrae los ficheros de la carpeta media(imágenes, audios, videos) y tambien extrae las imágenes encontradas en Profile Pictures.

Databases : Aqui podremos encontrarnos una serie de ficheros con extensión “db.crypt”, Whatsapp cifra los archivos SQLite con AES pero siempre usa la misma key “346a23652a46392b4d73257c67317e352e3372482177652c” y de este modo podré decodificarlos.

Media : Aqui nos encontramos con una seríe de archivos (imágenes, audios, videos y wallpapers).

Profile Pictures : Aqui nos encontraremos con todas las imágenes de perfil(de usuario) que hemos mirado desde nuestro whatsapp.
NOTA IMPORTANTE : Para extraer la información de todos estos archivos que hemos obtenido he codeado un script que automatiza todo el proceso (a excepción del proceso de obtención de los ficheros , puesto que se supone que tenemos acceso físico al terminal.)_











Ahora os mostraré un esquema en forma de arbol para comprender un poco como funciona el script que he preparado:
· WhatsApp Metadata Extractor :
_       - main_manage.py (main de consola en forma de cliente)_
_       - DB_Extractor.py (extrae los metadatos de la BD)_
_       - metaimg_extractor.py (extrae los metadatos de los .jpg encontrados)_

He dividido el proyecto en 3 scripts, main_manage es el encargado de interactuar con el cliente (el que debemos ejecutar), DB_Extractor es el encargado de realizar las consultas con la BD para extraer toda la información(la que nos interesa) y metaimg_extractor es el encargado de buscar en “Media” y en “Profile Pictures” en busca de metadatos en los archivos .jpg (La mayoria vienen con ellos eliminados por defecto pero no me digas por qué algunas imágenes no se filtran y son subidas sin filtrarse).

Sin más os dejo los codes :

main_manage.py :

\# -\*- coding: utf-8 \*-\*  
import DB\_Extractor, metaimg\_extractor  
  
class WhatsApp\_Extractor():  
  
    def \_\_init\_\_(self):  
        self.\_\_opt()  
  
    def \_\_opt(self):  
        #Uncomment the OPTION that you want to use  
  
        #self.\_\_opt1()  #-> DB METADATA EXTRACTOR  
        #self.\_\_opt2()  #-> IMG METADATA EXTRACTOR  
        #self.\_\_opt3()  #-> BOTH, OPT1 AND OPT2  
  
    def \_\_opt1(self):  
        print "DB METADATA"  
        print "------------"  
        DB\_Extractor.DB\_Extractor()  
        print "------------"  
  
    def \_\_opt2(self):  
        print "IMG META"  
        print "------------"  
        metaimg\_extractor.IMG\_Meta()  
        print "------------"  
  
    def \_\_opt3(self):  
        print "DB METADATA"  
        print "------------"  
        DB\_Extractor.DB\_Extractor()  
        print "------------"  
        print "\\nIMG META"  
        print "------------"  
        metaimg\_extractor.IMG\_Meta()  
        print "------------"  
  
WhatsApp\_Extractor()  

DB_Extractor.py :

\# -\*- coding: utf-8 \*-\*  
#Script to extract the metadata from the WhatsApp crypted DB  
  
import sqlite3  
from Crypto.Cipher import AES  
  
class DB\_Extractor():  
  
    def \_\_init\_\_(self):  
        self.\_manage\_do()  
  
    def \_manage\_do(self):  
        try:  
            self.\_\_DB\_Breaker('msgstore.db.crypt')  
            self.\_\_DB\_conn()  
            self.\_\_SQL\_Consulter()  
            #Log exporter  
        except:  
            print "Error starting the script"  
  
    def \_\_DB\_Breaker(self, DBPath):  
        self.DBPath = DBPath  
        #breaking the hash  
        f = open(self.DBPath, 'rb')  
        key = "346a23652a46392b4d73257c67317e352e3372482177652c"  
        #triying to break the hash  
        try:  
            key = key.decode('hex')  
            cipher = AES.new(key, 1)  
            decoded = cipher.decrypt(f.read())  
            #Saving into a new db file  
            try:  
                decoded\_DB = open('metadb.db', 'wb')  
                decoded\_DB.write(decoded)  
                decoded\_DB.close()  
                print "metadb.db has been created in the same directory"  
            except:  
                print "An error has ocurred creating the decoded DB"  
        except:  
            print "Error decoding the hash"  
  
  
    def \_\_DB\_conn(self):  
        #triying to connect with the sqlite database  
        try:  
            self.conn = sqlite3.connect('metadb.db')  
            self.consult = self.conn.cursor()  
        except:  
            print "An error has ocurred connecting with the SQLite DB"  
  
  
    def \_\_SQL\_Consulter(self):  
        #Divided in :  
            # Messages  
            # Chat\_list  
  
        def \_\_Messages():  
            #SQLConsult  
            try:  
                self.consult.execute("SELECT key\_remote\_jid, key\_from\_me, \\  
                remote\_resource, status, datetime(timestamp), data, media\_url, media\_mime\_type, \\  
                media\_size, latitude, longitude FROM messages;")  
  
            except:  
                print "An error has ocurred doing the SQL Consult"  
  
            def \_\_Shower():  
                #Message details  
                #nota : parsear status, comprobar si yo envio o recivo  
  
                for data in self.consult:  
                    try:  
                        print "\\nMessages Details:"  
                        print "----------------------"  
  
                        if str(data\[2\]):  
                            if str(data\[1\]) == '1':  
                                print "From: me"  
                                print "To: %s(group), integrant: %s"%(str(data\[0\]), str(data\[2\]))  
                            else:  
                                print "From: %s(group), integrant: %s"%(str(data\[0\]), str(data\[2\]))  
                                print "To: me"  
                        else:  
                            if str(data\[1\]) == '1':  
                                print "From: me"  
                                print "To: " + str(data\[0\])  
                            else:  
                                print "From: " + str(data\[0\])  
                                print "To: me"  
  
                        print "Status: " + str(data\[3\])  
                        print "Timestamp: " + str(data\[4\])  
                        print "Message: " + str(data\[5\])  
                        print "Media content: %s, type: %s, size: %s"%(str(data\[6\]), str(data\[7\]), str(data\[8\]))  
                        print "Location(Lat: %s, Long: %s)"%(str(data\[9\]), str(data\[10\]))  
                        print "----------------------"  
  
                    except:  
                        continue  
                        print "ERROR showing message details"  
  
            \_\_Shower()  
  
  
        def \_\_Chat\_list():  
            #SQLConsult  
            try:  
                self.consult.execute("SELECT id, \\  
                key\_remote\_jid FROM chat\_list;")  
  
            except:  
                print "An error has ocurred doing the SQL Consult"  
  
            def \_\_Shower():  
                #Chat list details  
                for data in self.consult:  
                    try:  
                        print "\\nChat\_list"  
                        print "ID: " + str(data\[0\])  
                        print "Number: " + str(data\[1\])  
                        print "----------------------"  
                    except:  
                        continue  
                        print "ERROR showing chat list details"  
  
            \_\_Shower()  
  
        #Initializing  
        \_\_Messages()  
        \_\_Chat\_list()  
  

metaimg_extractor.py :

\# -\*- coding: utf-8 \*-\*  
import os, exif  
  
class IMG\_Meta():  
  
    def \_\_init\_\_(self):  
        try:  
            self.\_\_Media\_extractor()  
            print "------------------------------------------------------\\n"  
            self.\_\_Profile\_extractor()  
        except:  
            print "An error has ocurred starting the script"  
    def \_\_Media\_extractor(self):  
        try:  
            images = os.listdir('Media/WhatsApp Images/')  
        except:  
            print "An error has ocurred listing the files into the directory"  
  
        def \_\_Shower():  
            for i in images:  
                print "-------------"  
                print i  
                obj = exif.extract\_EXIF('Media/WhatsApp Images/%s' % i)  
                print "-------------"  
  
        \_\_Shower()  
  
    def \_\_Profile\_extractor(self):  
        try:  
            images = os.listdir('Profile Pictures/')  
        except:  
            print "An error has ocurred listing the files into the directory"  
  
        def \_\_Shower():  
            for i in images:  
                print "-------------"  
                print i  
                obj = exif.extract\_EXIF('Profile Pictures/%s' % i)  
                print "-------------"  
  
        \_\_Shower()  
  

Unas imágenes trabajando :

DB_Extractor :

IMG extractor :

El archivo “Exif” que importamos en el metaimg_extractor podemos encontrarlo en el proyecto de grampus en bitbucket

PD : El Forense podría llegar a hacerse en mayor profundidad, en este caso solo tratamos los datos que podrían ser más relevantes como conversaciones, envio de archivos y el análisis de los metadatos de las imágenes.

En fin, esto es todo, el script os automatizará todo el trabajo “duro”

Saludos !! , Sanko.

Share on
Support the author with

Avatar
WRITTEN BY