From 5c5e1702969767628ddea583c0f2b764b7cea8cc Mon Sep 17 00:00:00 2001 From: vakarisz Date: Thu, 17 Feb 2022 13:18:10 +0200 Subject: [PATCH 01/18] Island: Add processors for credentials --- .../telemetry/processing/credentials.py | 7 ++++ .../__init__.py | 0 .../credentials/credentials_parser.py | 39 ++++++++++++++++++ .../credentials/identities/__init__.py | 0 .../identities/username_processor.py | 2 + .../credentials/secrets/__init__.py | 0 .../credentials/secrets/lm_hash_processor.py | 5 +++ .../credentials/secrets/nt_hash_processor.py | 5 +++ .../credentials/secrets/password_processor.py | 5 +++ .../credentials/secrets/ssh_key_processor.py | 40 +++++++++++++++++++ 10 files changed, 103 insertions(+) create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials.py rename monkey/monkey_island/cc/services/telemetry/processing/{system_info_collectors => credentials}/__init__.py (100%) create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/__init__.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/username_processor.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/__init__.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/lm_hash_processor.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/nt_hash_processor.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/password_processor.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/ssh_key_processor.py diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials.py new file mode 100644 index 000000000..fa772d1fd --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials.py @@ -0,0 +1,7 @@ +from monkey_island.cc.services.telemetry.processing.credentials.credentials_parser import ( + parse_credentials, +) + + +def process_credentials_telemetry(telemetry: dict): + parse_credentials(telemetry) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/__init__.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials/__init__.py similarity index 100% rename from monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/__init__.py rename to monkey/monkey_island/cc/services/telemetry/processing/credentials/__init__.py 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 new file mode 100644 index 000000000..af022b678 --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py @@ -0,0 +1,39 @@ +import logging + +from infection_monkey.i_puppet import CredentialType + +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__) + +SECRET_PROCESSORS = { + CredentialType.PASSWORD: process_password, + CredentialType.NT_HASH: process_nt_hash, + CredentialType.LM_HASH: process_lm_hash, + CredentialType.SSH_KEYPAIR: process_ssh_key, +} + +IDENTITY_PROCESSORS = { + CredentialType.USERNAME: process_username, +} + + +def parse_credentials(credentials: dict): + for credential in credentials["credentials"]: + if is_ssh_keypair(credentials): + IDENTITY_PROCESSORS[CredentialType.SSH_KEYPAIR](credential, credentials["monkey_guid"]) + else: + for identity in credential["identities"]: + IDENTITY_PROCESSORS[identity["type"]](identity) + for secret in credential["secrets"]: + SECRET_PROCESSORS[secret["type"]](secret) + + +def is_ssh_keypair(credentials: dict) -> bool: + return bool( + filter(credentials["secrets"], lambda secret: secret["type"] == CredentialType.SSH_KEYPAIR) + ) 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 new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..c13af4d67 --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials/identities/username_processor.py @@ -0,0 +1,2 @@ +def process_username(): + pass 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 new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..4cc4c28e3 --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/lm_hash_processor.py @@ -0,0 +1,5 @@ +from monkey_island.cc.services.config import ConfigService + + +def process_lm_hash(lm_hash: dict): + ConfigService.creds_add_ntlm_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 new file mode 100644 index 000000000..e29e2eef0 --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/nt_hash_processor.py @@ -0,0 +1,5 @@ +from monkey_island.cc.services.config import ConfigService + + +def process_nt_hash(nt_hash: dict): + 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 new file mode 100644 index 000000000..6d3331db6 --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/password_processor.py @@ -0,0 +1,5 @@ +from monkey_island.cc.services.config import ConfigService + + +def process_password(password: dict): + 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 new file mode 100644 index 000000000..df0557115 --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/ssh_key_processor.py @@ -0,0 +1,40 @@ +from common.common_consts.credentials_type import CredentialsType +from monkey_island.cc.models import Monkey +from monkey_island.cc.server_utils.encryption import get_datastore_encryptor +from monkey_island.cc.services.config import ConfigService + + +class SSHKeyProcessingError(ValueError): + def __init__(self, msg=""): + self.msg = f"Error while processing ssh keypair: {msg}" + super().__init__(self.msg) + + +def process_ssh_key(credentials: dict, monkey_guid: str): + if len(credentials["identities"]) != 1: + raise SSHKeyProcessingError( + f'SSH credentials have {len(credentials["identities"])}' f" users associated with it!" + ) + + for ssh_key in credentials["secrets"]: + if not ssh_key["type"] == CredentialsType.SSH_KEYPAIR: + raise SSHKeyProcessingError("SSH credentials contain secrets that are not keypairs") + + if not ssh_key["public_key"] or not ssh_key["private_key"]: + raise SSHKeyProcessingError("Private or public key missing!") + + # TODO SSH key should be associated with IP that monkey exploited + ip = Monkey.get_single_monkey_by_guid(monkey_guid).ip_addresses[0] + username = credentials["identities"][0]["username"] + + ConfigService.ssh_add_keys( + user=username, + public_key=ssh_key["public_key"], + private_key=ssh_key["private_key"], + ip=ip, + ) + + +def encrypt_system_info_ssh_keys(ssh_key: dict): + for field in ["public_key", "private_key"]: + ssh_key[field] = get_datastore_encryptor().encrypt(ssh_key[field]) From 597fe358064afe936fb4742e4d9ded70fc7abd7f Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 17 Feb 2022 15:28:23 +0100 Subject: [PATCH 02/18] Island: Remove WMI handler that processed wmi info * Leftover from broken info gathering package --- .../telemetry/processing/system_info.py | 12 -- .../monkey_island/cc/services/wmi_handler.py | 181 ------------------ 2 files changed, 193 deletions(-) delete mode 100644 monkey/monkey_island/cc/services/wmi_handler.py diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index 7d7f404ce..06ee2e168 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -2,11 +2,9 @@ import logging from monkey_island.cc.server_utils.encryption import get_datastore_encryptor from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import ( # noqa: E501 SystemInfoTelemetryDispatcher, ) -from monkey_island.cc.services.wmi_handler import WMIHandler logger = logging.getLogger(__name__) @@ -16,7 +14,6 @@ def process_system_info_telemetry(telemetry_json): telemetry_processing_stages = [ process_ssh_info, process_credential_info, - process_wmi_info, dispatcher.dispatch_collector_results_to_relevant_processors, ] @@ -96,12 +93,3 @@ def add_system_info_creds_to_config(creds): ConfigService.creds_add_lm_hash(creds[user]["lm_hash"]) if "ntlm_hash" in creds[user] and creds[user]["ntlm_hash"]: ConfigService.creds_add_ntlm_hash(creds[user]["ntlm_hash"]) - - -def process_wmi_info(telemetry_json): - users_secrets = {} - - if "wmi" in telemetry_json["data"]: - monkey_id = NodeService.get_monkey_by_guid(telemetry_json["monkey_guid"]).get("_id") - wmi_handler = WMIHandler(monkey_id, telemetry_json["data"]["wmi"], users_secrets) - wmi_handler.process_and_handle_wmi_info() diff --git a/monkey/monkey_island/cc/services/wmi_handler.py b/monkey/monkey_island/cc/services/wmi_handler.py deleted file mode 100644 index d2f3441f9..000000000 --- a/monkey/monkey_island/cc/services/wmi_handler.py +++ /dev/null @@ -1,181 +0,0 @@ -from monkey_island.cc.database import mongo -from monkey_island.cc.services.groups_and_users_consts import GROUPTYPE, USERTYPE - - -class WMIHandler(object): - ADMINISTRATORS_GROUP_KNOWN_SID = "1-5-32-544" - - def __init__(self, monkey_id, wmi_info, user_secrets): - - self.monkey_id = monkey_id - self.info_for_mongo = {} - self.users_secrets = user_secrets - if not wmi_info: - self.users_info = "" - self.groups_info = "" - self.groups_and_users = "" - self.services = "" - self.products = "" - else: - self.users_info = wmi_info["Win32_UserAccount"] - self.groups_info = wmi_info["Win32_Group"] - self.groups_and_users = wmi_info["Win32_GroupUser"] - self.services = wmi_info["Win32_Service"] - self.products = wmi_info["Win32_Product"] - - def process_and_handle_wmi_info(self): - - self.add_groups_to_collection() - self.add_users_to_collection() - self.create_group_user_connection() - self.insert_info_to_mongo() - if self.info_for_mongo: - self.add_admin(self.info_for_mongo[self.ADMINISTRATORS_GROUP_KNOWN_SID], self.monkey_id) - self.update_admins_retrospective() - self.update_critical_services() - - def update_critical_services(self): - critical_names = ("W3svc", "MSExchangeServiceHost", "dns", "MSSQL$SQLEXPRES") - mongo.db.monkey.update({"_id": self.monkey_id}, {"$set": {"critical_services": []}}) - - services_names_list = [str(i["Name"])[2:-1] for i in self.services] - products_names_list = [str(i["Name"])[2:-2] for i in self.products] - - for name in critical_names: - if name in services_names_list or name in products_names_list: - mongo.db.monkey.update( - {"_id": self.monkey_id}, {"$addToSet": {"critical_services": name}} - ) - - def build_entity_document(self, entity_info, monkey_id=None): - general_properties_dict = { - "SID": str(entity_info["SID"])[4:-1], - "name": str(entity_info["Name"])[2:-1], - "machine_id": monkey_id, - "member_of": [], - "admin_on_machines": [], - } - - if monkey_id: - general_properties_dict["domain_name"] = None - else: - general_properties_dict["domain_name"] = str(entity_info["Domain"])[2:-1] - - return general_properties_dict - - def add_users_to_collection(self): - for user in self.users_info: - if not user.get("LocalAccount"): - base_entity = self.build_entity_document(user) - else: - base_entity = self.build_entity_document(user, self.monkey_id) - base_entity["NTLM_secret"] = self.users_secrets.get(base_entity["name"], {}).get( - "ntlm_hash" - ) - base_entity["SAM_secret"] = self.users_secrets.get(base_entity["name"], {}).get("sam") - base_entity["secret_location"] = [] - - base_entity["type"] = USERTYPE - self.info_for_mongo[base_entity.get("SID")] = base_entity - - def add_groups_to_collection(self): - for group in self.groups_info: - if not group.get("LocalAccount"): - base_entity = self.build_entity_document(group) - else: - base_entity = self.build_entity_document(group, self.monkey_id) - base_entity["entities_list"] = [] - base_entity["type"] = GROUPTYPE - self.info_for_mongo[base_entity.get("SID")] = base_entity - - def create_group_user_connection(self): - for group_user_couple in self.groups_and_users: - group_part = group_user_couple["GroupComponent"] - child_part = group_user_couple["PartComponent"] - group_sid = str(group_part["SID"])[4:-1] - groups_entities_list = self.info_for_mongo[group_sid]["entities_list"] - child_sid = "" - - if isinstance(child_part, str): - child_part = str(child_part) - name = None - domain_name = None - if "cimv2:Win32_UserAccount" in child_part: - # domain user - domain_name = child_part.split('cimv2:Win32_UserAccount.Domain="')[1].split( - '",Name="' - )[0] - name = child_part.split('cimv2:Win32_UserAccount.Domain="')[1].split( - '",Name="' - )[1][:-2] - - if "cimv2:Win32_Group" in child_part: - # domain group - domain_name = child_part.split('cimv2:Win32_Group.Domain="')[1].split( - '",Name="' - )[0] - name = child_part.split('cimv2:Win32_Group.Domain="')[1].split('",Name="')[1][ - :-2 - ] - - for entity in self.info_for_mongo: - if ( - self.info_for_mongo[entity]["name"] == name - and self.info_for_mongo[entity]["domain"] == domain_name - ): - child_sid = self.info_for_mongo[entity]["SID"] - else: - child_sid = str(child_part["SID"])[4:-1] - - if child_sid and child_sid not in groups_entities_list: - groups_entities_list.append(child_sid) - - if child_sid: - if child_sid in self.info_for_mongo: - self.info_for_mongo[child_sid]["member_of"].append(group_sid) - - def insert_info_to_mongo(self): - for entity in list(self.info_for_mongo.values()): - if entity["machine_id"]: - # Handling for local entities. - mongo.db.groupsandusers.update( - {"SID": entity["SID"], "machine_id": entity["machine_id"]}, entity, upsert=True - ) - else: - # Handlings for domain entities. - if not mongo.db.groupsandusers.find_one({"SID": entity["SID"]}): - mongo.db.groupsandusers.insert_one(entity) - else: - # if entity is domain entity, add the monkey id of current machine to - # secrets_location. - # (found on this machine) - if entity.get("NTLM_secret"): - mongo.db.groupsandusers.update_one( - {"SID": entity["SID"], "type": USERTYPE}, - {"$addToSet": {"secret_location": self.monkey_id}}, - ) - - def update_admins_retrospective(self): - for profile in self.info_for_mongo: - groups_from_mongo = mongo.db.groupsandusers.find( - {"SID": {"$in": self.info_for_mongo[profile]["member_of"]}}, - {"admin_on_machines": 1}, - ) - - for group in groups_from_mongo: - if group["admin_on_machines"]: - mongo.db.groupsandusers.update_one( - {"SID": self.info_for_mongo[profile]["SID"]}, - {"$addToSet": {"admin_on_machines": {"$each": group["admin_on_machines"]}}}, - ) - - def add_admin(self, group, machine_id): - for sid in group["entities_list"]: - mongo.db.groupsandusers.update_one( - {"SID": sid}, {"$addToSet": {"admin_on_machines": machine_id}} - ) - entity_details = mongo.db.groupsandusers.find_one( - {"SID": sid}, {"type": USERTYPE, "entities_list": 1} - ) - if entity_details.get("type") == GROUPTYPE: - self.add_admin(entity_details, machine_id) From a8717dc69104758bad9efc4ac4b38f172bdb0c12 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Thu, 17 Feb 2022 10:37:20 +0200 Subject: [PATCH 03/18] Agent: rename and move credentials_type enum to common --- .../common_consts/credentials_type.py} | 2 +- .../credential_components/lm_hash.py | 5 +++-- .../credential_components/nt_hash.py | 5 +++-- .../credential_components/password.py | 5 +++-- .../credential_components/ssh_keypair.py | 5 +++-- .../credential_components/username.py | 5 +++-- monkey/infection_monkey/i_puppet/__init__.py | 11 +++++------ .../i_puppet/credential_collection/__init__.py | 1 - .../credential_collection/i_credential_component.py | 4 ++-- .../cc/services/telemetry/processing/processing.py | 1 + 10 files changed, 24 insertions(+), 20 deletions(-) rename monkey/{infection_monkey/i_puppet/credential_collection/credential_type.py => common/common_consts/credentials_type.py} (79%) diff --git a/monkey/infection_monkey/i_puppet/credential_collection/credential_type.py b/monkey/common/common_consts/credentials_type.py similarity index 79% rename from monkey/infection_monkey/i_puppet/credential_collection/credential_type.py rename to monkey/common/common_consts/credentials_type.py index ef00f3732..e818b1e5c 100644 --- a/monkey/infection_monkey/i_puppet/credential_collection/credential_type.py +++ b/monkey/common/common_consts/credentials_type.py @@ -1,7 +1,7 @@ from enum import Enum -class CredentialType(Enum): +class CredentialsType(Enum): USERNAME = 1 PASSWORD = 2 NT_HASH = 3 diff --git a/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py b/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py index 7706540a3..a7be177a8 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py @@ -1,9 +1,10 @@ from dataclasses import dataclass, field -from infection_monkey.i_puppet import CredentialType, ICredentialComponent +from common.common_consts.credentials_type import CredentialsType +from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class LMHash(ICredentialComponent): - credential_type: CredentialType = field(default=CredentialType.LM_HASH, init=False) + credential_type: CredentialsType = field(default=CredentialsType.LM_HASH, init=False) lm_hash: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py b/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py index e6932c4c5..d23f42a1d 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py @@ -1,9 +1,10 @@ from dataclasses import dataclass, field -from infection_monkey.i_puppet import CredentialType, ICredentialComponent +from common.common_consts.credentials_type import CredentialsType +from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class NTHash(ICredentialComponent): - credential_type: CredentialType = field(default=CredentialType.NT_HASH, init=False) + credential_type: CredentialsType = field(default=CredentialsType.NT_HASH, init=False) nt_hash: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/password.py b/monkey/infection_monkey/credential_collectors/credential_components/password.py index 701c9fcde..19477ab18 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/password.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/password.py @@ -1,9 +1,10 @@ from dataclasses import dataclass, field -from infection_monkey.i_puppet import CredentialType, ICredentialComponent +from common.common_consts.credentials_type import CredentialsType +from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class Password(ICredentialComponent): - credential_type: CredentialType = field(default=CredentialType.PASSWORD, init=False) + credential_type: CredentialsType = field(default=CredentialsType.PASSWORD, init=False) password: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py b/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py index c5f377c44..6d54dafe4 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py @@ -1,10 +1,11 @@ from dataclasses import dataclass, field -from infection_monkey.i_puppet import CredentialType, ICredentialComponent +from common.common_consts.credentials_type import CredentialsType +from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class SSHKeypair(ICredentialComponent): - credential_type: CredentialType = field(default=CredentialType.SSH_KEYPAIR, init=False) + credential_type: CredentialsType = field(default=CredentialsType.SSH_KEYPAIR, init=False) private_key: str public_key: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/username.py b/monkey/infection_monkey/credential_collectors/credential_components/username.py index 208849061..f1587955f 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/username.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/username.py @@ -1,9 +1,10 @@ from dataclasses import dataclass, field -from infection_monkey.i_puppet import CredentialType, ICredentialComponent +from common.common_consts.credentials_type import CredentialsType +from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class Username(ICredentialComponent): - credential_type: CredentialType = field(default=CredentialType.USERNAME, init=False) + credential_type: CredentialsType = field(default=CredentialsType.USERNAME, init=False) username: str diff --git a/monkey/infection_monkey/i_puppet/__init__.py b/monkey/infection_monkey/i_puppet/__init__.py index 1c16f6df2..767826297 100644 --- a/monkey/infection_monkey/i_puppet/__init__.py +++ b/monkey/infection_monkey/i_puppet/__init__.py @@ -1,10 +1,4 @@ from .plugin_type import PluginType -from .credential_collection import ( - Credentials, - CredentialType, - ICredentialCollector, - ICredentialComponent, -) from .i_puppet import ( IPuppet, ExploiterResultData, @@ -16,3 +10,8 @@ from .i_puppet import ( UnknownPluginError, ) from .i_fingerprinter import IFingerprinter +from .credential_collection import ( + Credentials, + ICredentialCollector, + ICredentialComponent, +) diff --git a/monkey/infection_monkey/i_puppet/credential_collection/__init__.py b/monkey/infection_monkey/i_puppet/credential_collection/__init__.py index 8bfa68b38..a97d8373f 100644 --- a/monkey/infection_monkey/i_puppet/credential_collection/__init__.py +++ b/monkey/infection_monkey/i_puppet/credential_collection/__init__.py @@ -1,4 +1,3 @@ from .i_credential_collector import ICredentialCollector from .credentials import Credentials from .i_credential_component import ICredentialComponent -from .credential_type import CredentialType diff --git a/monkey/infection_monkey/i_puppet/credential_collection/i_credential_component.py b/monkey/infection_monkey/i_puppet/credential_collection/i_credential_component.py index d1c005886..5846c7ecf 100644 --- a/monkey/infection_monkey/i_puppet/credential_collection/i_credential_component.py +++ b/monkey/infection_monkey/i_puppet/credential_collection/i_credential_component.py @@ -1,10 +1,10 @@ from abc import ABC, abstractmethod -from .credential_type import CredentialType +from common.common_consts.credentials_type import CredentialsType class ICredentialComponent(ABC): @property @abstractmethod - def credential_type(self) -> CredentialType: + def credential_type(self) -> CredentialsType: pass diff --git a/monkey/monkey_island/cc/services/telemetry/processing/processing.py b/monkey/monkey_island/cc/services/telemetry/processing/processing.py index 44cd5c0cc..00d403937 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/processing.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/processing.py @@ -12,6 +12,7 @@ from monkey_island.cc.services.telemetry.processing.tunnel import process_tunnel logger = logging.getLogger(__name__) TELEMETRY_CATEGORY_TO_PROCESSING_FUNC = { + TelemCategoryEnum.CREDENTIALS: process_credentials_telemetry, TelemCategoryEnum.TUNNEL: process_tunnel_telemetry, TelemCategoryEnum.STATE: process_state_telemetry, TelemCategoryEnum.EXPLOIT: process_exploit_telemetry, From 5471e9854c23197f73e238c00bf73b2642e6f208 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Thu, 17 Feb 2022 17:27:09 +0200 Subject: [PATCH 04/18] Island: remove credentials parsing boundary --- .../cc/services/telemetry/processing/credentials.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials.py diff --git a/monkey/monkey_island/cc/services/telemetry/processing/credentials.py b/monkey/monkey_island/cc/services/telemetry/processing/credentials.py deleted file mode 100644 index fa772d1fd..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials.py +++ /dev/null @@ -1,7 +0,0 @@ -from monkey_island.cc.services.telemetry.processing.credentials.credentials_parser import ( - parse_credentials, -) - - -def process_credentials_telemetry(telemetry: dict): - parse_credentials(telemetry) From 73434537fee092779547d542c8416dbfab40bd93 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Thu, 17 Feb 2022 17:28:05 +0200 Subject: [PATCH 05/18] Island: remove system_info processing file No system info telemetries need to be processed anymore --- .../telemetry/processing/processing.py | 6 +- .../telemetry/processing/system_info.py | 95 ------------------- 2 files changed, 3 insertions(+), 98 deletions(-) delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/system_info.py diff --git a/monkey/monkey_island/cc/services/telemetry/processing/processing.py b/monkey/monkey_island/cc/services/telemetry/processing/processing.py index 00d403937..0dd93aab1 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/processing.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/processing.py @@ -2,22 +2,22 @@ import logging from common.common_consts.telem_categories import TelemCategoryEnum 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 from monkey_island.cc.services.telemetry.processing.state import process_state_telemetry -from monkey_island.cc.services.telemetry.processing.system_info import process_system_info_telemetry from monkey_island.cc.services.telemetry.processing.tunnel import process_tunnel_telemetry logger = logging.getLogger(__name__) TELEMETRY_CATEGORY_TO_PROCESSING_FUNC = { - TelemCategoryEnum.CREDENTIALS: process_credentials_telemetry, + TelemCategoryEnum.CREDENTIALS: parse_credentials, TelemCategoryEnum.TUNNEL: process_tunnel_telemetry, TelemCategoryEnum.STATE: process_state_telemetry, TelemCategoryEnum.EXPLOIT: process_exploit_telemetry, TelemCategoryEnum.SCAN: process_scan_telemetry, - TelemCategoryEnum.SYSTEM_INFO: process_system_info_telemetry, TelemCategoryEnum.POST_BREACH: process_post_breach_telemetry, TelemCategoryEnum.AWS_INFO: process_aws_telemetry, # `lambda *args, **kwargs: None` is a no-op. diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py deleted file mode 100644 index 06ee2e168..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ /dev/null @@ -1,95 +0,0 @@ -import logging - -from monkey_island.cc.server_utils.encryption import get_datastore_encryptor -from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import ( # noqa: E501 - SystemInfoTelemetryDispatcher, -) - -logger = logging.getLogger(__name__) - - -def process_system_info_telemetry(telemetry_json): - dispatcher = SystemInfoTelemetryDispatcher() - telemetry_processing_stages = [ - process_ssh_info, - process_credential_info, - dispatcher.dispatch_collector_results_to_relevant_processors, - ] - - # Calling safe_process_telemetry so if one of the stages fail, we log and move on instead of - # failing the rest of - # them, as they are independent. - for stage in telemetry_processing_stages: - safe_process_telemetry(stage, telemetry_json) - - -def safe_process_telemetry(processing_function, telemetry_json): - # noinspection PyBroadException - try: - processing_function(telemetry_json) - except Exception as err: - logger.error( - "Error {} while in {} stage of processing telemetry.".format( - str(err), processing_function.__name__ - ), - exc_info=True, - ) - - -def process_ssh_info(telemetry_json): - if "ssh_info" in telemetry_json["data"]: - ssh_info = telemetry_json["data"]["ssh_info"] - encrypt_system_info_ssh_keys(ssh_info) - if telemetry_json["data"]["network_info"]["networks"]: - # We use user_name@machine_ip as the name of the ssh key stolen, thats why we need ip - # from telemetry - add_ip_to_ssh_keys(telemetry_json["data"]["network_info"]["networks"][0], ssh_info) - add_system_info_ssh_keys_to_config(ssh_info) - - -def add_system_info_ssh_keys_to_config(ssh_info): - for user in ssh_info: - ConfigService.creds_add_username(user["name"]) - # Public key is useless without private key - if user["public_key"] and user["private_key"]: - ConfigService.ssh_add_keys( - user["public_key"], user["private_key"], user["name"], user["ip"] - ) - - -def add_ip_to_ssh_keys(ip, ssh_info): - for key in ssh_info: - key["ip"] = ip["addr"] - - -def encrypt_system_info_ssh_keys(ssh_info): - for idx, user in enumerate(ssh_info): - for field in ["public_key", "private_key", "known_hosts"]: - if ssh_info[idx][field]: - ssh_info[idx][field] = get_datastore_encryptor().encrypt(ssh_info[idx][field]) - - -def process_credential_info(telemetry_json): - if "credentials" in telemetry_json["data"]: - creds = telemetry_json["data"]["credentials"] - add_system_info_creds_to_config(creds) - replace_user_dot_with_comma(creds) - - -def replace_user_dot_with_comma(creds): - for user in creds: - if -1 != user.find("."): - new_user = user.replace(".", ",") - creds[new_user] = creds.pop(user) - - -def add_system_info_creds_to_config(creds): - for user in creds: - ConfigService.creds_add_username(creds[user]["username"]) - if "password" in creds[user] and creds[user]["password"]: - ConfigService.creds_add_password(creds[user]["password"]) - if "lm_hash" in creds[user] and creds[user]["lm_hash"]: - ConfigService.creds_add_lm_hash(creds[user]["lm_hash"]) - if "ntlm_hash" in creds[user] and creds[user]["ntlm_hash"]: - ConfigService.creds_add_ntlm_hash(creds[user]["ntlm_hash"]) From c96674f8340c6e1516092a597e386db74453ade3 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Thu, 17 Feb 2022 17:29:23 +0200 Subject: [PATCH 06/18] Island, Agent: fixed imports to reference credential type enum in common --- monkey/infection_monkey/i_puppet/i_puppet.py | 3 ++- .../processing/credentials/credentials_parser.py | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/monkey/infection_monkey/i_puppet/i_puppet.py b/monkey/infection_monkey/i_puppet/i_puppet.py index 79bd3b4fe..82f6b8b94 100644 --- a/monkey/infection_monkey/i_puppet/i_puppet.py +++ b/monkey/infection_monkey/i_puppet/i_puppet.py @@ -4,7 +4,8 @@ from collections import namedtuple from enum import Enum from typing import Dict, List, Sequence -from . import Credentials, PluginType +from . import PluginType +from .credential_collection import Credentials class PortStatus(Enum): 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 af022b678..2dfc08aa2 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,6 +1,6 @@ import logging -from infection_monkey.i_puppet import CredentialType +from common.common_consts.credentials_type import CredentialsType from .identities.username_processor import process_username from .secrets.lm_hash_processor import process_lm_hash @@ -11,21 +11,21 @@ from .secrets.ssh_key_processor import process_ssh_key logger = logging.getLogger(__name__) SECRET_PROCESSORS = { - CredentialType.PASSWORD: process_password, - CredentialType.NT_HASH: process_nt_hash, - CredentialType.LM_HASH: process_lm_hash, - CredentialType.SSH_KEYPAIR: process_ssh_key, + CredentialsType.PASSWORD: process_password, + CredentialsType.NT_HASH: process_nt_hash, + CredentialsType.LM_HASH: process_lm_hash, + CredentialsType.SSH_KEYPAIR: process_ssh_key, } IDENTITY_PROCESSORS = { - CredentialType.USERNAME: process_username, + CredentialsType.USERNAME: process_username, } def parse_credentials(credentials: dict): for credential in credentials["credentials"]: if is_ssh_keypair(credentials): - IDENTITY_PROCESSORS[CredentialType.SSH_KEYPAIR](credential, credentials["monkey_guid"]) + IDENTITY_PROCESSORS[CredentialsType.SSH_KEYPAIR](credential, credentials["monkey_guid"]) else: for identity in credential["identities"]: IDENTITY_PROCESSORS[identity["type"]](identity) @@ -35,5 +35,5 @@ def parse_credentials(credentials: dict): def is_ssh_keypair(credentials: dict) -> bool: return bool( - filter(credentials["secrets"], lambda secret: secret["type"] == CredentialType.SSH_KEYPAIR) + filter(credentials["secrets"], lambda secret: secret["type"] == CredentialsType.SSH_KEYPAIR) ) From b224348881114afcfc3f694d65d1ef34c2271acd Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 17 Feb 2022 19:33:47 +0100 Subject: [PATCH 07/18] Island: Fix credential collector parsing for SSH --- .../credentials/credentials_parser.py | 18 +++++++++++------- .../credentials/secrets/ssh_key_processor.py | 4 +++- 2 files changed, 14 insertions(+), 8 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 2dfc08aa2..e237f0139 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 @@ -23,17 +23,21 @@ IDENTITY_PROCESSORS = { def parse_credentials(credentials: dict): - for credential in credentials["credentials"]: - if is_ssh_keypair(credentials): - IDENTITY_PROCESSORS[CredentialsType.SSH_KEYPAIR](credential, credentials["monkey_guid"]) + + for credential in credentials["data"]: + if is_ssh_keypair(credential): + SECRET_PROCESSORS[CredentialsType.SSH_KEYPAIR](credential, credentials["monkey_guid"]) else: for identity in credential["identities"]: - IDENTITY_PROCESSORS[identity["type"]](identity) + IDENTITY_PROCESSORS[identity["credential_type"]](identity) for secret in credential["secrets"]: - SECRET_PROCESSORS[secret["type"]](secret) + SECRET_PROCESSORS[secret["credential_type"]](secret) -def is_ssh_keypair(credentials: dict) -> bool: +def is_ssh_keypair(credential: dict) -> bool: return bool( - filter(credentials["secrets"], lambda secret: secret["type"] == CredentialsType.SSH_KEYPAIR) + filter( + lambda secret: secret["credential_type"] == CredentialsType.SSH_KEYPAIR, + credential["secrets"], + ) ) 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 index df0557115..47ecc265a 100644 --- 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 @@ -17,7 +17,7 @@ def process_ssh_key(credentials: dict, monkey_guid: str): ) for ssh_key in credentials["secrets"]: - if not ssh_key["type"] == CredentialsType.SSH_KEYPAIR: + if not ssh_key["credential_type"] == CredentialsType.SSH_KEYPAIR.name: raise SSHKeyProcessingError("SSH credentials contain secrets that are not keypairs") if not ssh_key["public_key"] or not ssh_key["private_key"]: @@ -27,6 +27,8 @@ def process_ssh_key(credentials: dict, monkey_guid: str): ip = Monkey.get_single_monkey_by_guid(monkey_guid).ip_addresses[0] username = credentials["identities"][0]["username"] + encrypt_system_info_ssh_keys(ssh_key) + ConfigService.ssh_add_keys( user=username, public_key=ssh_key["public_key"], From 036388e7047f79ba395fe4c8d50e6bff832bc39a Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Fri, 18 Feb 2022 11:55:27 +0000 Subject: [PATCH 08/18] Agent: don't log the contents of credentials telemetries --- monkey/infection_monkey/telemetry/credentials_telem.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/monkey/infection_monkey/telemetry/credentials_telem.py b/monkey/infection_monkey/telemetry/credentials_telem.py index 5da7040d5..c0573d942 100644 --- a/monkey/infection_monkey/telemetry/credentials_telem.py +++ b/monkey/infection_monkey/telemetry/credentials_telem.py @@ -17,6 +17,9 @@ class CredentialsTelem(BaseTelem): """ self._credentials = credentials + def send(self, log_data=True): + super().send(log_data=False) + def get_data(self) -> Dict: # TODO: At a later time we can consider factoring this into a Serializer class or similar. return json.loads(json.dumps(self._credentials, default=_serialize)) From b3446764255450b00c3c01149979846d0933c11e Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Fri, 18 Feb 2022 11:56:21 +0000 Subject: [PATCH 09/18] Agent: add basic log statements to the mimikatz collector --- .../mimikatz_collector/mimikatz_credential_collector.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/monkey/infection_monkey/credential_collectors/mimikatz_collector/mimikatz_credential_collector.py b/monkey/infection_monkey/credential_collectors/mimikatz_collector/mimikatz_credential_collector.py index 1cbef911e..0ef75ed1b 100644 --- a/monkey/infection_monkey/credential_collectors/mimikatz_collector/mimikatz_credential_collector.py +++ b/monkey/infection_monkey/credential_collectors/mimikatz_collector/mimikatz_credential_collector.py @@ -1,3 +1,4 @@ +import logging from typing import Sequence from infection_monkey.credential_collectors import LMHash, NTHash, Password, Username @@ -6,10 +7,15 @@ from infection_monkey.i_puppet.credential_collection import Credentials, ICreden from . import pypykatz_handler from .windows_credentials import WindowsCredentials +logger = logging.getLogger(__name__) + class MimikatzCredentialCollector(ICredentialCollector): + def collect_credentials(self, options=None) -> Sequence[Credentials]: + logger.info("Attempting to collect windows credentials with pypykatz.") creds = pypykatz_handler.get_windows_creds() + logger.info(f"Pypykatz gathered {len(creds)} credentials.") return MimikatzCredentialCollector._to_credentials(creds) @staticmethod From d874cd9d5aaac1d0348c0b56b29c194ae2e35bd0 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Fri, 18 Feb 2022 14:22:43 +0000 Subject: [PATCH 10/18] Agent: fix broken pwd import on windows for ssh_handler.py --- .../credential_collectors/ssh_collector/ssh_handler.py | 1 - 1 file changed, 1 deletion(-) diff --git a/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py b/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py index 98ca0df4a..5dba2bbf3 100644 --- a/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py +++ b/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py @@ -30,7 +30,6 @@ def get_ssh_info(telemetry_messenger: ITelemetryMessenger) -> Iterable[Dict]: def _get_home_dirs() -> Iterable[Dict]: import pwd - root_dir = _get_ssh_struct("root", "") home_dirs = [ _get_ssh_struct(x.pw_name, x.pw_dir) for x in pwd.getpwall() if x.pw_dir.startswith("/home") From bb760c7e8ae7d22a04470c0013b1f48ebaff6704 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 21 Feb 2022 10:58:58 +0200 Subject: [PATCH 11/18] Island: fix detection if credential is a keypair --- .../processing/credentials/credentials_parser.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 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 e237f0139..cd738f4b4 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 @@ -36,8 +36,9 @@ def parse_credentials(credentials: dict): def is_ssh_keypair(credential: dict) -> bool: return bool( - filter( - lambda secret: secret["credential_type"] == CredentialsType.SSH_KEYPAIR, - credential["secrets"], - ) + [ + secret + for secret in credential["secrets"] + if secret["credential_type"] == CredentialsType.SSH_KEYPAIR + ] ) From 4b3750076a8a7c8110cd001eb832c282e322f2ae Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Mon, 21 Feb 2022 12:40:11 +0000 Subject: [PATCH 12/18] Agent, Island, Common: change code to process CredentialType value Island: rename credentials_type.py --- monkey/common/common_consts/credentials_type.py | 10 +++++----- .../credential_components/lm_hash.py | 2 +- .../credential_components/nt_hash.py | 2 +- .../credential_components/password.py | 2 +- .../credential_components/ssh_keypair.py | 2 +- .../credential_components/username.py | 2 +- .../processing/credentials/credentials_parser.py | 14 +++++++------- .../credentials/secrets/ssh_key_processor.py | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/monkey/common/common_consts/credentials_type.py b/monkey/common/common_consts/credentials_type.py index e818b1e5c..0aeb79630 100644 --- a/monkey/common/common_consts/credentials_type.py +++ b/monkey/common/common_consts/credentials_type.py @@ -2,8 +2,8 @@ from enum import Enum class CredentialsType(Enum): - USERNAME = 1 - PASSWORD = 2 - NT_HASH = 3 - LM_HASH = 4 - SSH_KEYPAIR = 5 + USERNAME = "username" + PASSWORD = "password" + NT_HASH = "nt_hash" + LM_HASH = "lm_hash" + SSH_KEYPAIR = "ssh_keypair" diff --git a/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py b/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py index a7be177a8..721e5a822 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py @@ -6,5 +6,5 @@ from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class LMHash(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.LM_HASH, init=False) + credential_type: CredentialsType = field(default=CredentialsType.LM_HASH.value, init=False) lm_hash: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py b/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py index d23f42a1d..c7d0de042 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py @@ -6,5 +6,5 @@ from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class NTHash(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.NT_HASH, init=False) + credential_type: CredentialsType = field(default=CredentialsType.NT_HASH.value, init=False) nt_hash: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/password.py b/monkey/infection_monkey/credential_collectors/credential_components/password.py index 19477ab18..5615c20f7 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/password.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/password.py @@ -6,5 +6,5 @@ from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class Password(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.PASSWORD, init=False) + credential_type: CredentialsType = field(default=CredentialsType.PASSWORD.value, init=False) password: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py b/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py index 6d54dafe4..29f91a15d 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py @@ -6,6 +6,6 @@ from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class SSHKeypair(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.SSH_KEYPAIR, init=False) + credential_type: CredentialsType = field(default=CredentialsType.SSH_KEYPAIR.value, init=False) private_key: str public_key: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/username.py b/monkey/infection_monkey/credential_collectors/credential_components/username.py index f1587955f..7ed37e89c 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/username.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/username.py @@ -6,5 +6,5 @@ from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class Username(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.USERNAME, init=False) + credential_type: CredentialsType = field(default=CredentialsType.USERNAME.value, init=False) username: str 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 cd738f4b4..47be30a63 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 @@ -11,14 +11,14 @@ from .secrets.ssh_key_processor import process_ssh_key logger = logging.getLogger(__name__) SECRET_PROCESSORS = { - CredentialsType.PASSWORD: process_password, - CredentialsType.NT_HASH: process_nt_hash, - CredentialsType.LM_HASH: process_lm_hash, - CredentialsType.SSH_KEYPAIR: process_ssh_key, + CredentialsType.PASSWORD.value: process_password, + CredentialsType.NT_HASH.value: process_nt_hash, + CredentialsType.LM_HASH.value: process_lm_hash, + CredentialsType.SSH_KEYPAIR.value: process_ssh_key, } IDENTITY_PROCESSORS = { - CredentialsType.USERNAME: process_username, + CredentialsType.USERNAME.value: process_username, } @@ -26,7 +26,7 @@ def parse_credentials(credentials: dict): for credential in credentials["data"]: if is_ssh_keypair(credential): - SECRET_PROCESSORS[CredentialsType.SSH_KEYPAIR](credential, credentials["monkey_guid"]) + SECRET_PROCESSORS[CredentialsType.SSH_KEYPAIR.value](credential, credentials["monkey_guid"]) else: for identity in credential["identities"]: IDENTITY_PROCESSORS[identity["credential_type"]](identity) @@ -39,6 +39,6 @@ def is_ssh_keypair(credential: dict) -> bool: [ secret for secret in credential["secrets"] - if secret["credential_type"] == CredentialsType.SSH_KEYPAIR + if secret["credential_type"] == CredentialsType.SSH_KEYPAIR.value ] ) 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 index 47ecc265a..61d03b2d1 100644 --- 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 @@ -17,7 +17,7 @@ def process_ssh_key(credentials: dict, monkey_guid: str): ) for ssh_key in credentials["secrets"]: - if not ssh_key["credential_type"] == CredentialsType.SSH_KEYPAIR.name: + if not ssh_key["credential_type"] == CredentialsType.SSH_KEYPAIR.value: raise SSHKeyProcessingError("SSH credentials contain secrets that are not keypairs") if not ssh_key["public_key"] or not ssh_key["private_key"]: From 600753b53cec34539666fe45370034dc78c19554 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 21 Feb 2022 17:22:36 +0200 Subject: [PATCH 13/18] Island: add username processor --- .../credentials/identities/username_processor.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 index c13af4d67..79b09901b 100644 --- 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 @@ -1,2 +1,5 @@ -def process_username(): - pass +from monkey_island.cc.services.config import ConfigService + + +def process_username(username: dict): + ConfigService.creds_add_username(username["username"]) From 80bf5618204200df32b82d99082b9666c1267cd7 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 21 Feb 2022 17:23:28 +0200 Subject: [PATCH 14/18] Island: fix a bug in lm_hash_processor.py --- .../processing/credentials/secrets/lm_hash_processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 4cc4c28e3..7c5d5f3fa 100644 --- 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 @@ -2,4 +2,4 @@ from monkey_island.cc.services.config import ConfigService def process_lm_hash(lm_hash: dict): - ConfigService.creds_add_ntlm_hash(lm_hash["lm_hash"]) + ConfigService.creds_add_lm_hash(lm_hash["lm_hash"]) From c87297eb2afa88956da579fb8239a9b9208bc47a Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 21 Feb 2022 17:24:55 +0200 Subject: [PATCH 15/18] Island: fix a bug in lm_hash_processor.py --- .../credentials/test_mimikatz_processing.py | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_mimikatz_processing.py diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_mimikatz_processing.py b/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_mimikatz_processing.py new file mode 100644 index 000000000..b61341a34 --- /dev/null +++ b/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_mimikatz_processing.py @@ -0,0 +1,92 @@ +from copy import deepcopy +from datetime import datetime + +import dpath.util +import mongoengine +import pytest + +from common.config_value_paths import ( + LM_HASH_LIST_PATH, + NTLM_HASH_LIST_PATH, + PASSWORD_LIST_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, +) + +MIMIKATZ_TELEM_TEMPLATE = { + "monkey_guid": "272405690278083", + "telem_category": "credentials", + "timestamp": datetime(2022, 2, 18, 11, 51, 15, 338953), + "command_control_channel": {"src": "10.2.2.251", "dst": "10.2.2.251:5000"}, + "data": None, +} + +fake_username = "m0nk3y_user" +mimikatz_telem_usernames = deepcopy(MIMIKATZ_TELEM_TEMPLATE) +mimikatz_telem_usernames["data"] = [ + {"identities": [{"username": fake_username, "credential_type": "username"}], "secrets": []} +] + +fake_nt_hash = "c1c58f96cdf212b50837bc11a00be47c" +fake_lm_hash = "299BD128C1101FD6" +fake_password = "trytostealthis" +mimikatz_telem = deepcopy(MIMIKATZ_TELEM_TEMPLATE) +mimikatz_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"}, + ], + } +] + +mimikatz_empty_telem = deepcopy(MIMIKATZ_TELEM_TEMPLATE) +mimikatz_empty_telem["data"] = [{"identities": [], "secrets": []}] + + +@pytest.fixture +def fake_mongo(monkeypatch): + mongo = mongoengine.connection.get_connection() + monkeypatch.setattr("monkey_island.cc.services.config.mongo", mongo) + config = ConfigService.get_default_config() + ConfigService.update_config(config, should_encrypt=True) + return mongo + + +@pytest.mark.usefixtures("uses_database") +def test_mimikatz_username_parsing(fake_mongo): + parse_credentials(mimikatz_telem_usernames) + config = ConfigService.get_config(should_decrypt=True) + assert fake_username in dpath.util.get(config, USER_LIST_PATH) + + +@pytest.mark.usefixtures("uses_database") +def test_mimikatz_telemetry_parsing(fake_mongo): + parse_credentials(mimikatz_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.usefixtures("uses_database") +def test_empty_mimikatz_telemetry_parsing(fake_mongo): + 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(mimikatz_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) From 719d8dd2ade99dadd5b227c41b3500099aec2830 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Tue, 22 Feb 2022 16:12:02 +0200 Subject: [PATCH 16/18] Island, Agent, Common: rename CredentialsType to CredentialComponentType --- ...s_type.py => credential_component_type.py} | 2 +- .../credential_components/lm_hash.py | 6 ++- .../credential_components/nt_hash.py | 6 ++- .../credential_components/password.py | 6 ++- .../credential_components/ssh_keypair.py | 6 ++- .../credential_components/username.py | 6 ++- .../i_credential_component.py | 4 +- .../credentials/credentials_parser.py | 37 ++++++------------- .../credentials/secrets/ssh_key_processor.py | 4 +- 9 files changed, 36 insertions(+), 41 deletions(-) rename monkey/common/common_consts/{credentials_type.py => credential_component_type.py} (80%) diff --git a/monkey/common/common_consts/credentials_type.py b/monkey/common/common_consts/credential_component_type.py similarity index 80% rename from monkey/common/common_consts/credentials_type.py rename to monkey/common/common_consts/credential_component_type.py index 0aeb79630..76326e50e 100644 --- a/monkey/common/common_consts/credentials_type.py +++ b/monkey/common/common_consts/credential_component_type.py @@ -1,7 +1,7 @@ from enum import Enum -class CredentialsType(Enum): +class CredentialComponentType(Enum): USERNAME = "username" PASSWORD = "password" NT_HASH = "nt_hash" diff --git a/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py b/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py index 721e5a822..1fef78437 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/lm_hash.py @@ -1,10 +1,12 @@ from dataclasses import dataclass, field -from common.common_consts.credentials_type import CredentialsType +from common.common_consts.credential_component_type import CredentialComponentType from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class LMHash(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.LM_HASH.value, init=False) + credential_type: CredentialComponentType = field( + default=CredentialComponentType.LM_HASH.value, init=False + ) lm_hash: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py b/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py index c7d0de042..07b9f859a 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/nt_hash.py @@ -1,10 +1,12 @@ from dataclasses import dataclass, field -from common.common_consts.credentials_type import CredentialsType +from common.common_consts.credential_component_type import CredentialComponentType from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class NTHash(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.NT_HASH.value, init=False) + credential_type: CredentialComponentType = field( + default=CredentialComponentType.NT_HASH.value, init=False + ) nt_hash: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/password.py b/monkey/infection_monkey/credential_collectors/credential_components/password.py index 5615c20f7..3a05e3599 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/password.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/password.py @@ -1,10 +1,12 @@ from dataclasses import dataclass, field -from common.common_consts.credentials_type import CredentialsType +from common.common_consts.credential_component_type import CredentialComponentType from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class Password(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.PASSWORD.value, init=False) + credential_type: CredentialComponentType = field( + default=CredentialComponentType.PASSWORD.value, init=False + ) password: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py b/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py index 29f91a15d..6abd314bb 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/ssh_keypair.py @@ -1,11 +1,13 @@ from dataclasses import dataclass, field -from common.common_consts.credentials_type import CredentialsType +from common.common_consts.credential_component_type import CredentialComponentType from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class SSHKeypair(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.SSH_KEYPAIR.value, init=False) + credential_type: CredentialComponentType = field( + default=CredentialComponentType.SSH_KEYPAIR.value, init=False + ) private_key: str public_key: str diff --git a/monkey/infection_monkey/credential_collectors/credential_components/username.py b/monkey/infection_monkey/credential_collectors/credential_components/username.py index 7ed37e89c..791dd6abe 100644 --- a/monkey/infection_monkey/credential_collectors/credential_components/username.py +++ b/monkey/infection_monkey/credential_collectors/credential_components/username.py @@ -1,10 +1,12 @@ from dataclasses import dataclass, field -from common.common_consts.credentials_type import CredentialsType +from common.common_consts.credential_component_type import CredentialComponentType from infection_monkey.i_puppet import ICredentialComponent @dataclass(frozen=True) class Username(ICredentialComponent): - credential_type: CredentialsType = field(default=CredentialsType.USERNAME.value, init=False) + credential_type: CredentialComponentType = field( + default=CredentialComponentType.USERNAME.value, init=False + ) username: str diff --git a/monkey/infection_monkey/i_puppet/credential_collection/i_credential_component.py b/monkey/infection_monkey/i_puppet/credential_collection/i_credential_component.py index 5846c7ecf..c4471ebfb 100644 --- a/monkey/infection_monkey/i_puppet/credential_collection/i_credential_component.py +++ b/monkey/infection_monkey/i_puppet/credential_collection/i_credential_component.py @@ -1,10 +1,10 @@ from abc import ABC, abstractmethod -from common.common_consts.credentials_type import CredentialsType +from common.common_consts.credential_component_type import CredentialComponentType class ICredentialComponent(ABC): @property @abstractmethod - def credential_type(self) -> CredentialsType: + def credential_type(self) -> CredentialComponentType: pass 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 47be30a63..9c4661e1d 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,44 +1,29 @@ import logging +from typing import Mapping -from common.common_consts.credentials_type import CredentialsType +from common.common_consts.credential_component_type import CredentialComponentType 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__) SECRET_PROCESSORS = { - CredentialsType.PASSWORD.value: process_password, - CredentialsType.NT_HASH.value: process_nt_hash, - CredentialsType.LM_HASH.value: process_lm_hash, - CredentialsType.SSH_KEYPAIR.value: process_ssh_key, + CredentialComponentType.PASSWORD.value: process_password, + CredentialComponentType.NT_HASH.value: process_nt_hash, + CredentialComponentType.LM_HASH.value: process_lm_hash, } IDENTITY_PROCESSORS = { - CredentialsType.USERNAME.value: process_username, + CredentialComponentType.USERNAME.value: process_username, } -def parse_credentials(credentials: dict): - +def parse_credentials(credentials: Mapping): for credential in credentials["data"]: - if is_ssh_keypair(credential): - SECRET_PROCESSORS[CredentialsType.SSH_KEYPAIR.value](credential, credentials["monkey_guid"]) - else: - for identity in credential["identities"]: - IDENTITY_PROCESSORS[identity["credential_type"]](identity) - for secret in credential["secrets"]: - SECRET_PROCESSORS[secret["credential_type"]](secret) - - -def is_ssh_keypair(credential: dict) -> bool: - return bool( - [ - secret - for secret in credential["secrets"] - if secret["credential_type"] == CredentialsType.SSH_KEYPAIR.value - ] - ) + for identity in credential["identities"]: + IDENTITY_PROCESSORS[identity["credential_type"]](identity) + for secret in credential["secrets"]: + SECRET_PROCESSORS[secret["credential_type"]](secret) 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 index 61d03b2d1..b6b898fda 100644 --- 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 @@ -1,4 +1,4 @@ -from common.common_consts.credentials_type import CredentialsType +from common.common_consts.credentials_type import CredentialComponentType from monkey_island.cc.models import Monkey from monkey_island.cc.server_utils.encryption import get_datastore_encryptor from monkey_island.cc.services.config import ConfigService @@ -17,7 +17,7 @@ def process_ssh_key(credentials: dict, monkey_guid: str): ) for ssh_key in credentials["secrets"]: - if not ssh_key["credential_type"] == CredentialsType.SSH_KEYPAIR.value: + if not ssh_key["credential_type"] == CredentialComponentType.SSH_KEYPAIR.value: raise SSHKeyProcessingError("SSH credentials contain secrets that are not keypairs") if not ssh_key["public_key"] or not ssh_key["private_key"]: From 0cbfc79a923e202432f969d3592f4effa9b68348 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Tue, 22 Feb 2022 16:28:08 +0200 Subject: [PATCH 17/18] Island: remove unfinished ssh key processor --- .../credentials/secrets/ssh_key_processor.py | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/ssh_key_processor.py 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 b6b898fda..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/secrets/ssh_key_processor.py +++ /dev/null @@ -1,42 +0,0 @@ -from common.common_consts.credentials_type import CredentialComponentType -from monkey_island.cc.models import Monkey -from monkey_island.cc.server_utils.encryption import get_datastore_encryptor -from monkey_island.cc.services.config import ConfigService - - -class SSHKeyProcessingError(ValueError): - def __init__(self, msg=""): - self.msg = f"Error while processing ssh keypair: {msg}" - super().__init__(self.msg) - - -def process_ssh_key(credentials: dict, monkey_guid: str): - if len(credentials["identities"]) != 1: - raise SSHKeyProcessingError( - f'SSH credentials have {len(credentials["identities"])}' f" users associated with it!" - ) - - for ssh_key in credentials["secrets"]: - if not ssh_key["credential_type"] == CredentialComponentType.SSH_KEYPAIR.value: - raise SSHKeyProcessingError("SSH credentials contain secrets that are not keypairs") - - if not ssh_key["public_key"] or not ssh_key["private_key"]: - raise SSHKeyProcessingError("Private or public key missing!") - - # TODO SSH key should be associated with IP that monkey exploited - ip = Monkey.get_single_monkey_by_guid(monkey_guid).ip_addresses[0] - username = credentials["identities"][0]["username"] - - encrypt_system_info_ssh_keys(ssh_key) - - ConfigService.ssh_add_keys( - user=username, - public_key=ssh_key["public_key"], - private_key=ssh_key["private_key"], - ip=ip, - ) - - -def encrypt_system_info_ssh_keys(ssh_key: dict): - for field in ["public_key", "private_key"]: - ssh_key[field] = get_datastore_encryptor().encrypt(ssh_key[field]) From 8c90a98d05bb287b0b1d8de95e1b096722ab483e Mon Sep 17 00:00:00 2001 From: vakarisz Date: Tue, 22 Feb 2022 17:12:48 +0200 Subject: [PATCH 18/18] UT: rename mimikatz credential processing to credential processing --- ...ssing.py => test_credential_processing.py} | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) rename monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/{test_mimikatz_processing.py => test_credential_processing.py} (82%) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_mimikatz_processing.py b/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_credential_processing.py similarity index 82% rename from monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_mimikatz_processing.py rename to monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_credential_processing.py index b61341a34..173b9662f 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_mimikatz_processing.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/telemetry/processing/credentials/test_credential_processing.py @@ -16,7 +16,7 @@ from monkey_island.cc.services.telemetry.processing.credentials.credentials_pars parse_credentials, ) -MIMIKATZ_TELEM_TEMPLATE = { +CREDENTIAL_TELEM_TEMPLATE = { "monkey_guid": "272405690278083", "telem_category": "credentials", "timestamp": datetime(2022, 2, 18, 11, 51, 15, 338953), @@ -25,16 +25,16 @@ MIMIKATZ_TELEM_TEMPLATE = { } fake_username = "m0nk3y_user" -mimikatz_telem_usernames = deepcopy(MIMIKATZ_TELEM_TEMPLATE) -mimikatz_telem_usernames["data"] = [ +cred_telem_usernames = deepcopy(CREDENTIAL_TELEM_TEMPLATE) +cred_telem_usernames["data"] = [ {"identities": [{"username": fake_username, "credential_type": "username"}], "secrets": []} ] fake_nt_hash = "c1c58f96cdf212b50837bc11a00be47c" fake_lm_hash = "299BD128C1101FD6" fake_password = "trytostealthis" -mimikatz_telem = deepcopy(MIMIKATZ_TELEM_TEMPLATE) -mimikatz_telem["data"] = [ +cred_telem = deepcopy(CREDENTIAL_TELEM_TEMPLATE) +cred_telem["data"] = [ { "identities": [{"username": fake_username, "credential_type": "username"}], "secrets": [ @@ -45,8 +45,8 @@ mimikatz_telem["data"] = [ } ] -mimikatz_empty_telem = deepcopy(MIMIKATZ_TELEM_TEMPLATE) -mimikatz_empty_telem["data"] = [{"identities": [], "secrets": []}] +cred_empty_telem = deepcopy(CREDENTIAL_TELEM_TEMPLATE) +cred_empty_telem["data"] = [{"identities": [], "secrets": []}] @pytest.fixture @@ -59,15 +59,15 @@ def fake_mongo(monkeypatch): @pytest.mark.usefixtures("uses_database") -def test_mimikatz_username_parsing(fake_mongo): - parse_credentials(mimikatz_telem_usernames) +def test_cred_username_parsing(fake_mongo): + 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.usefixtures("uses_database") -def test_mimikatz_telemetry_parsing(fake_mongo): - parse_credentials(mimikatz_telem) +def test_cred_telemetry_parsing(fake_mongo): + 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) @@ -76,14 +76,14 @@ def test_mimikatz_telemetry_parsing(fake_mongo): @pytest.mark.usefixtures("uses_database") -def test_empty_mimikatz_telemetry_parsing(fake_mongo): +def test_empty_cred_telemetry_parsing(fake_mongo): 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(mimikatz_empty_telem) + parse_credentials(cred_empty_telem) config = ConfigService.get_config(should_decrypt=True) assert default_usernames == dpath.util.get(config, USER_LIST_PATH)