Información blog

Linux, tutoriales, noticias, sistemas, redes y seguridad informática, entre otras cosas.

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

lunes, 19 de febrero de 2018

Cómo registrar qué USBs se han conectado en Linux

La recopilación de información es cada día más importante; en servidores siempre lo ha sido, pero en los equipos de sobremesa ha ido cobrando importancia paulatinamente  y hoy en día se ha demostrado que es importante tener registrada toda la información por si en un futuro nos pudiese llegar a ser útil. Hoy quiero hablar sobre el registro de USBs en Linux. Linux tiene la gran ventaja de tener una enorme cantidad de logs, pero los logs no siempre te registran todos los datos que uno desea y corremos el peligro de que dichos logs sean borrados o se roten mediante utilidades tales como logrotate; utilidades especialmente comunes en servidores. Por eso puede ser interesante tener una herramienta corriendo en segundo plano cuya única función sea registrar qué USBs se han conectado/desconectado, la hora en la que lo han hecho, datos útiles tales como el número de serie y de paso, registrar su actividad a ser posible.

portada_registro_usb

En este caso no optaremos a herramientas de terceros sino que tiraremos de conceptos de Linux y los aglutinaremos en un script que automatice todo ello... Además, en este caso, no almacenaremos la información en un fichero en texto plano, sino que vamos a almacenarla en una mini base de datos en formato SQLite... El motivo por el cual se ha optado por dicha opción es simple: SQLite requiere instalar pocas herramientas en el equipo lo cual es perfecto en equipos de sobremesa; además es una base de datos que consume muy pocos recursos por parte del equipo y al mismo tiempo tiene la gran ventaja de seguir siendo una base de datos basada en el lenguaje SQL, con lo cual podríamos hacer consultar de su información mediante consultas SQL mediante SELECTs con sus respectivos filtros, etc... Haciendo que la consulta de la información en el futuro sea muchísimo más eficiente, con la contrapartida de que se requieren unos conocimientos básicos de SQL para poder sacarle partido.

Teniendo esto en cuenta, comencemos con la instalación de las dependencias necesarias para que nuestra solución funcione... Dependiendo de qué distribución tengamos y las herramientas que tengamos instaladas, puede ser que ya tengamos todo lo necesario, pero para asegurarnos haremos:
apt-get install sqlite
Teniendo todo preparado, pasaríamos a crearnos primero la mini base de datos que almacenará la información de los USBs. En mi caso en particular he creado la base de datos en /var y la he llamado listaUsbs.db con lo que su creación sería tal que así:
sqlite /var/listaUSBs.db
Esto no solo crearía la base de datos, sino que estaríamos dentro de ella, con lo que pasaríamos a crear la tabla en cuestión. En mi caso he llamado a la tabla listausbs y su creación (junto con sus respectivas columnas) sería la siguiente:
CREATE TABLE lista_usbs (NOMBRE,FECHA_DETECT,FECHA_DESCONEX,
IDVENDOR,IDPRODUCT,MANUFACT,IPRODUCT,SERIAL);
En esta base de datos guardaremos toda la información importante tal como el nombre completo, la fecha de detección del USB, el fabricante y el numero de serie... Información que puede sernos útil en el futuro. Con esto claro, podemos crear un script en el que por un lado monitoricemos en tiempo real toda la actividad USB mediante tcpdump, y por otro lado también podemos tener constancia de qué USB se ha conectado en qué momento; esto lo podemos lograr mediante el siguiente script, al cual yo he llamado registrador_usbs.sh y que ha sido probado en Debian 8:


#!/bin/bash

