Mostrando entradas con la etiqueta DFIR. Mostrar todas las entradas
Mostrando entradas con la etiqueta DFIR. Mostrar todas las entradas

En este artículo abordaré la recuperación de mensajes borrado en la aplicación WhatsApp, como ya comente en la parte I y II, la capacidad de recuperación de mensajes eliminados es inversamente proporcional al periodo de tiempo transcurrido desde que se produjo el hecho, así como a la intensidad de uso de la aplicación en dicho periodo. 

Es decir, cuanto mayor sea la intensidad y el tiempo transcurrido menor es la probabilidad de recuperar la información.


Recuperando mensajes eliminados de WhatsApp - Recovery Data

Si recordamos en la segunda parte, el timestamp de un mensaje consta de 6 bytes y se encuentra justo a continuación de los datos, tal y como se puede ver en la siguiente imagen:


ST2Labs 13 - Cell Data to Offset 11358
Pero antes de ponernos manos a la obra y decodificar el timestamp, se puede analizar la base de datos en busca de información eliminada, para ello, se deben de examinar el espacio sin utilizar (unallocated), los freeblock o incluso los freelist.

En las base de datos SQLite, existe la posibilidad de indicar que un registro (cell record) ha sido eliminado marcando el mismo como "freeblock" dentro de una página, además si se elimina una página entera, se puede marcar como Freelist. 

La información residual que queda en una base de datos cuando no se sigue el estándar, es aquella que es eliminada desde la aplicación (chat) y simplemente se elimina su "indexación" en la base de datos, es decir, en aquel espacio que no esta asignado a ninguna función  es denominado unallocated, y puede contener información que previamente ha sido eliminada, y que por tanto, no se encuentra indexada en la base de datos.

Por tanto resumiendo, la información eliminada puede estar ubicada en:

 - unallocated space
 - freeblock
 - freelist

Además, si la base de datos es configurada con "rollback", puede existir archivos WAL (Write-Ahead Log) o Journal, que permite guardar una copia de seguridad de una página mientras esta se esta modificando y no ha recibido un "commit". 

Si existe el fichero db-wal o db-journal, es muy recomendable realizar un análisis forense de dichos archivos, en busca de información relevante. Si existen esto archivos, no se recomienda abrir la base de datos con un visor de SQLite, ya que puede ejecutar un "commit" pendiente y borrar por completo toda la información que pudiera contener.

En nuestro caso, no disponemos de archivo db-wal, por lo que procedemos a analizar la información contenida en el archivo y que no esta consideraba como "válida", es decir, analizaremos todos los freeblock, unallocated y freelist que existan.

