Merge pull request #2197 from guardicore/2176-remove-credentials-intercepting-telemetry-messenger

2176 remove credentials intercepting telemetry messenger
This commit is contained in:
Mike Salvatore 2022-08-18 06:39:42 -04:00 committed by GitHub
commit c55098e186
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 47 additions and 116 deletions

View File

@ -4,6 +4,7 @@ from abc import abstractmethod
from datetime import datetime from datetime import datetime
from typing import Dict from typing import Dict
from common.event_queue import IEventQueue
from common.utils.exceptions import FailedExploitationError from common.utils.exceptions import FailedExploitationError
from infection_monkey.i_puppet import ExploiterResultData from infection_monkey.i_puppet import ExploiterResultData
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
@ -31,6 +32,7 @@ class HostExploiter:
self.exploit_attempts = [] self.exploit_attempts = []
self.host = None self.host = None
self.telemetry_messenger = None self.telemetry_messenger = None
self.event_queue = None
self.options = {} self.options = {}
self.exploit_result = {} self.exploit_result = {}
@ -58,6 +60,7 @@ class HostExploiter:
host, host,
current_depth: int, current_depth: int,
telemetry_messenger: ITelemetryMessenger, telemetry_messenger: ITelemetryMessenger,
event_queue: IEventQueue,
agent_repository: IAgentRepository, agent_repository: IAgentRepository,
options: Dict, options: Dict,
interrupt: threading.Event, interrupt: threading.Event,
@ -65,6 +68,7 @@ class HostExploiter:
self.host = host self.host = host
self.current_depth = current_depth self.current_depth = current_depth
self.telemetry_messenger = telemetry_messenger self.telemetry_messenger = telemetry_messenger
self.event_queue = event_queue
self.agent_repository = agent_repository self.agent_repository = agent_repository
self.options = options self.options = options
self.interrupt = interrupt self.interrupt = interrupt

View File

@ -1,6 +1,7 @@
import threading import threading
from typing import Dict, Type from typing import Dict, Type
from common.event_queue import IEventQueue
from infection_monkey.model import VictimHost from infection_monkey.model import VictimHost
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
@ -21,10 +22,12 @@ class ExploiterWrapper:
self, self,
exploit_class: Type[HostExploiter], exploit_class: Type[HostExploiter],
telemetry_messenger: ITelemetryMessenger, telemetry_messenger: ITelemetryMessenger,
event_queue: IEventQueue,
agent_repository: IAgentRepository, agent_repository: IAgentRepository,
): ):
self._exploit_class = exploit_class self._exploit_class = exploit_class
self._telemetry_messenger = telemetry_messenger self._telemetry_messenger = telemetry_messenger
self._event_queue = event_queue
self._agent_repository = agent_repository self._agent_repository = agent_repository
def exploit_host( def exploit_host(
@ -35,18 +38,23 @@ class ExploiterWrapper:
host, host,
current_depth, current_depth,
self._telemetry_messenger, self._telemetry_messenger,
self._event_queue,
self._agent_repository, self._agent_repository,
options, options,
interrupt, interrupt,
) )
def __init__( def __init__(
self, telemetry_messenger: ITelemetryMessenger, agent_repository: IAgentRepository self,
telemetry_messenger: ITelemetryMessenger,
event_queue: IEventQueue,
agent_repository: IAgentRepository,
): ):
self._telemetry_messenger = telemetry_messenger self._telemetry_messenger = telemetry_messenger
self._event_queue = event_queue
self._agent_repository = agent_repository self._agent_repository = agent_repository
def wrap(self, exploit_class: Type[HostExploiter]): def wrap(self, exploit_class: Type[HostExploiter]):
return ExploiterWrapper.Inner( return ExploiterWrapper.Inner(
exploit_class, self._telemetry_messenger, self._agent_repository exploit_class, self._telemetry_messenger, self._event_queue, self._agent_repository
) )

View File

