Integrando fuentes confiables a tu MISP y validando con ZeroMQ

En FINSIN tenemos nuestro sistema MISP para intercambiar indicadores de compromiso (IOC) de manera gratuita con la comunidad.

Como hemos dicho en el artículo Liberamos los IOCs de FINSIN! nuestra plataforma MISP es cerrada, pero los indicadores que salen de ahí son abiertos para todo público.

Mientras integremos indicadores nuestros podemos tener la confianza de que son indicadores serios y que pasaron por lo menos nuestra validación, pero ¿qué pasa cuando queremos integrar a otras fuentes? ¿qué pasa cuando sus indicadores tienen distinto criterio que los tuyos?

El caso con ThreatFox

Les comento el caso que tuvimos con ThreatFox (https://threatfox.abuse.ch/), que es un proyecto de Abuse.ch (sus proyectos son muy buenos!) que justamente busca juntar IOC que comparte la comunidad, pero que la gracia es que además le agregan un indicador interno de confianza.

Como guinda de la torta, el 17 de marzo lanzaron un anuncio en Twitter que dice lo siguiente:

La integración ahora es a nivel nativo en MISP, mucho más fácil de realizar, y para 3 de sus proyectos más importantes!! Muchas gracias!!

Con esta información partimos a integrar inmediatamente el proyecto de ThreatFox, como un feed externo más (https://www.circl.lu/doc/misp/managing-feeds/), y de esta forma se van generando diariamente eventos con todos los indicadores que ellos hayan compartido.

Lamentablemente luego de hacer esta integración tuvimos un pequeño problema de definiciones. Esto lo podemos ver en las siguientes imágenes.

Por ejemplo, en la imagen anterior, tenemos que publicaron IOCs con 100% de confianza, pero también tenemos que hay otros con confianza moderada de 50%, y cuando integramos ambos a nuestro sistema los declaramos como “maliciosos” a ambos, lo cual no nos dejaba conforme.

La lógica en MISP

En nuestro caso queremos que solamente si es de 75% de confianza hacia arriba los marque como “maliciosos”, los demás los podemos integrar, pero no declararlos como amenaza.

Cuando tenemos un evento en MISP, nuestra forma de decir que ese IOC es “malicioso” y digno de bloquear es activando el flag “to_ids” del atributo.

Entonces, cuando nos llega un evento de ThreatFox queremos validar el nivel de confianza que tienen asignado y forzar la marca “to_ids” solamente si es que el nivel de confianza de los datos es de 75% o más.

Los de ThreatFox asignan el nivel de confianza a través de un comentario, por lo que se vería así:

Por ejemplo, en la imagen anterior tenemos 2 atributos, en el cual el primero está marcado con el flag “to_ids” y el segundo no, justamente porque el payload de Agent Tesla no tiene el nivel de confianza suficiente. Lo malo es que teníamos que hacer el cambio a mano cada vez que recibíamos el evento. ¿Qué podemos hacer?

ZeroMQ al rescate

ZeroMQ es un proyecto de mensajería open source que tiene muchísimo tiempo de vida y es usado en diversos proyectos de distintas compañías como: Microsoft, Facebook, Spotify, etc. y además viene como parte de las herramientas integradas a MISP.

Hace un tiempo estábamos jugando con las posibilidades de automatización que te da la integración por defecto entre ZeroMQ y MISP. Lamentablemente la documentación de las posibilidades no está hecha tan a profundidad como uno quisiera (https://www.circl.lu/doc/misp/misp-zmq/), pero te sienta las bases de como hacerlo.

La idea por detrás de esta integración es que cada vez que se realizan acciones dentro de MISP se producen mensajes, los cuales se envían a través de ZeroMQ a los que quieran recibirlos (suscriptores de esos mensajes). Con eso se pueden integrar códigos y lógicas que de otra forma serían imposibles o por lo menos necesitaríamos modificar el código de MISP.

Para ello, solamente necesitamos activar el plugin, y “listo”, tenemos la cola funcionando.

Volviendo a nuestro problema con los eventos de ThreatFox, según la configuración que tenemos con el feed, siempre que se reciban datos nuevos se publica el evento automáticamente, entonces tenemos ese momento para poder validar los datos.

Programando un poco

Ahora tenemos que programar un poco para poder tener esta lógica, partamos por recibir los eventos que van siendo publicados:

logging.info('Starting confidence level checker')
while loop:
    socks = dict(poller.poll(timeout=None))
    if socket in socks and socks[socket] == zmq.POLLIN:
        message = socket.recv()
        topic, s, m = message.decode('utf-8').partition(" ")
        if topic not in filters:
            continue
        logging.info('Receiving message')
        j = json.loads(m)

        if j["Event"]["id"] not in events_verified:
            events_verified.append(j["Event"]["id"])

            # This is the main part of the code
            logging.info("Starting loop through event.")
            loop_through_event(j, misp)

        else:
            logging.info('Event ' + j["Event"]["id"] + ' already checked')

        time.sleep(0.1)

Como ven, el código base es casi el mismo que el que sale en la documentación, solo que agrego una validación para ver si es que el evento ya ha sido procesado por el script o no, en la variable events_verified. Como un pequeño detalle, sabemos que el evento viene en formato JSON, por eso tenemos la línea:

j = json.loads(m)

Con este código listo, tenemos que implementar la funcionalidad de la función loop_through_event. En esta función, necesitamos revisar los atributos del evento y revisar su nivel de confianza.

def loop_through_event(j, misp):
    for o in j["Event"]["Object"]:
        for a in o["Attribute"]:
            check_and_update(a, misp)
    for a in j["Event"]["Attribute"]:
        check_and_update(a, misp)
    
    misp.publish(j["Event"]["id"], alert=False)

Lo más importante de este código es el hecho que tengo que hacer un doble loop, primero por todos los Objects y luego por la lista de Attributes sueltos, porque de lo contrario se nos quedarían afuera muchos datos.

Aparte tenemos que re-publicar el evento, porque cada cambio que hagamos (aunque sea por API) deja el evento como “no publicado”, por lo que al final de todos los cambios debemos publicarlo nuevamente.

Finalmente nos queda la función de check_and_update, con la que validamos los datos de cada atributo para ver si es que tiene el comentario de nivel de confianza.

def check_and_update(a, misp):
    if "Tag" in a:
        tags = a["Tag"]
    else:
        tags = []
    con = check_confidence(a["comment"])
    to_ids = False
    if con is not False:
        if int(con) == 100:
            to_ids = True
            if not check_for_tag(a,tag_100):
                tags.append({"name":tag_100})
        elif int(con) >= 75:
            to_ids = True
            if not check_for_tag(a,tag_75):
                tags.append({"name":tag_75})
        elif int(con) >= 50:
            if not check_for_tag(a,tag_50):
                tags.append({"name":tag_50})
        elif int(con) >= 25:
            if not check_for_tag(a,tag_25):
                tags.append({"name":tag_25})
        attr = {"uuid": a["uuid"], "to_ids": to_ids, "Tag":tags}
        misp.update_attribute(attr)

Con esto tenemos más o menos armado el script, basta con hacerlo correr en el equipo y esperar la publicación de algún evento de los amigos de ThreatFox.

PS: Es bueno dejarlo corriendo con un screen, tmux o nohup, para que aguante una desconexión (o si te poner creativo, un servicio).

Conclusiones

Primero me gustaría agradecer a la gente de Abuse.ch con sus proyectos, porque hacen un tremendo trabajo y comparten mucha información muy actualizada de las amenazas del día de hoy, cualquier equipo de ciberseguridad debe que usar por lo menos uno de ellos como información:

Proyectos de abuse.ch

MISP es un sistema excelente para poder utilizar como concentrador de información y expandir sus funcionalidades es bastante sencillo, si es que uno se integra a la cola de ZeroMQ. Toda la información que necesitas está ahí a la mano, y solo la imaginación es el límite.

Por ejemplo, uno podría pensar que armar una solución tipo SOAR amarrada a este tipo de mensajerías no es tanto más complejo, pero eso lo dejo como ejercicio para el lector.

Como siempre, la idea es que esta información la podamos compartir, les dejo el script completo que vimos anteriormente y que actualmente tenemos para la validación (https://gist.github.com/joydragon/830075b7da2b4a5c6a02913797f03e69)

Cualquier cosa nos comentan.

Muchas gracias por leer hasta acá.

Una respuesta a “Integrando fuentes confiables a tu MISP y validando con ZeroMQ

Add yours

Deje un comentario

Crea una web o blog en WordPress.com

Subir ↑