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

lunes, 14 de julio de 2014

Cómo hacer un volcado de memoria (Memory Dump) en Linux?

Por diferentes motivos podríamos querer tener un volcado de memoria de un sistema Linux, por ejemplo:

  • Cuestiones legales, como en un caso de análisis forense sobre un host 
  • Cuestiones de debug, ante un crash del sistema
  • Cuestiones de la vida, curiosidad, etc
La idea de esta entrada es presentar una forma razonable de hacerlo en sistemas GNU/Linux.

Primera aproximación, a por /dev/mem

La primera idea y la mas documentada es leer el dispositivo /dev/mem . Gracias a algún programador (Wietse Venema según el man) existe una aplicación llamada memdump que se encarga precisamente de leer este dispositivo y devolvernos por STDOUT el contenido. Hasta acá parecía todo maravilloso y simple. Entonces probemos memdump:

root@corrientes:/home/jpavlik# memdump  > volcado.mem

La linea anterior me llevó directo a un gigantesco kernel panic y un consecuente reinicio de la PC (posiblemente un problema de mi versión de Ubuntu 13.04, dado que la misma prueba en otros sistemas no terminó en un crash pero tampoco en un dump satisfactorio), por lo tanto vamos a buscar otro camino.
Dado que /dev/mem es un dispositivo

root@corrientes:/home/jpavlik# file /dev/mem 
/dev/mem: character special
root@corrientes:/home/jpavlik# 

lo vamos a tratar como tal y leeremos con dd:

root@corrientes:/home/jpavlik# dd if=/dev/mem of=volcado.mem bs=1M 
dd: leyendo «/dev/mem»: Operación no permitida
1+0 registros leídos
1+0 registros escritos
1048576 bytes (1,0 MB) copiados, 0,125726 s, 8,3 MB/s
root@corrientes:/home/jpavlik# 

si bien esta vez no generamos un gran crash, tampoco obtuvimos un volcado real dado que solo logramos leer 1Mb... y la operación fue detenida.

Leyendo un poco en google resulta ser que existe una opción en tiempo de compilación del kernel que define si será posible o no acceder en espacio de usuario al dispositivo /dev/mem de manera irestricta o no. En nuestro caso

root@corrientes:/home/jpavlik# grep "CONFIG_STRICT_DEVMEM" /usr/src/linux-headers-3.8.0-35-generic/.config
CONFIG_STRICT_DEVMEM=y
root@corrientes:/home/jpavlik# 

la restricción se encuentra efectivamente activada. Dado que al parecer no es posible desactivarla en tiempo de ejecución hay que buscar otro camino que nos permita alcanzar nuestro objetivo.

LiME Forensics

LiME, Linux Memory Extractor es un módulo de linux que nos permitirá acceder a la memoria volatil de manera irestricta ya que a diferencia de memdup o dd, no se ejecuta en espacio de usuario sino en espacio de kernel. Algo muy interesante de LiME es que haciendo uso de la compilación cruzada es posible compilar el módulo para correrlo en dispositivos Android y lograr volcados de memoria de los mismos.
El código de LiME está accesible en http://code.google.com/p/lime-forensics/downloads/list?can=1&q=&colspec=Filename+Summary+Uploaded+ReleaseDate+Size+DownloadCount , una vez descargado podemos acceder a su documentación que viene en un PDF o compilarlo sin demasiadas vueltas:

jpavlik@corrientes:~/LiME$ ls
doc  lime-forensics-1.1-r17.tar.gz  src
jpavlik@corrientes:~/LiME$ cd src/
jpavlik@corrientes:~/LiME/src$ make
make -C /lib/modules/3.8.0-35-generic/build M=/home/jpavlik/LiME/src modules
make[1]: se ingresa al directorio «/usr/src/linux-headers-3.8.0-35-generic»
  CC [M]  /home/jpavlik/LiME/src/tcp.o
  CC [M]  /home/jpavlik/LiME/src/disk.o
  CC [M]  /home/jpavlik/LiME/src/main.o
/home/jpavlik/LiME/src/main.c: En la función ‘__check_dio’:
/home/jpavlik/LiME/src/main.c:56:1: aviso: devolución desde un tipo de puntero incompatible [activado por defecto]
  LD [M]  /home/jpavlik/LiME/src/lime.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/jpavlik/LiME/src/lime.mod.o
  LD [M]  /home/jpavlik/LiME/src/lime.ko