@ -9,7 +9,7 @@ import os
import re import re
import tempfile import tempfile
from binascii import unhexlify from binascii import unhexlify
from typing import Dict, List, Optional, Tuple from typing import Dict, List, Optional, Sequence, Tuple
import impacket import impacket
from impacket.dcerpc.v5 import epm, nrpc, rpcrt, transport from impacket.dcerpc.v5 import epm, nrpc, rpcrt, transport
@ -17,6 +17,7 @@ from impacket.dcerpc.v5.dtypes import NULL
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
from common.credentials import Credentials, LMHash, NTHash, Username from common.credentials import Credentials, LMHash, NTHash, Username
from common.events import CredentialsStolenEvent
from infection_monkey.exploit.HostExploiter import HostExploiter from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.wmi_tools import WmiTools from infection_monkey.exploit.tools.wmi_tools import WmiTools
from infection_monkey.exploit.zerologon_utils.dump_secrets import DumpSecrets from infection_monkey.exploit.zerologon_utils.dump_secrets import DumpSecrets
@ -30,6 +31,19 @@ from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
ZEROLOGON_EXPLOITER_TAG = "zerologon-exploiter"
T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003"
T1098_ATTACK_TECHNIQUE_TAG = "attack-t1098"
ZEROLOGON_EVENT_TAGS = frozenset(
{
ZEROLOGON_EXPLOITER_TAG,
T1003_ATTACK_TECHNIQUE_TAG,
T1098_ATTACK_TECHNIQUE_TAG,
}
)
class ZerologonExploiter(HostExploiter): class ZerologonExploiter(HostExploiter):
_EXPLOITED_SERVICE = "Netlogon" _EXPLOITED_SERVICE = "Netlogon"
@ -284,14 +298,20 @@ class ZerologonExploiter(HostExploiter):
def send_extracted_creds_as_credential_telemetry( def send_extracted_creds_as_credential_telemetry(
self, user: str, lmhash: str, nthash: str self, user: str, lmhash: str, nthash: str
) -> None: ) -> None:
self.telemetry_messenger.send_telemetry( extracted_credentials = [
CredentialsTelem(
[
Credentials(Username(user), LMHash(lmhash)), Credentials(Username(user), LMHash(lmhash)),
Credentials(Username(user), NTHash(nthash)), Credentials(Username(user), NTHash(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]):
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]) -> str:
if not self.save_HKLM_keys_locally(username, user_pwd_hashes): if not self.save_HKLM_keys_locally(username, user_pwd_hashes):

View File

@ -66,9 +66,6 @@ from infection_monkey.puppet.puppet import Puppet
from infection_monkey.system_singleton import SystemSingleton from infection_monkey.system_singleton import SystemSingleton
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
from infection_monkey.telemetry.attack.t1107_telem import T1107Telem from infection_monkey.telemetry.attack.t1107_telem import T1107Telem
from infection_monkey.telemetry.messengers.credentials_intercepting_telemetry_messenger import (
CredentialsInterceptingTelemetryMessenger,
)
from infection_monkey.telemetry.messengers.exploit_intercepting_telemetry_messenger import ( from infection_monkey.telemetry.messengers.exploit_intercepting_telemetry_messenger import (
ExploitInterceptingTelemetryMessenger, ExploitInterceptingTelemetryMessenger,
) )
@ -214,11 +211,8 @@ class InfectionMonkey:
victim_host_factory = self._build_victim_host_factory(local_network_interfaces) victim_host_factory = self._build_victim_host_factory(local_network_interfaces)
telemetry_messenger = CredentialsInterceptingTelemetryMessenger( telemetry_messenger = ExploitInterceptingTelemetryMessenger(
ExploitInterceptingTelemetryMessenger(
self._telemetry_messenger, self._monkey_inbound_tunnel self._telemetry_messenger, self._monkey_inbound_tunnel
),
propagation_credentials_repository,
) )
self._master = AutomatedMaster( self._master = AutomatedMaster(
@ -278,7 +272,7 @@ class InfectionMonkey:
agent_repository = CachingAgentRepository( agent_repository = CachingAgentRepository(
f"https://{self._control_client.server_address}", self._control_client.proxies f"https://{self._control_client.server_address}", self._control_client.proxies
) )
exploit_wrapper = ExploiterWrapper(self._telemetry_messenger, agent_repository) exploit_wrapper = ExploiterWrapper(self._telemetry_messenger, event_queue, agent_repository)
puppet.load_plugin( puppet.load_plugin(
"HadoopExploiter", exploit_wrapper.wrap(HadoopExploiter), PluginType.EXPLOITER "HadoopExploiter", exploit_wrapper.wrap(HadoopExploiter), PluginType.EXPLOITER
@ -296,13 +290,9 @@ class InfectionMonkey:
"MSSQLExploiter", exploit_wrapper.wrap(MSSQLExploiter), PluginType.EXPLOITER "MSSQLExploiter", exploit_wrapper.wrap(MSSQLExploiter), PluginType.EXPLOITER
) )
zerologon_telemetry_messenger = CredentialsInterceptingTelemetryMessenger(
self._telemetry_messenger, propagation_credentials_repository
)
zerologon_wrapper = ExploiterWrapper(zerologon_telemetry_messenger, agent_repository)
puppet.load_plugin( puppet.load_plugin(
"ZerologonExploiter", "ZerologonExploiter",
zerologon_wrapper.wrap(ZerologonExploiter), exploit_wrapper.wrap(ZerologonExploiter),
PluginType.EXPLOITER, PluginType.EXPLOITER,
) )

View File

@ -1,40 +0,0 @@
from functools import singledispatch
from infection_monkey.credential_repository import IPropagationCredentialsRepository
from infection_monkey.telemetry.credentials_telem import CredentialsTelem
from infection_monkey.telemetry.i_telem import ITelem
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
class CredentialsInterceptingTelemetryMessenger(ITelemetryMessenger):
def __init__(
self,
telemetry_messenger: ITelemetryMessenger,
credentials_store: IPropagationCredentialsRepository,
):
self._telemetry_messenger = telemetry_messenger
self._credentials_store = credentials_store
def send_telemetry(self, telemetry: ITelem):
_send_telemetry(telemetry, self._telemetry_messenger, self._credentials_store)
# Note: We can use @singledispatchmethod instead of @singledispatch if we migrate to Python 3.8 or
# later.
@singledispatch
def _send_telemetry(
telemetry: ITelem,
telemetry_messenger: ITelemetryMessenger,
credentials_store: IPropagationCredentialsRepository,
):
telemetry_messenger.send_telemetry(telemetry)
@_send_telemetry.register
def _(
telemetry: CredentialsTelem,
telemetry_messenger: ITelemetryMessenger,
credentials_store: IPropagationCredentialsRepository,
):
credentials_store.add_credentials(telemetry.credentials)
telemetry_messenger.send_telemetry(telemetry)

View File

@ -36,6 +36,7 @@ def powershell_arguments(http_and_https_both_enabled_host):
"options": options, "options": options,
"current_depth": 2, "current_depth": 2,
"telemetry_messenger": MagicMock(), "telemetry_messenger": MagicMock(),
"event_queue": MagicMock(),
"agent_repository": mock_agent_repository, "agent_repository": mock_agent_repository,
"interrupt": threading.Event(), "interrupt": threading.Event(),
} }

View File

@ -1,52 +0,0 @@
from unittest.mock import MagicMock
from common.credentials import Credentials, Password, SSHKeypair, Username
from infection_monkey.telemetry.credentials_telem import CredentialsTelem
from infection_monkey.telemetry.messengers.credentials_intercepting_telemetry_messenger import (
CredentialsInterceptingTelemetryMessenger,
)
TELEM_CREDENTIALS = [
Credentials(
Username("user1"),
SSHKeypair(public_key="some_public_key", private_key="some_private_key"),
),
Credentials(Username("root"), Password("password")),
]
class MockCredentialsTelem(CredentialsTelem):
def __init(self, credentials):
super().__init__(credentials)
def get_data(self):
return {}
def test_credentials_generic_telemetry(TestTelem):
mock_telemetry_messenger = MagicMock()
mock_credentials_repository = MagicMock()
telemetry_messenger = CredentialsInterceptingTelemetryMessenger(
mock_telemetry_messenger, mock_credentials_repository
)
telemetry_messenger.send_telemetry(TestTelem())
assert mock_telemetry_messenger.send_telemetry.called
assert not mock_credentials_repository.add_credentials.called
def test_successful_intercepting_credentials_telemetry():
mock_telemetry_messenger = MagicMock()
mock_credentials_repository = MagicMock()
mock_empty_credentials_telem = MockCredentialsTelem(TELEM_CREDENTIALS)
telemetry_messenger = CredentialsInterceptingTelemetryMessenger(
mock_telemetry_messenger, mock_credentials_repository
)
telemetry_messenger.send_telemetry(mock_empty_credentials_telem)
assert mock_telemetry_messenger.send_telemetry.called
assert mock_credentials_repository.add_credentials.called