From 45b2558dddc8b58278b7326e39640ad64b6de1bf Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 6 Jul 2022 12:55:00 +0200 Subject: [PATCH 1/8] Island: Import ICredentialsRepository from __init__ --- monkey/monkey_island/cc/repository/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/monkey_island/cc/repository/__init__.py b/monkey/monkey_island/cc/repository/__init__.py index d90f6aac6..344644f3c 100644 --- a/monkey/monkey_island/cc/repository/__init__.py +++ b/monkey/monkey_island/cc/repository/__init__.py @@ -10,3 +10,4 @@ from .i_agent_configuration_repository import IAgentConfigurationRepository from .file_agent_configuration_repository import FileAgentConfigurationRepository from .i_simulation_repository import ISimulationRepository from .file_simulation_repository import FileSimulationRepository +from .i_credentials_repository import ICredentialsRepository From dc1eb5f12cf40027082734d32e65c90ce1574300 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 6 Jul 2022 12:58:23 +0200 Subject: [PATCH 2/8] Island: Use ICredentialsRepository to retrieve propagation credentials --- .../cc/resources/propagation_credentials.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/monkey/monkey_island/cc/resources/propagation_credentials.py b/monkey/monkey_island/cc/resources/propagation_credentials.py index d2d03730c..43dca03ba 100644 --- a/monkey/monkey_island/cc/resources/propagation_credentials.py +++ b/monkey/monkey_island/cc/resources/propagation_credentials.py @@ -1,15 +1,16 @@ +from flask import make_response + +from monkey_island.cc.repository import ICredentialsRepository from monkey_island.cc.resources.AbstractResource import AbstractResource -from monkey_island.cc.services.config import ConfigService class PropagationCredentials(AbstractResource): urls = ["/api/propagation-credentials"] + def __init__(self, credentials_repository: ICredentialsRepository): + self._credentials_repository = credentials_repository + def get(self): - config = ConfigService.get_flat_config(should_decrypt=True) + propagation_credentials = self._credentials_repository.get_all_credentials() - propagation_credentials = ConfigService.get_config_propagation_credentials_from_flat_config( - config - ) - - return {"propagation_credentials": propagation_credentials} + return make_response({"propagation_credentials": propagation_credentials}) From dda5e377642f3bc752102786798ca879518213b4 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 6 Jul 2022 13:01:26 +0200 Subject: [PATCH 3/8] Island: Remove unneeded function from ConfigService * get_flat_config * get_config_propagation_credentials_from_flat_config --- monkey/monkey_island/cc/services/config.py | 30 ------------------- .../monkey_island/cc/services/test_config.py | 17 ----------- 2 files changed, 47 deletions(-) delete mode 100644 monkey/tests/unit_tests/monkey_island/cc/services/test_config.py diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index ac7844ca2..ea40c52a1 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -1,7 +1,6 @@ import collections import functools import logging -from typing import Dict, List from common.config_value_paths import ( LM_HASH_LIST_PATH, @@ -98,25 +97,6 @@ class ConfigService: mongo_key = ".".join(config_key_as_arr) mongo.db.config.update({}, {"$set": {mongo_key: value}}) - @staticmethod - def get_flat_config(should_decrypt=True): - config_json = ConfigService.get_config(should_decrypt) - flat_config_json = {} - for i in config_json: - if i == "ransomware": - # Don't flatten the ransomware because ransomware payload expects a dictionary #1260 - flat_config_json[i] = config_json[i] - continue - for j in config_json[i]: - for k in config_json[i][j]: - if isinstance(config_json[i][j][k], dict): - for key, value in config_json[i][j][k].items(): - flat_config_json[key] = value - else: - flat_config_json[k] = config_json[i][j][k] - - return flat_config_json - # Not added to interface because it's doable by get_config_field + set_config_field @staticmethod def add_item_to_config_set_if_dont_exist(item_path_array, item_value, should_encrypt): @@ -251,13 +231,3 @@ class ConfigService: if is_decrypt else get_datastore_encryptor().encrypt(config_arr) ) - - @staticmethod - def get_config_propagation_credentials_from_flat_config(config) -> Dict[str, List[str]]: - return { - "exploit_user_list": config.get("exploit_user_list", []), - "exploit_password_list": config.get("exploit_password_list", []), - "exploit_lm_hash_list": config.get("exploit_lm_hash_list", []), - "exploit_ntlm_hash_list": config.get("exploit_ntlm_hash_list", []), - "exploit_ssh_keys": config.get("exploit_ssh_keys", []), - } diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py b/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py deleted file mode 100644 index 37249c2bc..000000000 --- a/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py +++ /dev/null @@ -1,17 +0,0 @@ -from monkey_island.cc.services.config import ConfigService - -# If tests fail because config path is changed, sync with -# monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js - - -def test_get_config_propagation_credentials_from_flat_config(flat_monkey_config): - expected_creds = { - "exploit_lm_hash_list": ["lm_hash_1", "lm_hash_2"], - "exploit_ntlm_hash_list": ["nt_hash_1", "nt_hash_2", "nt_hash_3"], - "exploit_password_list": ["test", "iloveyou", "12345"], - "exploit_ssh_keys": [{"private_key": "my_private_key", "public_key": "my_public_key"}], - "exploit_user_list": ["Administrator", "root", "user", "ubuntu"], - } - - creds = ConfigService.get_config_propagation_credentials_from_flat_config(flat_monkey_config) - assert creds == expected_creds From a27edfa94b0e82a3acd71e174e7be01f41564ca9 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 6 Jul 2022 13:04:01 +0200 Subject: [PATCH 4/8] UT: Add test for GET propagation credentials --- monkey/tests/monkey_island/__init__.py | 1 + .../propagation_credentials_repository.py | 62 +++++++++++++++++++ .../resources/test_propagation_credentials.py | 28 +++++++++ 3 files changed, 91 insertions(+) create mode 100644 monkey/tests/monkey_island/propagation_credentials_repository.py create mode 100644 monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py diff --git a/monkey/tests/monkey_island/__init__.py b/monkey/tests/monkey_island/__init__.py index 935752c37..1f3305665 100644 --- a/monkey/tests/monkey_island/__init__.py +++ b/monkey/tests/monkey_island/__init__.py @@ -3,3 +3,4 @@ from .mock_file_repository import MockFileRepository, FILE_CONTENTS, FILE_NAME from .open_error_file_repository import OpenErrorFileRepository from .in_memory_agent_configuration_repository import InMemoryAgentConfigurationRepository from .in_memory_simulation_configuration import InMemorySimulationRepository +from .propagation_credentials_repository import PropagationCredentialsRepository diff --git a/monkey/tests/monkey_island/propagation_credentials_repository.py b/monkey/tests/monkey_island/propagation_credentials_repository.py new file mode 100644 index 000000000..4ac1350fc --- /dev/null +++ b/monkey/tests/monkey_island/propagation_credentials_repository.py @@ -0,0 +1,62 @@ +from typing import Sequence + +from monkey_island.cc.repository import ICredentialsRepository +from monkey_island.cc.services.telemetry.processing.credentials import Credentials + +fake_username = "m0nk3y_user" +fake_special_username = "m0nk3y.user" +fake_nt_hash = "c1c58f96cdf212b50837bc11a00be47c" +fake_lm_hash = "299BD128C1101FD6" +fake_password_1 = "trytostealthis" +fake_password_2 = "password" +fake_password_3 = "12345678" +propagation_credentials_1 = { + "identities": [{"username": fake_username, "credential_type": "USERNAME"}], + "secrets": [ + {"nt_hash": fake_nt_hash, "credential_type": "NT_HASH"}, + {"lm_hash": fake_lm_hash, "credential_type": "LM_HASH"}, + {"password": fake_password_1, "credential_type": "PASSWORD"}, + ], +} + +propagation_credentials_2 = { + "identities": [ + {"username": fake_username, "credential_type": "USERNAME"}, + {"username": fake_special_username, "credential_type": "USERNAME"}, + ], + "secrets": [ + {"password": fake_password_1, "credential_type": "PASSWORD"}, + {"password": fake_password_2, "credential_type": "PASSWORD"}, + {"password": fake_password_3, "credential_type": "PASSWORD"}, + ], +} + + +class PropagationCredentialsRepository(ICredentialsRepository): + def get_configured_credentials(self) -> Sequence[Credentials]: + pass + + def get_stolen_credentials(self) -> Sequence[Credentials]: + pass + + def get_all_credentials(self) -> Sequence[Credentials]: + + return [ + Credentials.from_mapping(propagation_credentials_1, monkey_guid="some_guid"), + Credentials.from_mapping(propagation_credentials_2, monkey_guid="second_guid"), + ] + + def save_configured_credentials(self, credentials: Credentials): + pass + + def save_stolen_credentials(self, credentials: Credentials): + pass + + def remove_configured_credentials(self): + pass + + def remove_stolen_credentials(self): + pass + + def remove_all_credentials(self): + pass diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py new file mode 100644 index 000000000..374a6db9c --- /dev/null +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py @@ -0,0 +1,28 @@ +import json + +import pytest +from tests.common import StubDIContainer +from tests.monkey_island import PropagationCredentialsRepository +from tests.unit_tests.monkey_island.conftest import get_url_for_resource + +from monkey_island.cc.repository import ICredentialsRepository +from monkey_island.cc.resources.propagation_credentials import PropagationCredentials + + +@pytest.fixture +def flask_client(build_flask_client): + container = StubDIContainer() + + container.register(ICredentialsRepository, PropagationCredentialsRepository) + + with build_flask_client(container) as flask_client: + yield flask_client + + +def test_propagation_credentials_endpoint_get(flask_client): + propagation_credentials_url = get_url_for_resource(PropagationCredentials) + + resp = flask_client.get(propagation_credentials_url) + + assert resp.status_code == 200 + assert len(json.loads(resp.data)["propagation_credentials"]) == 2 From 794277797b58d93e8507fd3339f651e72838e4c1 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 6 Jul 2022 14:48:01 +0200 Subject: [PATCH 5/8] UT: Rename PropagationCredentialsRepository to StubPropagationCredentialsRepository --- monkey/tests/monkey_island/__init__.py | 2 +- ...pository.py => stub_propagation_credentials_repository.py} | 2 +- .../cc/resources/test_propagation_credentials.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename monkey/tests/monkey_island/{propagation_credentials_repository.py => stub_propagation_credentials_repository.py} (96%) diff --git a/monkey/tests/monkey_island/__init__.py b/monkey/tests/monkey_island/__init__.py index 1f3305665..df36a5d01 100644 --- a/monkey/tests/monkey_island/__init__.py +++ b/monkey/tests/monkey_island/__init__.py @@ -3,4 +3,4 @@ from .mock_file_repository import MockFileRepository, FILE_CONTENTS, FILE_NAME from .open_error_file_repository import OpenErrorFileRepository from .in_memory_agent_configuration_repository import InMemoryAgentConfigurationRepository from .in_memory_simulation_configuration import InMemorySimulationRepository -from .propagation_credentials_repository import PropagationCredentialsRepository +from .stub_propagation_credentials_repository import StubPropagationCredentialsRepository diff --git a/monkey/tests/monkey_island/propagation_credentials_repository.py b/monkey/tests/monkey_island/stub_propagation_credentials_repository.py similarity index 96% rename from monkey/tests/monkey_island/propagation_credentials_repository.py rename to monkey/tests/monkey_island/stub_propagation_credentials_repository.py index 4ac1350fc..3e3978e36 100644 --- a/monkey/tests/monkey_island/propagation_credentials_repository.py +++ b/monkey/tests/monkey_island/stub_propagation_credentials_repository.py @@ -32,7 +32,7 @@ propagation_credentials_2 = { } -class PropagationCredentialsRepository(ICredentialsRepository): +class StubPropagationCredentialsRepository(ICredentialsRepository): def get_configured_credentials(self) -> Sequence[Credentials]: pass diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py index 374a6db9c..26e9fb233 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py @@ -2,7 +2,7 @@ import json import pytest from tests.common import StubDIContainer -from tests.monkey_island import PropagationCredentialsRepository +from tests.monkey_island import StubPropagationCredentialsRepository from tests.unit_tests.monkey_island.conftest import get_url_for_resource from monkey_island.cc.repository import ICredentialsRepository @@ -13,7 +13,7 @@ from monkey_island.cc.resources.propagation_credentials import PropagationCreden def flask_client(build_flask_client): container = StubDIContainer() - container.register(ICredentialsRepository, PropagationCredentialsRepository) + container.register(ICredentialsRepository, StubPropagationCredentialsRepository) with build_flask_client(container) as flask_client: yield flask_client From 777897cb742181a2b0367570ce6c804a0c4b7f0d Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 6 Jul 2022 15:16:05 +0200 Subject: [PATCH 6/8] UT: Compare actual propagation credentials vs expected --- monkey/tests/monkey_island/__init__.py | 4 ++++ .../stub_propagation_credentials_repository.py | 8 ++++---- .../cc/resources/test_propagation_credentials.py | 14 ++++++++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/monkey/tests/monkey_island/__init__.py b/monkey/tests/monkey_island/__init__.py index df36a5d01..ee3098390 100644 --- a/monkey/tests/monkey_island/__init__.py +++ b/monkey/tests/monkey_island/__init__.py @@ -4,3 +4,7 @@ from .open_error_file_repository import OpenErrorFileRepository from .in_memory_agent_configuration_repository import InMemoryAgentConfigurationRepository from .in_memory_simulation_configuration import InMemorySimulationRepository from .stub_propagation_credentials_repository import StubPropagationCredentialsRepository +from .stub_propagation_credentials_repository import ( + PROPAGATION_CREDENTIALS_1, + PROPAGATION_CREDENTIALS_2, +) diff --git a/monkey/tests/monkey_island/stub_propagation_credentials_repository.py b/monkey/tests/monkey_island/stub_propagation_credentials_repository.py index 3e3978e36..7eeec1815 100644 --- a/monkey/tests/monkey_island/stub_propagation_credentials_repository.py +++ b/monkey/tests/monkey_island/stub_propagation_credentials_repository.py @@ -10,7 +10,7 @@ fake_lm_hash = "299BD128C1101FD6" fake_password_1 = "trytostealthis" fake_password_2 = "password" fake_password_3 = "12345678" -propagation_credentials_1 = { +PROPAGATION_CREDENTIALS_1 = { "identities": [{"username": fake_username, "credential_type": "USERNAME"}], "secrets": [ {"nt_hash": fake_nt_hash, "credential_type": "NT_HASH"}, @@ -19,7 +19,7 @@ propagation_credentials_1 = { ], } -propagation_credentials_2 = { +PROPAGATION_CREDENTIALS_2 = { "identities": [ {"username": fake_username, "credential_type": "USERNAME"}, {"username": fake_special_username, "credential_type": "USERNAME"}, @@ -42,8 +42,8 @@ class StubPropagationCredentialsRepository(ICredentialsRepository): def get_all_credentials(self) -> Sequence[Credentials]: return [ - Credentials.from_mapping(propagation_credentials_1, monkey_guid="some_guid"), - Credentials.from_mapping(propagation_credentials_2, monkey_guid="second_guid"), + Credentials.from_mapping(PROPAGATION_CREDENTIALS_1, monkey_guid="some_guid"), + Credentials.from_mapping(PROPAGATION_CREDENTIALS_2, monkey_guid="second_guid"), ] def save_configured_credentials(self, credentials: Credentials): diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py index 26e9fb233..e1469b1ea 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py @@ -2,7 +2,11 @@ import json import pytest from tests.common import StubDIContainer -from tests.monkey_island import StubPropagationCredentialsRepository +from tests.monkey_island import ( + PROPAGATION_CREDENTIALS_1, + PROPAGATION_CREDENTIALS_2, + StubPropagationCredentialsRepository, +) from tests.unit_tests.monkey_island.conftest import get_url_for_resource from monkey_island.cc.repository import ICredentialsRepository @@ -25,4 +29,10 @@ def test_propagation_credentials_endpoint_get(flask_client): resp = flask_client.get(propagation_credentials_url) assert resp.status_code == 200 - assert len(json.loads(resp.data)["propagation_credentials"]) == 2 + actual_propagation_credentials = json.loads(resp.data)["propagation_credentials"] + assert len(actual_propagation_credentials) == 2 + + del actual_propagation_credentials[0]["monkey_guid"] + assert actual_propagation_credentials[0] == PROPAGATION_CREDENTIALS_1 + del actual_propagation_credentials[1]["monkey_guid"] + assert actual_propagation_credentials[1] == PROPAGATION_CREDENTIALS_2 From af1ab34aa33bfa19e964b5a7e8ae1d4751e947d9 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 7 Jul 2022 10:24:33 +0200 Subject: [PATCH 7/8] Island: Return a list in Propagation Credentials endpoint --- monkey/monkey_island/cc/resources/propagation_credentials.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/resources/propagation_credentials.py b/monkey/monkey_island/cc/resources/propagation_credentials.py index 43dca03ba..8b14e9b1f 100644 --- a/monkey/monkey_island/cc/resources/propagation_credentials.py +++ b/monkey/monkey_island/cc/resources/propagation_credentials.py @@ -1,4 +1,4 @@ -from flask import make_response +from flask import jsonify from monkey_island.cc.repository import ICredentialsRepository from monkey_island.cc.resources.AbstractResource import AbstractResource @@ -13,4 +13,4 @@ class PropagationCredentials(AbstractResource): def get(self): propagation_credentials = self._credentials_repository.get_all_credentials() - return make_response({"propagation_credentials": propagation_credentials}) + return jsonify(propagation_credentials) From f806f848fafbb1105a26b48484370e34e6fa68af Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 7 Jul 2022 10:25:23 +0200 Subject: [PATCH 8/8] UT: Return a list in Propagation Credentials * Add TODOs to change to Credentials from common.credentials --- .../monkey_island/stub_propagation_credentials_repository.py | 1 + .../monkey_island/cc/resources/test_propagation_credentials.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/monkey/tests/monkey_island/stub_propagation_credentials_repository.py b/monkey/tests/monkey_island/stub_propagation_credentials_repository.py index 7eeec1815..7bf6f85a7 100644 --- a/monkey/tests/monkey_island/stub_propagation_credentials_repository.py +++ b/monkey/tests/monkey_island/stub_propagation_credentials_repository.py @@ -32,6 +32,7 @@ PROPAGATION_CREDENTIALS_2 = { } +# TODO: Use Credentials from common.credentials when serialization is implemented class StubPropagationCredentialsRepository(ICredentialsRepository): def get_configured_credentials(self) -> Sequence[Credentials]: pass diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py index e1469b1ea..08b8e942f 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py @@ -29,9 +29,10 @@ def test_propagation_credentials_endpoint_get(flask_client): resp = flask_client.get(propagation_credentials_url) assert resp.status_code == 200 - actual_propagation_credentials = json.loads(resp.data)["propagation_credentials"] + actual_propagation_credentials = json.loads(resp.data) assert len(actual_propagation_credentials) == 2 + # TODO: delete the removal of monkey_guid key when the serialization of credentials del actual_propagation_credentials[0]["monkey_guid"] assert actual_propagation_credentials[0] == PROPAGATION_CREDENTIALS_1 del actual_propagation_credentials[1]["monkey_guid"]