make[1]: se sale del directorio «/usr/src/linux-headers-3.8.0-35-generic»
strip --strip-unneeded lime.ko
mv lime.ko lime-3.8.0-35-generic.ko
make tidy
make[1]: se ingresa al directorio «/home/jpavlik/LiME/src»
rm -f *.o *.mod.c Module.symvers Module.markers modules.order \.*.o.cmd \.*.ko.cmd \.*.o.d
rm -rf \.tmp_versions
make[1]: se sale del directorio «/home/jpavlik/LiME/src»
jpavlik@corrientes:~/LiME/src$ 

el módulo debe haber sido compilado en el mismo directorio:

jpavlik@corrientes:~/LiME/src$ file lime-3.8.0-35-generic.ko 
lime-3.8.0-35-generic.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=0xef9209d7b1872ae63655f3df94d98986f7bdd105, not stripped
jpavlik@corrientes:~/LiME/src$ 

como todo módulo es necesario cargarlo para poder hacer uso de sus funcionalidades. Para esto acudimos el comando insmod (como root, claro) y le pasamos los argumentos necesarios para hacer un dump crudo (raw) a través de la red (la prueba la hacemos sobre una VM just in case...):

  • Desde la VM de la cual obtendremos el volcado de memoria ejecutamos
localhost src # insmod lime-3.3.8-gentoo.ko "path=tcp:4444 format=raw"

  • En la máquina donde recibiremos el volcado ejecutamos:
root@corrientes:~# nc 172.16.254.68 4444 > volcado.mem

Luego de unos segundos (dependiendo de la cantidad de ram de la VM y la velocidad de trasnferencia de la red) tendremos el archivo volcado.mem a nuestro disposición:

root@corrientes:~# ll volcado.mem -h
-rw-r--r-- 1 root root 256M jul 14 15:25 volcado.mem
root@corrientes:~# 

Podemos apreciar que el tamaño del archivo nos indica que la VM de origen tiene solo 256Mbytes asignados como memoria RAM. 

Y de esta manera conseguimos nuestro volcado de memoria, ahora habría que analizarlo según los objetivos de cada caso. 

Una primera aproximación de análisis muy simple, podríamos hacerla usando el comando strings y analizar las cadenas obtenidas.

lunes, 8 de abril de 2013

Recuperando información totalmente sobreescrita


Hace un par de días comencé un posgrado en seguridad de la información y se dió una charla muy interesante. El punto de la conversación era la posibilidad de recuperar archivos de una memoria flash que había sido COMPLETAMENTE sobreescrita, esto dio lugar básicamente a dos opiniones:

-NO, no es posible recuperar nada si la memoria fue completamente sobre escrita.
-SI, si es posible.

En particular yo estaba en el primer grupo, aunque alguna vez leí que en los soportes magnéticos esto podría ser cierto por la naturaleza magnética de los mismos. Pero ahora estabamos hablando de memorias de tipo FLASH.

En la mayoría de los casos (por no decir todos, aunque posiblemente sean todos) las memorias flash a.k.a. pendrives, tienen particiones de tipo FAT. Este tipo de sistema de archivos son mundialmente conocidos por su mecanismo de borrado que, mmm digamos, no borra. Suena loco, pero si, técnicamente lo que borramos NO se elimina del dispositivo, sino que solamente se marca como espacio libre disponible nuevamente.

Como prueba plantee el siguiente escenario:

-Cree en mi pendrive una partición de 128Mbytes (por una cuestión de tiempo, no valía la pena hacerla mas grande).
-Formatee la partición con un sistema de archivos tipo FAT.
-Copié a la partición una serie de archivos, archivos de texto, binarios, documentos de office, sin llegar a ocupar la totalidad del dispositivo.
-Luego eliminé todos los archivos y con dd generé un archivo que ocupara la totalidad de la partición (128Mbytes).
-Use las herramientas de sleuthkit forensic analysis para intentar recuperar los archivos eliminados y sobreescritos.

Estado inicial del pendrive

root@moon:/home/juan# fdisk -lu /dev/sdb

