Visualización de líneas de tiempo con Gource

Hola, secuaces:

Este noviembre pasado de 2018 tuve la inmensa suerte de participar como ponente en el Congreso de Seguridad Informática #HoneyCON, organizado por Honey Sec, en su edición de 2018. La presentación expuesta, que podéis ver en mi sitio de Slideshare, llevaba por título "Generación y visualización de líneas de tiempo".



Introducción


¿Por qué líneas de tiempo? Porque existen multitud de herramientas para generar líneas de tiempo y existen multitud de formas de visualizar esas líneas de tiempo.

Una línea de tiempo es la realización y visualización de una lista de eventos estableciendo un orden cronológico. Es decir, para hacer una línea de tiempo hay que ordenar cronológicamente toda la actividad de un sistema, o del artefacto objetivo de la linea de tiempo. Y esa línea de tiempo nos va a indicar que algo ha pasado, en un momento determinado, sobre un elemento en particular. Ahí es donde entran en juego las marcas de tiempo, que son las encargadas de indicarnos qué actividad se ha llevado a cabo.
Las líneas de tiempo son muy útiles para obtener rápidamente una relación de toda la actividad
En mi humilde opinión, una línea de tiempo se debe realizar sobre cualquier análisis, sí o sí, independientemente del caso. Es cierto que podemos analizar cualquier artefacto de una forma individual, un artefacto en el que se ha producido 'X' evento, pero puede que no seamos capaces de ver qué ha provocado ese evento. De nada nos sirve analizar un artefacto en particular, si no somos capaces de asociarlo a otro, dentro de un contexto. Y, ¿Cómo se analiza todo dentro de un contexto? Con una línea de tiempo.

En lo referente a las líneas de tiempo, creo que hice un buen trabajo con dos artículos que publiqué en @fwhibbit_blog:
En la presentación que expuse, y a modo de ejemplo, mostré algunas herramientas no comerciales capaces de generar líneas de tiempo:
Existen muchas más herramientas, proyectos y scripts.

Todas estas herramientas son capaces de generar líneas de tiempo, bien sobre un sistema de ficheros, bien sobre algún artefacto en particular, con multitud de opciones de salida y de formatos. Y todas las líneas de tiempo que generemos con todas estas herramientas pueden ser visualizadas de distintas formas, (Mediante gráficos, textos, ...).

Implementando líneas de tiempo en Gource


Conocí 'Gource' gracias a Ryan Benson. Concretamente, a través de su sitio web, 'Obsidian Forensics', con una entrada donde presentaba un script que parsea el fichero 'Manifest.mbdb' y formatea su salida para hacerlo compatible con 'Gource', (mbdbls). Desde entonces me he interesado mucho por esta herramienta porque creo que tiene mucho potencial a nivel forense.

¿Por qué no llevar su uso al siguiente nivel, a una línea de tiempo de un sistema de ficheros?

¿Qué es 'Gource'? Es una herramienta que fue creada para mostrar los proyectos de software como un árbol animado.

¿Qué necesita 'Gource' para funcionar? Un 'custom log format' con cuatro campos delimitados por 'pipe', (|):
  • Una marca de tiempo en formato Unix.
  • Un nombre de usuario.
  • El tipo de actividad que se ha llevado a cabo, (A, M, D).
  • Un elemento sobre el que la acción ha tenido lugar.



'Gource' dispone de muchas opciones de visualización. Permite desplazamientos por todos sus nodos, permite señalar un elemento con el ratón, permite el uso del scroll del ratón para opciones de zoom, permite empezar en una fecha señalada, permite terminar en una fecha señalada, permite el uso de escalas de tiempo, ...

Dadas las muchas posibilidades que tenemos para generar líneas de tiempo, es fácil encontrar el modo en el que establecer un formato adecuado para su visualización con 'Gource'. Porque,
Sé lo que tengo y sé lo que quiero para formatear la línea de tiempo, (Pensamiento lateral).
Así pues, por ejemplo, si hemos generado una línea de tiempo dinámica con 'Plaso', donde somos nosotros quienes elegimos las columnas que van a ser mostradas, podemos establecer el formato adecuado con 'Timeline Explorer', exportarlo y usar una pequeña fórmula para cambiar el formato de la columna de las fechas.


Y después de ello, podemos usar una simple orden en línea de comandos con 'sed', para terminar de generar el 'Custom Log Format' que necesitamos.


Estas operaciones las podemos llevar a cabo con cualquier línea de tiempo que hayamos generado, según nuestros intereses.


Es cierto que es un trabajo manual, pero no lleva más de unos pocos minutos y el resultado creo que es realmente bueno. En el siguiente vídeo puedes ver un ejemplo de visualización de una línea de tiempo realizada con 'Plaso' y formateada para su procesado con 'Gource'. La velocidad del vídeo se corresponde a la del tiempo real, realizando saltos de tiempo cuando existe ausencia de actividad.


Tienes disponible en mi carpeta de Google Drive un fichero 'Custom Log Format' de un Sistema Windows y otro de un Sistema Linux, generados manualmente desde una línea de tiempo de 'Plaso' para que puedas hacer las pruebas que desees.

No obstante, podemos automatizar el proceso.

Mactime2Gource


