From 13a94804b44150877ab2b6d195478c4427acaaaf Mon Sep 17 00:00:00 2001 From: Shreya Date: Tue, 29 Jun 2021 16:02:20 +0530 Subject: [PATCH 01/10] cc: Add checkbox for ransomware encryption --- .../cc/services/config_schema/ransomware.py | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/ransomware.py b/monkey/monkey_island/cc/services/config_schema/ransomware.py index bf7d5aced..09f9c80ea 100644 --- a/monkey/monkey_island/cc/services/config_schema/ransomware.py +++ b/monkey/monkey_island/cc/services/config_schema/ransomware.py @@ -2,23 +2,36 @@ RANSOMWARE = { "title": "Ransomware", "type": "object", "properties": { - "directories": { - "title": "Directories to encrypt", + "encryption": { + "title": "Encryption", "type": "object", "properties": { - "linux_dir": { - "title": "Linux encryptable directory", - "type": "string", - "default": "", - "description": "Files in the specified directory will be encrypted " - "using bitflip to simulate ransomware.", + "should_encrypt": { + "title": "Encrypt files", + "type": "boolean", + "default": True, + "description": "Selected files will be encrypted using bitflip to simulate " + "ransomware. Enter target directories below.", }, - "windows_dir": { - "title": "Windows encryptable directory", - "type": "string", - "default": "", - "description": "Files in the specified directory will be encrypted " - "using bitflip to simulate ransomware.", + "directories": { + "title": "Directories to encrypt", + "type": "object", + "properties": { + "linux_dir": { + "title": "Linux encryptable directory", + "type": "string", + "default": "", + "description": "Files in the specified directory will be encrypted " + "using bitflip to simulate ransomware.", + }, + "windows_dir": { + "title": "Windows encryptable directory", + "type": "string", + "default": "", + "description": "Files in the specified directory will be encrypted " + "using bitflip to simulate ransomware.", + }, + }, }, }, }, From 4035d9d213f9c318851e465b56fcc584aa356744 Mon Sep 17 00:00:00 2001 From: Shreya Date: Tue, 29 Jun 2021 16:17:28 +0530 Subject: [PATCH 02/10] agent: Modify ransomware payload to work with modified ransomware config schema --- .../ransomware/ransomware_payload.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/monkey/infection_monkey/ransomware/ransomware_payload.py b/monkey/infection_monkey/ransomware/ransomware_payload.py index 698da80d4..1027b5def 100644 --- a/monkey/infection_monkey/ransomware/ransomware_payload.py +++ b/monkey/infection_monkey/ransomware/ransomware_payload.py @@ -21,7 +21,10 @@ README_DEST = "README.txt" class RansomwarePayload: def __init__(self, config: dict, telemetry_messenger: ITelemetryMessenger): - target_directories = config["directories"] + self.should_encrypt = config["encryption"]["should_encrypt"] + LOG.info(f"Encryption routine for ransomware simulation enabled: {self.should_encrypt}") + + target_directories = config["encryption"]["directories"] LOG.info( f"Windows dir configured for encryption is \"{target_directories['windows_dir']}\"" ) @@ -44,9 +47,11 @@ class RansomwarePayload: self._telemetry_messenger = telemetry_messenger def run_payload(self): - LOG.info("Running ransomware payload") - file_list = self._find_files() - self._encrypt_files(file_list) + if self.should_encrypt: + LOG.info("Running ransomware payload") + file_list = self._find_files() + self._encrypt_files(file_list) + self._leave_readme() def _find_files(self) -> List[Path]: From a1efd915b1165e47f9c37429c3dcbbcd0fca4581 Mon Sep 17 00:00:00 2001 From: Shreya Date: Tue, 29 Jun 2021 16:23:30 +0530 Subject: [PATCH 03/10] cc: Fix grammar in ransomware config schema --- 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 09f9c80ea..17475d019 100644 --- a/monkey/monkey_island/cc/services/config_schema/ransomware.py +++ b/monkey/monkey_island/cc/services/config_schema/ransomware.py @@ -36,7 +36,7 @@ RANSOMWARE = { }, }, "other_behaviors": { - "title": "Other Behaviors", + "title": "Other behavior", "type": "object", "properties": { "readme": { From 392ece29a014c89d93e6507d1607f7e659526c0d Mon Sep 17 00:00:00 2001 From: Shreya Date: Tue, 29 Jun 2021 16:39:27 +0530 Subject: [PATCH 04/10] tests: Modify/add tests for ransomware payload as per ransomware config schema changes --- .../ransomware/test_ransomware_payload.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) 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 80677ecf2..d5c48e815 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 @@ -32,7 +32,13 @@ def with_extension(filename): @pytest.fixture def ransomware_payload_config(ransomware_target): return { - "directories": {"linux_dir": str(ransomware_target), "windows_dir": str(ransomware_target)}, + "encryption": { + "should_encrypt": True, + "directories": { + "linux_dir": str(ransomware_target), + "windows_dir": str(ransomware_target), + }, + }, "other_behaviors": {"readme": False}, } @@ -127,6 +133,18 @@ def test_skip_already_encrypted_file(ransomware_target, ransomware_payload): ) +def test_encryption_skipped_if_configured_false( + ransomware_payload_config, ransomware_target, telemetry_messenger_spy +): + ransomware_payload_config["encryption"]["should_encrypt"] = False + + ransomware_payload = RansomwarePayload(ransomware_payload_config, telemetry_messenger_spy) + ransomware_payload.run_payload() + + assert hash_file(ransomware_target / ALL_ZEROS_PDF) == ALL_ZEROS_PDF_CLEARTEXT_SHA256 + assert hash_file(ransomware_target / TEST_KEYBOARD_TXT) == TEST_KEYBOARD_TXT_CLEARTEXT_SHA256 + + def test_telemetry_success(ransomware_payload, telemetry_messenger_spy): ransomware_payload.run_payload() From 619695d5bc9a0c017c4a9d42e921f37f97217063 Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 30 Jun 2021 13:34:38 +0530 Subject: [PATCH 05/10] agent: Rename `self.should_encrypt` to `self.encryption_enabled` in ransomware payload --- monkey/infection_monkey/ransomware/ransomware_payload.py | 6 +++--- .../monkey_island/cc/services/config_schema/ransomware.py | 2 +- .../infection_monkey/ransomware/test_ransomware_payload.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/monkey/infection_monkey/ransomware/ransomware_payload.py b/monkey/infection_monkey/ransomware/ransomware_payload.py index 1027b5def..d252db389 100644 --- a/monkey/infection_monkey/ransomware/ransomware_payload.py +++ b/monkey/infection_monkey/ransomware/ransomware_payload.py @@ -21,8 +21,8 @@ README_DEST = "README.txt" class RansomwarePayload: def __init__(self, config: dict, telemetry_messenger: ITelemetryMessenger): - self.should_encrypt = config["encryption"]["should_encrypt"] - LOG.info(f"Encryption routine for ransomware simulation enabled: {self.should_encrypt}") + self.encryption_enabled = config["encryption"]["enabled"] + LOG.info(f"Encryption routine for ransomware simulation enabled: {self.encryption_enabled}") target_directories = config["encryption"]["directories"] LOG.info( @@ -47,7 +47,7 @@ class RansomwarePayload: self._telemetry_messenger = telemetry_messenger def run_payload(self): - if self.should_encrypt: + if self.encryption_enabled: LOG.info("Running ransomware payload") file_list = self._find_files() self._encrypt_files(file_list) diff --git a/monkey/monkey_island/cc/services/config_schema/ransomware.py b/monkey/monkey_island/cc/services/config_schema/ransomware.py index 17475d019..50f23f162 100644 --- a/monkey/monkey_island/cc/services/config_schema/ransomware.py +++ b/monkey/monkey_island/cc/services/config_schema/ransomware.py @@ -6,7 +6,7 @@ RANSOMWARE = { "title": "Encryption", "type": "object", "properties": { - "should_encrypt": { + "enabled": { "title": "Encrypt files", "type": "boolean", "default": True, 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 d5c48e815..d5b2fae57 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 @@ -33,7 +33,7 @@ def with_extension(filename): def ransomware_payload_config(ransomware_target): return { "encryption": { - "should_encrypt": True, + "enabled": True, "directories": { "linux_dir": str(ransomware_target), "windows_dir": str(ransomware_target), @@ -136,7 +136,7 @@ def test_skip_already_encrypted_file(ransomware_target, ransomware_payload): def test_encryption_skipped_if_configured_false( ransomware_payload_config, ransomware_target, telemetry_messenger_spy ): - ransomware_payload_config["encryption"]["should_encrypt"] = False + ransomware_payload_config["encryption"]["enabled"] = False ransomware_payload = RansomwarePayload(ransomware_payload_config, telemetry_messenger_spy) ransomware_payload.run_payload() From aecb80566baf4e5c6eaec687f376076e14417c68 Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 30 Jun 2021 13:43:06 +0530 Subject: [PATCH 06/10] cc: Reword ransomware configuration fields' descriptions --- .../cc/services/config_schema/ransomware.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/ransomware.py b/monkey/monkey_island/cc/services/config_schema/ransomware.py index 50f23f162..78933107e 100644 --- a/monkey/monkey_island/cc/services/config_schema/ransomware.py +++ b/monkey/monkey_island/cc/services/config_schema/ransomware.py @@ -10,26 +10,28 @@ RANSOMWARE = { "title": "Encrypt files", "type": "boolean", "default": True, - "description": "Selected files will be encrypted using bitflip to simulate " - "ransomware. Enter target directories below.", + "description": "Ransomware encryption will be simulated by flipping every bit " + "in the files contained within the target directories.", }, "directories": { "title": "Directories to encrypt", "type": "object", "properties": { "linux_dir": { - "title": "Linux encryptable directory", + "title": "Linux target directory", "type": "string", "default": "", "description": "Files in the specified directory will be encrypted " - "using bitflip to simulate ransomware.", + "using bitflip. If no directory is specified, no files will be " + "encrypted.", }, "windows_dir": { - "title": "Windows encryptable directory", + "title": "Windows target directory", "type": "string", "default": "", "description": "Files in the specified directory will be encrypted " - "using bitflip to simulate ransomware.", + "using bitflip. If no directory is specified, no files will be " + "encrypted.", }, }, }, From 771aa747a87af070a5227570c02d9ce71c782fa4 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Jun 2021 06:53:27 -0400 Subject: [PATCH 07/10] Agent: encryption_enabled renamed using "private" naming convention --- monkey/infection_monkey/ransomware/ransomware_payload.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/ransomware/ransomware_payload.py b/monkey/infection_monkey/ransomware/ransomware_payload.py index d252db389..6486fb4d8 100644 --- a/monkey/infection_monkey/ransomware/ransomware_payload.py +++ b/monkey/infection_monkey/ransomware/ransomware_payload.py @@ -21,8 +21,10 @@ README_DEST = "README.txt" class RansomwarePayload: def __init__(self, config: dict, telemetry_messenger: ITelemetryMessenger): - self.encryption_enabled = config["encryption"]["enabled"] - LOG.info(f"Encryption routine for ransomware simulation enabled: {self.encryption_enabled}") + self._encryption_enabled = config["encryption"]["enabled"] + LOG.info( + f"Encryption routine for ransomware simulation enabled: {self._encryption_enabled}" + ) target_directories = config["encryption"]["directories"] LOG.info( @@ -47,7 +49,7 @@ class RansomwarePayload: self._telemetry_messenger = telemetry_messenger def run_payload(self): - if self.encryption_enabled: + if self._encryption_enabled: LOG.info("Running ransomware payload") file_list = self._find_files() self._encrypt_files(file_list) From 9a58d5bc7addc2e4042a2fea310e87534d7b3d0a Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Jun 2021 07:24:37 -0400 Subject: [PATCH 08/10] Island: Reword ransomware target directory descriptions --- .../cc/services/config_schema/ransomware.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/ransomware.py b/monkey/monkey_island/cc/services/config_schema/ransomware.py index 78933107e..fbc2e485e 100644 --- a/monkey/monkey_island/cc/services/config_schema/ransomware.py +++ b/monkey/monkey_island/cc/services/config_schema/ransomware.py @@ -21,17 +21,17 @@ RANSOMWARE = { "title": "Linux target directory", "type": "string", "default": "", - "description": "Files in the specified directory will be encrypted " - "using bitflip. If no directory is specified, no files will be " - "encrypted.", + "description": "A path to a directory on Linux systems that can be " + "used to safely simulate the encryption behavior of ransomware. If no " + "directory is specified, no files will be encrypted.", }, "windows_dir": { "title": "Windows target directory", "type": "string", "default": "", - "description": "Files in the specified directory will be encrypted " - "using bitflip. If no directory is specified, no files will be " - "encrypted.", + "description": "A path to a directory on Windows systems that can be " + "used to safely simulate the encryption behavior of ransomware. If no " + "directory is specified, no files will be encrypted.", }, }, }, From 946641f9a25a6e9b6786b8518bec6c8c39dfc5e8 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Jun 2021 07:29:53 -0400 Subject: [PATCH 09/10] Rename {windows,linux}_dir to *_target_dir for consistency --- .../infection_monkey/ransomware/ransomware_payload.py | 10 ++++++---- .../cc/services/config_schema/ransomware.py | 4 ++-- .../ransomware/test_ransomware_payload.py | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/monkey/infection_monkey/ransomware/ransomware_payload.py b/monkey/infection_monkey/ransomware/ransomware_payload.py index 6486fb4d8..13e8015d6 100644 --- a/monkey/infection_monkey/ransomware/ransomware_payload.py +++ b/monkey/infection_monkey/ransomware/ransomware_payload.py @@ -28,14 +28,16 @@ class RansomwarePayload: target_directories = config["encryption"]["directories"] LOG.info( - f"Windows dir configured for encryption is \"{target_directories['windows_dir']}\"" + "Windows dir configured for encryption is " + target_directories["windows_target_dir"] + ) + LOG.info( + f"Linux dir configured for encryption is \"{target_directories['linux_target_dir']}\"" ) - LOG.info(f"Linux dir configured for encryption is \"{target_directories['linux_dir']}\"") self._target_dir = ( - target_directories["windows_dir"] + target_directories["windows_target_dir"] if is_windows_os() - else target_directories["linux_dir"] + else target_directories["linux_target_dir"] ) self._readme_enabled = config["other_behaviors"]["readme"] diff --git a/monkey/monkey_island/cc/services/config_schema/ransomware.py b/monkey/monkey_island/cc/services/config_schema/ransomware.py index fbc2e485e..c30c1a392 100644 --- a/monkey/monkey_island/cc/services/config_schema/ransomware.py +++ b/monkey/monkey_island/cc/services/config_schema/ransomware.py @@ -17,7 +17,7 @@ RANSOMWARE = { "title": "Directories to encrypt", "type": "object", "properties": { - "linux_dir": { + "linux_target_dir": { "title": "Linux target directory", "type": "string", "default": "", @@ -25,7 +25,7 @@ RANSOMWARE = { "used to safely simulate the encryption behavior of ransomware. If no " "directory is specified, no files will be encrypted.", }, - "windows_dir": { + "windows_target_dir": { "title": "Windows target directory", "type": "string", "default": "", 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 d5b2fae57..36dc6615e 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 @@ -35,8 +35,8 @@ def ransomware_payload_config(ransomware_target): "encryption": { "enabled": True, "directories": { - "linux_dir": str(ransomware_target), - "windows_dir": str(ransomware_target), + "linux_target_dir": str(ransomware_target), + "windows_target_dir": str(ransomware_target), }, }, "other_behaviors": {"readme": False}, From 169bb341061bda4bb415e9746de29ef4abcfeea3 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Jun 2021 07:43:18 -0400 Subject: [PATCH 10/10] Agent: Simplify and improve logging in RansomwarePayload --- .../ransomware/ransomware_payload.py | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/monkey/infection_monkey/ransomware/ransomware_payload.py b/monkey/infection_monkey/ransomware/ransomware_payload.py index 13e8015d6..dcc0055de 100644 --- a/monkey/infection_monkey/ransomware/ransomware_payload.py +++ b/monkey/infection_monkey/ransomware/ransomware_payload.py @@ -1,6 +1,7 @@ import logging import shutil from pathlib import Path +from pprint import pformat from typing import List, Optional, Tuple from infection_monkey.ransomware.bitflip_encryptor import BitflipEncryptor @@ -21,28 +22,18 @@ README_DEST = "README.txt" class RansomwarePayload: def __init__(self, config: dict, telemetry_messenger: ITelemetryMessenger): + LOG.debug(f"Ransomware payload configuration:\n{pformat(config)}") + self._encryption_enabled = config["encryption"]["enabled"] - LOG.info( - f"Encryption routine for ransomware simulation enabled: {self._encryption_enabled}" - ) + self._readme_enabled = config["other_behaviors"]["readme"] target_directories = config["encryption"]["directories"] - LOG.info( - "Windows dir configured for encryption is " + target_directories["windows_target_dir"] - ) - LOG.info( - f"Linux dir configured for encryption is \"{target_directories['linux_target_dir']}\"" - ) - self._target_dir = ( target_directories["windows_target_dir"] if is_windows_os() else target_directories["linux_target_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) @@ -59,6 +50,7 @@ class RansomwarePayload: self._leave_readme() def _find_files(self) -> List[Path]: + LOG.info(f"Collecting files in {self._target_dir}") if not self._target_dir: return [] @@ -67,6 +59,8 @@ class RansomwarePayload: ) def _encrypt_files(self, file_list: List[Path]) -> List[Tuple[Path, Optional[Exception]]]: + LOG.info(f"Encrypting files in {self._target_dir}") + results = [] for filepath in file_list: try: