0

EDIT:

Solved by creating rules with auditctl and then getting the logs from an specific key with ausearch.


I'm basically creating a tool to detect Ransomware activity with honeypots spread across the file system. The program functionality is pretty simple:

  • Only works on Linux;
  • There are honeypots in various directories in the file system;
  • Each honeypot created will have an unique hash and a absolute path store in a json file;
  • If watchdog observer detects a modification in one of the honeypots, it will compare the current hash with the hash stored in the json file;
  • If the hashes are different, then it's malicious activity, so, kill the process modifying the honeypot file.

I managed to do all of this, and I created a custom and simple Ransomware to test this functionality above. But there is a major problem:

To kill the malicious process, I need to get the PID of the process modifying the honeypot file, but my custom ransomware is so fast that I can't get the process PID. If I place a sleep(0.064) method in the custom ransomware encrypt function, I can detect the ransomware PID an then kill it. But if the sleep value goes bellow 0.064, I just can't get the process PID modifying the file anymore...

I don't know if watchdog observer is to slow to detect this and I should use another module that does the same thing, or a I should create one file system monitor from scratch, or if there is an way to get this malicious process PID.

The functionality of the honeypot modification detector can be see bellow (file_monitor.py):

import hashlib
import json
import os
import signal
import subprocess
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import logging


class FileMonitor:
    def __init__(self, directory_list, honeypot_file_name, path_to_config_folder, json_file_name):
        self.directory_list = directory_list
        self.honeypot_file_name = honeypot_file_name
        self.path_to_config_folder = path_to_config_folder
        self.json_file_name = json_file_name

    class EventHandler(FileSystemEventHandler):
        def __init__(self, data):
            self.directory_list = data[0]
            self.honeypot_file_name = data[1]
            self.path_to_config_folder = data[2]
            self.json_file_name = data[3]

        def on_modified(self, event):
            if self.honeypot_file_name in event.src_path:
                try:
                    pids_in_honeypot = subprocess.check_output(["fuser", "-u", event.src_path], stderr=subprocess.DEVNULL).decode().strip().replace(" ", ",").split(",")
                    for dict in json_file_hashes:
                        if event.src_path == dict['absolute_path']:
                            with open(event.src_path, 'rb') as honeypot_file:
                                file_data = honeypot_file.read()
                                current_hash = hashlib.md5(file_data).hexdigest()
                                if current_hash != dict['hash']:
                                    logger.debug(f"Honeypot in {event.src_path} was modified!")
                                    try:
                                        file_monitor_pid = os.getpid()
                                        for pid in pids_in_honeypot:
                                            if str(pid) != str(file_monitor_pid):
                                                logger.debug(f"The Ransomware process PID is: {pid}")
                                                #os.kill(int(pid), signal.SIGKILL)
                                                logger.debug(f"Ransomware with process PID {pid} was killed!")
                                    except Exception as e:
                                        logger.error(f'{str(e.__class__.__name__)}')
                                        continue
                except Exception as e:
                    logger.error("The fuser command returned nothing.")
                    pass

    def run(self):
        global observers
        observers = []
        observer = Observer()
        event_handler = self.EventHandler([self.directory_list, self.honeypot_file_name, self.path_to_config_folder, self.json_file_name])

        for directory in self.directory_list:
            # Criação do observer
            observer.schedule(event_handler, directory, recursive=True)
            # Colocando o observer criado na lista dos observers
            observers.append(observer)

        observer.start()

        global json_file_hashes
        json_file_path = os.path.join(self.path_to_config_folder, self.json_file_name)
        if os.path.exists(self.path_to_config_folder):
            try:
                with open(os.path.join(json_file_path)) as json_file:
                    json_file_hashes = json.load(json_file)
            except FileNotFoundError:
                logger.error(f'Could not find {self.json_file_name} in {self.path_to_config_folder}')
                quit()

        try:
            while True:
                continue
        except KeyboardInterrupt:
            for observer in observers:
                observer.unschedule_all()
                observer.stop()
                observer.join()


if __name__ == "__main__":
    from logger import logger
    logging.getLogger("watchdog.observers.inotify_buffer").disabled = True
    fm = FileMonitor(
        directory_list=["/home/matheusheidemann/Documents/Github/Python-Ransomware-Detector/ransomware-samples/encrypt-test"],
        honeypot_file_name=".r4n50mw4r3-d373c70r.txt",
        path_to_config_folder="/home/matheusheidemann/Documents/Github/Python-Ransomware-Detector/software/config",
        json_file_name="ransom-detector-hashes-list.json"
    )
    fm.run()
else:
    from software.logger import logger

The full code can be found on this Github repo: https://github.com/its0v3r/Python-Ransomware-Detector

The important files for this process are in the software folder.

When I have sleep(0.064) on my basic Ransomware, I'm able to detect the Ransomware PID: Success to get Ransomware PID

When I don't have sleep(0.064) or sleep(0.063) or lower on my basic Ransomware, I'm not able to detect the Ransomware PID (PS: the PID being printed in the terminal at the left is the file_monitor.py PID): Not being able to get the Ransomware PID

This is what my def on_modified() function is calling and the stats (used snakeviz + cProfiler + pstats): Performance log

I would be extremely grateful if someone can bring a light to this issue, I'm really lost about what should I do now.

PS: I know there is some hardcoded stuff I'm my code, I'm only testing stuff at the moment, there are still a lot of changes to be done.

1 Answers1

0

Solved by creating rules with auditctl and then getting the logs from an specific key with ausearch.