#CAPTURAMOS TODO EL TRAFICO USB
modprobe usbmon
nohup tcpdump -i usbmon1 -w /tmp/captura.cap &
while true;
do
        #COMPROBAMOS SI SE HA CONECTADO ALGUN USB NUEVO
        if [ ! -f /tmp/listausbs2.txt ];
        then
                touch /tmp/listausbs2.txt
        fi
        lsusb > /tmp/listausbs.txt
        diff /tmp/listausbs.txt /tmp/listausbs2.txt
        if [ $? -eq 1 ]
        then
                diff /tmp/listausbs.txt /tmp/listausbs2.txt > /tmp/cambio.txt
                cat /tmp/cambio.txt |tail -n +2 > /tmp/cambio2.txt
                while read CAMBIO;
                do
                echo ${CAMBIO} > /tmp/cambio3.txt
                cat /tmp/cambio3.txt |grep "<"
                if [ $? -eq 0 ];
                then
                        #SI ES UNA CONEXION NUEVA LA REGISTRAMOS
                        NOMBRE="$( cat /tmp/cambio3.txt |cut -d '<' -f 2 |cut -d ':' -f 2- | cut -d 'D' -f 2- )"
                        echo $NOMBRE
                        lsusb -D /dev/bus/usb/$(lsusb |grep "${NOMBRE}" |awk {'print $2'})/$(lsusb |grep "${NOMBRE}" |awk {'print $4'} |cut -d ":" -f 1) > /tmp/usb_detallado.txt
                        FECHA_DETECT=$(date)
                        FECHA_DESCONEX=''
                        IDVENDOR=$(cat /tmp/usb_detallado.txt |grep idVendor |awk '{for (i=2; i<NF; i++) printf $i " "; if (NF >= 2) print $NF; }')
                        IDPRODUCT=$(cat /tmp/usb_detallado.txt |grep idProduct |awk '{for (i=2; i<NF; i++) printf $i " "; if (NF >= 2) print $NF; }')
                        MANUFACT=$(cat /tmp/usb_detallado.txt |grep iManufacturer |awk '{for (i=2; i<NF; i++) printf $i " "; if (NF >= 2) print $NF; }')
                        IPRODUCT=$(cat /tmp/usb_detallado.txt |grep iProduct |awk '{for (i=2; i<NF; i++) printf $i " "; if (NF >= 2) print $NF; }')
                        SERIAL=$(cat /tmp/usb_detallado.txt |grep iSerial |awk '{for (i=2; i<NF; i++) printf $i " "; if (NF >= 2) print $NF; }')
                        sqlite /var/listaUSBs.db "INSERT INTO lista_usbs VALUES ('${NOMBRE}','${FECHA_DETECT}','${FECHA_DESCONEX}','${IDVENDOR}','${IDPRODUCT}','${MANUFACT}','${IPRODUCT}','${SERIAL}');"
                        rm /tmp/usb_detallado.txt
                fi
                cat /tmp/cambio3.txt |grep ">"
                if [ $? -eq 0 ];
                then
                        #SI ES UNA DESCONEXION ACTUALIZAMOS LOS DATOS CORRESPONDIENTES
                        NOMBRE="$( cat /tmp/cambio3.txt |cut -d '>' -f 2 |cut -d ':' -f 2- | cut -d 'D' -f 2- )"
                        FECHA_DESCONEX=$(date)
                        sqlite /var/listaUSBs.db "UPDATE lista_usbs SET FECHA_DESCONEX='${FECHA_DESCONEX}' WHERE FECHA_DESCONEX='' AND NOMBRE='${NOMBRE}';"
                fi
                done < /tmp/cambio2.txt
                rm /tmp/cambio.txt
                rm /tmp/cambio2.txt
                rm /tmp/cambio3.txt
        fi
        mv /tmp/listausbs.txt /tmp/listausbs2.txt
done

Con este script, solamente ejecutándolo en segundo plano estaríamos monitorizando en tiempo real toda la actividad mediante tcpdump, y registrándola en nuestra base de datos SQLite. Solamente habría que escribir:
./registrador_usbs.sh >/dev/null &
Dicha información podría ser consultada en el futuro mediante consultas SQL tales como:

Para ver todos los registros:
sqlite /var/listaUSBs.db "SELECT * FROM lista_usbs;"
Para ver un numero de serie concreto:
sqlite /var/listaUSBs.db "SELECT * FROM lista_usbs WHERE 
SERIAL='3 20060413092100000';"
Para eliminar todos los registros:
sqlite /var/listaUSBs.db "DELETE FROM lista_usbs;"

Con ello tendríamos todo monitorizado y registrado en nuestro equipo ganando un gran control sobre la actividad USB en nuestro equipo. Obviamente dicho script sería solamente un ejemplo teórico que puede ser modificado a nuestro gusto para que se adapte lo mejor posible a nuestras necesidades.

Espero que os haya resultado útil.

Saludos.

jueves, 1 de febrero de 2018

Cómo monitorizar eventos de un directorio en tiempo real con inotify en Linux

En ocasiones podemos vernos en la situación de querer tener un control de lo que ocurre dentro de un directorio; tal es así el control que queremos que podemos llegar a desear ver todos los eventos en tiempo real que ocurren dentro de un directorio, eventos tales como el listado de archivos, la creación y modificación de estos e incluso la eliminación. Generalmente podemos intentar jugar el comando history para ver los últimos comandos, examinar las últimas fechas de modificación de los ficheros, e incluso examinar sus metadatos, con el fin de averiguar lo máximo posible de lo que ocurre en nuestro equipo; especialmente cuando éste está siendo accedido por varios usuarios a la vez o simplemente tenemos miedo de que lo esté siendo. Es por ello que para ocasiones como esas puede ser muy interesante recurrir a herramientas de observación de eventos en tiempo real para Linux tales como inotify.

Inotify_portada