Disco /dev/sdb: 4063 MB, 4063232000 bytes
125 cabezas, 62 sectores/pista, 1024 cilindros, 7936000 sectores en total
Unidades = sectores de 1 * 512 = 512 bytes
Tamaño de sector (lógico / físico): 512 bytes / 512 bytes
Tamaño E/S (mínimo/óptimo): 512 bytes / 512 bytes
Identificador del disco: 0x00091593

Dispositivo Inicio    Comienzo      Fin      Bloques  Id  Sistema
/dev/sdb1   *          62     5750499     2875219    b  W95 FAT32
/dev/sdb2         5750500     7935999     1092750   83  Linux
root@moon:/home/juan# 

Inicialmente el pendrive tiene 2 particiones, una FAT32 y una partición linux. Elminé la partición FAT y volví a crearla en 128Mbytes.

root@moon:/home/juan# fdisk -u /dev/sdb

Orden (m para obtener ayuda): d
Número de partición (1-4): 1

Orden (m para obtener ayuda): w
¡Se ha modificado la tabla de particiones!

Llamando a ioctl() para volver a leer la tabla de particiones.
Se están sincronizando l1os discos.

Partición eliminada:

root@moon:/home/juan# fdisk -l /dev/sdb

Disco /dev/sdb: 4063 MB, 4063232000 bytes
125 cabezas, 62 sectores/pista, 1024 cilindros, 7936000 sectores en total
Unidades = sectores de 1 * 512 = 512 bytes
Tamaño de sector (lógico / físico): 512 bytes / 512 bytes
Tamaño E/S (mínimo/óptimo): 512 bytes / 512 bytes
Identificador del disco: 0x00091593

Dispositivo Inicio    Comienzo      Fin      Bloques  Id  Sistema
/dev/sdb2         5750500     7935999     1092750   83  Linux
root@moon:/home/juan# 

Ahora creo la partición de 128Mbytes,

root@moon:/home/juan# fdisk -u /dev/sdb

Orden (m para obtener ayuda): n
Acción de la orden
e   Partición extendida
   p   Partición primaria (1-4)
p
Número de partición (1-4, valor predeterminado 1): 1
Primer sector (2048-7935999, valor predeterminado 2048): 
Se está utilizando el valor predeterminado 2048
Último sector, +sectores o +tamaño{K,M,G} (2048-5750499, valor predeterminado 5750499): +128M

Orden (m para obtener ayuda): p

Disco /dev/sdb: 4063 MB, 4063232000 bytes
125 cabezas, 62 sectores/pista, 1024 cilindros, 7936000 sectores en total
Unidades = sectores de 1 * 512 = 512 bytes
Tamaño de sector (lógico / físico): 512 bytes / 512 bytes
Tamaño E/S (mínimo/óptimo): 512 bytes / 512 bytes
Identificador del disco: 0x00091593

Dispositivo Inicio    Comienzo      Fin      Bloques  Id  Sistema
/dev/sdb1            2048      264191      131072   83  Linux
/dev/sdb2         5750500     7935999     1092750   83  Linux

Orden (m para obtener ayuda): w
¡Se ha modificado la tabla de particiones!

Llamando a ioctl() para volver a leer la tabla de particiones.
Se están sincronizando los discos.
root@moon:/home/juan# 

Formateo la partición con FAT32:

root@moon:/home/juan# mkfs.vfat -F 32 /dev/sdb1
mkfs.vfat 3.0.9 (31 Jan 2010)
root@moon:/home/juan# mount /dev/sdb1 /media/
root@moon:/home/juan# mount|grep vfat
/dev/sdb1 on /media type vfat (rw)
root@moon:/home/juan# df -h|grep media
/dev/sdb1             127M   512  127M   1% /media
root@moon:/home/juan# 

Listo, ahora copiamos los archivos:

