Con el desarrollo progresivo de los métodos de investigación forense, en los foros públicos, BBS's empezaron a aparecer posts referentes a las técnicas que los intrusos pueden utilizar para evitar que un forense cualificado pueda llevar acabo su trabajo con éxito. El trabajo del investigador forense depende de las pruebas encontradas en el sistema de ficheros de la máquina comprometida en todo caso, en el supuesto de que no exista ninguna prueba la eficacía de la investigación se reduce a nada.
El objetivo detrás de cualquier investigación realizada por un forense o un equipo de respuesta rápida sobre un sistema de ficheros puede ser de tipo 'legal' o 'casual'. Teniendo en consideración que estos términos no tienen un significado estandarizado para describir los motivos de una investigación y cada uno de ellos se diferencia bastante del otro debemos detallar más.
Investigación Legal: La mayoría de las investigaciones forenses de tipo legal tienen como objetivo asistir a los órganos oficiales a llevar acabo una investigación criminal a fin de llevar ante la justicia al culpable del delito. En investigaciones de este tipo es imprescindible seguir de forma estricta los procedimientos para el tratamiento de pruebas que van a ser presentadas en el juzgado. Por ejemplo, el mero error de sobreescribir cualquier prueba en el sistema de ficheros por información aleatoria (pérdida de datos) es suficiente para considerar el resto de las pruebas de la misma índole como inviables por parte de un juez o fiscal. Investigaciones legales, a menudo, únicamente se limitan a la conservación de datos y esfuerzos de mantener la integridad de información en el sistema de ficheros una vez el hecho del compromiso ha sido probado. Las pruebas tras ser tratadas de forma correcta se transfieren al poder de órganos oficiales para ser analizados por parte de sus recursos. El nivel de participación del forense en la investigación una vez las pruebas han sido transferidas depende del deseo del denunciante y la voluntad de órganos oficiales.
Investigación Casual: Cualquier tipo de investigación casual no tiene como objetivo la persecución legal del individuo responsable del acto criminal. La investigación se realiza por el interés desde el punto de vista forense, por lo tanto las técnicas, herramientas y metodología utilizada puede ser usada de forma más agresiva. La realización de una investigación forense casual requiere más conocimiento y experiencia por parte del investigador, ya que en estos casos no existen requerimientos estrictos de terceros referentes a la cantidad y calidad de pruebas obtenidas.
Indiferentemente del tipo de investigación los pasos iniciales deben ser básicamente los mismos en cada caso:
El concepto de prueba se forma por el contenido de los ficheros (datos) y la información sobre los ficheros (meta-datos). Basándose en las pruebas obtenidas del sistema de ficheros el investigador debe intentar a:
Como un ejemplo de proceso forense examinaremos un caso de recuperación de un fichero eliminado.
Cuando hablamos de borrar un archivo bajo GNU/Linux, Unix queremos decir que el contador interno de enlaces inode (i_links_count) se decrementa a 0. El decremento es alcanzado eliminando todos los pares de inodes de la tabla de directorio referentes al nombre del fichero. Una vez el inode es eliminado, el núcleo marcará este recurso como disponible para uso por otros ficheros o procesos, nada más. El inode eliminado va a seguir conteniendo la información sobre el fichero referenciado y los bloques de datos a que el inode hace referencia seguirán teniendo el contenido del archivo. Este estado se mantendrá hasta que el espacio se re-asigne y se reuse sobreescribiendo los datos residuales. Por lo tanto la recuperación de ficheros eliminados es esencial para cualquier analista forense, dicho en otras palabras la recuperación de archivos se reduce a la búsqueda de inodes con datos pero con el contador de enlaces a 0 (es decir no vírgenes). El resultado es el listado de inodes borrados. Los punteros indicarán el offset de bloques que contienen los datos del fichero, lo que permitirá posiblemente recuperar el/los archivo/s eliminados. Aunque los bloques de datos ya estén ocupados por otra información (imposible recuperar el/los fichero/s) el analista puede obtener mucha información sobre lo que ha ocurrido en el sistema de ficheros examinando los meta-datos presentes en el directorio de entradas y inodes.
Los meta-datos no son asequibles a través de la interfaz de llamadas de sistema del núcleo, por lo tanto no son alterables por las herramientas estándares del sistema operativo (desde el punto de vista forense). La industria forense digital hasta ahora tenía pocos problemas para analizar de forma efectiva sistemas de ficheros de servidores comprometidos, pero este hecho está cambiando.
[Subir]
Definición: El término de evasión forense (anti-forensics) se refiere a las técnicas de eliminación y/o de ocultación de pruebas para complicar o imposibilitar la efectividad del análisis forense.
El análisis forense informático está ocupando rápidamente un lugar importante en procedimientos de respuesta a incidentes. Hace varios años sólo existía un número limitado de profesionales y aplicaciones capaces de detectar de forma estandarizada los indicios en una investigación forense, incrementándose últimamente la demanda de estos profesionales y el número de herramientas disponibles.
Es asombroso, que a pesar del interés creciente en el área de informática forense, dentro de la industria de seguridad informática, se habla muy poco sobre temas de evasión forense o anti-forensics. Para remediar la carencia de la cobertura, este anexo, basado en la publicación del Phrack, presenta algunas técnicas y estrategias de evasión al análisis forense sobre sistemas de ficheros GNU/Linux y Unix. Están incluidos ejemplos de estas técnicas utilizando como base el sistema de ficheros utilizadas de forma más común - ext2fs.
[Subir]
b. Resumen Sistema de Ficheros ext2fs
Esta sección describirá la teoría del sistema de ficheros de Unix sin centrarse en las implementaciones o distribuciones específicas, cubriendo la estructura interna de meta datos usados para organizar el sistema de ficheros. Los archivos dentro del sistema operativo Unix son streams continuos de bytes de longitud arbitraria usados para la entrada y salida. Este documento se centrara en archivos en su sentido amplio de almacenamiento de datos en el disco y su organización por sistemas de ficheros.
Los datos en un disco con sistema de fichero Unix se dividen normalmente en dos grupos, la información sobre los archivos y los datos dentro de los archivos. La información de organización y estadística de sistema de ficheros (normalmente sólo visible al núcleo) se llama los "meta datos", e incluye los siguientes partes: el super-block, los inodes y los datos de directorio. El contenido almacenado dentro de los ficheros se considera simplemente como "información".
Para crear la imagen abstracta de un fichero el kernel tiene que traducir de forma transparente al usuario los datos almacenados en uno o más sectores del disco duro en una secuencia de bytes. El sistema de ficheros se utiliza para no perder de vista cuales, y en qué orden deben ser agrupados los datos para montar un fichero. Además, los grupos de sectores deben ser guardados de forma separada y ser visibles al sistema operativo de forma individual. Por esa razón existen varios tipos de "meta-datos", siendo cada uno de los tipos responsable de realizar una de las siguientes tareas.
El contenido de un archivo se almacena en bloques de datos que son clusters lógicos de sectores del disco duro. Cuanto más alto es el número de sectores por bloque de datos cuanta más rápida es la velocidad de la E/S del disco, mejorando el rendimiento del sistema de ficheros. Al mismo tiempo, cuanto más grande es el tamaño de bloques de datos más espacio de disco duro se derrocha para los archivos que no terminan en los límites del bloque. Los sistemas de ficheros modernos típicamente tienen el tamaño del bloque de 4096 o 8192 bytes y combaten el despilfarro del disco con "fragmentación" (algo no tratado en este documento).
La parte del disco dedicada a bloques de datos se organiza como un array, y los bloques son referidos por sus offsets dentro de este array. El estado de un bloque particular, es decir "libre" contra "utilizado", se almacena en un bitmap llamado "block bitmap".
Los bloques de datos son ordenados y organizados en archivos por inodes. El inode es la estructura de meta datos que representa archivos visibles al usuario; un inode para cada archivo único. Cada inode contiene un array de punteros del bloque de datos y otra información adicional sobre el archivo. Esa información adicional incluye los parámetros de UID, GID, tamaño, permisos, MAC, y otros ciertos datos. La cantidad de espacio limitada disponible para los inodes significa que el array del bloque puede contener solamente un número reducido de punteros.
Para permitir que los tamaños de los ficheros tengan un tamaño substancial, los inodes emplean "bloques indirectos". Un bloque indirecto actúa como una extensión al array del bloque, almacenando punteros adicionales. Los siguientes bloques indirectos contienen referencias a otros bloques indirectos, y estos otros bloques indirectos contienen referencia a siguientes bloques respectivamente (hasta almacenar el fichero). Los inodes se almacenan en un array llamado inode table, y son referidos por sus índices basados en 0 dentro de esta tabla. El estado de un inode, es decir libre contra utilizado, se almacena en un bitmap llamado de forma original "inode bitmap".
Los archivos, es decir, inodes, están asociados a nombres de los ficheros a través de las estructuras especiales llamadas directory entries y almacenadas dentro de ficheros de directorio. Estas estructuras se almacenan uno al lado del otro dentro del archivo de directorio. Las entradas de directorios tienen siguiente estructura básica:
struct dirent { int inode; short rec_size; short name_len; char file_name[NAME_LEN]; };
El elemento 'inode' de la estructura dirent contiene el número del inode que hace referencia al nombre del fichero, almacenado en la variable 'file_name'. Para ahorrar el espacio, la longitud real del nombre del fichero se registra variable 'name_len' y el espacio restante en el array file_name bajo el índice NAME_LEN y se utilizar por la siguiente estructura de entrada de directorio. El tamaño de un dirent se redondea generalmente hasta aproximadamente 2**2, y este dato se almacena en la variable 'rec_size'. Cuando se quita el enlace del nombre/inode del archivo, el valor del inode se fija a 0 y 'rec_size' del dirent precedente se extiende para abarcar el dirent eliminado. Esto tiene el efecto de almacenar los nombres de archivos suprimidos dentro de ficheros de directorio.
Cada vez que un nombre del archivo se asocia a un inode, el contador interno dentro del inode se incrementa. Asimismo, cada vez que se quita este enlace, el contador se decrementa. Cuando este contador alcanza el valor de 0, no quedan referencias al inode dentro de la estructura del directorio; eso significa que el archivo es borrado. Los archivos que han sido suprimidos pueden tener sus recursos, bloques de los datos, el inode sí mismo liberados con seguridad. Esto se logra modificando los bitmaps respectivos.
Los archivos de directorios se organizan de forma lógica como un árbol que empieza desde el directorio raíz. Este archivo de directorio de raíz se asocia al inode conocido (2) de modo que el núcleo pueda localizarlo, y monta el sistema de ficheros.
Para montar un sistema de ficheros el núcleo necesita conocer el tamaño y la ubicación de meta datos. La primera parte de meta datos - el "super block", se almacena en una ubicación conocida. El super-block contiene la información sobre el número de inodes y de bloques, del tamaño de un bloque, y mucha otra información adicional. Basándose en los datos contenidos dentro del super-block, el kernel puede calcular las localizaciones y los tamaños de la tabla de inodes y de la porción de los datos del disco.
Por razones del rendimiento, ningún sistema de ficheros moderno tiene sólo una tabla del inode y un array del bloque. Al contrario, los inodes y los bloques se organizan en grupos distribuidos a través del disco. Estos grupos normalmente contienen sus bitmaps privados de sus inodes y bloques, así como las copias del super-block para facilitar la recuperación en caso de la pérdida de datos.
En la siguiente sección cubriremos más en detalle la organización del sistema de ficheros ext2fs.
[Subir]
El 'second extended file system' (ext2fs) es un sistema de ficheros estandar de Linux OS. Este capítulo proporcionará detalles necesarios para conocer a fondo la organización de este sistema de ficheros. La lectura de este paper no servirá como sustitución al estudio de las especificaciones de este sistema de ficheros y examen de de los src del kernel y de la librería ext2fs. A continuación está la descripción del sistema de ficheros ext2 empezando por los bloques de datos, inodes y concluyendo con directorios.
Bloques - La unidad básica de un sistema de ficheros es un bloque de datos utilizado para almacenar el contenido de los ficheros. Tipicamente, desde el punto de vista físico y independientemente del sistema de ficheros, la unidad más pequeña de espacio en el disco duro es un sector (512 bytes), pero es muy poco desde el punto de vista del ratio entrada/salida de datos. Para incrementar el rendimiento múltiples sectores están agrupados en un cluster y son considerados como una unidad de almacenamiento de datos - bloque. Un bloque típico puede tener en ext2fs un tamañode 4096 bytes, pero también puede ser de 2048 bytes y incluso 1024 (8, 4 y 2 sectores respectivamente).
Inodes - La segunda parte del sistema de ficheros son inodes - el corazón del sistema de ficheros ext2fs. Los inodes contienen meta-datos sobre cada fichero incluyendo punteros (1) a los bloques de datos asociados, permisos (2) de los ficheros, tamaños (3), propietarios (4), grupos (5) así como mucha otra información útil. El formato de un inode ext2 es el siguiente:
--------------------------------------------------------------------------- struct ext2_inode { __u16 i_mode; /* Modo del Fichero */ __u16 i_uid; /* UID Propietario */ __u32 i_size; /* Tamaño en bytes */ __u32 i_atime; /* Fecha de Acceso */ __u32 i_ctime; /* Fecha de Creación */ __u32 i_mtime; /* Fecha de Modificación */ __u32 i_dtime; /* Fecha Eliminación */ __u16 i_gid; /* GID Propietario */ __u16 i_links_count; /* Contador de enlaces */ __u32 i_blocks; /* Contador de bloques */ __u32 i_flags; /* Marcadores Fichero */ union { struct { __u32 l_i_reserved1; } linux1; struct { __u32 h_i_translator; } hurd1; struct { __u32 m_i_reserved1; } masix1; } osd1; /* Información dependiente del Sistema Operativo 1 */ __u32 i_block[EXT2_N_BLOCKS];/* Punteros a los Bloques */ __u32 i_version; /* Versión de fichero NFS */ __u32 i_file_acl; /* Fichero ACL */ __u32 i_dir_acl; /* Directorio ACL */ __u32 i_faddr; /* Dirección del fragmente */ union { struct { __u8 l_i_frag; /* Número Fragmento */ __u8 l_i_fsize; /* Tamaño Fragmento */ __u16 i_pad1; __u32 l_i_reserved2[2]; } linux2; struct { __u8 h_i_frag; /* Número Fragmento */ __u8 h_i_fsize; /* Tamaño Fragmento */ __u16 h_i_mode_high; __u16 h_i_uid_high; __u16 h_i_gid_high; __u32 h_i_author; } hurd2; struct { __u8 m_i_frag; /* Número Fragmento */ __u8 m_i_fsize; /* Tamaño Fragmento */ __u16 m_pad1; __u32 m_i_reserved2[2]; } masix2; } osd2; /* Información dependiente del Sistema Operativo 2 */ }; ---------------------------------------------------------------------------
Existen dos uniones porque ext2fs ha sido diseñado para ser utilizado por sistemas operativas ligeramente diferentes (implementaciones, distros). Aparte de las cosas puntuales los únicos elementos de la unión que importan son estructuras linux1 y linux2, el resto de las estructuras simplemente ahora pueden ser consideradas como facilidades adicionales ya que en la última implementación ext2fs se ignoran. El uso del resto de los valores de un inode están explicadas a continuación:
--------------------------------------------------------------------------- #define EXT2_SECRM_FL 0x00000001 /* Borrado Seguro */ #define EXT2_UNRM_FL 0x00000002 /* Recuperación */ #define EXT2_COMPR_FL 0x00000004 /* Compresión del Fichero */ #define EXT2_SYNC_FL 0x00000008 /* Actualización Sincronizada */ #define EXT2_IMMUTABLE_FL 0x00000010 /* Fichero inmutable */ #define EXT2_APPEND_FL 0x00000020 /* Únicamente añadir contenido */ #define EXT2_NODUMP_FL 0x00000040 /* No permitir el dump del fichero */ #define EXT2_NOATIME_FL 0x00000080 /* No actualizar el registro atime */ /* Reservado para el uso de compresión de datos... */ #define EXT2_DIRTY_FL 0x00000100 #define EXT2_COMPRBLK_FL 0x00000200 /* Comprimir clusters */ #define EXT2_NOCOMP_FL 0x00000400 /* No realizar compresión */ #define EXT2_ECOMPR_FL 0x00000800 /* Error de compresión */ /* Fin marcadores de compresión --- algunos no se utilizan */ #define EXT2_BTREE_FL 0x00001000 /* formato directorio btree */ #define EXT2_RESERVED_FL 0x80000000 /* reservado para la librería ext2 */ ---------------------------------------------------------------------------
--------------------------------------------------------------------------- #define EXT2_NDIR_BLOCKS 12 #define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS #define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) ---------------------------------------------------------------------------
Algunos inodes tienen un significado especial dentro del sistema de ficheros.
--------------------------------------------------------------------------- #define EXT2_BAD_INO 1 /* Inode de bloques dañados */ #define EXT2_ROOT_INO 2 /* Inode de Raiz */ #define EXT2_ACL_IDX_INO 3 /* Inode ACL */ #define EXT2_ACL_DATA_INO 4 /* Inode ACL */ #define EXT2_BOOT_LOADER_INO 5 /* Inode del boot loader */ #define EXT2_UNDEL_DIR_INO 6 /* Inode de recuperación de un directorio borrado */ ---------------------------------------------------------------------------
El inode de bloques dañados contiene punteros a los bloques de datos que contienen sectores dañados en el disco duro. El inode raiz es el directorio raiz que contiene el inicio del todo el arbol de directorio. El resto de los inodes no se utilizan normalmente en sistemas de producción. El primer inode utilizado para los ficheros de usuarios es el 11. Este inode es el directorio "lost+found", creado por la herramienta mkfs.
Superblock - El superblock es el único medio básico para proporcionarl al kernel la información del estado del sistema de ficheros. Este bloque indica el número de inodes, bloques, grupos y además mucha otra información adicional. Los elementos dentro del superblock cambian más frecuentemente que la información sobre inodes o datos del grupo porque libext2fs añade más funcionalidades a ext2fs que puede no ser implementado dentro del kernel. El formato que examinamos es de e2fsprogs-1.19. El super block es de 1024 bytes, y su offset está a 1024 bytes del inicio de una partición.
El formato del super block es el siguiente:
--------------------------------------------------------------------------- struct ext2fs_sb { __u32 s_inodes_count; /* Contador de inodes */ __u32 s_blocks_count; /* Contador de bloques */ __u32 s_r_blocks_count; /* Contador bloques reservados */ __u32 s_free_blocks_count; /* Contador bloques libres */ __u32 s_free_inodes_count; /* Contador inodes libres */ __u32 s_first_data_block; /* Primer bloque de datos */ __u32 s_log_block_size; /* Tamaño del bloque */ __s32 s_log_frag_size; /* Tamaño fragmento */ __u32 s_blocks_per_group; /* # Bloques por grupo */ __u32 s_frags_per_group; /* # Fragmentos por grupo */ __u32 s_inodes_per_group; /* # Inodes por grupo */ __u32 s_mtime; /* Fecha de montura */ __u32 s_wtime; /* Fecha escritura */ __u16 s_mnt_count; /* Contador de montura */ __s16 s_max_mnt_count; /* Contador número máximo monturas */ __u16 s_magic; /* Firma mágica */ __u16 s_state; /* Estado sistema de ficheros */ __u16 s_errors; /* Comportamiento al encontrar errores */ __u16 s_minor_rev_level; /* Nivel de revisión - menor */ __u32 s_lastcheck; /* Fecha de última comprobación */ __u32 s_checkinterval; /* Periodo máximo entre comprobaciones */ __u32 s_creator_os; /* Sistema Operativo */ __u32 s_rev_level; /* Nivel de Revisión */ __u16 s_def_resuid; /* UID por defecto para bloques reservados */ __u16 s_def_resgid; /* GID por defecto para bloques reservados */ /* * Estos campos son para superblocks de EXT2_DYNAMIC_REV. * * Nota informativa: la diferencia entre las carácteristicas compatibles y * las incompatibles es que si dentro de las carácteristicas no soportadas * un valor está marcado y kernel no lo reconoce, rechazará la montura del * del sistema de ficheros. * */ __u32 s_first_ino; /* Primer inode no reservado */ __u16 s_inode_size; /* Tamaño estructura inode */ __u16 s_block_group_nr; /* grupo de bloques # de este superblock */ __u32 s_feature_compat; /* características compatibles */ __u32 s_feature_incompat; /* características incompatibles */ __u32 s_feature_ro_compat; /* carácteristicas de solo lectura */ __u8 s_uuid[16]; /* Uuid de 128-bit del volumen */ char s_volume_name[16]; /* nombre volumen */ char s_last_mounted[64]; /* último punto de montura */ __u32 s_algorithm_usage_bitmap; /* para compresión */ /* * Sugerencias de rendimiento. Si el registro EXT2_FEATURE_COMPAT_DIR_PREALLOC * está activado, los directorios se reservan. */ __u8 s_prealloc_blocks; /* Número de bloques intentar reservar */ __u8 s_prealloc_dir_blocks; /* Número bloques reservar para directorios */ __u16 s_padding1; /* * Soporte para journaling. */ __u8 s_journal_uuid[16]; /* uuid del superblock del journal */ __u32 s_journal_inum; /* número inode del fichero journal */ __u32 s_journal_dev; /* número de dispositivo del fichero journal */ __u32 s_last_orphan; /* inicio de la lista de inodes a eliminar */ __u32 s_reserved[197]; /* Marca de finalización del bloque */ }; ---------------------------------------------------------------------------
-------------------------------------------------------------------------- #define EXT2_VALID_FS 0x0001 /* Desmontado correctamente */ #define EXT2_ERROR_FS 0x0002 /* Errores detectados */ ---------------------------------------------------------------------------
--------------------------------------------------------------------------- #define EXT2_ERRORS_CONTINUE 1 /* Continuar ejecución */ #define EXT2_ERRORS_RO 2 /* Remontar el sistema de ficheros en solo lectura */ #define EXT2_ERRORS_PANIC 3 /* Generar Pánico */ #define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE ---------------------------------------------------------------------------
--------------------------------------------------------------------------- #define EXT2_OS_LINUX 0 #define EXT2_OS_HURD 1 #define EXT2_OS_MASIX 2 #define EXT2_OS_FREEBSD 3 #define EXT2_OS_LITES 4 ---------------------------------------------------------------------------
--------------------------------------------------------------------------- #define EXT2_GOOD_OLD_REV 0 /* Formato original */ #define EXT2_DYNAMIC_REV 1 /* Formato V2 con tamaño de inodes dinámico */ #define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV ---------------------------------------------------------------------------
--------------------------------------------------------------------------- #define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 ---------------------------------------------------------------------------
--------------------------------------------------------------------------- #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 ---------------------------------------------------------------------------
--------------------------------------------------------------------------- #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 ---------------------------------------------------------------------------
Grupos- Grupos Ext2fs se utilizan para organizar los clusters de bloques y inodes. Cada uno de los grupos contiene un bitmap libre de inodes y un inode libre. De forma adicional cada grupo tiene una copia del superblock para ayudar en la prevensión de la pérdida de datos. Descriptores de grupos están almacenados en el bloque después del super block, y luego a continuación están los bitmaps y tablas de inodes. Luego vienen los bloques de datos.
El formato de los descriptores del grupo son siguientes:
----------------------------------------------------------------------------- struct ext2_group_desc { __u32 bg_block_bitmap; /* Bloque del bloque bitmap */ __u32 bg_inode_bitmap; /* Inodes del bloque bitmap */ __u32 bg_inode_table; /* Bloque de tablas inode */ __u16 bg_free_blocks_count; /* Contador de libres bloques */ __u16 bg_free_inodes_count; /* Contador de libres inodes */ __u16 bg_used_dirs_count; /* Contador de directorios */ __u16 bg_pad; __u32 bg_reserved[3]; }; -----------------------------------------------------------------------------
Directorios - Directorios se utilizan para organizar ficheros a nivel del sistema operativo. El contenido del fichero de directorio es un array de estructuras de directorios. Cada fichero de directorio contiene el nombre del fichero dentro del mismo directorio y el inodel del fichero.
El formato de entradas de directorios en ext2 es el siguiente:--------------------------------------------------------------------------- struct ext2_dir_entry_2 { __u32 inode; /* Número Inode */ __u16 rec_len; /* Tamaño de la entrada */ __u8 name_len; /* Tamaño del nombre */ __u8 file_type; char name[EXT2_NAME_LEN]; /* Nombre del fichero */ }; ---------------------------------------------------------------------------
--------------------------------------------------------------------------- #define EXT2_FT_UNKNOWN 0 #define EXT2_FT_REG_FILE 1 #define EXT2_FT_DIR 2 #define EXT2_FT_CHRDEV 3 #define EXT2_FT_BLKDEV 4 #define EXT2_FT_FIFO 5 #define EXT2_FT_SOCK 6 #define EXT2_FT_SYMLINK 7 ---------------------------------------------------------------------------
Eso concluye la descripción del nivel físico del sistema de
ficheros ext2fs.
[Subir]
En el capítulo anterior se trataron los conceptos básicos de análisis forense y también se hizo una mención indirecta de algunos métodos de subversión del análisis, mientras que, de aquí para adelante, nos centraremos en el tema de evasión forense.
Evasión forense es un intento de mitigar la cantidad y calidad de información un investigador puede encontrar. Cada uno de los pasos del análisis puede ser explotado y subvertido. Este white paper se centra principalmente en la subversión de la fase de recolección de datos del sistema de ficheros durante la investigación.
Los mecanismos principales para alcanzar este objetivo son: técnicas de destrucción (1) y ocultación (2) de datos. A lo largo del white paper se hará referencia a la explotación de algunas vulnerabilidades del proceso de análisis y recolección de datos.
El estudio forense es extremadamente vulnerable a subversión cuando la información, en su estado básico (raw data image), se convierte en pruebas (por ejemplo emails). Cada paso de la conversión es vulnerable por la complejidad y procesos abstractos que se realizan sobre los datos. Cuando se trabaja con los datos cualquier despiste puede resultar en pérdida de detalles y los detalles en realidad son las partes más importantes del rompecabezas. Cuando los detalles desaparecen, se crean vacíos importantes que pueden ser explotados. El despiste no es la única fuente de errores, sino también los fallos en las herramientas forenses frecuentemente utilizadas. Bugs en las implementaciones de estas herramientas proporcionan mejores oportunidades de explotación para agentes evasivos.
Pocas cosas pueden ser hechas de forma remota por un agente evasivo a fin de prevenir que el sistema de ficheros se salve, asimismo nos centraremos en la siguiente fase del análisis forense - prevención de recogida de pruebas del sistema de ficheros. Se puede frenar la recogida de información a través de destrucción o ocultación de la misma. De estos dos mecanismos la destrucción de datos es la más fiable ya que no deja ninguna pista el investigador puede recoger y analizar. Esta técnica proporciona medios para la eliminación segura de huellas y pruebas existentes para cubrirse las huellas del atacante de forma más efectiva.
Ocultación de información sólo es efectiva cuando el analista no sabe dónde buscarla, siendo la integridad del medio de almacenamiento imposible de garantizar a largo plazo. Por esa razón, la ocultación de datos debe ser combinada con ataques a las fases de estudio de datos recogidos (por ejemplo formatos propietarios de ficheros) y de examen (por ejemplo cifrado). Técnicas de ocultación son útiles en caso de que los datos se tengan que guardar durante un periodo esencial de tiempo (por ejemplo fotos artísticas de señoritas posando).
Los dos toolkits incluidos en la siguiente sección del white paper proporcionan
una demostración de las dos técnicas de evasión forense:
destrucción de datos y ocultación. Utilizaremos estos toolkits
para dar ejemplos detallados de destrucción y ocultación de datos
a continuación. La primera técnica que examinaremos en detalle
es la ocultación.
[Subir]
Aquellos hackers con conocimientos superiores que rozan la frontera de imaginación de los wannabes no dejan nada a la suerte y gracias a ellos han empezado existir series de herramientas de evasión o de encubrimiento de huellas. Si nos hubieran dicho por los años 1999 que aparte del zapper clásico existían herramientas que permitían borrar el rastro o por lo menos hacerlo tan confuso para el investigador, nos sorprenderíamos, pero no tanto como se sorprenden cada día miles de administradores de servidores cuando saben que hubo compromiso pero no encuentran huellas con las más avanzadas técnicas de investigación. En esta sección del whitepaper hablaremos sobre las herramientas más avanzadas y secretas que existen para encubrir huellas y daremos pistas de como detectar su uso.
[Subir]
Una de las herramientas más comúnes para el análisis forense del sistema de ficheros Unix es "The Coroner's Toolkit" desarrollada por Dan Farmer y Wietse Venema. A pesar de ser casí la única aplicación en la que han confiado los analistas forenses durante años, la herramienta podría ser mejorada a lo largo de años y los fallos que ocurrían en las primeras versiones siguien produciendose hoy en día. El sistema de ficheros más utilizada de Unix tiene un error que permite al atacante almacenar datos aleatorios en ubicaciones que TCT no puede ni localizar ni examinar.
El TCT falla a la hora de recrear las especificaciones de sistema de ficheros a la hora de analizar implementaciones de Berkley Fast File System (FFS o UFS), y Second Extended File system (ext2fs). El fallo consiste en asumir que ningún bloque de datos puede ser asignado al inode antes del root inode, fallando también a tener en cuenta los inodes de los bloques dañados.
Historicamente, el inode de bloques dañados fue utilizado para referenciar bloques que contienen sectores dañados en el disco duro, previniendo que estos bloques estén utilizados por el sistema operativo. El FFS dejó de utilizar este método, lo que evita la explotación de este error, pero ext2fs siguie utilizando la misma técnica de marcación.
La realización del ataque de ocultación al sistema de ficheros significa para un intruso la manipulación del sistema de ficheros dentro de las especificaciones implementadas de la herramienta de verificación de integridad del FS: fsck. Sería de interés saber que pocos investigadores han pensado en utilizar un fsck para detectarlo y intrusos incautos pueden haber sobrepasado el marco de seguridad de las especificaciones.
La versión de esa herramienta diseñada para funcionar con el
sistema de ficheros ext2 todavía utiliza los inodes de bloques dañados
para estos sectores en el disco, por lo tanto las especificaciones permiten
tener un número ilimitado de bloques dañados, y este hecho no
levanta sospechas a la hora de realizar un chequeo del disco. Desgraciadamente
la parte del código de reconocimiento del sistema de ficheros en TCT
no realiza verificación del inode de bloques dañados ya que no
lo considera de interés alguno. El código de TCT así como
de TASK realiza la siguiente verificación errónea:
/* * Verificación de integridad */ if (inum < EXT2_ROOT_INO || inum > ext2fs->fs.s_inodes_count) error("invalid inode number: %lu", (ULONG) inum);
El primer inode que puede ser reservado en un sistema de ficheros ext2 es de hecho el inode de bloques dañados (inode 1) y no el inode de raíz (inode 2). Por razones de fallos en implementación es posible almacenar información en bloques marcados como bloques dañados, es decir referenciados por el inode de bloques dañados. Usando esa técnica se puede almacenar allí la información y tenerla oculta de cualquier analista que usa herramientas como TCT o TASK. Para ilustrar la gravedad de este tipo de ataques a continuación están algunos ejemplos que muestran como crear un espacio oculto, copiar allí la información y sacarla de allí cuando se necesite (ver también el código de la aplicación RuneFS adjunto).
Ejemplo de creación de espacio oculto:
# df -k /dev/hda6 Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda6 1011928 20 960504 1% /mnt # ./bin/mkrune -v /dev/hda6 +++ bb_blk +++ bb_blk->start = 33275 bb_blk->end = 65535 bb_blk->group = 1 bb_blk->size = 32261 +++ rune size: 126M # df -k /dev/hda6 Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda6 1011928 129196 831328 14% /mnt # e2fsck -f /dev/hda6 e2fsck 1.26 (3-Feb-2002) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information /dev/hda6: 11/128768 files (0.0% non-contiguous), 36349/257032 blocks #
Este ejemplo demuestra la reserva de 126 mb. para el espacio oculto en el disco duro, demostrando que la pérdida de este espacio se queda registrada por el núcleo. Es evidente que el espacio oculto no viola las especificaciones ext2, por lo tanto fsck no se queja.
Ejemplo de uso del espacio oculto:
# cat readme.tools | ./bin/runewr /dev/hda6 # ./bin/runerd /dev/hda6 > f # diff f readme.tools #
Este segundo ejemplo muestra como datos pueden ser insertados y extraídos del espacio de almacenamiento oculto sin pérdida de datos. Mientras que este ejemplo no entra en detalle de técnicas de almacenamiento en el espacio oculto, es suficiente para presentar el uso de RuneFS.
Ejemplo de mala implementación de reconocimiento de sistema de ficheros ext2fs.
# ./icat /dev/hda6 1 /icat: invalid inode number: 1 #
Este ultimo ejemplo ilustra como un analista forense es incapaz de localizar el almacenamiento oculto con herramientas TCT. Es evidente que pueden haber muchos problemas cuando se examina el sistema de ficheros con herramientas con fallos.
Aunque los últimos ejemplos son realimente asombrosos, existen ciertos problemas con RuneFS. Esa versión de RuneFS que viene a continuación es bastante anticuada; Gnugq, el redactor del Phrack en que me baso para cumplimentar mi white paper, la ha escrito en Noviembre del año 2000. La versión actual de RuneFS tiene soporte para reserva de espacio dinámica, soporta cifrado y estructura de directorios y puede llegar a ser hasta 2 Gb. Afortunadamente el software de Gnugq es privado y no se distribuye al público.
Al fin y al cabo el uso la última versión de RuneFS tiene una
mayor desventaja ya que el secreto y la técnica de implementación
ya es de dominio público (obviamente, por el número de lectores
Phrack, y espero de éste artículo). Esta desventaja subraya que
técnicas de ocultación de datos se encuentran bastante anticuadas
y no serán útiles si el analista sabe dónde buscar la información.
La ocultación sólo puede ser utilizada en combinación con
métodos de ofuscación y/o cifrado de datos.
[Subir]
El sistema de ficheros (supuestamente) contiene el seguimiento completo de operaciones de entrada y salida de datos del equipo. El analista forense involucrado en la investigación intenta extraer esa información para examinarla.
Aparte de las dificultades impuestas por los fallos en las implementaciones de herramientas forenses comúnmente utilizadas, el analista lo tendrá mucho más difícil todavía extrayendo la información del sistema de ficheros en caso de que simplemente no esté allí.
Esta sección cubrirá técnicas y herramientas utilizadas por los intrusos para eliminar cualquier evidencia de compromiso en el sistema de ficheros. Estas metodologías han sido reunidas en la aplicación “The Defiler’s Toolkit (TDT)” que puede ser descargada al final del artículo.
La mayor complicación con la reunión de pruebas es que deben estar allí para recogerlas. Los datos no existentes, obviamente, no pueden ser recogidos, siendo por lo tanto imposible sin estos datos seguir con la investigación.
La limpieza del sistema de ficheros es una de las prácticas de evasión utilizadas por los intrusos con un nivel alto de conocimientos. El resultado de la aplicación de ésta metodología resulta en la eliminación definitiva de las pruebas de borrado de ficheros existidos anteriormente. The Defiler’s Toolkit proporciona herramientas para eliminar huellas del sistema de ficheros con precisión quirúrgica, erradicando de forma selectiva la información que puede ser utilizada posiblemente como prueba. Utilizando este juego de herramientas el intruso puede frustrar desde el principio toda la investigación.
Dentro del sistema de ficheros Unix todos los siguientes elementos pueden contener pruebas de las actividades del intruso:
Desgraciadamente las herramientas más avanzadas de eliminación de datos borran solo el contenido de bloques de datos, dejando intactos las entradas de directorio y inodes. Junto con este white-paper viene una versión del toolkit capaz de realizar una limpieza selectiva del disco duro. TDT consiste de dos aplicaciones: necrofile y klismafile que conjuntamente hacen un trabajo perfecto de eliminación segura de existencia de fichero. El objetivo de cada una de esas aplicaciones será descrito de forma individual a continuación.
[Subir]
Necrofile es una herramienta de detección y eliminación segura de inodes “borrados”. La aplicación puede ser utilizada para:
Los inodes “vírgenes” no proporcionan ninguna información al investigador sobre la existencia o borrado del fichero manipulado por el intruso.
Necrofile también incluye la funcionalidad de erradicar de forma segura el contenido de los bloques de datos a los que hace referencia el inode. Sin embargo, en este momento no es conveniente utilizar esa funcionalidad por los conflictos con los procesos de lectura y escritura del disco controlados por el núcleo.
Al ejecutar la aplicación se le debe proporcionar un sistema de ficheros donde realizar la búsqueda y informar de como se debe proceder con los inodes “borrados” localizados en la partición. Necrofile verifica de forma reiterada todos los inodes del sistema de ficheros especificada y verificando el estado de cada uno de ellos. En caso de que la aplicación haya sido arrancada con la opción de limpieza Necrofile limpia el inode “borrado” y lo inserta en la tabla de inodes en su estado virgen.
[Subir]
Ejemplo de localización de inodes borrados utilizando TCT:
# ./ils /dev/hda6 class|host|device|start_time ils|XXX|/dev/hda6|1026771982 st_ino|st_alloc|st_uid|st_gid|st_mtime|st_atime|st_ctime|st_dtime|st_mode|\ st_nlink|st_size|st_block0|st_block1 12|f|0|0|1026771841|1026771796|1026771958|1026771958|100644|0|86|545|0 13|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|546|0 14|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|547|0 15|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|548|0 16|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|549|0 17|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|550|0 18|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|551|0 19|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|552|0 20|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|553|0 21|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|554|0 22|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|555|0 23|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|556|0 24|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|557|0 25|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|558|0 26|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|559|0 27|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|560|0 28|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|561|0 29|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|562|0 30|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|563|0 31|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|564|0 32|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|565|0 33|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|566|0 34|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|567|0 35|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|568|0 36|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|569|0 37|f|0|0|1026771842|1026771796|1026771958|1026771958|100644|0|86|570|0 #
Ejemplo de utilización de Necrofile para localizar y limpiar los inodes borrados.
# ./necrofile -v -v -v -v /dev/hda6 Scrubbing device: /dev/hda6 12 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 13 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 14 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 15 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 16 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 17 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 18 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 19 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 20 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 21 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 22 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 23 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 24 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 25 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 26 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 27 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 28 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 29 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 30 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 31 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 32 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 33 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 34 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 35 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 36 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f 37 = m: 0x3d334d4d a: 0x3d334d4d c: 0x3d334d4f d: 0x3d334d4f
#
Ejemplo de como TCT no es capaz de localizar ningún inode borrado:
# ./ils /dev/hda6 class|host|device|start_time ils|XXX|/dev/hda6|1026772140 st_ino|st_alloc|st_uid|st_gid|st_mtime|st_atime|st_ctime|st_dtime|st_mode|\ st_nlink|st_size|st_block0|st_block1 #
Se necesita poco comentario para acompañar los ejemplos. La utilidad “ils” que forma parte de TCT muestra los inodes borrados para su posible recuperación.
Necrofile se ejecuta en el modo más detallado soportado por la aplicación, para demostrar como se localiza y limpia los mismos inodes encontrados por ils.
El uso de esta herramienta puede ser más efectivo si se utiliza para eliminar las huellas dejadas en los periodos determinados de tiempo, de esta manera los forenses tienen dificultades detectando la limpieza intencionada de los inodes.
En caso de que Necrofile se utilice para limpiar todos los inodes “borrados” del disco y el forense encuentre que no hay ningún inode “borrado” se confirmará su sospecha del compromiso y eliminación intencionada de pruebas por un hacker.
Después de que los inodes “borrados” hayan sido convertidos en inodes “vírgenes” ils no es capaz de localizarles.
Una vez los meta-datos que forman parte del inode han sido limpiados con éxito
el intruso procede a barrer sus huellas en otros lugares del sistema de ficheros
- las entradas de directorios.
Klismafile permite borrar de forma segura las entradas de directorio borradas. Cuando el nombre del fichero o el enlace inode se termina, el contenido de la entrada de directorio no se sobrescribe, sino se añade al espacio de la entrada precedente. Klismafile realizará una búsqueda en el fichero de directorio para localizar las entradas eliminadas y las sobrescribirá. Las expresiones regulares pueden ser utilizadas para limitar el número de entradas quitadas.
Para ejecutar la herramienta se debe proporcionarla con un directorio dónde realizar la búsqueda, y también puede realizar búsqueda recursiva en todos los directorios que encuentre.
Klismafile intentará localizar dirents eliminados y una vez encontrados los comparará con la expresión regular ‘file_name’ proporcionada como argumento del programa. Por defecto el ‘file_name’ es ‘*’. La utilidad sobrescribirá los dirents que coinciden con la expresión regular con ceros.
Klismafile no es una herramienta totalmente segura, y puede ser detectada su utilización observando que la entrada del directorio precedente al eliminado tiene el campo rec_len mayor de lo que debería ser, por lo tanto se puede asumir que herramientas como Klismafile o similares han manipulado el contenido del fichero de directorio. Actualmente no existen herramientas para realizar esa detección de forma automática, pero no tardarán en aparecer.
Ejemplo: la utilidad fls proporciona el listado de entradas de directorio.
# ./fls -d /dev/hda6 2 ? * 0: a ? * 0: b ? * 0: c ? * 0: d ? * 0: e ? * 0: f ? * 0: g ? * 0: h ? * 0: i ? * 0: j ? * 0: k ? * 0: l ? * 0: m ? * 0: n ? * 0: o ? * 0: p ? * 0: q ? * 0: r ? * 0: s ? * 0: t ? * 0: u ? * 0: v ? * 0: w ? * 0: x ? * 0: y ? * 0: z #
Ejemplo de como Klismafile realiza la limpieza.
# ./klismafile -v /mnt Scrubbing device: /dev/hda6 cleansing / -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> w -> x -> y -> z Total files found: 29 Directories checked: 1 Dirents removed : 26 #
Ejemplo de como fls no es capaz de encontrar ninguna entrada.
# ./fls -d /dev/hda6 2 #
Estos ejemplos demuestran claramente que la utilidad ‘fls’ – una parte de la caja de herramientas TCT-UTILS, sirve para examinar los ficheros de directorios. En el primer ejemplo el uso de la utilidad devuelve el listado de entradas de directorio borradas en el directorio raíz del sistema de ficheros.
Klismafile se ejecuta en modo detallado, visualizando y sobrescribiendo cada entrada de directorio que encuentra. Una vez acabado el trabajo de sobrescritura, fls no es capaz de mostrar ninguna entrada eliminada en el fichero de directorio.
Aviso: El núcleo de linux 2.4.x utiliza la técnica de cacheo del fichero de directorios en la memoria, por lo tanto si el intruso no tiene cuidado a la hora de utilizar esta herramienta sus cambios pueden no haberse realizado en la versión física del fichero sino sólo en la memoria (una razón más para desenchufar el equipo y no apagarlo de forma correcta).
[Subir]