Inotify es una herramienta con la capacidad de observar eventos en tiempo real dentro de un directorio, lo que nos otorga un gran conocimiento en comparación con otras herramientas, si bien, tal y como he matizado al principio, requiere monitorizar en tiempo real para poder ser funcional. Esta utilidad no está instalada por defecto en el sistema, sino que requiere ser instalada, si bien afortunadamente es realmente sencillo pues está incluida dentro de los repositorios oficiales del sistema:
apt-get install inotify-tools
Esto hará que se instalen dos herramientas: Inotifywait e Inotifywatch. El que nos interesa en concreto es Inotifywait pues ofrece una enorme información.

Un modo muy básico de usar Inotifywait sería de la siguiente forma:
inotifywait /tmp
El problema que tiene usar este comando directamente es que efectivamente escuchará los eventos de dicho directorio, pero no será capaz de escuchar los eventos de los subdirectorios de éste y además al recibir un solo evento inotifywait se cerraría automáticamente. Es por ello que conviene conocer cómo usarla para poder sacarle de verdad provecho.

Hay diferentes parámetros y opciones, pero los más importantes serían los de a continuación:

Comencemos con el parámetro -m; La inclusión de este parámetro hará que inotify entre en modo monitorización, con lo que podrá recibir eventos continuamente sin llegar a cerrarse a menos que nosotros le mandemos la señal necesaria para que se detenga. Dicho parámetro también podría especificarse también mediante --monitor. Otro parámetro muy útil sería el -r; Al usar este parámetro estaríamos indicando que se monitorizase todo el directorio en cuestión y también todos los subdirectorios. El parámetro en cuestión también podría especificarse mediante --recursive. El último que en mi opinión es también importante tener en cuenta sería el -e; Este último es más "opcional" que los dos anteriores, pero puede ser de una enorme utilidad, ya que sirve de filtrador de eventos; es decir que con dicho parámetro veríamos los eventos que nosotros queramos y no todos, que sería lo que se nos mostraría por defecto. El parámetro también puede ser llamado mediante --events. Obviamente, para poder filtrar los eventos, habría que conocer cuales son... Son un número considerable y, desgraciadamente, no todos son fáciles de recordar, pero es bueno conocer al menos su existencia:

  • access: Este sería uno de los más veríamos, ya que indica que un fichero o el contenido de un directorio ha sido leído. 
  • modify: Este parámetro haría que se nos notifique de los cambios que se realicen en el entorno que estamos monitorizando.
  • attrib: Este es ligeramente más raro que el resto, pues solamente notificaría los cambios en los atributos de los ficheros o directorios.
  • close_nowrite: Se notifica cuando se ha cerrado un fichero o directorio que ha sido abierto en modo solo lectura.
  • close_write: Se notifica cuando se cierra un fichero o directorio en modo escritura.
  • open: Especifica que un fichero o directorio ha sido abierto; este mensaje también es de los que más aparecen junto con access.
  • moved_to: Este evento implica que algo ha sido movido hacia el directorio que estamos monitorizando.
  • moved_from: Este evento indica que algo ha sido movido desde el directorio que estamos monitorizando.
  • move: Este evento indica que va a haber una actividad de movimiento dentro del directorio que monitorizamos, ya sea desde o hacia el directorio en cuestión.
  • create: En este caso se indicaría que algo (ya sea fichero o directorio) ha sido creado dentro del lugar que estamos monitorizando.
  • delete: Al contrario que create, en este caso se detectaría que algo se ha eliminado.
  • delete_self: Esto indica que el fichero o directorio que estamos monitorizando acaba de ser eliminado.
  • umount: Aquí se detectaría que el sistema de ficheros en que se aloja aquello que estamos monitorizando, acaba de ser desmontado.

Es conveniente resaltar que generalmente querremos ver todos los eventos, pero es importante conocer qué eventos se monitorizan para así poder hacer filtrados en caso de tener una necesidad muy concreta...

Teniendo estos conceptos claros podemos hacer cosas como la siguiente:
inotifywait -r -m /tmp
Con dicho comando estaríamos monitorizando todos los eventos dentro de la carpeta /tmp y todos sus subdirectorios; además estaría recibiendo constantemente eventos hasta que se le indique lo contrario, con lo que si abriésemos otra terminal podríamos realizar las acciones de a continuación:
cd /tmp && ls && touch test && echo prueba > test && rm test
Si viésemos los eventos visualizados por inotifywait veríamos lo siguiente:

inotifywait

