From e5702032d9a9aafd8b1be04687307c3e309b6a3a Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 11 Jul 2022 17:21:39 +0200 Subject: [PATCH 1/6] Island: Use ICredentialsRepository in credentials telemetry processing --- .../credentials/credentials_parser.py | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py index 8ab905ce6..aba21a1e1 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py @@ -2,10 +2,9 @@ import logging from itertools import chain from typing import Mapping -from common.credentials import CredentialComponentType -from monkey_island.cc.models import StolenCredentials +from common.credentials import CredentialComponentType, Credentials +from monkey_island.cc.repository import ICredentialsRepository -from .credentials import Credentials from .identities.username_processor import process_username from .secrets.lm_hash_processor import process_lm_hash from .secrets.nt_hash_processor import process_nt_hash @@ -23,19 +22,24 @@ CREDENTIAL_COMPONENT_PROCESSORS = { } -def parse_credentials(telemetry_dict: Mapping): - credentials = [ - Credentials.from_mapping(credential, telemetry_dict["monkey_guid"]) - for credential in telemetry_dict["data"] - ] +class CredentialsParser: + """ + This class parses and stores telemetry credentials. + """ - for credential in credentials: - _store_in_db(credential) - for cred_comp in chain(credential.identities, credential.secrets): - credential_type = CredentialComponentType[cred_comp["credential_type"]] - CREDENTIAL_COMPONENT_PROCESSORS[credential_type](cred_comp, credential) + def __init__(self, credentials_repository: ICredentialsRepository): + self._credentials_repository = credentials_repository + def __call__(self, telemetry_dict): + self._parse_credentials(telemetry_dict) -def _store_in_db(credentials: Credentials): - stolen_cred_doc = StolenCredentials.from_credentials(credentials) - stolen_cred_doc.save() + def _parse_credentials(self, telemetry_dict: Mapping): + credentials = [ + Credentials.from_mapping(credential) for credential in telemetry_dict["data"] + ] + self._credentials_repository.save_stolen_credentials(credentials) + + for credential in credentials: + for cred_comp in chain(credential.identities, credential.secrets): + credential_type = CredentialComponentType[cred_comp["credential_type"]] + CREDENTIAL_COMPONENT_PROCESSORS[credential_type](cred_comp, credential) From 2ad2d9474624d8033b95e89c1a61c3a7b67ee443 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 11 Jul 2022 17:22:55 +0200 Subject: [PATCH 2/6] Island: Remove from_credentials in StolenCredentials model --- monkey/monkey_island/cc/models/stolen_credentials.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/monkey/monkey_island/cc/models/stolen_credentials.py b/monkey/monkey_island/cc/models/stolen_credentials.py index f1ac83933..968610165 100644 --- a/monkey/monkey_island/cc/models/stolen_credentials.py +++ b/monkey/monkey_island/cc/models/stolen_credentials.py @@ -3,7 +3,6 @@ from __future__ import annotations from mongoengine import Document, ListField, ReferenceField from monkey_island.cc.models import Monkey -from monkey_island.cc.services.telemetry.processing.credentials import Credentials class StolenCredentials(Document): @@ -20,12 +19,3 @@ class StolenCredentials(Document): monkey = ReferenceField(Monkey) identities = ListField() secrets = ListField() - - @staticmethod - def from_credentials(credentials: Credentials) -> StolenCredentials: - stolen_creds = StolenCredentials() - - stolen_creds.secrets = [secret["credential_type"] for secret in credentials.secrets] - stolen_creds.identities = credentials.identities - stolen_creds.monkey = Monkey.get_single_monkey_by_guid(credentials.monkey_guid).id - return stolen_creds From 9d904fa9818efbd3362dae156e4cb8eeeb6d01f6 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 11 Jul 2022 17:24:20 +0200 Subject: [PATCH 3/6] Island: Add None as telemetry processing func for Credentials --- .../cc/services/telemetry/processing/processing.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/processing.py b/monkey/monkey_island/cc/services/telemetry/processing/processing.py index 709097ee0..569957c75 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/processing.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/processing.py @@ -3,9 +3,6 @@ import logging from common.common_consts.telem_categories import TelemCategoryEnum from monkey_island.cc.models.telemetries import save_telemetry from monkey_island.cc.services.telemetry.processing.aws_info import process_aws_telemetry -from monkey_island.cc.services.telemetry.processing.credentials.credentials_parser import ( - parse_credentials, -) from monkey_island.cc.services.telemetry.processing.exploit import process_exploit_telemetry from monkey_island.cc.services.telemetry.processing.post_breach import process_post_breach_telemetry from monkey_island.cc.services.telemetry.processing.scan import process_scan_telemetry @@ -18,7 +15,7 @@ TELEMETRY_CATEGORY_TO_PROCESSING_FUNC = { # `lambda *args, **kwargs: None` is a no-op. TelemCategoryEnum.ATTACK: lambda *args, **kwargs: None, TelemCategoryEnum.AWS_INFO: process_aws_telemetry, - TelemCategoryEnum.CREDENTIALS: parse_credentials, + TelemCategoryEnum.CREDENTIALS: None, # this is set in monkey_island/cc/services/initialize.py TelemCategoryEnum.EXPLOIT: process_exploit_telemetry, TelemCategoryEnum.POST_BREACH: process_post_breach_telemetry, TelemCategoryEnum.SCAN: process_scan_telemetry, From e816f8084654f2cefaa50e2cbf63c423f99f6940 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 11 Jul 2022 17:25:21 +0200 Subject: [PATCH 4/6] Island: Resolve CredentialsParser in DI * It also changes telemetry processing functions to use CredentialsParser object. This will be refactored! --- monkey/monkey_island/cc/services/initialize.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py index d51383132..7d9bde9e6 100644 --- a/monkey/monkey_island/cc/services/initialize.py +++ b/monkey/monkey_island/cc/services/initialize.py @@ -5,6 +5,7 @@ from pymongo import MongoClient from common import DIContainer from common.aws import AWSInstance +from common.common_consts.telem_categories import TelemCategoryEnum from common.configuration import ( DEFAULT_AGENT_CONFIGURATION, DEFAULT_RANSOMWARE_AGENT_CONFIGURATION, @@ -31,6 +32,12 @@ from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH from monkey_island.cc.services import AWSService, IslandModeService from monkey_island.cc.services.post_breach_files import PostBreachFilesService from monkey_island.cc.services.run_local_monkey import LocalMonkeyRunService +from monkey_island.cc.services.telemetry.processing.credentials.credentials_parser import ( + CredentialsParser, +) +from monkey_island.cc.services.telemetry.processing.processing import ( + TELEMETRY_CATEGORY_TO_PROCESSING_FUNC, +) from monkey_island.cc.setup.mongo.mongo_setup import MONGO_URL from . import AuthenticationService, JsonFileUserDatastore @@ -51,6 +58,10 @@ def initialize_services(data_dir: Path) -> DIContainer: _register_repositories(container, data_dir) _register_services(container) + # Note: A hack to resolve credentials parser + # It changes telemetry processing function, this will be refactored! + _patch_credentials_parser(container) + # This is temporary until we get DI all worked out. PostBreachFilesService.initialize(container.resolve(IFileRepository)) AuthenticationService.initialize(data_dir, JsonFileUserDatastore(data_dir)) @@ -129,3 +140,9 @@ def _register_services(container: DIContainer): container.register_instance(AWSService, container.resolve(AWSService)) container.register_instance(LocalMonkeyRunService, container.resolve(LocalMonkeyRunService)) container.register_instance(IslandModeService, container.resolve(IslandModeService)) + + +def _patch_credentials_parser(container: DIContainer): + TELEMETRY_CATEGORY_TO_PROCESSING_FUNC[TelemCategoryEnum.CREDENTIALS] = container.resolve( + CredentialsParser + ) From d477dc0197791f0fb72ca234b17d9306916d8995 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 11 Jul 2022 17:50:23 +0200 Subject: [PATCH 5/6] Island: Remove separate credentials telemetry parser --- .../processing/credentials/__init__.py | 1 - .../processing/credentials/credentials.py | 19 --- .../credentials/credentials_parser.py | 23 +--- .../credentials/identities/__init__.py | 0 .../identities/username_processor.py | 8 -- .../credentials/secrets/__init__.py | 0 .../credentials/secrets/lm_hash_processor.py | 8 -- .../credentials/secrets/nt_hash_processor.py | 8 -- .../credentials/secrets/password_processor.py | 8 -- .../credentials/secrets/ssh_key_processor.py | 32 ----- .../credentials/test_credential_processing.py | 112 ------------------ .../credentials/test_ssh_key_processing.py | 43 ------- 12 files changed, 2 insertions(+), 260 deletions(-) delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials.py delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/__init__.py delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/username_processor.py delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/__init__.py delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/lm_hash_processor.py delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/nt_hash_processor.py delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/password_processor.py delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/ssh_key_processor.py delete mode 100644 monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_credential_processing.py delete mode 100644 monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_ssh_key_processing.py diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/__init__.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/__init__.py index 034f2e83b..e69de29bb 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/__init__.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials/__init__.py @@ -1 +0,0 @@ -from .credentials import Credentials diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials.py deleted file mode 100644 index 25fe5835f..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import Any, Mapping, Sequence - - -@dataclass(frozen=True) -class Credentials: - identities: Sequence[Mapping] - secrets: Sequence[Mapping] - monkey_guid: str - - @staticmethod - def from_mapping(cred_dict: Mapping[str, Any], monkey_guid: str) -> Credentials: - return Credentials( - identities=cred_dict["identities"], - secrets=cred_dict["secrets"], - monkey_guid=monkey_guid, - ) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py index aba21a1e1..be14047be 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py @@ -1,26 +1,11 @@ import logging -from itertools import chain from typing import Mapping -from common.credentials import CredentialComponentType, Credentials +from common.credentials import Credentials from monkey_island.cc.repository import ICredentialsRepository -from .identities.username_processor import process_username -from .secrets.lm_hash_processor import process_lm_hash -from .secrets.nt_hash_processor import process_nt_hash -from .secrets.password_processor import process_password -from .secrets.ssh_key_processor import process_ssh_key - logger = logging.getLogger(__name__) -CREDENTIAL_COMPONENT_PROCESSORS = { - CredentialComponentType.LM_HASH: process_lm_hash, - CredentialComponentType.NT_HASH: process_nt_hash, - CredentialComponentType.PASSWORD: process_password, - CredentialComponentType.SSH_KEYPAIR: process_ssh_key, - CredentialComponentType.USERNAME: process_username, -} - class CredentialsParser: """ @@ -37,9 +22,5 @@ class CredentialsParser: credentials = [ Credentials.from_mapping(credential) for credential in telemetry_dict["data"] ] - self._credentials_repository.save_stolen_credentials(credentials) - for credential in credentials: - for cred_comp in chain(credential.identities, credential.secrets): - credential_type = CredentialComponentType[cred_comp["credential_type"]] - CREDENTIAL_COMPONENT_PROCESSORS[credential_type](cred_comp, credential) + self._credentials_repository.save_stolen_credentials(credentials) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/__init__.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/username_processor.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/username_processor.py deleted file mode 100644 index 1b2febdb9..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/username_processor.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Mapping - -from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.telemetry.processing.credentials import Credentials - - -def process_username(username: Mapping, _: Credentials): - ConfigService.creds_add_username(username["username"]) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/__init__.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/lm_hash_processor.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/lm_hash_processor.py deleted file mode 100644 index 4939c81bf..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/lm_hash_processor.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Mapping - -from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.telemetry.processing.credentials import Credentials - - -def process_lm_hash(lm_hash: Mapping, _: Credentials): - ConfigService.creds_add_lm_hash(lm_hash["lm_hash"]) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/nt_hash_processor.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/nt_hash_processor.py deleted file mode 100644 index 82f82af89..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/nt_hash_processor.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Mapping - -from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.telemetry.processing.credentials import Credentials - - -def process_nt_hash(nt_hash: Mapping, _: Credentials): - ConfigService.creds_add_ntlm_hash(nt_hash["nt_hash"]) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/password_processor.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/password_processor.py deleted file mode 100644 index 6df5a33ce..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/password_processor.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Mapping - -from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.telemetry.processing.credentials import Credentials - - -def process_password(password: Mapping, _: Credentials): - ConfigService.creds_add_password(password["password"]) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/ssh_key_processor.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/ssh_key_processor.py deleted file mode 100644 index be8ecf08a..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/ssh_key_processor.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Mapping - -from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.telemetry.processing.credentials import Credentials - - -class SSHKeyProcessingError(ValueError): - def __init__(self, msg=""): - self.msg = f"Error while processing ssh keypair: {msg}" - super().__init__(self.msg) - - -def process_ssh_key(keypair: Mapping, credentials: Credentials): - if len(credentials.identities) != 1: - raise SSHKeyProcessingError( - f"SSH credentials have {len(credentials.identities)} users associated with it!" - ) - - if not _contains_both_keys(keypair): - raise SSHKeyProcessingError("Private or public key missing") - - ConfigService.ssh_add_keys( - public_key=keypair["public_key"], - private_key=keypair["private_key"], - ) - - -def _contains_both_keys(ssh_key: Mapping) -> bool: - try: - return ssh_key["public_key"] and ssh_key["private_key"] - except KeyError: - return False diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_credential_processing.py b/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_credential_processing.py deleted file mode 100644 index d12ba15e4..000000000 --- a/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_credential_processing.py +++ /dev/null @@ -1,112 +0,0 @@ -from copy import deepcopy - -import dpath.util -import pytest -from tests.unit_tests.monkey_island.cc.services.telemetry.processing.credentials.conftest import ( - CREDENTIAL_TELEM_TEMPLATE, -) - -from common.config_value_paths import ( - LM_HASH_LIST_PATH, - NTLM_HASH_LIST_PATH, - PASSWORD_LIST_PATH, - USER_LIST_PATH, -) -from common.credentials import CredentialComponentType -from monkey_island.cc.models import StolenCredentials -from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.telemetry.processing.credentials.credentials_parser import ( - parse_credentials, -) - -fake_username = "m0nk3y_user" -cred_telem_usernames = deepcopy(CREDENTIAL_TELEM_TEMPLATE) -cred_telem_usernames["data"] = [ - {"identities": [{"username": fake_username, "credential_type": "USERNAME"}], "secrets": []} -] - -fake_special_username = "$m0nk3y.user" -cred_telem_special_usernames = deepcopy(CREDENTIAL_TELEM_TEMPLATE) -cred_telem_special_usernames["data"] = [ - { - "identities": [{"username": fake_special_username, "credential_type": "USERNAME"}], - "secrets": [], - } -] - -fake_nt_hash = "c1c58f96cdf212b50837bc11a00be47c" -fake_lm_hash = "299BD128C1101FD6" -fake_password = "trytostealthis" -cred_telem = deepcopy(CREDENTIAL_TELEM_TEMPLATE) -cred_telem["data"] = [ - { - "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, "credential_type": "PASSWORD"}, - ], - } -] - -cred_empty_telem = deepcopy(CREDENTIAL_TELEM_TEMPLATE) -cred_empty_telem["data"] = [{"identities": [], "secrets": []}] - - -@pytest.mark.slow -@pytest.mark.usefixtures("uses_database", "fake_mongo", "insert_fake_monkey") -def test_cred_username_parsing(): - parse_credentials(cred_telem_usernames) - config = ConfigService.get_config(should_decrypt=True) - assert fake_username in dpath.util.get(config, USER_LIST_PATH) - - -@pytest.mark.slow -@pytest.mark.usefixtures("uses_database", "fake_mongo", "insert_fake_monkey") -def test_cred_special_username_parsing(): - parse_credentials(cred_telem_special_usernames) - config = ConfigService.get_config(should_decrypt=True) - assert fake_special_username in dpath.util.get(config, USER_LIST_PATH) - - -@pytest.mark.slow -@pytest.mark.usefixtures("uses_database", "fake_mongo", "insert_fake_monkey") -def test_cred_telemetry_parsing(): - parse_credentials(cred_telem) - config = ConfigService.get_config(should_decrypt=True) - assert fake_username in dpath.util.get(config, USER_LIST_PATH) - assert fake_nt_hash in dpath.util.get(config, NTLM_HASH_LIST_PATH) - assert fake_lm_hash in dpath.util.get(config, LM_HASH_LIST_PATH) - assert fake_password in dpath.util.get(config, PASSWORD_LIST_PATH) - - -@pytest.mark.slow -@pytest.mark.usefixtures("uses_database", "fake_mongo", "insert_fake_monkey") -def test_cred_storage_in_db(): - parse_credentials(cred_telem) - cred_docs = list(StolenCredentials.objects()) - assert len(cred_docs) == 1 - - stolen_creds = cred_docs[0] - assert fake_username == stolen_creds.identities[0]["username"] - assert CredentialComponentType.PASSWORD.name in stolen_creds.secrets - assert CredentialComponentType.LM_HASH.name in stolen_creds.secrets - assert CredentialComponentType.NT_HASH.name in stolen_creds.secrets - - -@pytest.mark.slow -@pytest.mark.usefixtures("uses_database", "fake_mongo", "insert_fake_monkey") -def test_empty_cred_telemetry_parsing(): - default_config = deepcopy(ConfigService.get_config(should_decrypt=True)) - default_usernames = dpath.util.get(default_config, USER_LIST_PATH) - default_nt_hashes = dpath.util.get(default_config, NTLM_HASH_LIST_PATH) - default_lm_hashes = dpath.util.get(default_config, LM_HASH_LIST_PATH) - default_passwords = dpath.util.get(default_config, PASSWORD_LIST_PATH) - - parse_credentials(cred_empty_telem) - config = ConfigService.get_config(should_decrypt=True) - - assert default_usernames == dpath.util.get(config, USER_LIST_PATH) - assert default_nt_hashes == dpath.util.get(config, NTLM_HASH_LIST_PATH) - assert default_lm_hashes == dpath.util.get(config, LM_HASH_LIST_PATH) - assert default_passwords == dpath.util.get(config, PASSWORD_LIST_PATH) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_ssh_key_processing.py b/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_ssh_key_processing.py deleted file mode 100644 index 6c3161cd3..000000000 --- a/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_ssh_key_processing.py +++ /dev/null @@ -1,43 +0,0 @@ -from copy import deepcopy - -import dpath.util -import pytest -from tests.unit_tests.monkey_island.cc.services.telemetry.processing.credentials.conftest import ( - CREDENTIAL_TELEM_TEMPLATE, -) - -from common.config_value_paths import SSH_KEYS_PATH, USER_LIST_PATH -from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.telemetry.processing.credentials.credentials_parser import ( - parse_credentials, -) - -fake_private_key = "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAACmFlczI1N\n" -fake_partial_secret = {"private_key": fake_private_key, "credential_type": "SSH_KEYPAIR"} - -fake_username = "ubuntu" -fake_public_key = ( - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1u2+50OFRnzOGHpWo69" - "tc02oMXudeML7pOl7rqXLmdxuj monkey@krk-wpas5" -) -fake_secret_full = { - "private_key": fake_private_key, - "public_key": fake_public_key, - "credential_type": "SSH_KEYPAIR", -} -fake_identity = {"username": fake_username, "credential_type": "USERNAME"} - -ssh_telem = deepcopy(CREDENTIAL_TELEM_TEMPLATE) -ssh_telem["data"] = [{"identities": [fake_identity], "secrets": [fake_secret_full]}] - - -@pytest.mark.slow -@pytest.mark.usefixtures("uses_encryptor", "uses_database", "fake_mongo", "insert_fake_monkey") -def test_ssh_credential_parsing(): - parse_credentials(ssh_telem) - config = ConfigService.get_config(should_decrypt=True) - ssh_keypairs = dpath.util.get(config, SSH_KEYS_PATH) - assert len(ssh_keypairs) == 1 - assert ssh_keypairs[0]["private_key"] == fake_private_key - assert ssh_keypairs[0]["public_key"] == fake_public_key - assert fake_username in dpath.util.get(config, USER_LIST_PATH) From 9f060a2dd959e04c598ee19588cd964288f87f01 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 11 Jul 2022 17:51:46 +0200 Subject: [PATCH 6/6] Island: Remove config credentials adders --- monkey/monkey_island/cc/services/config.py | 47 ---------------------- 1 file changed, 47 deletions(-) diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index ea40c52a1..68fc46aac 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -9,7 +9,6 @@ from common.config_value_paths import ( PBA_LINUX_FILENAME_PATH, PBA_WINDOWS_FILENAME_PATH, SSH_KEYS_PATH, - USER_LIST_PATH, ) from monkey_island.cc.database import mongo from monkey_island.cc.server_utils.encryption import ( @@ -97,52 +96,6 @@ class ConfigService: mongo_key = ".".join(config_key_as_arr) mongo.db.config.update({}, {"$set": {mongo_key: value}}) - # 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): - item_key = ".".join(item_path_array) - items_from_config = ConfigService.get_config_value(item_path_array, should_encrypt) - if item_value in items_from_config: - return - if should_encrypt: - if isinstance(item_value, dict): - item_value = encrypt_dict(SENSITIVE_SSH_KEY_FIELDS, item_value) - else: - item_value = get_datastore_encryptor().encrypt(item_value) - mongo.db.config.update({}, {"$addToSet": {item_key: item_value}}) - - @staticmethod - def creds_add_username(username): - ConfigService.add_item_to_config_set_if_dont_exist( - USER_LIST_PATH, username, should_encrypt=False - ) - - @staticmethod - def creds_add_password(password): - ConfigService.add_item_to_config_set_if_dont_exist( - PASSWORD_LIST_PATH, password, should_encrypt=True - ) - - @staticmethod - def creds_add_lm_hash(lm_hash): - ConfigService.add_item_to_config_set_if_dont_exist( - LM_HASH_LIST_PATH, lm_hash, should_encrypt=True - ) - - @staticmethod - def creds_add_ntlm_hash(ntlm_hash): - ConfigService.add_item_to_config_set_if_dont_exist( - NTLM_HASH_LIST_PATH, ntlm_hash, should_encrypt=True - ) - - @staticmethod - def ssh_add_keys(public_key, private_key): - ConfigService.add_item_to_config_set_if_dont_exist( - SSH_KEYS_PATH, - {"public_key": public_key, "private_key": private_key}, - should_encrypt=True, - ) - @staticmethod def _filter_none_values(data): if isinstance(data, dict):