[Ubuntu-ni] Para los Fans de ext3
Carlos Ortiz Gutierrez
cortizg en ubuntu.org.ni
Jue Oct 4 21:10:37 BST 2007
Porqué es difícil recuperar un fichero borrado de
EXT3<http://belinux.wordpress.com/2007/07/16/porque-es-dificil-recuperar-un-fichero-borrado-de-ext3/>Posted
by makj under
HowTO <http://es.wordpress.com/tag/howto/> ,
Seguridad<http://es.wordpress.com/tag/seguridad/>,
Tutorial <http://es.wordpress.com/tag/tutorial/>
[traducción del artículo original que se encuentra en ésta
página<http://linux.sys-con.com/read/117909.htm>
]
Todos lo hemos hecho antes: accidentalmente tecleas el argumento incorrecto
al hacer *rm* o seleccionas el fichero incorrecto para su borrado, al pulsar
enter te das cuenta de tu error y tu estómago da un vuelco. Y cuando vas a
buscar la copia de seguridad del sistema no hay ninguna.
Hay muchas herramientas de desborrado para sistemas FAT y NTFS, pero hay muy
pocas para EXT3, que es actualmente el sistema de fichero por defecto de
muchas distribuciones Linux. Esto es debido al modo en que los ficheros EXT3
son eliminados: información crucial que almacena donde está localizado el
contenido del fichero es eliminada durante el proceso de borrado.
En este artículo, echaremos un vistazo a bajo nivel de porqué la
recuperación es dificil y a algunas aproximaciones que son efectivas algunas
veces. Usaremos herramientas de código abierto para la recuperación, pero
las técnicas no son completamente automáticas.
*¿Qué es un fichero?*
Antes de poder ver como recuperar ficheros, necesitamos ver como se
almacenan. Típicamente, los sistemas de ficheros están localizados dentro de
particiones de disco, que a su vez está organizada en sectores (usualmente
de 512 bytes). Cuando la partición está formateada usando EXT3, los sectores
consecutivos son agrupados en bloques, cuyo rango puede variar entre 1024 y
4096 bytes. Los bloques son agrupados juntos en grupos de bloques, cuyo
tamaño será de decenas de miles de bloques. Cada ficheros tiene sus datos
almacenados en tres ubicaciones principales: bloques, inodos y entradas de
directorio. El contenido del fichero se almacena en bloques, que son
dispuestos para el uso exclusivo de ese fichero, expandiéndose por tantos
bloques como sea necesario. Idealmente, el fichero debería utilizar bloques
consecutivos, pero esto no es siempre posible.
Los metadatos del fichero son almacenados en una estructura de inodo, que se
encuentra en una tabla de inodos colocada en el inicio de un grupo de
bloques. Hay un número finito de inodos y cada uno es asignado a un grupo de
bloques. Los metadatos de un fichero incluyen los datos temporales tales
como la última modificación, el último acceso, el último cambio y la fecha
de borrado. También incluye el tamaño del fichero, el identificador de
usuario y de grupo, los permisos, y las direcciones de los bloques donde se
puede encontrar el contenido del fichero.
Las direcciones de los primeros 12 bloques son guardadas en el inodo y las
direcciones adicionales son almacenadas externamente en bloques, llamados
bloques indirectos. Si el fichero requiere muchos bloques y no todas las
direcciones caben en un bloque indirecto, un doble bloque indirecto es usado
cuya dirección se incluye en el inodo. El doble bloque indirecto contiene
direcciones de bloques indirectos simples, que contienen direcciones de
bloques con datos de fichero. Hay incluso direcciones indirectas triples en
el inodo que añaden una capa más de punteros.
Por último, el nombre del fichero está almacenado en una estructura de
entrada de directorio ubicada en un bloque asignado al directorio padre del
fichero. Un directorio EXT3 es parecido a un fichero y sus bloques contienen
una lista de estructuras de entradas de directorio, cada una conteniendo el
nombre de un fichero y las dirección del inodo en el que se almacenan los
metadatos del fichero. Con el comando *ls -i* puedes ver la dirección del
inodo que corresponde a cada nombre de fichero. Se puede ver la relación
entre una entrada de directorio, el inodo y los bloques en la Figura
1<http://res.sys-con.com/story/aug05/117909/linux-carrier-fig1.gif>
.
Cuando un nuevo fichero es creado, el sistema operativo (SO) debe elegir que
bloques e inodo asignará al fichero. Linux intentará asignar los bloques y
el inodo en el mismo grupo de bloques que su directorio padre. Esto provoca
que los ficheros en un mismo directorio estén mucho más cercanos.
Posteriormente usaremos este hecho para restringir donde buscar datos
eliminados.
El sistema de ficheros EXT3 tiene un *journal* (*nota del traductor:* me
permito aquí mantener el término en inglés por comodidad en lugar de usar
bitácora o diario de registro, ya que cualquiera de los dos queda algo raro)
que registra las actualizaciones de los metadatos del sistea ANTES de que la
actualización ocurra. En caso de una caída del sistema, el SO lee el journal
y podrá reprocesar o deshacer las transacciones registradas para que la
recuperación sea mucho más rápida que examinar cada estructura de metadatos,
que era el antiguo y lentísimo mecanismo. Las estructuras de metadatos de
ejemplo incluyen las entradas de directorio que almacenan nombres de fichero
e inodos que almacenan los metadatos del fichero. El journal contiene el
bloque entero que está siendo actualizado, no solo el valor que está
cambiando. Cuando un nuevo fichero es creato, el journa debería contener la
versión actualizada de los bloques que contienen la entrada del directorio y
el inodo.
*El proceso de borrado*
Varias cosas ocurren cuando un fichero es borrado de un sistema EXT3 en
Linux. Hay que tener en cuenta que el SO debe decidir exactamente que ocurre
cuando un fichero es eliminado y éste artículo asume un sistema Linux
general.
Como mínimo, el SO debe marcar cada uno de los bloques, el inodo y la
entrada de directorio como no-asignados para que ficheros posteriores puedan
usarlos. Esta mínima aproximación es lo que ocurría hace años con los
sistemas EXT2. En ese caso, el proceso de recuperación era relativamente
simple ya que el inodo aún contenía las direcciones de los bloques del
contenido del fichero y herramientas tales como debugfs y e2undel podían
re-crear el fichero fácilmente. Esto funcionaba mientras que los bloques no
habían sido asignados a un nuevo fichero y el contenido original no había
sido sobreescrito.
Con EXT3, hay un paso adicional que hace la recuperación mucho más difícil:
cuando los bloques son desasignados, el tamaño del fichero y las direcciones
de los bloques en el inodo son limpiados; por tanto ya no podemos determinar
donde estaba el contenido del fichero. Podemos ver la relación entre la
entrada de directorio, el inodo y los bloques de un fichero desasignado en
la Figura 2<http://res.sys-con.com/story/aug05/117909/linux-carrier-fig2.gif>
.
*Aproximaciones de recuperación*
Ahora que conocemos los componente involucrados con los ficheros y cuales
son limpiados durante el borrado, podemos examinar dos aproximaciones a la
recuperación de ficheros (aparte de usar un backup). La primera aproximación
usa el tipo de aplicación del fichero eliminado y la segunda aproximación
usa los datos en el journal. Independientemente de la aproximación, debería
dejar de usar el sistema de ficheros porque podría crear un fichero que
sobreescriba los datos que está tratando de recuperar, puede detener su
sistema y poner el disco en otro ordenador con un sistema Linux como un
disco esclavo (*slave*) o arrancar desde un Linux LiveCD (knoppix o
necromantux son buenas distribuciones para este tipo de tareas).
El primer paso para ambas técnicas es determinar la dirección del inodo del
fichero eliminado. Esto puede ser determinado usando debugfs o The Sleuth
Kit (TSK). Mostraré aquí el método usando debugfs ya que esta herramiento se
incluye en muchas distribuciones Linux y es un depurador del sistema de
ficheros. Para empezar con debugfs, debe saber el nombre del dispositivo de
la partición que contiene el fichero eliminado. En mi ejemplo, he iniciado
desde un LiveCD y el fichero está ubicado en /dev/hda5:
# debugfs /dev/hda5
debugfs 1.37 (21-Mar-2005)
debugfs:
Podemos usar el comando *cd* para cambiar al directorio del fichero
eliminado:
debugfs: cd /home/carrier/
El comando *ls -d* listará los ficheros asignados y eliminados del
directorio. Recuerde que la estructura de entrada de directorio almacena el
nombre e inodo de los ficheros y este listado nos dará ambos valores ya que
ninguno es eliminado durante el proceso de borrado. Los ficheros eliminados
tendrán su dirección de inodo delimitado por "<" y ">":
debugfs: ls -d
415848 (12) . 376097 (12) .. 415864 (16) .bashrc
[…]
<415926> (28) oops.dat
El fichero que estamos intentando recuperar es */home/carrier/oops.dat* y
podemos verlo previamente asociado al inodo 415,926. El "(28)" nos indica la
longitud de la estructura de entrada de directorio, pero eso no nos
interesa.
*Recuperación por "esculpido" de ficheros (file carving) *
La primera técnica de recuperación, llamada *file carving* (*nota del
traductor:* mantendré el nombre en inglés), utiliza las firmas del fichero
eliminado. Muchos tipos de ficheros tienen valores estándar en los primeros
bytes de la cabecera del fichero, y ésta técnica de recuperación busca los
valores de cabecera del fichero eliminado para determinar donde puede que
empezara el fichero. Por ejemplo, los ficheros JPEG empiezan con 0xFFD8 y
terminan con 0xFFD9. Para recuperar un fichero JPEG eliminado, deberíamos
buscar en los dos primeros bytes de cada bloque hasta encontrarnos con la
marca OxFFD8. Cuando encontrásemos ese bloque, deberíamos buscar un bloque
con los bytes 0xFFD9 en él. Los datos intermedios se asume que era el
fichero. Desafortunadamente, no todos los tipos de ficheros tienen una firma
final, por tanto determinar el final es dificil. Un ejemplo de una
herramiento de código abierto que hace *file carving *es foremost, también
existen varias herramientas comerciales.
Podemos ejecutar una herramienta como *foremost* en un sistema de ficheros
completo, pero acabaríamos probablemente con demasiados ficheros, incluyendo
algunos ya asignados. Será preferible lanzarlo sobre cuantos menos datos sea
posible. La primera manera en que podemos restringir el tamaño de los datos
es examinar sólo los grupos de bloques donde el fichero estaba ubicado.
Recuerde que los inodos y los bloques de un fichero están asociados a un
mismo grupo de bloques, si hay espacio. En nuestro caso, sabemos que inodo
usaba el fichero y por tanto podemos examinar sólo los bloques del mismo
grupo. El comando* imap* en *debugfs* nos indicará a que grupo de bloques
pertenece un inodo:
debugfs: imap <415926> Inode 415926 is part of block group 25
located at block 819426, offset 0×0a80
La salida del comando *fsstat* en *TSK* nos dirá también lo siguiente:
# fsstat /dev/hda5
[…]
Group: 25:
Inode Range: 408801 - 425152
Block Range: 819200 - 851967
A continuación, necesitamos determinar los bloques que están en el grupo de
bloques del fichero eliminado. Podemos verlos en la salida del comando *
fsstat* mostrado anteriormente, pero si estuvieramos usando *debugfs*,
necesitamos calcular el rango. El comando stats nos da el número de bloques
en cada grupo:
debugfs: stats
[…]
Blocks per group: 32768
[…]
Puesto que estamos buscando en el grupo de bloques 25, el rango de bloques
va desde 819,200 (25 * 32,768) hasta el 851,967 (26 * 32,768 - 1). Si nos
centramos sólo en estos bloques, estaremos mirando en 128Mb en lugar de en
el sistema de ficheros completo. Aún así, si no podemos encontrar el fichero
en estos bloques, necesitaremos mirar en todo el sistema de ficheros.
El siguiente paso para reducir los datos a analizar es extraer los bloques
no asignados del sistema de ficheros ya que ahí es donde nuestro fichero
eliminado estará. *debugfs* no nos permite actualmente extraer el espacio no
asignado de sólo un grupo de bloques específico, por tanto deberemos usar la
herramienta *dls* de *TSK*.
# dls /dev/hda5 819200-851867 > /mnt/unalloc.dat
El comando anterior nos guardará los bloques no asignados en el grupo de
bloqes 25 en un fichero llamado /mnt/unalloc.dat . Asegurese que este
fichero esté en un sistema de ficheros diferente ya que de otro modo podría
acabar sobreescribiendo su fichero eliminado.
Ahora podemos ejecutar la herramienta foremost sobre los datos no asignados.
foremost puede recuperar sólo tipos de ficheros para los que se haya
configurado. Si foremost no tiene la firma de cabecera para el tipo del
fichero eliminado, deberá examinar algunos ficheros similar y personalizar
el fichero de configuración. Podemos ejecutarlo del siguiente modo:
# foremost -d -i /mnt/unalloc.dat -o /mnt/output/
La opción -d intentará detectar que bloques son indirectos y no los incluirá
en el fichero final. El directorio /mnt/output contendrá los ficheros que
hayan podido ser recuperados. Si su fichero no está ahí, puede expandir su
búsqueda a todos los bloques no asignados en el sistema de ficheros en lugar
de sólo a los bloques del grupo.
*Recuperación basada en journal*
El segundo método para tratar de recuperar ficheros es usar el journal. Ya
hemos visto que las actualizaciones de inodos se guardan primero en el
journal, pero el concepto importante es que el bloque entero en el que el
inodo está ubicado es guardado en el journal. Por tanto, cuando un inodo es
actualizado, el journal contendrá copias de otros inodos almacenados en el
mismo bloque. Versiones anteriores del inodo de nuestro fichero elimiando
pueden existir en el journal porque otro fichero fuera actualizado antes del
borrado.
La maner más fácil de buscar versiones anteriores del inodo es usando el
comando* logdump -i *en *debugfs*:
debugfs: logdump -i <415926>
Inode 415926 is at group 25, block 819426, offset 2688
Journal starts at block 1, transaction 104588
FS block 819426 logged at sequence 104940, journal block 2687
(inode block for inode 415926):
Inode: 415926 Type: regular Mode: 0664 Flags: 0×0
User: 500 Group: 500 Size: 2048000
[…]
Blocks: (0+12): 843274 (IND): 843286
[…]
En este caso, podemos encontrar una copia previa del inodo y los bloques del
contenido del fichero están listados en la última línea. La última línea
muestra que el primer bloque del fichero es 843,274 y los siguientes 12
bloques en el sistema de ficheros son los siguientes 12 bloques del fichero.
El fichero es grande y necesita un bloque indirecto, que está localizado en
el bloque 843,286. Hasta aquí, todos los bloques son consecutivos y no había
fragmentación. El bloque 843,286 contiene el resto de direcciones de
bloques, así que podríamos buscar en una versión anterior para descubrir
donde está ubicado el resto del fichero. Podemos ver si hay una copia en el
journal usando* logdump -b*:
debugfs: logdump -b 843286 -c
Desafortunadamente, no encontramos una copia del bloque que contiene la
lista original de punteros de bloque así que, si queremos recuperar el
fichero deberemos asumir que el resto del contenido del fichero está
guardado en el bloque 843,287 y siguientes. Una aproximación más avanzada
podría también considerar qué bloques están actualmente asignados y
saltarnoslos. Los datos pueden ser extraidos con herramientas tales como *dd
* o *Linux Disk Editor*. El journal puede ser consultado también usando las
herramientas *jls* y *jcat* de *TSK*.
*Conclusión*
La recuperación de ficheros con EXT3 no es una tema trivial, lo que refuerza
el concepto de la importancia de hacer copias de seguridad de los ficheros.
Si el fichero no estaba fragmentado, la búsqueda de su firma de cabecera
puede ser útil, pero la herramienta necesita saber ignorar los bloques
indirectos y donde parar de copiar (no todos los ficheros tienen una marca
de final de fichero). Restringiendo la búsqueda al grupo de bloques local
puede ahorrar mucho tiempo. El journal puede ser útil si los ficheros cerca
del fichero eliminado han sido reciéntemente actualizados y por tanto existe
una versión previa del inodo, pero esto no está siempre garantizado y el
bloque indirecto del fichero puede no existir.
--
Carlos Ortiz Gutierrez
cortizg en ubuntu.org.ni
cortizg en gmail.com
mobil:5058338893
ubuntu user #: 14177
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: https://lists.ubuntu.com/archives/ubuntu-ni/attachments/20071004/3b7a55a3/attachment.htm
Más información sobre la lista de distribución Ubuntu-ni