Al final se estarían viendo en tiempo real todas las acciones realizadas, desde la creación del archivo hasta la eliminación de éste. Además si queremos podemos dejar que el proceso inotifywait esté corriendo en segundo plano y que vuelque todo el contenido en fichero para poder analizarlo más tarde con tranquilidad, extrayendo las conclusiones que deseemos. Esto requeriría hacer simplemente la siguiente modificación en el anterior comando:
inotifywait -r -m /tmp > /var/inotify.log &
Dicho proceso tendría que ser finalizado mediante un kill, o llevado a primer plano para poder finalizarse.

Como podéis ver el tener controlado un directorio o un grupo de éstos puede llegar a ser útil pues gracias a ello podemos tener un mayor conocimiento de lo que ocurre dentro de nuestro sistema.

Espero que os haya resultado útil.

Saludos.

martes, 30 de mayo de 2017

Cómo extraer una contraseña Windows de la memoria RAM con Volatility y Hashcat en Linux

Anteriormente hice un pequeño artículo explicando cómo poder consultar información de la RAM con GNU/Linux, usando LiME para extraer un volcado de ésta, y Volatility para analizar dicho volcado, pero lo cierto es que si bien dicha combinación es útil, solamente se mostró un atisbo de lo que Volatility puede hacer... Volatility es una herramienta forense de gran potencia que tiene una enorme cantidad de opciones y si bien es obvio que dominar, e incluso conocer, todas es muy complicado, sí que hay una serie de opciones que son, en mi opinión, realmente interesantes. Una de ellas es nada más y nada menos que la extracción de una contraseña.

RAM_portada

Supongamos que nos han dado un volcado de memoria RAM en mano, llamado /root/volcado.dmp, y que no tenemos información alguna de dicho volcado más allá de que procede de un Windows... Es decir que no sabemos siquiera de qué sistema operativo procede... ¿Qué hacer con dicho volcado? Doy por supuesto que Volatility está instalado (en caso contrario recomiendo leer primero el artículo citado arriba); aún así, simplemente para recordar la estructura de esta herramienta, ésta sería:

volatility -f volcado_a_analizar --profile perfil_del_volcado acción

A sabiendas de ésto, lo primero que tendríamos que hacer sería un análisis global de dicho volcado, aunque sea para tener una idea general de lo que tenemos en nuestras manos... En este caso sabemos que el volcado viene de un sistema Windows, pero no sabemos que versión de éste, con lo que lo primero que haremos será una extracción global de la información de la imagen, lo cual se hace gracias a la acción imageinfo, que no requiere de perfil alguno:

volatility -f /tmp/volcado.dmp imageinfo

Volatility_imageinfo
Información global volcado RAM volatility

De aquí el dato más importante para nosotros sería el de "Suggested Profile(s)" ya que éste nos diría qué perfil nos recomienda usar Volatility... En este caso el perfil que usaremos será el de Win7SP1x86... Lo bueno que tiene Volatility es que ya tiene varios perfiles creados que podemos usar a nuestro gusto, si bien la desventaja que tiene es que los perfiles de sistemas Linux tienen que ser creados por nosotros... En este caso no tenemos la necesidad de crear el perfil, con lo que ya podemos extraer la información que queremos con el perfil sugerido.

En este caso en concreto queremos extraer la contraseña, cosa que es más sencillo de lo que parece, ya que solo requiere de un comando:

volatility -f volcado.dmp --profile Win7SP1x86 hashdump > /tmp/hashes.txt

Este comando nos volcará los hashes de las contraseñas de los diferentes usuarios en un fichero llamado hashes.txt alojado en /tmp/; Hashes que obviamente, son completamente ilegibles, al menos en un principio. En mi caso el contenido del fichero hashes.txt sería el siguiente:

hash

O para verlo mejor:

Ivan:1000:aad3b435b51404eeaad3b435b51404ee:b9f917853e3dbf6e6831ecce60725930:::

Con los hashes en nuestro poder, tenemos dos opciones: Instalar Hashcat en nuestra distribución de Linux o usar un equipo/máquina virtual con Kali que tiene dicha herramienta instalada. Por experiencia propia recomiendo la segunda opción, al instalar Hashcat en nuestra distribución habitual (Debian, Ubuntu o derivados...) suelen haber problemas a la hora de ejecutarlo.

Hashcat usaría la siguiente estructura:

hashcat --force -m tipo_hash -a tipo_ataque -o fichero_salida fichero_hash ruta_diccionario --show

Aquí hay dos puntos que hay que tener en cuenta:

El primero es el tipo de hash... Aquí no basta con poner el tipo en modo texto, sino que se asigna mediante un numero que la herramienta asocia a un tipo de hash hay decenas y decenas de tipos de hash, pero aquí basta saber con que el valor numérico que nos vale a nosotros en este caso en concreto es el 1000: NTLM. En caso de querer conocer más tipos de hashes y su respectivos números, recomiendo visitar la wiki oficial: https://hashcat.net/wiki/doku.php?id=hashcat