Para automatizar el proceso de generación de un 'Custom Log Format' opté por partir de una línea de tiempo tabulada, generada por 'mactime' de TSK, porque pienso que es una herramienta muy buena y con el equilibrio justo de profundidad, inversión de tiempo y tamaño de ficheros.

Y como nunca me he puesto a escribir código, le pedí ayuda a Guillermo Román, un buen amigo y co-fundador del Blog 'Follow the White Rabbit', para crear un pequeño script capaz de procesar una línea de tiempo generada con 'mactime' para formatearla a un 'Custom Log Format'. 

El script, que podéis encontrar en el sitio de Github de Guillermo, lo hemos hecho compatible para líneas de tiempo generadas desde sistemas Linux y Windows, y para ser ejecutado desde sistemas Linux y Windows, (Porque debes saber que no se interpretan igual en un sistema que en otro).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/usr/bin/python3

import sys, datetime, re

def main():
    # Regex to match the lines
    regex_date = "^(\D+\s\D+\s\d+\s\d+\s\d\d:\d\d:\d\d)\s+\d*\s+(....)\s+.+\s\d*\s+\d*\s+\d*.\d*.\d*.\s+(.*)$"
    regex_nodate = "^\s+\d*\s+(....)\s+.+\s\d*\s+\d*\s+\d*.\d*.\d*.\s+(.*)$"
    
    # Open input file
    filename = sys.argv[1]
    lines = open(filename, "r")
    
    # Last date detected, to keep control of multiple entries
    date_last = ""

    for line in lines: 
        line = line.rstrip()
        #print("Original: " + line)
        
        # Check if date line or sub-entry, and parse
        matches = re.search(regex_date,line)
        if matches:
            date_last = parse(matches, 1, date_last)
        if not matches:
            matches = re.search(regex_nodate,line)
            date_last = parse(matches, 0, date_last)
        if not matches:
            print("Error in line!")
            exit()

# Parses a line. Offset set to 1 if line with date, 0 if sub-entry.
def parse(matches, offset, date_last): 
    # Parse date
    if offset == 1:
        date_match = matches.group(1)
        date = datetime.datetime.strptime(date_match, "%a %b %d %Y %H:%M:%S")
        date_seconds = (date - datetime.datetime(1970,1,1)).total_seconds()
    else: 
        date_seconds = date_last

    # Parse M/A/C/B flag to A/M/D
    macb_match = matches.group(1+offset)
    if re.match("..c.",macb_match):
        macb = 'M'
    elif re.match("m...",macb_match):
        macb = 'M'
    elif re.match("...b",macb_match):
        macb = 'A'
    elif re.match(".a..",macb_match):
        macb = 'M'
    elif re.match("....",macb_match):
        macb = 'D'

    # Parse path
    path = matches.group(2+offset)
    # Was it deleted? Cut and set MACB to D(eleted)
    if path.endswith("(deleted)"): 
        path = path[:-10]
        macb = 'D'
        #print(path)
    elif path.endswith("(deleted-realloc)"):
        path = path[:-18]
        macb = 'D'
    # Trim ($FILE_NAME)
    if path.endswith("($FILE_NAME)"):
        path = path[:-13]

    # Print results
    print(str(int(date_seconds)) + "|USER|" + macb + "|" + path)
   
    # Return last date detected
    return date_seconds


if __name__ == "__main__":
    main()

Su funcionamiento es muy sencillo. Se ejecuta el script, se le indica la línea de tiempo tabulada generada con 'mactime' y se le indica un fichero de salida.


De este modo, pasamos de tener una línea de tiempo tabulada


A tener un 'Custom Log Format' compatible con 'Gource'


Puedes ver el resultado de su procesado con 'Gource' en el siguiente vídeo. La velocidad del vídeo se corresponde a la del tiempo real, realizando saltos de tiempo cuando existe ausencia de actividad.


Tienes disponible en mi carpeta de Google Drive un fichero 'Custom Log Format' de un Sistema Windows y otro de un Sistema Linux, generados con 'Mactime2Gource' para que puedas hacer las pruebas que desees.

Conclusiones


Creo que una línea de tiempo se debe realizar en cualquier caso. Lo considero algo básico porque siempre nos va a ser de ayuda para entender qué ha pasado, tanto si sabemos lo que buscamos como si no. Siempre va a ser una buena referencia que consultar.

Las líneas de tiempo son muy útiles para obtener rápidamente una relación de toda la actividad de los ficheros y eso nos va a servir para obtener pistas. Casi todo contiene marcas de tiempo, (Registros, Logs, Eventos, Sistema de ficheros, …).

Una línea de tiempo debe ser intuitiva, comprensible y fácil de estudiar. Por ello deberemos tratar, formatear, las líneas de tiempo que generemos con las distintas herramientas, para hacerlo más legible. Unas llevarán más tiempo que otras.

Una línea de tiempo no nos bastará para completar un análisis, pero es la mejor manera de ver que algo ha pasado, en un momento determinado, con un elemento en concreto. Hay que estudiar los elementos dentro de un contexto.

¿Por qué no ver una línea de tiempo como un árbol animado? Creo que es una muy buena manera de ver rápidamente esas pistas, ese tipo de actividad que ha sido llevada a cabo. Creo que puede ser de mucha ayuda para entender qué ha pasado.

Esto es todo.

Share:
spacer

No hay comentarios:

Publicar un comentario