mirror of https://github.com/CIRCL/AIL-framework
178 lines
5.8 KiB
Python
Executable File
178 lines
5.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*-coding:UTF-8 -*
|
|
"""
|
|
The Retro_Hunt trackers module
|
|
===================
|
|
|
|
"""
|
|
|
|
##################################
|
|
# Import External packages
|
|
##################################
|
|
import os
|
|
import sys
|
|
import time
|
|
import yara
|
|
|
|
sys.path.append(os.environ['AIL_BIN'])
|
|
##################################
|
|
# Import Project packages
|
|
##################################
|
|
from modules.abstract_module import AbstractModule
|
|
from lib.ail_core import get_objects_retro_hunted
|
|
from lib.ConfigLoader import ConfigLoader
|
|
from lib.objects import ail_objects
|
|
from lib import Tracker
|
|
|
|
class Retro_Hunt_Module(AbstractModule):
|
|
|
|
"""
|
|
Retro_Hunt module for AIL framework
|
|
"""
|
|
def __init__(self):
|
|
super(Retro_Hunt_Module, self).__init__()
|
|
config_loader = ConfigLoader()
|
|
self.pending_seconds = 5
|
|
|
|
# reset on each loop
|
|
self.retro_hunt = None
|
|
self.nb_objs = 0
|
|
self.nb_done = 0
|
|
self.progress = 0
|
|
self.obj = None
|
|
self.tags = []
|
|
|
|
self.redis_logger.info(f"Module: {self.module_name} Launched")
|
|
|
|
# # TODO: # start_time
|
|
# # end_time
|
|
def compute(self, task_uuid):
|
|
self.redis_logger.warning(f'{self.module_name}, starting Retro hunt task {task_uuid}')
|
|
print(f'starting Retro hunt task {task_uuid}')
|
|
self.progress = 0
|
|
# First launch
|
|
# restart
|
|
self.retro_hunt = Tracker.RetroHunt(task_uuid)
|
|
|
|
rule = self.retro_hunt.get_rule(r_compile=True)
|
|
timeout = self.retro_hunt.get_timeout()
|
|
self.tags = self.retro_hunt.get_tags()
|
|
|
|
self.redis_logger.debug(f'{self.module_name}, Retro Hunt rule {task_uuid} timeout {timeout}')
|
|
|
|
# Filters
|
|
filters = self.retro_hunt.get_filters()
|
|
if not filters:
|
|
filters = {}
|
|
for obj_type in get_objects_retro_hunted():
|
|
filters[obj_type] = {}
|
|
|
|
self.nb_objs = ail_objects.card_objs_iterators(filters)
|
|
|
|
# Resume
|
|
last_obj = self.retro_hunt.get_last_analyzed()
|
|
if last_obj:
|
|
last_obj_type, last_obj_subtype, last_obj_id = last_obj.split(':', 2)
|
|
else:
|
|
last_obj_type = None
|
|
last_obj_subtype = None
|
|
last_obj_id = None
|
|
|
|
self.nb_done = 0
|
|
self.update_progress()
|
|
|
|
for obj_type in filters:
|
|
if last_obj_type:
|
|
filters['start'] = f'{last_obj_subtype}:{last_obj_id}'
|
|
last_obj_type = None
|
|
for obj in ail_objects.obj_iterator(obj_type, filters):
|
|
self.obj = obj
|
|
content = obj.get_content(r_type='bytes')
|
|
if not content:
|
|
continue
|
|
|
|
rule.match(data=content, callback=self.yara_rules_match,
|
|
which_callbacks=yara.CALLBACK_MATCHES, timeout=timeout)
|
|
|
|
self.nb_done += 1
|
|
if self.nb_done % 10 == 0:
|
|
self.retro_hunt.set_last_analyzed(obj.get_type(), obj.get_subtype(r_str=True), obj.get_id())
|
|
self.retro_hunt.set_last_analyzed_cache(obj.get_type(), obj.get_subtype(r_str=True), obj.get_id())
|
|
|
|
# update progress
|
|
self.update_progress()
|
|
|
|
# PAUSE
|
|
if self.retro_hunt.to_pause():
|
|
self.retro_hunt.set_last_analyzed(obj.get_type(), obj.get_subtype(r_str=True), obj.get_id())
|
|
self.retro_hunt.pause()
|
|
return None
|
|
|
|
# Completed
|
|
self.retro_hunt.complete()
|
|
print(f'Retro Hunt {task_uuid} completed')
|
|
self.redis_logger.warning(f'{self.module_name}, Retro Hunt {task_uuid} completed')
|
|
|
|
def update_progress(self):
|
|
if self.nb_objs == 0:
|
|
new_progress = 100
|
|
else:
|
|
new_progress = self.nb_done * 100 / self.nb_objs
|
|
if int(self.progress) != int(new_progress):
|
|
print(new_progress)
|
|
self.retro_hunt.set_progress(new_progress)
|
|
self.progress = new_progress
|
|
|
|
def yara_rules_match(self, data):
|
|
obj_id = self.obj.get_id()
|
|
# print(data)
|
|
task_uuid = data['namespace']
|
|
|
|
self.redis_logger.info(f'{self.module_name}, Retro hunt {task_uuid} match found: {obj_id}')
|
|
print(f'Retro hunt {task_uuid} match found: {self.obj.get_type()} {obj_id}')
|
|
|
|
self.retro_hunt.add(self.obj.get_type(), self.obj.get_subtype(r_str=True), obj_id)
|
|
|
|
# TODO FILTER Tags
|
|
|
|
# TODO refactor Tags module for all object type
|
|
# Tags
|
|
if self.obj.get_type() == 'item':
|
|
for tag in self.tags:
|
|
msg = f'{tag};{obj_id}'
|
|
self.add_message_to_queue(msg, 'Tags')
|
|
else:
|
|
for tag in self.tags:
|
|
self.obj.add_tag(tag)
|
|
|
|
# # Mails
|
|
# EXPORTER MAILS
|
|
return yara.CALLBACK_CONTINUE
|
|
|
|
def run(self):
|
|
"""
|
|
Run Module endless process
|
|
"""
|
|
|
|
# Endless loop processing messages from the input queue
|
|
while self.proceed:
|
|
task_uuid = Tracker.get_retro_hunt_task_to_start()
|
|
if task_uuid:
|
|
# Module processing with the message from the queue
|
|
self.redis_logger.debug(task_uuid)
|
|
# try:
|
|
self.compute(task_uuid)
|
|
# except Exception as err:
|
|
# self.redis_logger.error(f'Error in module {self.module_name}: {err}')
|
|
# # Remove uuid ref
|
|
# self.remove_submit_uuid(uuid)
|
|
else:
|
|
# Wait before next process
|
|
self.redis_logger.debug(f'{self.module_name}, waiting for new message, Idling {self.pending_seconds}s')
|
|
time.sleep(self.pending_seconds)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
module = Retro_Hunt_Module()
|
|
module.run()
|