El segundo es el tipo de ataque... Aquí también se le dice un número para decirle qué tipo de ataque queremos... 0 diccionario, 1 sería híbrido (fuerza bruta y diccionario) y 3 sería por fuerza bruta... El tipo más común sería el híbrido (1), si bien requiere de un diccionario, diccionario que Kali ya tiene incorporado de por sí por defecto. El diccionario que nosotros usaremos se llamará wordlist.txt y en Kali se encuentra en: /usr/share/sqlmap/txt.

Con toda esta información el descifrado de éste hash sería tan sencillo como hacer:

hashcat --force -m 1000 -a 1 -o /tmp/crackeado.txt hashes.txt /usr/share/sqlmap/txt/wordlist.txt --show

Dependiendo de la fortaleza de la contraseña, el resultado tomará más o menos tiempo... En mi caso, al haber puesto una contraseña muy débil el resultado ha sido casi instantáneo... Para comprobar el resultado simplemente habría que consultar el fichero /tmp/crackeado.txt cuyo contenido, en este caso sería:

b9f917853e3dbf6e6831ecce60725930:passw0rd

Lo cual significaría que la contraseña del usuario Ivan sería passw0rd. Ahora bien, tras ver todo este proceso hay varios puntos a tener en cuenta.

El primero es que el proceso de extracción de hash, solamente es aplicable a un volcado de memoria RAM procedente de un sistema operativo Windows, ya que los sistemas GNU/Linux tienen otra forma de trabajar y almacenan los hashes de forma diferente.

Como segundo punto, habría que tener en cuenta que la extracción de un hash puede realizarse de diferentes formas... Aquí se ha mostrado con Volatility con el objetivo de mostrar que la memoria RAM tiene mucha más información de lo que en un principio nos puede parecer.

Otro punto importante es que Hashcat no está limitado a hashes de Windows, puede ser usado para hashes MD5,SHA-216... Es decir que si bien aquí se ha usado con un hash de Windows, con el fin de combinarlo con Volatility, puede ser usado con muchísimos más.

Por último, es importante ser conscientes de que el fin de este procedimiento es ser conscientes de la información almacenada en la memoria RAM y además tener la conciencia de que una contraseña insegura o un cifrado débil, puede tener consecuencias desastrosas...

Espero que este artículo os haya sido útil.

Saludos.

viernes, 3 de febrero de 2017

Memoria RAM en Linux; una valiosa fuente de información

La memoria RAM (Random Access Memory) es indispensable para el uso de cualquier tecnología, ya sea para dispositivos pequeños como para super-ordenadores; memoria que es usada todos los días por todo tipo de personas: personas que juegan con el móvil, gente que realiza tareas cotidianas en su ordenador, etc... Lo que muchos no tienen en cuenta es que esta memoria es exactamente eso: Una memoria, valga la redundancia; y como tal almacena mucha información; información que muchos no tienen en cuenta pero que puede resultar muy valiosa y/o peligrosa, dependiendo del caso.

Portada_RAM

Las pruebas que he realizado han sido sobre sistemas Debian y Ubuntu, pero perfectamente sería aplicable para equipos basados en Red Hat, con un par de modificaciones. Lo primero que necesitamos hacer para leer el contenido de la memoria RAM, es realizar un volcado de ésta en un fichero, para luego leer éste a placer. A lo largo del tiempo han habido diferentes métodos para volcar la memoria RAM, pero el más usado a día de hoy es el uso de LiME (Linux Memory Extractor); principalmente debido a que trabaja a nivel de Kernel y puede usarse para realizar un volcado de la memoria RAM de todo sistema que trabaje con un Kernel Linux, incluidos los móviles Android.

Dependiendo de la distribución que tengamos y de la versión de ésta, podemos vernos obligados por instalar LiME a mano, pero generalmente, las últimas versiones de la mayoría de las distribuciones nos permiten instalar la herramienta desde los repositorios; cosa altamente recomendable, ya que el instalarla a mano nos puede dar problemas debido a que suele requerir de ciertas dependencias externas. Para instalar la herramienta desde los repositorios basados en Debian, junto con una serie de dependencias que son importantes tener instaladas, habría que escribir el siguiente comando:

apt-get install make build-essential lime-forensics-dkms

La instalación es automática y a primera vista, no apreciaremos ningún cambio; es más, no veremos ningún comando que haga referencia a LiME. Esto es debido a que LiMe trabaja como si se tratase de un módulo del Kernel; un módulo que tendría que ser cargado a mano, ya que dicho módulo tiene la función de volcar la memoria, y es un módulo que no funciona de la misma forma que el resto. Aún así vayamos por pasos... ¿Donde se halla dicho módulo? Para no andar volviéndonos locos buscando éste, nuestra mejor opción es recurrir al comando modinfo:

