forked from p34709852/monkey
Agent: Handle interrupts in ransomware
This commit is contained in:
parent
05c5764487
commit
afbc313a7c
|
@ -43,12 +43,8 @@ class Ransomware:
|
||||||
file_list = self._find_files()
|
file_list = self._find_files()
|
||||||
self._encrypt_files(file_list, interrupt)
|
self._encrypt_files(file_list, interrupt)
|
||||||
|
|
||||||
if interrupt.is_set():
|
|
||||||
logger.debug("Received a stop signal, skipping remaining tasks of ransomware payload")
|
|
||||||
return
|
|
||||||
|
|
||||||
if self._config.readme_enabled:
|
if self._config.readme_enabled:
|
||||||
self._leave_readme_in_target_directory()
|
self._leave_readme_in_target_directory(interrupt)
|
||||||
|
|
||||||
def _find_files(self) -> List[Path]:
|
def _find_files(self) -> List[Path]:
|
||||||
logger.info(f"Collecting files in {self._target_directory}")
|
logger.info(f"Collecting files in {self._target_directory}")
|
||||||
|
@ -76,8 +72,12 @@ class Ransomware:
|
||||||
encryption_attempt = FileEncryptionTelem(str(filepath), success, error)
|
encryption_attempt = FileEncryptionTelem(str(filepath), success, error)
|
||||||
self._telemetry_messenger.send_telemetry(encryption_attempt)
|
self._telemetry_messenger.send_telemetry(encryption_attempt)
|
||||||
|
|
||||||
def _leave_readme_in_target_directory(self):
|
def _leave_readme_in_target_directory(self, interrupt: threading.Event):
|
||||||
try:
|
try:
|
||||||
|
if interrupt.is_set():
|
||||||
|
logger.debug("Received a stop signal, skipping leave readme")
|
||||||
|
return
|
||||||
|
|
||||||
self._leave_readme(README_SRC, self._readme_file_path)
|
self._leave_readme(README_SRC, self._readme_file_path)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.warning(f"An error occurred while attempting to leave a README.txt file: {ex}")
|
logger.warning(f"An error occurred while attempting to leave a README.txt file: {ex}")
|
||||||
|
|
|
@ -5,6 +5,7 @@ from unittest.mock import MagicMock
|
||||||
import pytest
|
import pytest
|
||||||
from tests.unit_tests.infection_monkey.payload.ransomware.ransomware_target_files import (
|
from tests.unit_tests.infection_monkey.payload.ransomware.ransomware_target_files import (
|
||||||
ALL_ZEROS_PDF,
|
ALL_ZEROS_PDF,
|
||||||
|
HELLO_TXT,
|
||||||
TEST_KEYBOARD_TXT,
|
TEST_KEYBOARD_TXT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -69,6 +70,11 @@ def mock_leave_readme():
|
||||||
return MagicMock()
|
return MagicMock()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def interrupt():
|
||||||
|
return threading.Event()
|
||||||
|
|
||||||
|
|
||||||
def test_files_selected_from_target_dir(
|
def test_files_selected_from_target_dir(
|
||||||
ransomware,
|
ransomware,
|
||||||
ransomware_options,
|
ransomware_options,
|
||||||
|
@ -86,6 +92,38 @@ def test_all_selected_files_encrypted(ransomware_test_data, ransomware, mock_fil
|
||||||
mock_file_encryptor.assert_any_call(ransomware_test_data / TEST_KEYBOARD_TXT)
|
mock_file_encryptor.assert_any_call(ransomware_test_data / TEST_KEYBOARD_TXT)
|
||||||
|
|
||||||
|
|
||||||
|
def test_interrupt_while_encrypting(
|
||||||
|
ransomware_test_data, interrupt, ransomware_options, build_ransomware
|
||||||
|
):
|
||||||
|
selected_files = [
|
||||||
|
ransomware_test_data / ALL_ZEROS_PDF,
|
||||||
|
ransomware_test_data / HELLO_TXT,
|
||||||
|
ransomware_test_data / TEST_KEYBOARD_TXT,
|
||||||
|
]
|
||||||
|
mfs = MagicMock(return_value=selected_files)
|
||||||
|
|
||||||
|
def _callback(file_path, *_):
|
||||||
|
# Block all threads here until 2 threads reach this barrier, then set stop
|
||||||
|
# and test that neither thread continues to scan.
|
||||||
|
if file_path.name == HELLO_TXT:
|
||||||
|
interrupt.set()
|
||||||
|
|
||||||
|
mfe = MagicMock(side_effect=_callback)
|
||||||
|
|
||||||
|
build_ransomware(ransomware_options, mfe, mfs).run(interrupt)
|
||||||
|
|
||||||
|
assert mfe.call_count == 2
|
||||||
|
mfe.assert_any_call(ransomware_test_data / ALL_ZEROS_PDF)
|
||||||
|
mfe.assert_any_call(ransomware_test_data / HELLO_TXT)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_readme_after_interrupt(ransomware, interrupt, mock_leave_readme):
|
||||||
|
interrupt.set()
|
||||||
|
ransomware.run(interrupt)
|
||||||
|
|
||||||
|
mock_leave_readme.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_encryption_skipped_if_configured_false(
|
def test_encryption_skipped_if_configured_false(
|
||||||
build_ransomware, ransomware_options, mock_file_encryptor
|
build_ransomware, ransomware_options, mock_file_encryptor
|
||||||
):
|
):
|
||||||
|
|
Loading…
Reference in New Issue