root@moon:/home/juan# ll /media/
total 10969
drwxr-xr-x  2 root root     512 2013-04-07 22:20 ./
drwxr-xr-x 25 root root    4096 2013-02-18 15:44 ../
-rwxr-xr-x  1 root root 3252736 2013-04-07 22:20 04030-SlippingInTheWindow_v1.0.doc*
-rwxr-xr-x  1 root root 4163672 2013-04-07 22:20 dopdf-7.exe*
-rwxr-xr-x  1 root root    5036 2013-04-07 22:20 france1.jpg*
-rwxr-xr-x  1 root root   20480 2013-04-07 22:20 strings.txt*
-rwxr-xr-x  1 root root  160256 2013-04-07 22:20 TARIFAS.doc*
-rwxr-xr-x  1 root root 3624496 2013-04-07 22:20 ZTEDrvSetup.exe*
root@moon:/home/juan# df -h|grep media
/dev/sdb1             127M   11M  116M   9% /media
root@moon:/home/juan# 

Desmontamos y volvemos a montar la unidad para que las operaciones pendientes se hagan si o si.

Borramos todos los archivos de la partición:

root@moon:/media# rm *
root@moon:/media# df -h|grep media
/dev/sdb1             127M   512  127M   1% /media
root@moon:/media# 

Escribimos ahora un archivo gigante que ocupe toda la partición:

root@moon:/media# dd if=/dev/zero of=archivo_gigante bs=1024
dd: escribiendo «archivo_gigante»: No queda espacio en el dispositivo
129039+0 registros leídos
129038+0 registros escritos
132134912 bytes (132 MB) copiados, 0,706763 s, 187 MB/s
root@moon:/media# 

Ocupé toda la partición con archivo_gigante, lleno de zeros obtenidos de "/dev/zero".

root@moon:~# df -h|grep media
/dev/sdb1             127M  127M   512 100% /media
root@moon:~# 

Para averiguar un poco de nuestra partición utilizamos fsstat,

root@moon:~# fsstat /dev/sdb1
FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: FAT32

OEM Name: mkdosfs
Volume ID: 0xb01a12a4
Volume Label (Boot Sector):            
Volume Label (Root Directory):
File System Type Label: FAT32   
Next Free Sector (FS Info): 25995
Free Sector Count (FS Info): 1

Sectors before file system: 0

File System Layout (in sectors)
Total Range: 0 - 262143
* Reserved: 0 - 31
** Boot Sector: 0
** FS Info Sector: 1
** Backup Boot Sector: 6
* FAT 0: 32 - 2048
* FAT 1: 2049 - 4065
* Data Area: 4066 - 262143
** Cluster Area: 4066 - 262143
*** Root Directory: 4066 - 4066

METADATA INFORMATION
--------------------------------------------
Range: 2 - 4129254
Root Directory: 2

CONTENT INFORMATION
--------------------------------------------
Sector Size: 512
Cluster Size: 512
Total Cluster Range: 2 - 258079

FAT CONTENTS (in sectors)
--------------------------------------------
4066-4066 (1) -> EOF
4067-25994 (21928) -> EOF
25996-262143 (236148) -> 4067

Fsstat nos muestra que tenemos dos entradas en la FAT, la primera es la correspondiente al directorio raiz, en la posición sector 4066. Y la segunda ocupa los sectores desde el sector 25996 hasta el 262143 y luego continua en el sector 4067 hata el 25994.

Podemos ver el contenido del sector correspondiente al directorio raíz y su contenido:

root@moon:~# dd if=/dev/sdb1 bs=512 skip=4066 count=1 > RAIZ
1+0 registros leídos
1+0 registros escritos
512 bytes (512 B) copiados, 0,001339 s, 382 kB/s
root@moon:~# cat RAIZ 
Bte����k����������������archikvo_giganARCHIV~1    d��B�B��B�U8��4030-~1DOC d���B�B���B�1�dopdf�-7.exe���OPDF-7 EXE d���B�B���B�▒X�?�francVe1.jpg���RANCE1 JPG d���B�B���B�8��strin gs.txt���TRINGS TXT ���B�B���B�8P�TARIFaAS.doc���ARIFAS DOC d���B�B���B�8r�xe����������������������ZTEDr�vSetup.e�TEDRV~1EXE ���B�B���B:0N7
root@moon:~# 

Podemos ver en la entrada de directorio que aún se preservan los nombres de los archivos que habíamos copiado en el dispositivo.
Si hacemos unos cálculos podemos asumir que nuestro archivo_gigante ocupa 258076 (236148 + 21928) sectores es decir unos 132134912 bytes, que CASUALMENTE es el número de bytes que escribió nuestro dd. Por lo pronto podemos asumir que la totalidad del dispositivo fue sobre escrito por este archivo y no podríamos recuperar ninguno de los otros.