modinfo lime

Gracias a este comando, lograríamos ver la información de dicho módulo, esté o no cargado en el kernel, cosa interesante, ya seas para conocer la ubicación de este módulo como la de cualquier otro. Este módulo en concreto tendría la siguiente ubicación (válida para cualquier Kernel): /lib/modules/$(uname -r)/updates/dkms/lime.ko.

A sabiendas de donde tenemos dicho módulo, tendríamos que cargarlo en el kernel; si bien el método para cargarlo es ligeramente diferente al habitual. La forma para cargar el módulo y, al mismo tiempo, realizar el volcado de la memoria RAM, sería:

insmod /lib/modules/$(uname -r)/updates/dkms/lime.ko "path=/tmp/RAM.lime format=lime"

El proceso tardaría desde unos segundos a varios minutos, dependiendo de la cantidad de RAM a volcar. Es importante tener en cuenta que tras terminar el proceso de volcado, el módulo lime quedaría cargado, pero no estaría continuando volcando memoria; es decir que tras cargar el módulo lime, tendríamos un volcado completo de la RAM.

Si deseasemos optar por un volcado desde un equipo remoto, tendríamos que cargar el módulo de la siguiente forma:

insmod /lib/modules/$(uname -r)/updates/dkms/lime.ko "path=tcp:4444 format=lime"

Para después desde un equipo remoto obtener el volcado de memoria. Imaginemos que hemos realizado el volcado de memoria de esta forma en un equipo con IP: 192.168.1.2; para obtener remotamente dicho volcado, el otro equipo tendría que tener netcat instalado y poder acceder a dicha IP y puerto (4444). Cumpliendo dichos requisitos, desde el otro equipo haríamos:

192.168.1.2 4444 > /tmp/RAM.lime


Como veis la obtención de la información de la memoria RAM no es difícil, si bien obviamente dicho volcado no es "legible"; es decir que no es un volcado en texto plano, sino que requiere de herramientas especiales que tengan la capacidad de leer la información existente en el archivo. Para este punto la mejor alternativa sería recurrir a la herramienta de lectura de volcados de memoria más famosa en Linux: Volatility.

Esta herramienta es famosa por ser Open Source y estar preparada para leer volcados de memoria extraídos tanto de Windows, Linux y Mac; siendo una herramienta de lo más versátil. Dicha utilidad puede ser descargada desde GitHub, pero al igual que con LiME, yo recomiendo que a ser posible se descargue desde los repositorios, ya que te descarga todas las librerías necesarias para ser plenamente operativa; cosa recomendable para evitarnos posibles problemas. La instalación de esta herramienta es muy sencilla, y debe de ir acompañada de otra utilidad que trabaja estrechamente con ésta, llamada dwardump; con lo que para instalar ambas herramientas juntas haríamos:

apt-get install dwarfdump volatility

Ahora bien, con tener esto instalado no basta; ya que Volatility trabaja con perfiles para leer la memoria; con lo que ésta tiene que tener un perfil que sea compatible con el volcado de memoria que se quiere leer. Un perfil sería un archivo, comprimido en formato zip, que contiene tanto la estructura como la información de un kernel, haciendo que Volatility sepa donde y cómo buscar la información en la RAM; sin dicho perfil Volatility no sabría qué buscar ni donde hacerlo. Volatility incluye perfiles Windows por defecto, pero por desgracia no tiene ni un solo perfil de Linux incluido por defecto con lo que tenemos dos opciones:

  • Descargarnos un perfil "preconstruido" desde: 

  • Crearnos nuestro propio perfil; cosa que generalmente se recomienda, ya que los perfiles que hay online son genéricos y se han creado bajo una versión de kernel y una CPU que no tiene por qué ser compatible con lo que nosotros tenemos. 

Es importante tener en cuenta que el perfil tiene que ser del mismo "tipo" que del sistema del que hemos extraído el volcado de memoria, ya que en caso contrario volatility será incapaz de leer el volcado de memoria. Por ejemplo si hemos hecho una extracción desde un Fedora; un perfil Debian no sería válido para leerlo.  

En este caso en concreto esa posible incompatibilidad no se va a dar ya que vamos a hacer un perfil propio nosotros mismos y al querer leer una captura de memoria RAM realizada en nuestro propio equipo, la compatibilidad va a ser del 100%.

Para crear el perfil, lo primero que tendremos que hacer será crear un módulo dwarf especialmente diseñado para nuestro sistema. Dicho módulo se encargaría de leer la información del sistema y hacerla legible para la herramienta, y es uno de los componentes del perfil que necesitamos crear para la lectura de la memoria. Para ello haremos lo siguiente:

  1. cd /usr/src/volatility-tools/linux/
  2. make

