From 14845c659a11d5bc8c647b7a96d7d277996e22c5 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 22 Jun 2021 14:59:14 -0400 Subject: [PATCH 1/4] agent: Add is_not_symlink_filter() Adds a filter that can be used with filter_files() to return only files that are not symlinks. --- monkey/infection_monkey/utils/dir_utils.py | 4 ++++ .../infection_monkey/utils/test_dir_utils.py | 22 +++++++++++++++++++ monkey/tests/utils.py | 9 ++++++++ 3 files changed, 35 insertions(+) create mode 100644 monkey/tests/utils.py diff --git a/monkey/infection_monkey/utils/dir_utils.py b/monkey/infection_monkey/utils/dir_utils.py index 3cc839d0e..31455535e 100644 --- a/monkey/infection_monkey/utils/dir_utils.py +++ b/monkey/infection_monkey/utils/dir_utils.py @@ -19,3 +19,7 @@ def file_extension_filter(file_extensions: Set): return f.suffix in file_extensions return inner_filter + + +def is_not_symlink_filter(f: Path): + return not f.is_symlink() diff --git a/monkey/tests/unit_tests/infection_monkey/utils/test_dir_utils.py b/monkey/tests/unit_tests/infection_monkey/utils/test_dir_utils.py index b8ff47a65..089563cee 100644 --- a/monkey/tests/unit_tests/infection_monkey/utils/test_dir_utils.py +++ b/monkey/tests/unit_tests/infection_monkey/utils/test_dir_utils.py @@ -1,7 +1,13 @@ +import os + +import pytest +from tests.utils import is_user_admin + from infection_monkey.utils.dir_utils import ( file_extension_filter, filter_files, get_all_regular_files_in_directory, + is_not_symlink_filter, ) FILES = ["file.jpg.zip", "file.xyz", "1.tar", "2.tgz", "2.png", "2.mpg"] @@ -91,3 +97,19 @@ def test_file_extension_filter(tmp_path): filtered_files = filter_files(files_in_dir, [file_extension_filter(valid_extensions)]) assert sorted(files[0:2]) == sorted(filtered_files) + + +@pytest.mark.skipif( + os.name == "nt" and not is_user_admin(), reason="Test requires admin rights on Windows" +) +def test_is_not_symlink_filter(tmp_path): + files = add_files_to_dir(tmp_path) + link_path = tmp_path / "symlink.test" + link_path.symlink_to(files[0], target_is_directory=False) + + files_in_dir = get_all_regular_files_in_directory(tmp_path) + filtered_files = filter_files(files_in_dir, [is_not_symlink_filter]) + + assert link_path in files_in_dir + assert len(filtered_files) == len(FILES) + assert link_path not in filtered_files diff --git a/monkey/tests/utils.py b/monkey/tests/utils.py new file mode 100644 index 000000000..1e55e9bc3 --- /dev/null +++ b/monkey/tests/utils.py @@ -0,0 +1,9 @@ +import ctypes +import os + + +def is_user_admin(): + if os.name == "posix": + return os.getuid() == 0 + + return ctypes.windll.shell32.IsUserAnAdmin() From 4eaa56847966c0980b4fffeb9cfbe34edb5401ff Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 22 Jun 2021 15:04:48 -0400 Subject: [PATCH 2/4] agent: Do not encrypt symlinks in ransomware simulation In order to keep Infection Monkey safe for production environments, the ransomware payload will explicitly ignore symlinks to prevent important files from accidentally getting encrypted. --- monkey/infection_monkey/ransomware/ransomware_payload.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/ransomware/ransomware_payload.py b/monkey/infection_monkey/ransomware/ransomware_payload.py index d6a36ab5b..3ad33c29f 100644 --- a/monkey/infection_monkey/ransomware/ransomware_payload.py +++ b/monkey/infection_monkey/ransomware/ransomware_payload.py @@ -6,6 +6,7 @@ from infection_monkey.utils.dir_utils import ( file_extension_filter, filter_files, get_all_regular_files_in_directory, + is_not_symlink_filter, ) from infection_monkey.utils.environment import is_windows_os @@ -24,7 +25,10 @@ class RansomewarePayload: self._encrypt_files(file_list) def _find_files(self): - file_filters = [file_extension_filter(VALID_FILE_EXTENSIONS_FOR_ENCRYPTION)] + file_filters = [ + file_extension_filter(VALID_FILE_EXTENSIONS_FOR_ENCRYPTION), + is_not_symlink_filter, + ] all_files = get_all_regular_files_in_directory(self.target_dir) return filter_files(all_files, file_filters) From 41bf137ee4817c731928bda9dc81b887d70af2d8 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 22 Jun 2021 15:24:36 -0400 Subject: [PATCH 3/4] agent: Add is_not_shortcut_filter() Adds a filter that can be used with filter_files() to return only files that are not Windows shortcuts. --- monkey/infection_monkey/utils/dir_utils.py | 4 ++++ .../infection_monkey/utils/test_dir_utils.py | 14 +++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/utils/dir_utils.py b/monkey/infection_monkey/utils/dir_utils.py index 31455535e..704556335 100644 --- a/monkey/infection_monkey/utils/dir_utils.py +++ b/monkey/infection_monkey/utils/dir_utils.py @@ -23,3 +23,7 @@ def file_extension_filter(file_extensions: Set): def is_not_symlink_filter(f: Path): return not f.is_symlink() + + +def is_not_shortcut_filter(f: Path): + return f.suffix != ".lnk" diff --git a/monkey/tests/unit_tests/infection_monkey/utils/test_dir_utils.py b/monkey/tests/unit_tests/infection_monkey/utils/test_dir_utils.py index 089563cee..8ebddf280 100644 --- a/monkey/tests/unit_tests/infection_monkey/utils/test_dir_utils.py +++ b/monkey/tests/unit_tests/infection_monkey/utils/test_dir_utils.py @@ -7,10 +7,12 @@ from infection_monkey.utils.dir_utils import ( file_extension_filter, filter_files, get_all_regular_files_in_directory, + is_not_shortcut_filter, is_not_symlink_filter, ) -FILES = ["file.jpg.zip", "file.xyz", "1.tar", "2.tgz", "2.png", "2.mpg"] +SHORTCUT = "shortcut.lnk" +FILES = ["file.jpg.zip", "file.xyz", "1.tar", "2.tgz", "2.png", "2.mpg", SHORTCUT] SUBDIRS = ["subdir1", "subdir2"] @@ -113,3 +115,13 @@ def test_is_not_symlink_filter(tmp_path): assert link_path in files_in_dir assert len(filtered_files) == len(FILES) assert link_path not in filtered_files + + +def test_is_not_shortcut_filter(tmp_path): + add_files_to_dir(tmp_path) + + files_in_dir = get_all_regular_files_in_directory(tmp_path) + filtered_files = filter_files(files_in_dir, [is_not_shortcut_filter]) + + assert len(filtered_files) == len(FILES) - 1 + assert SHORTCUT not in [f.name for f in filtered_files] From 2549f088d157c969ce1d2a1dd617a93139924f4f Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 22 Jun 2021 15:26:06 -0400 Subject: [PATCH 4/4] agent: Do not encrypt Windows shortcuts in ransomware simulation In order to keep Infection Monkey safe for production environments, the ransomware payload will explicitly ignore Windows shortcuts to prevent important files from accidentally getting encrypted. --- monkey/infection_monkey/ransomware/ransomware_payload.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monkey/infection_monkey/ransomware/ransomware_payload.py b/monkey/infection_monkey/ransomware/ransomware_payload.py index 3ad33c29f..d2c8f578d 100644 --- a/monkey/infection_monkey/ransomware/ransomware_payload.py +++ b/monkey/infection_monkey/ransomware/ransomware_payload.py @@ -6,6 +6,7 @@ from infection_monkey.utils.dir_utils import ( file_extension_filter, filter_files, get_all_regular_files_in_directory, + is_not_shortcut_filter, is_not_symlink_filter, ) from infection_monkey.utils.environment import is_windows_os @@ -27,6 +28,7 @@ class RansomewarePayload: def _find_files(self): file_filters = [ file_extension_filter(VALID_FILE_EXTENSIONS_FOR_ENCRYPTION), + is_not_shortcut_filter, is_not_symlink_filter, ]