From d477dc0197791f0fb72ca234b17d9306916d8995 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 11 Jul 2022 17:50:23 +0200 Subject: [PATCH] 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)