En caso de no habernos dado ningún mensaje de error, debería de haber creado dentro de la carpeta /usr/src/volatility-tools/linux, el fichero module.dwarf.

Ahora que tenemos el fichero creado, es hora de crear nuestro perfil, que se trata de un archivo comprimido que contiene el fichero que hemos creado y nuestro System.map. Dicho perfil se almacena dentro de /usr/lib/python2.7/dist-packages/volatility/plugins/overlays/linux (siempre y cuando lo hayamos instalado desde los repositorios) y para crearlo realizaríamos el siguiente comando:

  1. zip /usr/lib/python2.7/dist-packages/volatility/plugins/overlays/linux/Perfil.zip \
  2. /usr/src/volatility-tools/linux/module.dwarf /boot/System.map-$(uname -r)

Con el fichero comprimido alojado en la ubicación correcta, pasaríamos  a usar Volatility. Lo primero que deberíamos hace sería mirar que, efectivamente,  el perfil está preparado para ser usado. La mejor forma de saberlo sería con el comando de a continuación:

volatility --info |grep Linux

Perfil_Volatility

En este caso, veremos un perfil con nombre LinuxDebianx64 en cuya descripción dice claramente el tipo de perfil que es. Si os fijáis bien, el nombre que se ha puesto al perfil no importa (en mi caso he puesto antes como nombre Perfil.zip) ya que lo que le importa a Volatility es el contenido de dicho fichero zip. A sabiendas que tenemos un perfil válido, leeríamos el volcado de memoria, si bien antes de nada hay que tener en cuenta que la sintaxis de Volatility para leer un volcado es la siguiente:

volatility -f fichero.lime --profile nombre_perfil acción

Por ejemplo:

volatility -f /tmp/RAM.lime --profile LinuxDebianx64 linux_bash

Con este comando en concreto lo que haríamos sería obtener el historial de los últimos comandos realizados; una información que a primera vista puede parecer inofensiva, pero que puede ser muy valiosa... Pero no solo podemos obtener el historial; dependiendo de la acción que elijamos podemos obtener datos de lo más curiosos; hay muchísimas acciones pero las más útiles serían:

  • linux_pstree: Lista los procesos que estaban corriendo en el sistema cuando se realizó el volcado de la memoria.
  • linux_lsmod: Lista los módulos que estaban cargados en el kernel en el momento que se extrajo la memoria.
  • linux_netstat: Muy útil; con este se conocen los puertos abiertos en el equipo; una información muy valiosa y al mismo peligrosa.
  • linux_arp: Muestra la tabla ARP del equipo del que se ha realizado el volcado... Dicha información puede parecer inofensiva, pero recordad que la tabla ARP muestra la IP y la MAC de los "vecinos" de aquel equipo.
  • linux_ifconfig: La RAM también almacena la IP del equipo, con lo que obviamente es una información que puede extraerse de ésta.

Existen muchas más acciones que las que he mencionado, pero estas son mi opinión las más interesantes; ya que ofrecen una información de lo más curiosa... Y valiosa. 


Con este artículo no quiero dar a entender que la memoria RAM sea más o menos vulnerable que otros elementos de un equipo, pero sí que creo que es útil conocer lo valiosa que puede resultar como fuente de información dicha memoria; un factor que muchas veces no se tiene en cuenta.

Espero que os haya resultado útil.

Saludos.

viernes, 30 de septiembre de 2016

Cómo recuperar archivos borrados en Linux

En más de una ocasión he hablado de la importancia de la salvaguarda de datos y de diferentes métodos de prevención de borrados accidentales o recuperación de datos; tales como el uso del shred para borrar del todo un archivo o de cómo evitar que el comando rm sea tan "destructivo". Ambos conceptos son muy útiles en determinadas circunstancias, pero imaginemos que no hemos aplicado ningún método de prevención para que rm no borre como lo hace habitualmente, es decir que hemos ejecutado el comando rm y que éste ha hecho lo que debe, es decir borrar el archivo o al menos hacer que este no sea un recurso accesible... Los bytes de dicho archivo siguen estando allí a menos que sean sobrescritos, con lo que en caso de que un archivo haya sido borrado recientemente, tenemos altas posibilidades de recuperarlo, cosa que haremos en este artículo de hoy... Hay dos herramientas particularmente famosas que realizan tareas de recuperación; una de ellas es llamada photorec, mientras que la otra, que ha ido ganando popularidad estos últimos años, se trata de de foremost.

Portada_foremost

Foremost es una herramienta basada en consola cuya principal virtud es su facilidad de uso pues apenas requiere de curva de aprendizaje alguna... Además

 y si bien no es una utilidad que se encuentre instalada por defecto en el sistema, se puede instalar muy rápidamente mediante los repositorios oficiales tal que así:

