From d745e10bf111281b1300f7baed0765aaa775ea60 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 12:39:59 +0530 Subject: [PATCH 01/25] Agent: Accept event queue in Mimikatz collector's constructor --- .../mimikatz_collector/mimikatz_credential_collector.py | 4 ++++ 1 file changed, 4 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 e6bc04a31..e723b723c 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 @@ -2,6 +2,7 @@ import logging from typing import Sequence from common.credentials import Credentials, LMHash, NTHash, Password, Username +from common.event_queue import IEventQueue from infection_monkey.i_puppet import ICredentialCollector from infection_monkey.model import USERNAME_PREFIX @@ -12,6 +13,9 @@ logger = logging.getLogger(__name__) class MimikatzCredentialCollector(ICredentialCollector): + def __init__(self, event_queue: IEventQueue): + self._event_queue = event_queue + def collect_credentials(self, options=None) -> Sequence[Credentials]: logger.info("Attempting to collect windows credentials with pypykatz.") windows_credentials = pypykatz_handler.get_windows_creds() From b5058ce61124e3f87f343ad3bc61808137f97eba Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 13:13:00 +0530 Subject: [PATCH 02/25] Agent: Add event tag constants for Mimikatz credential collector --- .../mimikatz_credential_collector.py | 11 +++++++++++ 1 file changed, 11 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 e723b723c..fd6a05218 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 @@ -12,6 +12,17 @@ from .windows_credentials import WindowsCredentials logger = logging.getLogger(__name__) +MIMIKATZ_CREDENTIAL_COLLECTOR_TAG = "MimikatzCredentialsStolen" +T1003_ATTACK_TECHNIQUE_TAG = "T1003" +T1005_ATTACK_TECHNIQUE_TAG = "T1005" + +MIMIKATZ_EVENT_TAGS = { + MIMIKATZ_CREDENTIAL_COLLECTOR_TAG, + T1003_ATTACK_TECHNIQUE_TAG, + T1005_ATTACK_TECHNIQUE_TAG, +} + + class MimikatzCredentialCollector(ICredentialCollector): def __init__(self, event_queue: IEventQueue): self._event_queue = event_queue From e03f1407493fdf9e43182ea10a95049401d2e4f4 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 13:14:29 +0530 Subject: [PATCH 03/25] Agent: Add function to publish credentials stolen event in Mimikatz credential collector --- .../mimikatz_credential_collector.py | 10 ++++++++++ 1 file changed, 10 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 fd6a05218..43bb6bcc7 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 @@ -3,6 +3,7 @@ from typing import Sequence from common.credentials import Credentials, LMHash, NTHash, Password, Username from common.event_queue import IEventQueue +from common.events import CredentialsStolenEvent from infection_monkey.i_puppet import ICredentialCollector from infection_monkey.model import USERNAME_PREFIX @@ -64,3 +65,12 @@ class MimikatzCredentialCollector(ICredentialCollector): credentials.append(Credentials(identity, None)) return credentials + + def _publish_credentials_stolen_event(self, collected_credentials: Sequence[Credentials]): + credentials_stolen_event = CredentialsStolenEvent( + target=None, + tags=frozenset(MIMIKATZ_EVENT_TAGS), + stolen_credentials=collected_credentials, + ) + + self.event_queue.publish(credentials_stolen_event) From 56770d25c68e85f1b251efac72d54eb79676bbdf Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 13:14:59 +0530 Subject: [PATCH 04/25] Agent: Publish credentials stolen event in MimikatzCredentialCollector --- .../mimikatz_collector/mimikatz_credential_collector.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 43bb6bcc7..53197acad 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 @@ -31,8 +31,14 @@ class MimikatzCredentialCollector(ICredentialCollector): def collect_credentials(self, options=None) -> Sequence[Credentials]: logger.info("Attempting to collect windows credentials with pypykatz.") windows_credentials = pypykatz_handler.get_windows_creds() + logger.info(f"Pypykatz gathered {len(windows_credentials)} credentials.") - return MimikatzCredentialCollector._to_credentials(windows_credentials) + + collected_credentials = MimikatzCredentialCollector._to_credentials(windows_credentials) + + self._publish_credentials_stolen_event(collected_credentials) + + return collected_credentials @staticmethod def _to_credentials(windows_credentials: Sequence[WindowsCredentials]) -> Sequence[Credentials]: From c8a2c2156b95eb64bf29c422e4a803b666b1addf Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 13:24:02 +0530 Subject: [PATCH 05/25] Agent: Fix variable name in MimikatzCredentialCollector --- .../mimikatz_collector/mimikatz_credential_collector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 53197acad..da17f85c8 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 @@ -79,4 +79,4 @@ class MimikatzCredentialCollector(ICredentialCollector): stolen_credentials=collected_credentials, ) - self.event_queue.publish(credentials_stolen_event) + self._event_queue.publish(credentials_stolen_event) From f453ff21fd4715d96538b7402d289794be5da2ad Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 13:25:03 +0530 Subject: [PATCH 06/25] UT: Pass event queue to MimikatzCredentialCollector's constructor in tests --- .../credential_collectors/test_mimikatz_collector.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index 40d5728dd..a1196f204 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -1,8 +1,10 @@ from typing import Sequence +from unittest.mock import MagicMock import pytest from common.credentials import Credentials, LMHash, NTHash, Password, Username +from common.event_queue import IEventQueue from infection_monkey.credential_collectors import MimikatzCredentialCollector from infection_monkey.credential_collectors.mimikatz_collector.windows_credentials import ( WindowsCredentials, @@ -18,7 +20,8 @@ def patch_pypykatz(win_creds: [WindowsCredentials], monkeypatch): def collect_credentials() -> Sequence[Credentials]: - return MimikatzCredentialCollector().collect_credentials() + mock_event_queue = MagicMock(spec=IEventQueue) + return MimikatzCredentialCollector(mock_event_queue).collect_credentials() @pytest.mark.parametrize( From 95a3be027316f9d62f48ee6514ac96b964af5609 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 19:07:06 +0530 Subject: [PATCH 07/25] UT: Add test to check CredentialStolenEvent is published in MimikatzCredentialCollector --- .../test_mimikatz_collector.py | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index a1196f204..03ac9fae1 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -1,11 +1,19 @@ from typing import Sequence -from unittest.mock import MagicMock +from unittest.mock import MagicMock, Mock import pytest +from pubsub.core import Publisher from common.credentials import Credentials, LMHash, NTHash, Password, Username -from common.event_queue import IEventQueue +from common.event_queue import IEventQueue, PyPubSubEventQueue +from common.events import AbstractEvent from infection_monkey.credential_collectors import MimikatzCredentialCollector +from infection_monkey.credential_collectors.mimikatz_collector.mimikatz_credential_collector import ( + MIMIKATZ_CREDENTIAL_COLLECTOR_TAG, + MIMIKATZ_EVENT_TAGS, + T1003_ATTACK_TECHNIQUE_TAG, + T1005_ATTACK_TECHNIQUE_TAG, +) from infection_monkey.credential_collectors.mimikatz_collector.windows_credentials import ( WindowsCredentials, ) @@ -113,3 +121,30 @@ def test_pypykatz_result_parsing_no_secrets(monkeypatch): collected_credentials = collect_credentials() assert len(collected_credentials) == 1 assert collected_credentials == expected_credentials + + +@pytest.fixture +def event_queue() -> IEventQueue: + return PyPubSubEventQueue(Publisher()) + + +def test_pypykatz_credentials_stolen_event_published(monkeypatch, event_queue): + def subscriber(event: AbstractEvent): + subscriber.call_count += 1 + subscriber.call_tags |= event.tags + + subscriber.call_count = 0 + subscriber.call_tags = set() + + event_queue.subscribe_tag(MIMIKATZ_CREDENTIAL_COLLECTOR_TAG, subscriber) + event_queue.subscribe_tag(T1003_ATTACK_TECHNIQUE_TAG, subscriber) + event_queue.subscribe_tag(T1005_ATTACK_TECHNIQUE_TAG, subscriber) + + mimikatz_credential_collector = MimikatzCredentialCollector(event_queue) + monkeypatch.setattr( + "infection_monkey.credential_collectors.mimikatz_collector.pypykatz_handler", Mock() + ) + mimikatz_credential_collector.collect_credentials() + + assert subscriber.call_count == 3 + assert subscriber.call_tags == MIMIKATZ_EVENT_TAGS From b7ada959faf217b73d3851a60c827dc2a49592f5 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 19:09:50 +0530 Subject: [PATCH 08/25] UT: Simplify MimikatzCredentialCollector's event publishing test --- .../credential_collectors/test_mimikatz_collector.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index 03ac9fae1..dbf1bbda9 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -8,11 +8,8 @@ from common.credentials import Credentials, LMHash, NTHash, Password, Username from common.event_queue import IEventQueue, PyPubSubEventQueue from common.events import AbstractEvent from infection_monkey.credential_collectors import MimikatzCredentialCollector -from infection_monkey.credential_collectors.mimikatz_collector.mimikatz_credential_collector import ( - MIMIKATZ_CREDENTIAL_COLLECTOR_TAG, +from infection_monkey.credential_collectors.mimikatz_collector.mimikatz_credential_collector import ( # noqa: E501 MIMIKATZ_EVENT_TAGS, - T1003_ATTACK_TECHNIQUE_TAG, - T1005_ATTACK_TECHNIQUE_TAG, ) from infection_monkey.credential_collectors.mimikatz_collector.windows_credentials import ( WindowsCredentials, @@ -136,9 +133,8 @@ def test_pypykatz_credentials_stolen_event_published(monkeypatch, event_queue): subscriber.call_count = 0 subscriber.call_tags = set() - event_queue.subscribe_tag(MIMIKATZ_CREDENTIAL_COLLECTOR_TAG, subscriber) - event_queue.subscribe_tag(T1003_ATTACK_TECHNIQUE_TAG, subscriber) - event_queue.subscribe_tag(T1005_ATTACK_TECHNIQUE_TAG, subscriber) + for event_tag in MIMIKATZ_EVENT_TAGS: + event_queue.subscribe_tag(event_tag, subscriber) mimikatz_credential_collector = MimikatzCredentialCollector(event_queue) monkeypatch.setattr( From 2fbe9f3a4adaa949aa536d6893eafd1d7ca84100 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 19:14:45 +0530 Subject: [PATCH 09/25] UT: Create event_queue_subscriber fixture --- monkey/tests/unit_tests/conftest.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/monkey/tests/unit_tests/conftest.py b/monkey/tests/unit_tests/conftest.py index d1470c167..2d5132da0 100644 --- a/monkey/tests/unit_tests/conftest.py +++ b/monkey/tests/unit_tests/conftest.py @@ -8,6 +8,7 @@ MONKEY_BASE_PATH = str(Path(__file__).parent.parent.parent) sys.path.insert(0, MONKEY_BASE_PATH) from common.agent_configuration import DEFAULT_AGENT_CONFIGURATION, AgentConfiguration # noqa: E402 +from common.events import AbstractEvent # noqa: E402 @pytest.fixture(scope="session") @@ -50,3 +51,17 @@ def monkey_configs_dir(data_for_tests_dir) -> Path: @pytest.fixture def default_agent_configuration() -> AgentConfiguration: return DEFAULT_AGENT_CONFIGURATION + + +@pytest.fixture +def event_queue_subscriber(): + def fn(event: AbstractEvent): + fn.call_count += 1 + fn.call_types.add(event.__class__) + fn.call_tags |= event.tags + + fn.call_count = 0 + fn.call_types = set() + fn.call_tags = set() + + return fn From b6c700129444e8b0ce89319cc8812a60d9b3bd77 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 19:15:55 +0530 Subject: [PATCH 10/25] UT: Use event_queue_subscriber fixture in PyPubSubEventQueue tests --- .../event_queue/test_pypubsub_event_queue.py | 74 ++++++++----------- 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py b/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py index 741d9b8ee..e9035abfb 100644 --- a/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py +++ b/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py @@ -31,81 +31,69 @@ class TestEvent2(AbstractEvent): tags: FrozenSet = frozenset() -def new_subscriber() -> EventSubscriber: - def fn(event: AbstractEvent): - fn.call_count += 1 - fn.call_types.add(event.__class__) - fn.call_tags |= event.tags - - fn.call_count = 0 - fn.call_types = set() - fn.call_tags = set() - - return fn - - -@pytest.fixture -def subscriber() -> EventSubscriber: - return new_subscriber() - - @pytest.fixture def event_queue() -> IEventQueue: return PyPubSubEventQueue(Publisher()) -def test_subscribe_all(event_queue: IEventQueue, subscriber: EventSubscriber): - event_queue.subscribe_all_events(subscriber) +def test_subscribe_all(event_queue: IEventQueue, event_queue_subscriber: EventSubscriber): + event_queue.subscribe_all_events(event_queue_subscriber) event_queue.publish(TestEvent1(tags=frozenset({EVENT_TAG_1, EVENT_TAG_2}))) event_queue.publish(TestEvent1(tags=frozenset({EVENT_TAG_2}))) event_queue.publish(TestEvent1(tags=frozenset({"secret_tag"}))) event_queue.publish(TestEvent2()) - assert subscriber.call_count == 4 - assert TestEvent1 in subscriber.call_types - assert TestEvent2 in subscriber.call_types + assert event_queue_subscriber.call_count == 4 + assert TestEvent1 in event_queue_subscriber.call_types + assert TestEvent2 in event_queue_subscriber.call_types @pytest.mark.parametrize("type_to_subscribe", [TestEvent1, TestEvent2]) -def test_subscribe_types(event_queue: IEventQueue, subscriber: EventSubscriber, type_to_subscribe): - event_queue.subscribe_type(type_to_subscribe, subscriber) +def test_subscribe_types( + event_queue: IEventQueue, event_queue_subscriber: EventSubscriber, type_to_subscribe +): + event_queue.subscribe_type(type_to_subscribe, event_queue_subscriber) event_queue.publish(TestEvent1()) event_queue.publish(TestEvent2()) - assert subscriber.call_count == 1 - assert type_to_subscribe in subscriber.call_types + assert event_queue_subscriber.call_count == 1 + assert type_to_subscribe in event_queue_subscriber.call_types -def test_subscribe_tags_single_type(event_queue: IEventQueue, subscriber: EventSubscriber): - event_queue.subscribe_tag(EVENT_TAG_1, subscriber) +def test_subscribe_tags_single_type( + event_queue: IEventQueue, event_queue_subscriber: EventSubscriber +): + event_queue.subscribe_tag(EVENT_TAG_1, event_queue_subscriber) event_queue.publish(TestEvent1(tags=frozenset({EVENT_TAG_1, EVENT_TAG_2}))) event_queue.publish(TestEvent2(tags=frozenset({EVENT_TAG_2}))) - assert subscriber.call_count == 1 - assert len(subscriber.call_types) == 1 - assert TestEvent1 in subscriber.call_types - assert EVENT_TAG_1 in subscriber.call_tags + assert event_queue_subscriber.call_count == 1 + assert len(event_queue_subscriber.call_types) == 1 + assert TestEvent1 in event_queue_subscriber.call_types + assert EVENT_TAG_1 in event_queue_subscriber.call_tags -def test_subscribe_tags_multiple_types(event_queue: IEventQueue, subscriber: EventSubscriber): - event_queue.subscribe_tag(EVENT_TAG_2, subscriber) +def test_subscribe_tags_multiple_types( + event_queue: IEventQueue, event_queue_subscriber: EventSubscriber +): + event_queue.subscribe_tag(EVENT_TAG_2, event_queue_subscriber) event_queue.publish(TestEvent1(tags=frozenset({EVENT_TAG_1, EVENT_TAG_2}))) event_queue.publish(TestEvent2(tags=frozenset({EVENT_TAG_2}))) - assert subscriber.call_count == 2 - assert len(subscriber.call_types) == 2 - assert TestEvent1 in subscriber.call_types - assert TestEvent2 in subscriber.call_types - assert {EVENT_TAG_1, EVENT_TAG_2}.issubset(subscriber.call_tags) + assert event_queue_subscriber.call_count == 2 + assert len(event_queue_subscriber.call_types) == 2 + assert TestEvent1 in event_queue_subscriber.call_types + assert TestEvent2 in event_queue_subscriber.call_types + assert {EVENT_TAG_1, EVENT_TAG_2}.issubset(event_queue_subscriber.call_tags) -def test_type_tag_collision(event_queue: IEventQueue, subscriber: EventSubscriber): - event_queue.subscribe_type(TestEvent1, subscriber) +def test_type_tag_collision(event_queue: IEventQueue, event_queue_subscriber: EventSubscriber): + event_queue.subscribe_type(TestEvent1, event_queue_subscriber) event_queue.publish(TestEvent2(tags=frozenset({TestEvent1.__name__}))) - assert subscriber.call_count == 0 + assert event_queue_subscriber.call_count == 0 From 140967b05f0fffbdc0471e282a63801172493576 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 16 Aug 2022 19:16:25 +0530 Subject: [PATCH 11/25] UT: Use event_queue_subscriber fixture in MimikatzCredentialCollector tests --- .../test_mimikatz_collector.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index dbf1bbda9..0910aab1b 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -6,7 +6,6 @@ from pubsub.core import Publisher from common.credentials import Credentials, LMHash, NTHash, Password, Username from common.event_queue import IEventQueue, PyPubSubEventQueue -from common.events import AbstractEvent from infection_monkey.credential_collectors import MimikatzCredentialCollector from infection_monkey.credential_collectors.mimikatz_collector.mimikatz_credential_collector import ( # noqa: E501 MIMIKATZ_EVENT_TAGS, @@ -125,16 +124,11 @@ def event_queue() -> IEventQueue: return PyPubSubEventQueue(Publisher()) -def test_pypykatz_credentials_stolen_event_published(monkeypatch, event_queue): - def subscriber(event: AbstractEvent): - subscriber.call_count += 1 - subscriber.call_tags |= event.tags - - subscriber.call_count = 0 - subscriber.call_tags = set() - +def test_pypykatz_credentials_stolen_event_published( + monkeypatch, event_queue, event_queue_subscriber +): for event_tag in MIMIKATZ_EVENT_TAGS: - event_queue.subscribe_tag(event_tag, subscriber) + event_queue.subscribe_tag(event_tag, event_queue_subscriber) mimikatz_credential_collector = MimikatzCredentialCollector(event_queue) monkeypatch.setattr( @@ -142,5 +136,5 @@ def test_pypykatz_credentials_stolen_event_published(monkeypatch, event_queue): ) mimikatz_credential_collector.collect_credentials() - assert subscriber.call_count == 3 - assert subscriber.call_tags == MIMIKATZ_EVENT_TAGS + assert event_queue_subscriber.call_count == 3 + assert event_queue_subscriber.call_tags == MIMIKATZ_EVENT_TAGS From a0cf3d65f4f5c2d8c0a4c5cceec79d1adf448ba3 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 11:48:35 +0530 Subject: [PATCH 12/25] Agent: Rename variable in SSH handler --- .../credential_collectors/ssh_collector/ssh_handler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 097d59f40..2c5b55887 100644 --- a/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py +++ b/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py @@ -20,7 +20,7 @@ T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003" T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005" T1145_ATTACK_TECHNIQUE_TAG = "attack-t1145" -SSH_COLLECTOR_EVENT_TAG = { +SSH_COLLECTOR_EVENT_TAGS = { SSH_CREDENTIAL_COLLECTOR_TAG, T1003_ATTACK_TECHNIQUE_TAG, T1005_ATTACK_TECHNIQUE_TAG, @@ -165,7 +165,7 @@ def to_credentials(ssh_info: Iterable[Dict]) -> Sequence[Credentials]: def _publish_credentials_stolen_event(collected_credentials: Credentials, event_queue: IEventQueue): credentials_stolen_event = CredentialsStolenEvent( - tags=frozenset(SSH_COLLECTOR_EVENT_TAG), + tags=frozenset(SSH_COLLECTOR_EVENT_TAGS), stolen_credentials=[collected_credentials], ) From 457cc6be27ae6431b28fd893fc8393a8648a1423 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 11:49:43 +0530 Subject: [PATCH 13/25] Agent: Modify Mimikatz credential collector tag string --- .../mimikatz_collector/mimikatz_credential_collector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 da17f85c8..a426c040e 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 @@ -13,7 +13,7 @@ from .windows_credentials import WindowsCredentials logger = logging.getLogger(__name__) -MIMIKATZ_CREDENTIAL_COLLECTOR_TAG = "MimikatzCredentialsStolen" +MIMIKATZ_CREDENTIAL_COLLECTOR_TAG = "mimikatz-credentials-collector" T1003_ATTACK_TECHNIQUE_TAG = "T1003" T1005_ATTACK_TECHNIQUE_TAG = "T1005" From 7faf6d3ecfb6284a8d1c7c34843391f33f04ecc5 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 11:50:38 +0530 Subject: [PATCH 14/25] Agent: Modify Mimikatz credential collector's attack technique tags' strings --- .../mimikatz_collector/mimikatz_credential_collector.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 a426c040e..6c805561e 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 @@ -14,8 +14,8 @@ logger = logging.getLogger(__name__) MIMIKATZ_CREDENTIAL_COLLECTOR_TAG = "mimikatz-credentials-collector" -T1003_ATTACK_TECHNIQUE_TAG = "T1003" -T1005_ATTACK_TECHNIQUE_TAG = "T1005" +T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003" +T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005" MIMIKATZ_EVENT_TAGS = { MIMIKATZ_CREDENTIAL_COLLECTOR_TAG, From 8f789b9d606f92ce9efea37d38cbd1e457b230e8 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 11:52:02 +0530 Subject: [PATCH 15/25] Agent: Remove unneeded argument passed to CredentialsStolenEvent in MimikatzCredentialCollector --- .../mimikatz_collector/mimikatz_credential_collector.py | 1 - 1 file changed, 1 deletion(-) 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 6c805561e..592abffd4 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 @@ -74,7 +74,6 @@ class MimikatzCredentialCollector(ICredentialCollector): def _publish_credentials_stolen_event(self, collected_credentials: Sequence[Credentials]): credentials_stolen_event = CredentialsStolenEvent( - target=None, tags=frozenset(MIMIKATZ_EVENT_TAGS), stolen_credentials=collected_credentials, ) From eb17b2062503fb69159b59e137f5bbe88efde3bd Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 14:41:26 +0530 Subject: [PATCH 16/25] UT: Simplify MimikatzCredentialCollector's event publishing test --- .../test_mimikatz_collector.py | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index 0910aab1b..7ad4a1834 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -2,10 +2,10 @@ from typing import Sequence from unittest.mock import MagicMock, Mock import pytest -from pubsub.core import Publisher from common.credentials import Credentials, LMHash, NTHash, Password, Username -from common.event_queue import IEventQueue, PyPubSubEventQueue +from common.event_queue import IEventQueue +from common.events import CredentialsStolenEvent from infection_monkey.credential_collectors import MimikatzCredentialCollector from infection_monkey.credential_collectors.mimikatz_collector.mimikatz_credential_collector import ( # noqa: E501 MIMIKATZ_EVENT_TAGS, @@ -119,22 +119,23 @@ def test_pypykatz_result_parsing_no_secrets(monkeypatch): assert collected_credentials == expected_credentials -@pytest.fixture -def event_queue() -> IEventQueue: - return PyPubSubEventQueue(Publisher()) - - -def test_pypykatz_credentials_stolen_event_published( - monkeypatch, event_queue, event_queue_subscriber -): - for event_tag in MIMIKATZ_EVENT_TAGS: - event_queue.subscribe_tag(event_tag, event_queue_subscriber) - - mimikatz_credential_collector = MimikatzCredentialCollector(event_queue) +def test_mimikatz_credentials_stolen_event_published(monkeypatch): + mock_event_queue = MagicMock(spec=IEventQueue) + mock_subscriber = Mock() monkeypatch.setattr( "infection_monkey.credential_collectors.mimikatz_collector.pypykatz_handler", Mock() ) - mimikatz_credential_collector.collect_credentials() - assert event_queue_subscriber.call_count == 3 - assert event_queue_subscriber.call_tags == MIMIKATZ_EVENT_TAGS + for event_tag in MIMIKATZ_EVENT_TAGS: + mock_event_queue.subscribe_tag(event_tag, mock_subscriber) + + mimikatz_credential_collector = MimikatzCredentialCollector(mock_event_queue) + collected_credentials = mimikatz_credential_collector.collect_credentials() + + mock_event_queue.publish.assert_called_once() + + mock_event_queue_call_args = mock_event_queue.publish.call_args[0][0] + + assert isinstance(mock_event_queue_call_args, CredentialsStolenEvent) + assert mock_event_queue_call_args.tags == frozenset(MIMIKATZ_EVENT_TAGS) + assert mock_event_queue_call_args.stolen_credentials == collected_credentials From 11901b18358a91c52aef2e09cbb2f7d9f43cf4be Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 14:44:43 +0530 Subject: [PATCH 17/25] UT: Simplify variable logic in MimikatzCredentialCollector's event publishing test --- .../credential_collectors/test_mimikatz_collector.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index 7ad4a1834..aec06bfc1 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -121,9 +121,10 @@ def test_pypykatz_result_parsing_no_secrets(monkeypatch): def test_mimikatz_credentials_stolen_event_published(monkeypatch): mock_event_queue = MagicMock(spec=IEventQueue) - mock_subscriber = Mock() + mock_subscriber = mock_pypykatz_handler = Mock() monkeypatch.setattr( - "infection_monkey.credential_collectors.mimikatz_collector.pypykatz_handler", Mock() + "infection_monkey.credential_collectors.mimikatz_collector.pypykatz_handler", + mock_pypykatz_handler, ) for event_tag in MIMIKATZ_EVENT_TAGS: From f510b89c086689a778d5123cb69f009b6517cc2c Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 14:46:01 +0530 Subject: [PATCH 18/25] UT: Move event_queue_subscriber fixture back to test_pypubsub_event_queue.py --- .../event_queue/test_pypubsub_event_queue.py | 14 ++++++++++++++ monkey/tests/unit_tests/conftest.py | 15 --------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py b/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py index e9035abfb..d48d5fc00 100644 --- a/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py +++ b/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py @@ -36,6 +36,20 @@ def event_queue() -> IEventQueue: return PyPubSubEventQueue(Publisher()) +@pytest.fixture +def event_queue_subscriber(): + def fn(event: AbstractEvent): + fn.call_count += 1 + fn.call_types.add(event.__class__) + fn.call_tags |= event.tags + + fn.call_count = 0 + fn.call_types = set() + fn.call_tags = set() + + return fn + + def test_subscribe_all(event_queue: IEventQueue, event_queue_subscriber: EventSubscriber): event_queue.subscribe_all_events(event_queue_subscriber) diff --git a/monkey/tests/unit_tests/conftest.py b/monkey/tests/unit_tests/conftest.py index 2d5132da0..d1470c167 100644 --- a/monkey/tests/unit_tests/conftest.py +++ b/monkey/tests/unit_tests/conftest.py @@ -8,7 +8,6 @@ MONKEY_BASE_PATH = str(Path(__file__).parent.parent.parent) sys.path.insert(0, MONKEY_BASE_PATH) from common.agent_configuration import DEFAULT_AGENT_CONFIGURATION, AgentConfiguration # noqa: E402 -from common.events import AbstractEvent # noqa: E402 @pytest.fixture(scope="session") @@ -51,17 +50,3 @@ def monkey_configs_dir(data_for_tests_dir) -> Path: @pytest.fixture def default_agent_configuration() -> AgentConfiguration: return DEFAULT_AGENT_CONFIGURATION - - -@pytest.fixture -def event_queue_subscriber(): - def fn(event: AbstractEvent): - fn.call_count += 1 - fn.call_types.add(event.__class__) - fn.call_tags |= event.tags - - fn.call_count = 0 - fn.call_types = set() - fn.call_tags = set() - - return fn From f9f3daffa7775be23a01840be171b923da972497 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 14:48:16 +0530 Subject: [PATCH 19/25] UT: Add missing type hint to event_queue_subscriber fixture --- .../common/event_queue/test_pypubsub_event_queue.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py b/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py index d48d5fc00..006a27916 100644 --- a/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py +++ b/monkey/tests/unit_tests/common/event_queue/test_pypubsub_event_queue.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from ipaddress import IPv4Address -from typing import FrozenSet, Union +from typing import Callable, FrozenSet, Union from uuid import UUID import pytest @@ -37,7 +37,7 @@ def event_queue() -> IEventQueue: @pytest.fixture -def event_queue_subscriber(): +def event_queue_subscriber() -> Callable[[AbstractEvent], None]: def fn(event: AbstractEvent): fn.call_count += 1 fn.call_types.add(event.__class__) From 3dca01d5d563e5c357c2771ede239a81fe7a6c44 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 17:28:18 +0530 Subject: [PATCH 20/25] Agent: Define MIMIKATZ_EVENT_TAGS as a frozenset --- .../mimikatz_credential_collector.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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 592abffd4..a39023e0e 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 @@ -17,11 +17,13 @@ MIMIKATZ_CREDENTIAL_COLLECTOR_TAG = "mimikatz-credentials-collector" T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003" T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005" -MIMIKATZ_EVENT_TAGS = { - MIMIKATZ_CREDENTIAL_COLLECTOR_TAG, - T1003_ATTACK_TECHNIQUE_TAG, - T1005_ATTACK_TECHNIQUE_TAG, -} +MIMIKATZ_EVENT_TAGS = frozenset( + ( + MIMIKATZ_CREDENTIAL_COLLECTOR_TAG, + T1003_ATTACK_TECHNIQUE_TAG, + T1005_ATTACK_TECHNIQUE_TAG, + ) +) class MimikatzCredentialCollector(ICredentialCollector): @@ -74,7 +76,7 @@ class MimikatzCredentialCollector(ICredentialCollector): def _publish_credentials_stolen_event(self, collected_credentials: Sequence[Credentials]): credentials_stolen_event = CredentialsStolenEvent( - tags=frozenset(MIMIKATZ_EVENT_TAGS), + tags=MIMIKATZ_EVENT_TAGS, stolen_credentials=collected_credentials, ) From 5747c2e8b437342064468b5ba712e96159201f42 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 17:28:44 +0530 Subject: [PATCH 21/25] UT: Update MimikatzCredentialCollector test now that MIMIKATZ_EVENT_TAGS is a frozenset --- .../credential_collectors/test_mimikatz_collector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index aec06bfc1..a78f77de3 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -138,5 +138,5 @@ def test_mimikatz_credentials_stolen_event_published(monkeypatch): mock_event_queue_call_args = mock_event_queue.publish.call_args[0][0] assert isinstance(mock_event_queue_call_args, CredentialsStolenEvent) - assert mock_event_queue_call_args.tags == frozenset(MIMIKATZ_EVENT_TAGS) + assert mock_event_queue_call_args.tags == MIMIKATZ_EVENT_TAGS assert mock_event_queue_call_args.stolen_credentials == collected_credentials From 2c3b29493f2dac32bbb6dc4b3c8ec580ea26ce5f Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 17:29:48 +0530 Subject: [PATCH 22/25] Agent: Define SSH_COLLECTOR_EVENT_TAGS as a frozenset --- .../ssh_collector/ssh_handler.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) 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 2c5b55887..7d8a046f4 100644 --- a/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py +++ b/monkey/infection_monkey/credential_collectors/ssh_collector/ssh_handler.py @@ -20,12 +20,14 @@ T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003" T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005" T1145_ATTACK_TECHNIQUE_TAG = "attack-t1145" -SSH_COLLECTOR_EVENT_TAGS = { - SSH_CREDENTIAL_COLLECTOR_TAG, - T1003_ATTACK_TECHNIQUE_TAG, - T1005_ATTACK_TECHNIQUE_TAG, - T1145_ATTACK_TECHNIQUE_TAG, -} +SSH_COLLECTOR_EVENT_TAGS = frozenset( + ( + SSH_CREDENTIAL_COLLECTOR_TAG, + T1003_ATTACK_TECHNIQUE_TAG, + T1005_ATTACK_TECHNIQUE_TAG, + T1145_ATTACK_TECHNIQUE_TAG, + ) +) def get_ssh_info( @@ -165,7 +167,7 @@ def to_credentials(ssh_info: Iterable[Dict]) -> Sequence[Credentials]: def _publish_credentials_stolen_event(collected_credentials: Credentials, event_queue: IEventQueue): credentials_stolen_event = CredentialsStolenEvent( - tags=frozenset(SSH_COLLECTOR_EVENT_TAGS), + tags=SSH_COLLECTOR_EVENT_TAGS, stolen_credentials=[collected_credentials], ) From 43347400024b396a58a92398571c9d643324e516 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 17:31:06 +0530 Subject: [PATCH 23/25] UT: Simplify test_mimikatz_credentials_stolen_event_published --- .../credential_collectors/test_mimikatz_collector.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index a78f77de3..a3777b8e8 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -121,15 +121,12 @@ def test_pypykatz_result_parsing_no_secrets(monkeypatch): def test_mimikatz_credentials_stolen_event_published(monkeypatch): mock_event_queue = MagicMock(spec=IEventQueue) - mock_subscriber = mock_pypykatz_handler = Mock() + mock_pypykatz_handler = Mock() monkeypatch.setattr( "infection_monkey.credential_collectors.mimikatz_collector.pypykatz_handler", mock_pypykatz_handler, ) - for event_tag in MIMIKATZ_EVENT_TAGS: - mock_event_queue.subscribe_tag(event_tag, mock_subscriber) - mimikatz_credential_collector = MimikatzCredentialCollector(mock_event_queue) collected_credentials = mimikatz_credential_collector.collect_credentials() From 67220574918be9561bd9c35a16e7bda39d08b1eb Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 18:03:07 +0530 Subject: [PATCH 24/25] Agent: Use existing patch function in test_pypykatz_result_parsing_no_secrets --- .../credential_collectors/test_mimikatz_collector.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index a3777b8e8..74c852437 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -1,5 +1,5 @@ from typing import Sequence -from unittest.mock import MagicMock, Mock +from unittest.mock import MagicMock import pytest @@ -121,11 +121,7 @@ def test_pypykatz_result_parsing_no_secrets(monkeypatch): def test_mimikatz_credentials_stolen_event_published(monkeypatch): mock_event_queue = MagicMock(spec=IEventQueue) - mock_pypykatz_handler = Mock() - monkeypatch.setattr( - "infection_monkey.credential_collectors.mimikatz_collector.pypykatz_handler", - mock_pypykatz_handler, - ) + patch_pypykatz([], monkeypatch) mimikatz_credential_collector = MimikatzCredentialCollector(mock_event_queue) collected_credentials = mimikatz_credential_collector.collect_credentials() From 20f529d6a282814dd02a33cebb6ba16d6ce14790 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 18 Aug 2022 09:22:59 +0200 Subject: [PATCH 25/25] UT: Separate mimikatz credentials stolen event test --- .../test_mimikatz_collector.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py index 74c852437..12ca9d594 100644 --- a/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py +++ b/monkey/tests/unit_tests/infection_monkey/credential_collectors/test_mimikatz_collector.py @@ -124,12 +124,39 @@ def test_mimikatz_credentials_stolen_event_published(monkeypatch): patch_pypykatz([], monkeypatch) mimikatz_credential_collector = MimikatzCredentialCollector(mock_event_queue) - collected_credentials = mimikatz_credential_collector.collect_credentials() + mimikatz_credential_collector.collect_credentials() mock_event_queue.publish.assert_called_once() mock_event_queue_call_args = mock_event_queue.publish.call_args[0][0] assert isinstance(mock_event_queue_call_args, CredentialsStolenEvent) + + +def test_mimikatz_credentials_stolen_event_tags(monkeypatch): + mock_event_queue = MagicMock(spec=IEventQueue) + patch_pypykatz([], monkeypatch) + + mimikatz_credential_collector = MimikatzCredentialCollector(mock_event_queue) + mimikatz_credential_collector.collect_credentials() + + mock_event_queue_call_args = mock_event_queue.publish.call_args[0][0] + assert mock_event_queue_call_args.tags == MIMIKATZ_EVENT_TAGS + + +def test_mimikatz_credentials_stolen_event_stolen_credentials(monkeypatch): + mock_event_queue = MagicMock(spec=IEventQueue) + win_creds = [ + WindowsCredentials( + username="user2", password="secret2", lm_hash="0182BD0BD4444BF8FC83B5D9042EED2E" + ), + ] + patch_pypykatz(win_creds, monkeypatch) + + mimikatz_credential_collector = MimikatzCredentialCollector(mock_event_queue) + collected_credentials = mimikatz_credential_collector.collect_credentials() + + mock_event_queue_call_args = mock_event_queue.publish.call_args[0][0] + assert mock_event_queue_call_args.stolen_credentials == collected_credentials