Bueno, a intentar recuperar. Para esto voy a usar autopsy, un GUI web para sleuthkit.


Luego de agregar la imagen a autopsy la analizamos:


Y vemos:


A simple vista vemos que autopsy fue capaz de reconocer la previa existencia de todos los archivos e incluso sus tamaños. Por lo tanto intentamos recuperar france1.jpg.


Autopsy nos indica que france1.jpg tenia un tamaño de 5036 bytes y que comenzaba en el sector 18553. Por lo tanto esto significa que salvo que haya estado fragmentado el sistema de archivo, los sectores desde 18553 al 18563 pertenecian a france1.jpg (5036 bytes entran en 10 sectores de 512 bytes).

root@moon:/home/juan/borrar# dd if=/dev/sdb1 of=france1.jpg bs=512 skip=18553 count=10
10+0 registros leídos
10+0 registros escritos
5120 bytes (5,1 kB) copiados, 0,002215 s, 2,3 MB/s
root@moon:/home/juan/borrar# file france1.jpg 
france1.jpg: data
root@moon:/home/juan/borrar# 

Lamentablemente ya no es posible recuperar el archivo, solo obtuvimos 5120 bytes con ceros...

root@moon:/home/juan/borrar# hexdump -v france1.jpg 
0000000 0000 0000 0000 0000 0000 0000 0000 0000
0000010 0000 0000 0000 0000 0000 0000 0000 0000
0000020 0000 0000 0000 0000 0000 0000 0000 0000
0000030 0000 0000 0000 0000 0000 0000 0000 0000
0000040 0000 0000 0000 0000 0000 0000 0000 0000
0000050 0000 0000 0000 0000 0000 0000 0000 0000
0000060 0000 0000 0000 0000 0000 0000 0000 0000
0000070 0000 0000 0000 0000 0000 0000 0000 0000
...
00013f0 0000 0000 0000 0000 0000 0000 0000 0000
0001400
root@moon:/home/juan/borrar# 

Probemos ahora con ZTEDrvSetup.exe, según autopsy se trataba de un ejecutable de windows que pesaba 3624496 bytes y que comenzaba en el bloque 18916. Asumiendo lo mismo que en el archivo anterior, extraemos los datos desde el sector 18916 al sector 25996 (18916+7080).

root@moon:/home/juan/borrar# dd if=/dev/sdb1 of=ZTEDrvSetup.exe bs=512 skip=18916 count=7080
7080+0 registros leídos
7080+0 registros escritos
3624960 bytes (3,6 MB) copiados, 0,196779 s, 18,4 MB/s
root@moon:/home/juan/borrar# file ZTEDrvSetup.exe
ZTEDrvSetup.exe: data
root@moon:/home/juan/borrar# hexdump ZTEDrvSetup.exe
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
0374e00 ae12 25be 6b96 5383 fbe3 51b5 db26 8c30
0374e10 b291 8f4a 8715 ab6c a46a 389a 8ff4 6c0c
0374e20 b926 2552 f303 cdbc 4bee c8a3 0b9d 0000
0374e30 0000 0000 0000 0000 0000 0000 0000 0000
*
0375000
root@moon:/home/juan/borrar#

Sin éxito nuevamente.

Al parecer por métodos de software no es posible recuperar archivos en particiones FAT que fueron sobreescritas completamente. Esto tiene sentido ya que al escribir en todo el espacio disponible los archivos que fueron previamente eliminados son tratados como espacio libre y por lo tanto sobreescritos.

Si bien en principio no podemos recuperar los archivos, todavía contamos con información interesante como su tamaño y sus datos MAC (Modified, Accessed and Created).

Este mismo comportamiento es de esperarse en soportes magnéticos que tengan FAT como sistema de archivo. Por lo tanto la recuperación por software debería ser idéntica en ambos medios. De todas manera, podrían existir métodos de recuperación mas específicos para cada tecnología, donde no se analizaría solamente el sistema de archivo, sino también buffers y hasta el propio soporte (hardware).