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.
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.