From b22ccdb942d37c374ac08178de8be971077d562c Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 15 Aug 2022 17:09:32 +0200 Subject: [PATCH] Agent: Publish CredentialsStolenEvent each time we find a SSHKeypair --- .../ssh_collector/ssh_credential_collector.py | 26 +------------- .../ssh_collector/ssh_handler.py | 36 +++++++++++++++++-- .../test_ssh_credentials_collector.py | 8 +---- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_credential_collector.py b/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_credential_collector.py index 45cd227d8..c5659e2a8 100644 --- a/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_credential_collector.py +++ b/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_credential_collector.py @@ -1,19 +1,14 @@ import logging -import time from typing import Dict, Iterable, Sequence from common.credentials import Credentials, SSHKeypair, Username from common.event_queue import IEventQueue -from common.events import CredentialsStolenEvent -from infection_monkey.config import GUID from infection_monkey.credential_collectors.ssh_collector import ssh_handler from infection_monkey.i_puppet import ICredentialCollector from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger logger = logging.getLogger(__name__) -SSH_CREDENTIAL_COLLECTOR_TAG = "SSHCredentialsStolen" - class SSHCredentialCollector(ICredentialCollector): """ @@ -26,31 +21,12 @@ class SSHCredentialCollector(ICredentialCollector): def collect_credentials(self, _options=None) -> Sequence[Credentials]: logger.info("Started scanning for SSH credentials") - ssh_info = ssh_handler.get_ssh_info(self._telemetry_messenger) + ssh_info = ssh_handler.get_ssh_info(self._telemetry_messenger, self._event_queue) logger.info("Finished scanning for SSH credentials") ssh_collector_credentials = SSHCredentialCollector._to_credentials(ssh_info) - credentials_stolen_event = SSHCredentialCollector._generate_credentials_stolen_event( - ssh_collector_credentials - ) - self._event_queue.publish(credentials_stolen_event) - return ssh_collector_credentials - @staticmethod - def _generate_credentials_stolen_event( - collected_credentials: Sequence[Credentials], - ) -> CredentialsStolenEvent: - credentials_stolen_event = CredentialsStolenEvent( - source=GUID, - target=None, - timestamp=time.time(), - tags=frozenset({SSH_CREDENTIAL_COLLECTOR_TAG, "T1005", "T1145"}), - stolen_credentials=collected_credentials, - ) - - return credentials_stolen_event - @staticmethod def _to_credentials(ssh_info: Iterable[Dict]) -> Sequence[Credentials]: ssh_credentials = [] 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..a48424304 100644 --- a/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py +++ b/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py @@ -1,8 +1,13 @@ import glob import logging import os +import time +import uuid from typing import Dict, Iterable +from common.credentials import Credentials, SSHKeypair, Username +from common.event_queue import IEventQueue +from common.events import CredentialsStolenEvent from common.utils.attack_utils import ScanStatus from infection_monkey.telemetry.attack.t1005_telem import T1005Telem from infection_monkey.telemetry.attack.t1145_telem import T1145Telem @@ -12,9 +17,12 @@ from infection_monkey.utils.environment import is_windows_os logger = logging.getLogger(__name__) DEFAULT_DIRS = ["/.ssh/", "/"] +SSH_CREDENTIAL_COLLECTOR_TAG = "SSHCredentialsStolen" -def get_ssh_info(telemetry_messenger: ITelemetryMessenger) -> Iterable[Dict]: +def get_ssh_info( + telemetry_messenger: ITelemetryMessenger, event_queue: IEventQueue +) -> Iterable[Dict]: # TODO: Remove this check when this is turned into a plugin. if is_windows_os(): logger.debug( @@ -23,7 +31,7 @@ def get_ssh_info(telemetry_messenger: ITelemetryMessenger) -> Iterable[Dict]: return [] home_dirs = _get_home_dirs() - ssh_info = _get_ssh_files(home_dirs, telemetry_messenger) + ssh_info = _get_ssh_files(home_dirs, telemetry_messenger, event_queue) return ssh_info @@ -62,7 +70,7 @@ def _get_ssh_struct(name: str, home_dir: str) -> Dict: def _get_ssh_files( - usr_info: Iterable[Dict], telemetry_messenger: ITelemetryMessenger + usr_info: Iterable[Dict], telemetry_messenger: ITelemetryMessenger, event_queue: IEventQueue ) -> Iterable[Dict]: for info in usr_info: path = info["home_dir"] @@ -101,6 +109,16 @@ def _get_ssh_files( ScanStatus.USED, info["name"], info["home_dir"] ) ) + + collected_credentials = Credentials( + identity=Username(info["name"]), + secrets=SSHKeypair( + info["private_key"], info["public_key"] + ), + ) + _publish_credentials_stolen_event( + collected_credentials, event_queue + ) else: continue except (IOError, OSError): @@ -114,3 +132,15 @@ def _get_ssh_files( pass usr_info = [info for info in usr_info if info["private_key"] or info["public_key"]] return usr_info + + +def _publish_credentials_stolen_event(collected_credentials: Credentials, event_queue: IEventQueue): + credentials_stolen_event = CredentialsStolenEvent( + source=uuid.getnode(), + target=None, + timestamp=time.time(), + tags=frozenset({SSH_CREDENTIAL_COLLECTOR_TAG, "T1005", "T1145"}), + stolen_credentials=[collected_credentials], + ) + + event_queue.publish(credentials_stolen_event) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_ssh_credentials_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_ssh_credentials_collector.py index ddfd87426..d82236014 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_ssh_credentials_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_ssh_credentials_collector.py @@ -20,14 +20,10 @@ def mock_event_queue(): def patch_ssh_handler(ssh_creds, monkeypatch): monkeypatch.setattr( "infection_monkey.credential_collectors.ssh_collector.ssh_handler.get_ssh_info", - lambda _: ssh_creds, + lambda _, __: ssh_creds, ) -def patch_guid(monkeypatch): - monkeypatch.setattr("infection_monkey.config.GUID", "1-2-3-4-5-6") - - @pytest.mark.parametrize( "ssh_creds", [([{"name": "", "home_dir": "", "public_key": None, "private_key": None}]), ([])] ) @@ -39,7 +35,6 @@ def test_ssh_credentials_empty_results( patch_telemetry_messenger, mock_event_queue ).collect_credentials() assert not collected - mock_event_queue.publish.assert_called_once() def test_ssh_info_result_parsing(monkeypatch, patch_telemetry_messenger, mock_event_queue): @@ -86,4 +81,3 @@ def test_ssh_info_result_parsing(monkeypatch, patch_telemetry_messenger, mock_ev patch_telemetry_messenger, mock_event_queue ).collect_credentials() assert expected == collected - mock_event_queue.publish.assert_called_once()