Realizar esta tarea de forma manual es bastante tediosa, ya que para cada página se debe de extraer la información que existe entre la ultima "celda - registro" y el final de Cell Pointer Array (como recordáis del artículo anterior".

Pero además, puede exisitr espacio "unallocated" entre celdas, y /o freeblock (son aquellas celdas que han sido marcadas como disponibles) al realizar la acción de eliminar mensajes.

Vamos con un ejemplo:

Abrimos la base de datos con un editor hexadecimal y analizamos el contenido de toda la página 3, ya que consideramos que es la más indicada al ser la que contiene la información de "mensajes". Si se ha eliminado algún mensaje debe de ser de esta página.

Datos de interés para la página 3, según la información analizada en el articulo 2:

 - Offset page 3: 8192
 - Ultima celda (registro) Offset: 11358
 - Offset cell pointer: 8200
 - Size Cell Pointer: 8 bytes

Por tanto, el espacio "unallocated" entre la utlima celda (registro) y el final de Cell Pointer Array se puede calcular tal que así:

Ini unallocated Offset = 8208
Size = 11358 - 8208 =  3150 bytes

Con ayuda de un editor hexadecimal, se obtiene:

ST2Labs 14 - Unallocated database pace for page 3
Se puede observar que existen varios mensajes como información residual en la página 3 de la base de datos, el key_id (identificador único de cada mensaje) esta compuesto por un "hash" y un número de secuencia, además con el timestamp de los mensajes se puede realizar el timeline correspondiente.

Por ejemplo, se procede a analizar la información para el mensaje:

ST2Labs 15 - Recovery Delete Message - Whatsapp

No existe una forma normalizada de finalizar un mensaje, para calcular el tamaño exacto del mensaje, se debe de decodificar el cell header y el payloda header, sin embargo, para los datos que han sido eliminado (no están indexados) no se conoce el offset de los registro eliminados, por lo que no se puede a priori determinar el inicio de la celda, salvo mediante técnica de prueba y error. 


Por ello, obtener el timetamp, es coger los 6 bytes seguido al final del mensaje, para el caso de ejemplo, acaba sin ".", en otros casos puede que haya que probar más de una vez, por si el carácter "." forma parte del mensaje de texto o no.
En nuestro caso de ejemplo:

Timestamp: 01513407d3f8

Utilizando DFTime, la herramienta para convertir el timestamp a Fecha y Hora, se obtiene:

ST2Labs 16 - DFTime - Timestamp converter tools

Sin embargo, para asegurarse que no existe ningún otro mensaje eliminado disperso por la base de datos, se debe de analizar los freeblock dentro de la página 3.

La información, si existen freeblock o no, se encuentra dentro de la cabecera de cada una de las páginas, con ayuda de la herramienta DFSLite, se puede consultar todas y cada una de las cabeceras de las páginas de la base de datos, con el comando -B.

ST2Labs 17 - Page header - freeblock 
Se analiza la información, y para la página 3 se detecta que existen 2 freeblock, donde el offset del primer freeblock es 3514 relativo a al offset de la página. 

Se utiliza DFSLite, con la opción -u para obtener la información contenida dentro de los freeblock, y unallocated, tal que:

ST2Labs 18 - All messages recovery
Se ha utilizado strings para visualizar mejor los mensajes, pues la herramienta muestra la información en bruto (raw data). No obstante, para determinar el timestamp de los mensajes y montar un "timeline", se debe de abrir el archivo en hexadecimal y analizar de forma manual, tal y como se ha visto en este artículo.

Para descubrir todos los mensajes se deberá de analizar todas las páginas de la base de datos, por tanto cuanto mayor sea la base de datos, mas elaborado y mayor será el tiempo que se tardará en obtener los resultados.

Espero que haya sido de utilidad, a continuación os dejo el enlace al repositorio donde voy subiendo las herramientas.

DFTime Tools

Se puede descargar la herramienta desde el repositorio oficial de ST2Labs (https://github.com/ST2Labs/DFIR/tree/master/SQLite)

#ST2Labs
#GEOSystemSoftware

www.st2labs.com | www.seguridadparatodos.es

PD: El análisis de las freelist page os lo dejo como "trabajo" para casa. :) Al igual que realizar un análisis manual de los freeblock.


En esta segunda parte, se procederá a recuperar un mensaje que ha sido eliminado en la base de datos SQLite de la aplicación WhatsApp y se analizará la información obtenida para determinar cuando se envío el mensaje (timestamp) recuperado.

Estructura de SQLite (II)

Una vez que conocemos el esquema de la base de datos, y como se organiza la información útil (payload data) dentro de las celdas de cada una de las páginas, es conveniente conocer el formato completo del fichero SQLite (file format) para navegar en el fichero de forma adecuada.

Lo primero que se necesita es conocer el tamaño de las páginas y el número total de páginas que contiene la base de datos, esta información se encuentra dentro de la cabecera de la base de datos (database header).

Analizando la base de datos del ejemplo (msgstore.db) y utilizando mi propia herramienta DFSLite (Digital Forensics SQlite Tools) desarrollada para la ocasión, se obtiene que:

ST2Labs 4 - SQLite Database Header Info
Como se observa en la imagen anterior, se tiene que:
  • Page_size = 4096
  • Num_page = 27

La base de datos en el momento del análisis tiene un máximo de 27 páginas, como cada página tiene un tamaño especifico, se puede calcular el Offset de acceso al fichero para cada una de las páginas utilizando la siguiente formula:

Offset (pagina N) = (N -1) * Page_size 

Se debe de tener en cuenta que las páginas se numeran desde 1 hasta N, y que el Offset para la primera página es 0.

Cada página dentro de la base de datos (excepto la primera página) guardan el siguiente formato:
ST2Labs 5 - SQLite Page Format
Las celdas (registros) de la base de datos se rellenan desde el final de la página hacia el inicio, con objeto de permitir que el Cell Pointer Array aumente según se agregan registros a la página. 

Analizando el contenido del "Cell Pointer Array" se obtienen el número de celdas que contiene la página y el offset relativo a la página donde comienzan. Con DFSLite se puede obtener un listado con todos los Cell Pointer Array e información sobre los registros que existen en cada una de las páginas de la base de datos de la siguiente forma:

ST2Labs 6 - SQLite Page Cell Pointer Array Info
ST2labs 7 - SQLite All Cell for Page List

























Esta información es útil para identificar rápidamente que páginas tienen registros (celdas) de información y cuales no. Además de obtener el Offset absoluto y el número total de registros que hay dentro de la base de datos en cada página.

Toda esta información es interesante desde el punto de vista Forense, para centrar el análisis en aquellas páginas que no tengan registros (mayor espacio sin utilizar), en busca de posible información eliminada y que se encuentre almacenada.

Esto es posible, dado que como si de un sistema de ficheros se tratase cuando se elimina información de la base de datos, esta no se "borra" físicamente (no se sobrescribe de forma inmediata) simplemente se elimina el indice de localización de la información en la base de datos, y se queda residente en el fichero hasta que ésta sea sobrescrita posteriormente con otra información.

Por ello, el periodo de tiempo desde que un registro fue eliminado hasta que se analiza de forma forense es crucial para recuperar la mayor cantidad de información, influyendo directamente el nivel de intensidad de uso de la aplicación en ese tiempo con la capacidad de recuperación de información útil.

Hasta aquí la introducción resumida del formato SQLite, se puede profundizar más en el formato consultando la documentación oficial en el siguiente enlace

A continuación vamos directos a analizar la estructura de la tabla "Messages" de la aplicación WhatsApp dentro de la base de datos SQLite.

Estructura base datos Whatsapp

Tal y como se comprobó en el primer articulo, con ayuda de la herramienta sqlite_ex, se averigua que la tabla "messages" de WhatsApp se encuentra almacenada en la página 3 de la base de datos SQLite (msgstore.db).


Con ayuda de un editor hexadecimal, abrimos la base de datos y nos dirigimos al Offset = 8192 correspondiente a la página 3 (véase la formula comentada anteriormente para el cálculo). Para localizar rápidamente los registros dentro de la página, me apoyo en la DFSLite con la opción -p 3, para analizar la estructura del CellPointerArray de la página, tal que así:

ST2Labs 9 - Cell Pointer Array Info Page 3

El CellPointer Array se encuentra en el Offset: 8200, se realiza un Decode de "Data" y se obtiene el total de Offset relativos a la página donde se encuentran los registros válidos (existentes) dentro de la base de datos:

Decode Cell Pointer Array Data:

  -  Offsets:               [4048, 3390, 3269, 3166]

Con el Offset relativo a la página 3, se puede calcular el Offset de cada una de los registros válidos de la base de datos (msgstore.db).

por ejemplo: Cell Offset 3166 se corresponde con el Offset absoluto: 11358, se abre la base de datos con un editor hexadecimal y se obtiene:

ST2Labs 10 - Hexa Cell Data Offset 11358
La estructura de un registro (celda) de información de tipo Table, de una base de datos SQLite tiene la siguiente estructura:

ST2Labs 8 - Sqlite Cell File Format
Para calcular el tamaño de la celda, y el tamaño del payload la base de datos SQLite utiliza el tipo VarInt, que consiste en el algoritmo de codificación estático de Huffman de 64 bits, que permite codificar en un máximo de 9 bytes el tamaño de la celda y/o el payload data.

 ** Para este artículo, no se va a explicar como decodificar los tipo de datos VarInt.

Analizando la Información


Un registro (cell) dentro de la página 3 de la base de datos SQLite (msgstore.db) de la aplicación WhatsApp almacenará la información de la siguiente forma:

ST2Labs 11 - WhatsApp Cell Payload Data SQLite Struct


La información se almacena dentro de una "celda" de la base de datos SQLite de forma continua, la imagen 4 representa "payload data", por tanto lo más interesante es saber que después del mensaje "Data" a continuación le sigue el timestamp.

Analizando la información de la imagen 10, se puede observar que se tiene el Key_remote_jid | key_from_me | key_id | status | data | timestamp. Se ha escogido un registro "no borrado" de la base de datos para analizar, de forma que se pueda contrastar la información resultante.

Con ayuda de DFSLite, se puede extraer la información para el registro 11358 de la página 3, donde se resumen de la forma siguiente:

** Page 3     - Cell Data 1/4 Offset 11358

  -  RowID:           8
  -  Size:                101
  -  Header:            32
  -  Data: 
  
20004108270808290500000f0800000008080808000d0501010100000008
0000333436373432353639313540732e77686174736170702e6e65745557
6870734b34507765664330546f646f20656e206f7264656e210151245e46a
8300151245cfd47ffffff

Cada uno de los campos de la base de datos se codifica según lo que en SQLite se conoce como "Serial Type Codes Of The Record Format", como ya podéis imaginar con DFSLite he decodificado la información del PAYLOAD HEADER y se obtiene el tipo de cada uno de los campos de la base de datos y el tamaño, para el caso aquí se analiza, el timestamp es tipo Integer (48bits) ~ 6 bytes.

ST2Labs 12 - DFSLite Decode Cell SQLite Data

Analizando la información con ayuda de un editor hexadecimal:

ST2Labs 13 - Cell Data to Offset 11358
Ya tenemos el timestamp del mensaje de WhatsApp, solo hace falta decodificar el valor hexadecimal convertido a decimal para obtener un valor Fecha y Hora.

Pero esto lo haremos en la ultima parte de mi artículo donde publicaré el código de DFTime que convierte el timestamp de 6 bytes, y comentaré como recuperar mensjes "eliminados" de la base de datos.

#ST2Labs
#GEOSystemSoftware

www.st2labs.com | www.seguridadparatodos.es
Hace poco me he tenido que enfrentar al análisis forense de la aplicación Whatsapp en Android, y la sorpresa es la limitada información que existe al respecto. Whatsapp no tiene una API pública, y no sólo eso, sino que persigue claramente a quién tras aplicar ingeniería inversa publica información al respecto, me estoy refiriendo sobretodo a la información del protocolo interno de la aplicación.

Antecedentes

Independientemente de la información existente, mi reto no era descifrar la base de datos y recuperar los mensajes (sobre esto si se encuentra disponible un amplio abanico de artículos en Internet), sino recuperar mensajes eliminados de la base de datos, tanto si la aplicación ha sido eliminada (desinstalada) como si simplemente se ha eliminado el historial de chat desde el interfaz de la aplicación.

Por tanto, el trabajo es analizar la estructura interna de una base de datos SQLite, con el objetivo de recuperar la información que ha sido eliminada y que una sentencia SQL no es capaz de mostrar.

En este punto es donde empieza mi artículo, analizar el formato de SQLite para recuperar información eliminada.

Estructura de SQLite

Lo principal para analizar una base de datos SQLite internamente es conocer su formato interno, para ello lo mejor es consultar la documentación oficial (SQLite Database File Format) donde se explica como se organiza la información dentro del fichero con extensión .db (SQLite).

Una base de datos SQLite se organiza internamente en páginas, y dentro de cada página se almacenan los registros (filas), que se llaman celdas, correspondientes a la información de las tablas de la base de datos. Cada página tiene asignada una función dentro de la estructura del esquema de la base de datos (sql_master), es decir, una tabla de la base de datos almacena información en las celdas de una página.

De forma resumida, se puede representar el funcionamiento interno de una base de datos SQLite tal y como se puede ver en la siguiente imagen:

ST2Labs 1 - SQLite Format Brief
Para conocer el esquema de la base de datos, se puede ejecutar una sentencia SQL tal que así:

SELECT * FROM sqlite_master;
o bien, he creado mi propia herramienta que facilita la consulta de información de una base de datos SQLite, tal que así:

python sqlite_ex.py msgstore.db
ST2Labs 2 - WhatsApp sql_master (db_schema)

Además la herramienta permite hacer un "dump" de la base de datos, guardar en un archivo el esquema de la base de datos al completo, o mostrar la información de una tabla en particular, por ejemplo, y siguiendo con el hilo del articulo, vamos a consultar la información sobre la tabla "message" que es donde Whatsapp almacena la información de los mensajes que se intercambian.

python sqlite_ex.py -i messages msgstore.db
ST2Labs 3 - WhatsApp Messages Table Info

Volviendo a la imagen 2, se observa que la tabla "messages" de WhatsApp se encuentra almacenada en la página 3 de la base de datos SQLite (msgstore.db) y la imagen 3 nos muestra el "contenido" como será organizado en la celda que se generan dentro de la base de datos en la página 3.

Volveremos más tarde a esta información, que nos resultará útil más adelante cuando empiece a analizar la estructura interna del fichero msgstore.db para recuperar la información eliminada.

Pero esto lo dejo para mi siguiente artículo.

La herramienta que he utilizado en éste artículo la podéis encontrar en mi repositorio oficial (https://github.com/ST2Labs/DFIR) o descargar la versión para windows directamente a continuación:

sqlite_ex.exe

sha1: 
7IR6FALIEDG6EPAIE6LVMTZY2UFQVEOO (sha1 base 32)

sha-256: 
6FE6BB8DB06D1A8E17ACD8B79A372821B23260468A92B54EAE229906D32FFACF

sha-512: 
9D8A9AC6037F5F75367F31E2516D98613E8633C79536B99A76ACAD56865250A7845C8A411F1AB8213353DE7EB67AE3E429AAE063049E9A44B4E5E95444C3500C

Referencias:
[1] SQLlite File Format

#ST2Labs #GEOSystemSoftware
#DFIR
#Forensics



Hi every one!

This post I have decided write in english why? Answer is why not? In Digital Forensics it's so important to mantain integrity of evidence, is for this reason what you need read data without any modification. Sometime you get the "evidence" and write into a USB stick, then if you have to read data into windows device, you must enable write protetection for USB device to avoid any modification of them.

This is the target of this "post", I've wrote a simple batch script to "enable" and "disable" the USB write protection it as soon as you need. By default windows always allow write into USB device.

The usage is so easy, is like "stop / start",  before you plug the USB device you must used the script, so on all USB is write protected. And if you used script again, you disable it, so on the next USB device is not write protected.

Here the script:

@ECHO OFF &SETLOCAL
:: ****************
::
:: getUSBProtect v.01
::
:: @Fecha: 16/09/2015
:: @Version: 0.1
:: @Autor: Julian J. Gonzalez
:: @Dept: ST2Labs - www.seguridadparatodos.es
::
:: ****************

SET key="HKLM\System\CurrentControlSet\Control\StorageDevicePolicies"
SET value=WriteProtect

:: BatchGotAdmin
:-------------------------------------
REM  --> Check for permissions
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"

REM --> If error flag set, we do not have admin.
if '%errorlevel%' NEQ '0' (
    echo Requesting administrative privileges...
    goto UACPrompt
) else ( goto gotAdmin )

:UACPrompt
    echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
    echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\getadmin.vbs"

    "%temp%\getadmin.vbs"
    exit /B

:gotAdmin
    if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )
    pushd "%CD%"
    CD /D "%~dp0"
:--------------------------------------

:: Check if Key exist
reg query %key% >nul 2>&1
IF ERRORLEVEL 1 (
GOTO writeup
)

:: Key exist and now we can verify Registry Value
FOR /F "tokens=2*" %%A IN ('reg query %key% /v %value%') DO SET _base=%%B

:: Verify is WriteProtect is Enable
if %_base%==0x1 (
GOTO writeoff
) else ( GOTO writeup )

:writeup
reg add %key% /v %value% /t REG_DWORD /d 0x1 /f
mshta "about:<script>alert('USB Write Protect is Enable !!!');close()</script>"
GOTO:EOF

:writeoff
reg add %key% /v %value% /t REG_DWORD /d 0x0 /f
mshta "about:<script>alert('USB Write Protect is Disable !!!');close()</script>"
GOTO:EOF

Get the Script // Check my GitHub: 
https://github.com/ST2Labs/DFIR


How works

Windows control write protection on USB device through windows registry key:


SET key="HKLM\System\CurrentControlSet\Control\StorageDevicePolicies"
SET value=WriteProtect


Value 0 - Write Protection is disable
Value 1 - Write Protection is enable.

Remember, USB Device must be unplugged to make effect.

#Windows #Forensics #DFIR #ST2Labs
@seguridadxato2
@st2labs
@rhodius