diff --git a/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py index d7ea0744d..40905a28c 100644 --- a/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py +++ b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py @@ -1,7 +1,7 @@ from pprint import pformat from typing import List -from common.credentials import CredentialComponentType, Credentials +from common.credentials import Credentials, LMHash, NTHash, Username from envs.monkey_zoo.blackbox.analyzers.analyzer import Analyzer from envs.monkey_zoo.blackbox.analyzers.analyzer_log import AnalyzerLog from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient @@ -36,11 +36,11 @@ class ZerologonAnalyzer(Analyzer): credentials_on_island = set() for credentials in propagation_credentials: - if credentials.identity.credential_type is CredentialComponentType.USERNAME: + if isinstance(credentials.identity, Username): credentials_on_island.update([credentials.identity.username]) - if credentials.secret.credential_type is CredentialComponentType.NT_HASH: + if isinstance(credentials.secret, NTHash): credentials_on_island.update([credentials.secret.nt_hash]) - if credentials.secret.credential_type is CredentialComponentType.LM_HASH: + if isinstance(credentials.secret, LMHash): credentials_on_island.update([credentials.secret.lm_hash]) return list(credentials_on_island) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py index 478aa7373..daeaba2dd 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py @@ -87,9 +87,9 @@ test_agent_configuration = _add_credential_collectors(test_agent_configuration) test_agent_configuration = _add_http_ports(test_agent_configuration) CREDENTIALS = ( - Credentials(Username("m0nk3y"), None), - Credentials(None, Password("Ivrrw5zEzs")), - Credentials(None, Password("Xk8VDTsC")), + Credentials(identity=Username(username="m0nk3y"), secret=None), + Credentials(identity=None, secret=Password(password="Ivrrw5zEzs")), + Credentials(identity=None, secret=Password(password="Xk8VDTsC")), ) depth_1_a_test_configuration = dataclasses.replace(noop_test_configuration) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py index 109a600fc..550b7bc02 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py @@ -42,8 +42,8 @@ test_agent_configuration = _add_subnets(test_agent_configuration) test_agent_configuration = _add_tcp_ports(test_agent_configuration) CREDENTIALS = ( - Credentials(Username("m0nk3y"), None), - Credentials(None, Password("^NgDvY59~8")), + Credentials(identity=Username(username="m0nk3y"), secret=None), + Credentials(identity=None, secret=Password(password="^NgDvY59~8")), ) depth_2_a_test_configuration = dataclasses.replace(noop_test_configuration) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py index 049521858..d390b2262 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py @@ -56,14 +56,14 @@ test_agent_configuration = _add_subnets(test_agent_configuration) test_agent_configuration = _add_tcp_ports(test_agent_configuration) CREDENTIALS = ( - Credentials(Username("m0nk3y"), None), - Credentials(Username("m0nk3y-user"), None), - Credentials(None, Password("Passw0rd!")), - Credentials(None, Password("3Q=(Ge(+&w]*")), - Credentials(None, Password("`))jU7L(w}")), - Credentials(None, NTHash("d0f0132b308a0c4e5d1029cc06f48692")), - Credentials(None, NTHash("5da0889ea2081aa79f6852294cba4a5e")), - Credentials(None, NTHash("50c9987a6bf1ac59398df9f911122c9b")), + Credentials(identity=Username(username="m0nk3y"), secret=None), + Credentials(identity=Username(username="m0nk3y-user"), secret=None), + Credentials(identity=None, secret=Password(password="Passw0rd!")), + Credentials(identity=None, secret=Password(password="3Q=(Ge(+&w]*")), + Credentials(identity=None, secret=Password(password="`))jU7L(w}")), + Credentials(identity=None, secret=NTHash(nt_hash="d0f0132b308a0c4e5d1029cc06f48692")), + Credentials(identity=None, secret=NTHash(nt_hash="5da0889ea2081aa79f6852294cba4a5e")), + Credentials(identity=None, secret=NTHash(nt_hash="50c9987a6bf1ac59398df9f911122c9b")), ) depth_3_a_test_configuration = dataclasses.replace(noop_test_configuration) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_4_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_4_a.py index 83e9dc785..d4ab4e512 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_4_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_4_a.py @@ -49,11 +49,11 @@ test_agent_configuration = _add_subnets(test_agent_configuration) test_agent_configuration = _add_tcp_ports(test_agent_configuration) CREDENTIALS = ( - Credentials(Username("m0nk3y"), None), - Credentials(None, Password("3Q=(Ge(+&w]*")), - Credentials(None, Password("`))jU7L(w}")), - Credentials(None, Password("prM2qsroTI")), - Credentials(None, Password("t67TC5ZDmz")), + Credentials(identity=Username(username="m0nk3y"), secret=None), + Credentials(identity=None, secret=Password(password="3Q=(Ge(+&w]*")), + Credentials(identity=None, secret=Password(password="`))jU7L(w}")), + Credentials(identity=None, secret=Password(password="prM2qsroTI")), + Credentials(identity=None, secret=Password(password="t67TC5ZDmz")), ) depth_4_a_test_configuration = dataclasses.replace(noop_test_configuration) diff --git a/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py b/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py index f0432129d..bebccd081 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py +++ b/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py @@ -42,14 +42,14 @@ test_agent_configuration = _add_subnets(test_agent_configuration) test_agent_configuration = _add_tcp_ports(test_agent_configuration) CREDENTIALS = ( - Credentials(Username("Administrator"), None), - Credentials(Username("m0nk3y"), None), - Credentials(Username("user"), None), - Credentials(None, Password("Ivrrw5zEzs")), - Credentials(None, Password("Password1!")), - Credentials(None, NTHash("d0f0132b308a0c4e5d1029cc06f48692")), - Credentials(None, NTHash("5da0889ea2081aa79f6852294cba4a5e")), - Credentials(None, NTHash("50c9987a6bf1ac59398df9f911122c9b")), + Credentials(identity=Username(username="Administrator"), secret=None), + Credentials(identity=Username(username="m0nk3y"), secret=None), + Credentials(identity=Username(username="user"), secret=None), + Credentials(identity=None, secret=Password(password="Ivrrw5zEzs")), + Credentials(identity=None, secret=Password(password="Password1!")), + Credentials(identity=None, secret=NTHash(nt_hash="d0f0132b308a0c4e5d1029cc06f48692")), + Credentials(identity=None, secret=NTHash(nt_hash="5da0889ea2081aa79f6852294cba4a5e")), + Credentials(identity=None, secret=NTHash(nt_hash="50c9987a6bf1ac59398df9f911122c9b")), ) smb_pth_test_configuration = dataclasses.replace(noop_test_configuration) diff --git a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py index dc86ee2c8..90874f1a0 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py +++ b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py @@ -50,11 +50,11 @@ test_agent_configuration = _add_tcp_ports(test_agent_configuration) test_agent_configuration = _add_credential_collectors(test_agent_configuration) CREDENTIALS = ( - Credentials(Username("Administrator"), None), - Credentials(Username("m0nk3y"), None), - Credentials(Username("user"), None), - Credentials(None, Password("Ivrrw5zEzs")), - Credentials(None, Password("Password1!")), + Credentials(identity=Username(username="Administrator"), secret=None), + Credentials(identity=Username(username="m0nk3y"), secret=None), + Credentials(identity=Username(username="user"), secret=None), + Credentials(identity=None, secret=Password(password="Ivrrw5zEzs")), + Credentials(identity=None, secret=Password(password="Password1!")), ) wmi_mimikatz_test_configuration = dataclasses.replace(noop_test_configuration) diff --git a/monkey/common/common_consts/telem_categories.py b/monkey/common/common_consts/telem_categories.py index 0697fd4f7..843a2070a 100644 --- a/monkey/common/common_consts/telem_categories.py +++ b/monkey/common/common_consts/telem_categories.py @@ -1,7 +1,6 @@ class TelemCategoryEnum: ATTACK = "attack" AWS_INFO = "aws_info" - CREDENTIALS = "credentials" EXPLOIT = "exploit" FILE_ENCRYPTION = "file_encryption" POST_BREACH = "post_breach" diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index de19956c8..d9e48d5a0 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -25,7 +25,6 @@ from infection_monkey.exploit.zerologon_utils.options import OptionsForSecretsdu from infection_monkey.exploit.zerologon_utils.vuln_assessment import get_dc_details, is_exploitable from infection_monkey.exploit.zerologon_utils.wmiexec import Wmiexec from infection_monkey.i_puppet import ExploiterResultData -from infection_monkey.telemetry.credentials_telem import CredentialsTelem from infection_monkey.utils.capture_output import StdoutCapture from infection_monkey.utils.threading import interruptible_iter @@ -133,6 +132,8 @@ class ZerologonExploiter(HostExploiter): except BaseException as e: logger.info(f"Unexpected error: {e}") + return None + def attempt_exploit(self, rpc_con: rpcrt.DCERPC_v5) -> object: request = nrpc.NetrServerPasswordSet2() ZerologonExploiter._set_up_request(request, self.dc_name) @@ -221,9 +222,9 @@ class ZerologonExploiter(HostExploiter): finally: if rpc_con: - rpc_con.disconnect() + rpc_con.disconnect() # type: ignore[attr-defined] - def get_all_user_creds(self) -> List[Tuple[str, Dict]]: + def get_all_user_creds(self) -> Optional[List[Tuple[str, Dict]]]: try: options = OptionsForSecretsdump( # format for DC account - "NetBIOSName$@0.0.0.0" @@ -238,7 +239,7 @@ class ZerologonExploiter(HostExploiter): self._extract_user_creds_from_secrets(dumped_secrets=dumped_secrets) - creds_to_use_for_getting_original_pwd_hashes = [] + creds_to_use_for_getting_original_pwd_hashes: List[Tuple[str, Dict]] = [] admin = "Administrator" for user in self._extracted_creds.keys(): if user == admin: # most likely to work so try this first @@ -303,19 +304,20 @@ class ZerologonExploiter(HostExploiter): Credentials(identity=Username(username=user), secret=NTHash(nt_hash=nthash)), ] - self.telemetry_messenger.send_telemetry(CredentialsTelem(extracted_credentials)) self._publish_credentials_stolen_event(extracted_credentials) - def _publish_credentials_stolen_event(self, extracted_credentials: Sequence[Credentials]): + def _publish_credentials_stolen_event( + self, extracted_credentials: Sequence[Credentials] + ) -> None: credentials_stolen_event = CredentialsStolenEvent( tags=ZEROLOGON_EVENT_TAGS, stolen_credentials=extracted_credentials, ) self.event_queue.publish(credentials_stolen_event) - def get_original_pwd_nthash(self, username: str, user_pwd_hashes: List[str]) -> str: + def get_original_pwd_nthash(self, username: str, user_pwd_hashes: List[str]) -> Optional[str]: if not self.save_HKLM_keys_locally(username, user_pwd_hashes): - return + return None try: options = OptionsForSecretsdump( @@ -341,6 +343,8 @@ class ZerologonExploiter(HostExploiter): finally: self.remove_locally_saved_HKLM_keys() + return None + def save_HKLM_keys_locally(self, username: str, user_pwd_hashes: List[str]) -> bool: logger.info(f"Starting remote shell on victim with user: {username}") diff --git a/monkey/infection_monkey/master/automated_master.py b/monkey/infection_monkey/master/automated_master.py index dcda3de2c..586da8fe5 100644 --- a/monkey/infection_monkey/master/automated_master.py +++ b/monkey/infection_monkey/master/automated_master.py @@ -11,7 +11,6 @@ from infection_monkey.i_control_channel import IControlChannel, IslandCommunicat from infection_monkey.i_master import IMaster from infection_monkey.i_puppet import IPuppet from infection_monkey.model import VictimHostFactory -from infection_monkey.telemetry.credentials_telem import CredentialsTelem from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger from infection_monkey.telemetry.post_breach_telem import PostBreachTelem from infection_monkey.utils.propagation import maximum_depth_reached @@ -194,9 +193,7 @@ class AutomatedMaster(IMaster): def _collect_credentials(self, collector: PluginConfiguration): credentials = self._puppet.run_credential_collector(collector.name, collector.options) - if credentials: - self._telemetry_messenger.send_telemetry(CredentialsTelem(credentials)) - else: + if not credentials: logger.debug(f"No credentials were collected by {collector}") def _run_pba(self, pba: PluginConfiguration): diff --git a/monkey/infection_monkey/telemetry/credentials_telem.py b/monkey/infection_monkey/telemetry/credentials_telem.py deleted file mode 100644 index 439ec7f1a..000000000 --- a/monkey/infection_monkey/telemetry/credentials_telem.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Iterable - -from common.common_consts.telem_categories import TelemCategoryEnum -from common.credentials import Credentials -from infection_monkey.telemetry.base_telem import BaseTelem - - -class CredentialsTelem(BaseTelem): - telem_category = TelemCategoryEnum.CREDENTIALS - - def __init__(self, credentials: Iterable[Credentials]): - """ - Used to send information about stolen or discovered credentials to the Island. - :param credentials: An iterable containing credentials to be sent to the Island. - """ - self._credentials = credentials - - @property - def credentials(self) -> Iterable[Credentials]: - return iter(self._credentials) - - def send(self, log_data=True): - super().send(log_data=False) - - def get_data(self): - return [c.dict(simplify=True) for c in self._credentials] diff --git a/monkey/monkey_island/cc/resources/telemetry_feed.py b/monkey/monkey_island/cc/resources/telemetry_feed.py index feb408ae0..23b57f9be 100644 --- a/monkey/monkey_island/cc/resources/telemetry_feed.py +++ b/monkey/monkey_island/cc/resources/telemetry_feed.py @@ -85,10 +85,6 @@ class TelemetryFeed(AbstractResource): def get_scan_telem_brief(telem): return "Monkey discovered machine %s." % telem["data"]["machine"]["ip_addr"] - @staticmethod - def get_credentials_telem_brief(_): - return "Monkey collected stole some credentials." - @staticmethod def get_trace_telem_brief(telem): return "Trace: %s" % telem["data"]["msg"] @@ -116,7 +112,6 @@ class TelemetryFeed(AbstractResource): TELEM_PROCESS_DICT = { - TelemCategoryEnum.CREDENTIALS: TelemetryFeed.get_credentials_telem_brief, TelemCategoryEnum.EXPLOIT: TelemetryFeed.get_exploit_telem_brief, TelemCategoryEnum.POST_BREACH: TelemetryFeed.get_post_breach_telem_brief, TelemCategoryEnum.SCAN: TelemetryFeed.get_scan_telem_brief, diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py index 6f363f3ed..bba100c83 100644 --- a/monkey/monkey_island/cc/services/initialize.py +++ b/monkey/monkey_island/cc/services/initialize.py @@ -11,7 +11,6 @@ from common.agent_configuration import ( AgentConfiguration, ) from common.aws import AWSInstance -from common.common_consts.telem_categories import TelemCategoryEnum from common.event_queue import IAgentEventQueue, PyPubSubAgentEventQueue from common.utils.file_utils import get_binary_io_sha256_hash from monkey_island.cc.event_queue import IIslandEventQueue, PyPubSubIslandEventQueue @@ -40,12 +39,6 @@ from monkey_island.cc.server_utils.encryption import ILockableEncryptor, Reposit from monkey_island.cc.services import AWSService, IslandModeService from monkey_island.cc.services.attack.technique_reports.T1003 import T1003, T1003GetReportData 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 @@ -165,9 +158,3 @@ def _dirty_hacks(container: DIContainer): # Patches attack technique T1003 which is a static class # but it needs stolen credentials from the database T1003.get_report_data = container.resolve(T1003GetReportData) - - # Note: A hack to resolve credentials parser - # It changes telemetry processing function, this will be refactored! - TELEMETRY_CATEGORY_TO_PROCESSING_FUNC[TelemCategoryEnum.CREDENTIALS] = container.resolve( - CredentialsParser - ) 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 deleted file mode 100644 index f11d76002..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/credentials/credentials_parser.py +++ /dev/null @@ -1,24 +0,0 @@ -import logging -from typing import Mapping - -from common.credentials import Credentials -from monkey_island.cc.repository import ICredentialsRepository - -logger = logging.getLogger(__name__) - - -class CredentialsParser: - """ - This class parses and stores telemetry credentials. - """ - - def __init__(self, credentials_repository: ICredentialsRepository): - self._credentials_repository = credentials_repository - - def __call__(self, telemetry_dict, _agent_configuration): - self._parse_credentials(telemetry_dict, _agent_configuration) - - def _parse_credentials(self, telemetry_dict: Mapping, _agent_configuration): - credentials = [Credentials(**credential) for credential in telemetry_dict["data"]] - - self._credentials_repository.save_stolen_credentials(credentials) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/processing.py b/monkey/monkey_island/cc/services/telemetry/processing/processing.py index f3550077f..c09f9bc5f 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/processing.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/processing.py @@ -15,7 +15,6 @@ 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: 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, @@ -23,10 +22,6 @@ TELEMETRY_CATEGORY_TO_PROCESSING_FUNC = { TelemCategoryEnum.TRACE: lambda *args, **kwargs: None, } -# Don't save credential telemetries in telemetries collection. -# Credentials are stored in StolenCredentials documents -UNSAVED_TELEMETRIES = [TelemCategoryEnum.CREDENTIALS] - def process_telemetry(telemetry_json, agent_configuration: AgentConfiguration): try: @@ -38,8 +33,7 @@ def process_telemetry(telemetry_json, agent_configuration: AgentConfiguration): else: logger.info("Got unknown type of telemetry: %s" % telem_category) - if telem_category not in UNSAVED_TELEMETRIES: - save_telemetry(telemetry_json) + save_telemetry(telemetry_json) except Exception as ex: logger.error( diff --git a/monkey/tests/unit_tests/infection_monkey/telemetry/test_credentials_telem.py b/monkey/tests/unit_tests/infection_monkey/telemetry/test_credentials_telem.py deleted file mode 100644 index 6727e3fd5..000000000 --- a/monkey/tests/unit_tests/infection_monkey/telemetry/test_credentials_telem.py +++ /dev/null @@ -1,34 +0,0 @@ -import json - -import pytest - -from common.credentials import Credentials, Password, Username -from infection_monkey.telemetry.credentials_telem import CredentialsTelem - -USERNAME = "m0nkey" -PASSWORD = "mmm" -PUBLIC_KEY = "pub_key" -PRIVATE_KEY = "priv_key" - - -@pytest.fixture -def credentials_for_test(): - return Credentials(identity=Username(username=USERNAME), secret=Password(password=PASSWORD)) - - -def test_credential_telem_send(spy_send_telemetry, credentials_for_test): - - expected_data = [credentials_for_test.dict(simplify=True)] - - telem = CredentialsTelem([credentials_for_test]) - telem.send() - - assert json.loads(spy_send_telemetry.data) == expected_data - assert spy_send_telemetry.telem_category == "credentials" - - -def test_credentials_property(credentials_for_test): - telem = CredentialsTelem([credentials_for_test]) - - assert len(list(telem.credentials)) == 1 - assert list(telem.credentials)[0] == credentials_for_test