apt-get install foremost

Esta instalación incluirá todos los binarios necesarios para la recuperación de archivos, binarios que usarán una técnica llamada File Carving, que buscará archivos que hayan sido "eliminados" de la indexación del disco duro pero que físicamente se encuentre presentes en el disco, siempre y cuando éstos se encuentre íntegros; es por eso que cuanto más reciente haya sido la eliminación del archivo, más posibilidades habrán de que el archivo sea recuperado. Los formatos de archivo soportados son: jpg, gif, png, bmp, exe, rar, riff, wmv, mov, pdf, ole, doc, zip, htm y cpp; con lo que generalmente tendremos bastantes posibilidades de poder recuperar el archivo borrado en cuestión, si bien obviamente podemos tener la mala suerte de haber borrado un fichero en un formato "no reconocido".

A la hora de usar esta herramienta hay una recomendación muy importante, que es que el destino donde se guarde el archivo restaurado se guarde en una partición diferente a la del origen; es decir que si hemos borrado un archivo en un la partición /dev/sda1, lo suyo sería restaurarlo en una partición diferente que puede ser perfectamente una unidad USB, por ejemplo.

Imaginemos que cumplimos todas las recomendaciones; es decir que hemos borrado uno o varios ficheros y que tenemos una partición diferente a mano... Para ponerlo en un caso real, supongamos que teníamos varios archivos en un USB y que los hemos borrado y que deseamos restaurarlos en nuestro disco duro; la unidad USB siempre se encuentra en una partición distinta, con lo que jamás causaría conflicto con el resto, ya sea como partición de origen o de destino. Generalmente el disco duro sería /dev/sda1 y la unidad USB /dev/sdb1.

Para realizar esa restauración lo primero que haríamos sería crear un directorio donde almacenar nuestros archivos recuperados; tal y como hemos dicho antes, el destino de restauración sería el disco duro con lo que crearíamos un directorio en este. Un directorio de ejemplo podría llamarse recuperado, con lo que crearemos un directorio tal que así:

mkdir /tmp/recuperado

El destino estaría preparado, solamente quedaría conocer el origen, que sería el USB. Simplemente habría que conectar el USB y conocer el nombre de su "partición" escribiendo el comando:

fdisk -l

Ahí aparecerán todas las particiones, incluyendo por supuesto nuestro USB... En nuestro caso sería /dev/sdb1

Con todos los requisitos cumplidos, lo primero que habría que conocer es la estructura usada en foremost, la cual es muy sencilla:

foremost -t ${formato} -i ${origen} -o {destino}

Al hacer referencia al formato estaríamos diciendo si queremos recuperar los archivos de un formato en concreto o no... En caso de querer recuperar todos los archivos de todos los formatos disponibles, simplemente habría que poner all en el formato de recuperación, cosa que se suele hacer a menudo. En caso de querer poner un formato en concreto simplemente habría que poner uno de los mencionados anteriormente, tales como jpg, gif, rar... Para nuestro caso en concreto el comando de recuperación sería:

foremost -t all -i /dev/sdb1 -o /tmp/recuperado

El comando tardará cierto tiempo en realizar el proceso de recuperación, tiempo que generalmente variará dependiendo del tamaño del origen... Pasados unos minutos, el proceso finalizará y simplemente tendremos que desplazarnos al directorio de destino para disfrutar de nuestro contenido recuperado; aquí veremos que se han creado diferentes subdirectorios, uno por cada formato distinto que se ha restaurado, además de un fichero llamado audit.txt que contiene toda la información resumida de los ficheros restaurados . En mi caso por ejemplo tengo el siguiente listado:

Lista_recuperados

Cada directorio tendrá sus correspondientes ficheros, pero veréis que, desgraciadamente el nombre de cada uno de éstos es ininteligible... Esto se debe a que, cuando se borra el archivo, su nombre pasa a ser su número de inodo, tal y como también ocurre con los archivos recuperados en lost+found. Aún así, esto no supone un problema demasiado grande, pues estos ficheros conservan sus metadatos, con lo que si consultamos cualquier de los ficheros con la utilidad exiftool, podremos datos muy informativo, entre ellos su título, el cual nos dará una idea muy aproximada de las características del fichero, tal y como podemos ver en el fichero de a continuación:

exiftool_resultado

Gracias a la combinación de estas dos herramientas: Foremost y exiftool; la recuperación de archivos borrados es muy sencilla, y si bien obviamente la efectividad de esta técnica depende en gran parte de que los bytes del fichero no se hayan sobrescrito, podemos recuperar archivos borrados recientemente sin demasiadas complicaciones.

Espero que os haya resultado útil.

Saludos.