From 23b85acdfcf0d24f5fc8efd0c346d0b72aaab267 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Mon, 28 Jun 2021 14:07:02 -0400 Subject: [PATCH 1/3] Agent: Add placeholder README file for ransomware simulation --- .../pyinstaller_hooks/hook-infection_monkey.ransomware.py | 3 +++ monkey/infection_monkey/ransomware/__init__.py | 0 monkey/infection_monkey/ransomware/ransomware_readme.txt | 2 ++ 3 files changed, 5 insertions(+) create mode 100644 monkey/infection_monkey/pyinstaller_hooks/hook-infection_monkey.ransomware.py create mode 100644 monkey/infection_monkey/ransomware/__init__.py create mode 100644 monkey/infection_monkey/ransomware/ransomware_readme.txt diff --git a/monkey/infection_monkey/pyinstaller_hooks/hook-infection_monkey.ransomware.py b/monkey/infection_monkey/pyinstaller_hooks/hook-infection_monkey.ransomware.py new file mode 100644 index 000000000..4cedd58e7 --- /dev/null +++ b/monkey/infection_monkey/pyinstaller_hooks/hook-infection_monkey.ransomware.py @@ -0,0 +1,3 @@ +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("infection_monkey.ransomware") diff --git a/monkey/infection_monkey/ransomware/__init__.py b/monkey/infection_monkey/ransomware/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/infection_monkey/ransomware/ransomware_readme.txt b/monkey/infection_monkey/ransomware/ransomware_readme.txt new file mode 100644 index 000000000..8f480a536 --- /dev/null +++ b/monkey/infection_monkey/ransomware/ransomware_readme.txt @@ -0,0 +1,2 @@ +This is a placeholder README for the Infection Monkey Ransomware Simulation. +Don't panic :) From b312c11f440bd1a6c20b1cbcc5f7badd2f363961 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Mon, 28 Jun 2021 14:39:10 -0400 Subject: [PATCH 2/3] Agent: Leave a README.txt in ransomware target dir if it's configured --- .../ransomware/ransomware_payload.py | 15 +++++++++++ .../ransomware/test_ransomware_payload.py | 27 ++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/ransomware/ransomware_payload.py b/monkey/infection_monkey/ransomware/ransomware_payload.py index f46c5ae72..ec6da23ec 100644 --- a/monkey/infection_monkey/ransomware/ransomware_payload.py +++ b/monkey/infection_monkey/ransomware/ransomware_payload.py @@ -1,4 +1,5 @@ import logging +import shutil from pathlib import Path from typing import List, Optional, Tuple @@ -14,6 +15,9 @@ LOG = logging.getLogger(__name__) EXTENSION = ".m0nk3y" CHUNK_SIZE = 4096 * 24 +README_SRC = Path(__file__).parent / "ransomware_readme.txt" +README_DEST = "README.txt" + class RansomewarePayload: def __init__(self, config: dict, telemetry_messenger: ITelemetryMessenger): @@ -29,6 +33,9 @@ class RansomewarePayload: else target_directories["linux_dir"] ) + self._readme_enabled = config["other_behaviors"]["readme"] + LOG.info(f"README enabled: {self._readme_enabled}") + self._new_file_extension = EXTENSION self._valid_file_extensions_for_encryption = VALID_FILE_EXTENSIONS_FOR_ENCRYPTION.copy() self._valid_file_extensions_for_encryption.discard(self._new_file_extension) @@ -39,6 +46,7 @@ class RansomewarePayload: def run_payload(self): file_list = self._find_files() self._encrypt_files(file_list) + self._leave_readme() def _find_files(self) -> List[Path]: if not self._target_dir: @@ -67,3 +75,10 @@ class RansomewarePayload: def _send_telemetry(self, filepath: Path, error: str): encryption_attempt = RansomwareTelem((str(filepath), str(error))) self._telemetry_messenger.send_telemetry(encryption_attempt) + + def _leave_readme(self): + if self._readme_enabled: + try: + shutil.copyfile(README_SRC, Path(self._target_dir) / README_DEST) + except Exception as ex: + LOG.warning(f"An error occurred while attempting to leave a README.txt file: {ex}") diff --git a/monkey/tests/unit_tests/infection_monkey/ransomware/test_ransomware_payload.py b/monkey/tests/unit_tests/infection_monkey/ransomware/test_ransomware_payload.py index 35aef048c..5ebb5950c 100644 --- a/monkey/tests/unit_tests/infection_monkey/ransomware/test_ransomware_payload.py +++ b/monkey/tests/unit_tests/infection_monkey/ransomware/test_ransomware_payload.py @@ -1,5 +1,5 @@ import os -from pathlib import PurePath +from pathlib import Path, PurePath import pytest from tests.unit_tests.infection_monkey.ransomware.ransomware_target_files import ( @@ -22,7 +22,11 @@ from tests.unit_tests.infection_monkey.ransomware.ransomware_target_files import from tests.utils import hash_file, is_user_admin from infection_monkey.ransomware import ransomware_payload as ransomware_payload_module -from infection_monkey.ransomware.ransomware_payload import EXTENSION, RansomewarePayload +from infection_monkey.ransomware.ransomware_payload import ( + EXTENSION, + README_DEST, + RansomewarePayload, +) from infection_monkey.telemetry.i_telem import ITelem from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger @@ -42,7 +46,8 @@ def with_extension(filename): @pytest.fixture def ransomware_payload_config(ransomware_target): return { - "directories": {"linux_dir": str(ransomware_target), "windows_dir": str(ransomware_target)} + "directories": {"linux_dir": str(ransomware_target), "windows_dir": str(ransomware_target)}, + "other_behaviors": {"readme": False}, } @@ -166,3 +171,19 @@ def test_telemetry_failure(monkeypatch, ransomware_payload, telemetry_messenger_ assert "/file/not/exist" in telem_1.get_data()["ransomware_attempts"][0] assert "No such file or directory" in telem_1.get_data()["ransomware_attempts"][1] + + +def test_readme_false(ransomware_payload_config, ransomware_target, telemetry_messenger_spy): + ransomware_payload_config["other_behaviors"]["readme"] = False + ransomware_payload = RansomewarePayload(ransomware_payload_config, telemetry_messenger_spy) + + ransomware_payload.run_payload() + assert not Path(ransomware_target / README_DEST).exists() + + +def test_readme_true(ransomware_payload_config, ransomware_target, telemetry_messenger_spy): + ransomware_payload_config["other_behaviors"]["readme"] = True + ransomware_payload = RansomewarePayload(ransomware_payload_config, telemetry_messenger_spy) + + ransomware_payload.run_payload() + assert Path(ransomware_target / README_DEST).exists() From 92be6e72c24d1d589285116a9fc19b5a34ba09ba Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Mon, 28 Jun 2021 15:19:28 -0400 Subject: [PATCH 3/3] Island: Fix casing on README.TXT --- monkey/monkey_island/cc/services/config_schema/ransomware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/config_schema/ransomware.py b/monkey/monkey_island/cc/services/config_schema/ransomware.py index cbd4e4e72..bf7d5aced 100644 --- a/monkey/monkey_island/cc/services/config_schema/ransomware.py +++ b/monkey/monkey_island/cc/services/config_schema/ransomware.py @@ -27,7 +27,7 @@ RANSOMWARE = { "type": "object", "properties": { "readme": { - "title": "Create a README.TXT file", + "title": "Create a README.txt file", "type": "boolean", "default": True, "description": "Creates a README.txt ransomware note on infected systems.",