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()