diff --git a/monkey/common/agent_events/__init__.py b/monkey/common/agent_events/__init__.py index e185de1fa..8557e62af 100644 --- a/monkey/common/agent_events/__init__.py +++ b/monkey/common/agent_events/__init__.py @@ -2,4 +2,5 @@ from .abstract_agent_event import AbstractAgentEvent from .credentials_stolen_events import CredentialsStolenEvent from .ping_scan_event import PingScanEvent from .tcp_scan_event import TCPScanEvent +from .exploitation_event import ExploitationEvent from .propagation_event import PropagationEvent diff --git a/monkey/common/agent_events/exploitation_event.py b/monkey/common/agent_events/exploitation_event.py new file mode 100644 index 000000000..b51a4054a --- /dev/null +++ b/monkey/common/agent_events/exploitation_event.py @@ -0,0 +1,22 @@ +from ipaddress import IPv4Address + +from pydantic import Field + +from . import AbstractAgentEvent + + +class ExploitationEvent(AbstractAgentEvent): + """ + An event that occurs when the Agent exploits a host + + Attributes: + :param target: IP address of the exploited system + :param success: Status of the exploitation + :param exploiter_name: Name of the exploiter that triggered the event + :param error_message: Message if an error occurs during exploitation + """ + + target: IPv4Address + success: bool + exploiter_name: str + error_message: str = Field(default="") diff --git a/monkey/common/agent_events/tcp_scan_event.py b/monkey/common/agent_events/tcp_scan_event.py index f7950916a..335273082 100644 --- a/monkey/common/agent_events/tcp_scan_event.py +++ b/monkey/common/agent_events/tcp_scan_event.py @@ -11,6 +11,7 @@ class TCPScanEvent(AbstractAgentEvent): An event that occurs when the Agent performs a TCP scan on a host Attributes: + :param target: IP address of the scanned system :param ports: The scanned ports and their status (open/closed) """ diff --git a/monkey/tests/unit_tests/common/agent_events/test_exploitation_event.py b/monkey/tests/unit_tests/common/agent_events/test_exploitation_event.py new file mode 100644 index 000000000..54a7c67ad --- /dev/null +++ b/monkey/tests/unit_tests/common/agent_events/test_exploitation_event.py @@ -0,0 +1,82 @@ +from ipaddress import IPv4Address +from uuid import UUID + +import pytest + +from common.agent_events import ExploitationEvent + +TARGET_IP_STR = "192.168.1.10" +AGENT_ID = UUID("012e7238-7b81-4108-8c7f-0787bc3f3c10") +TIMESTAMP = 1664371327.4067292 + +EXPLOITATION_EVENT = ExploitationEvent( + source=AGENT_ID, + timestamp=TIMESTAMP, + target=IPv4Address(TARGET_IP_STR), + success=True, + exploiter_name="SSHExploiter", +) + +EXPLOITATION_OBJECT_DICT = { + "source": AGENT_ID, + "timestamp": TIMESTAMP, + "target": IPv4Address(TARGET_IP_STR), + "success": True, + "exploiter_name": "SSHExploiter", + "error_message": "", +} + +EXPLOITATION_SIMPLE_DICT = { + "source": str(AGENT_ID), + "timestamp": TIMESTAMP, + "target": TARGET_IP_STR, + "success": "true", + "exploiter_name": "SSHExploiter", + "error_message": "", +} + + +@pytest.mark.parametrize( + "EXPLOITATION_event_dict", [EXPLOITATION_OBJECT_DICT, EXPLOITATION_SIMPLE_DICT] +) +def test_constructor(EXPLOITATION_event_dict): + assert ExploitationEvent(**EXPLOITATION_event_dict) == EXPLOITATION_EVENT + + +@pytest.mark.parametrize( + "key, value", + [ + ("target", None), + ("success", "not-a-bool"), + ("exploiter_name", None), + ("error_message", None), + ], +) +def test_construct_invalid_field__type_error(key, value): + invalid_type_dict = EXPLOITATION_SIMPLE_DICT.copy() + invalid_type_dict[key] = value + + with pytest.raises(TypeError): + ExploitationEvent(**invalid_type_dict) + + +@pytest.mark.parametrize( + "key, value", + [ + ("target", "not-an-ip"), + ], +) +def test_construct_invalid_field__value_error(key, value): + invalid_type_dict = EXPLOITATION_SIMPLE_DICT.copy() + invalid_type_dict[key] = value + + with pytest.raises(ValueError): + ExploitationEvent(**invalid_type_dict) + + +def test_construct__extra_fields_forbidden(): + extra_field_dict = EXPLOITATION_SIMPLE_DICT.copy() + extra_field_dict["extra_field"] = 99 # red balloons + + with pytest.raises(ValueError): + ExploitationEvent(**extra_field_dict) diff --git a/vulture_allowlist.py b/vulture_allowlist.py index 45c700094..a844caddb 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -7,7 +7,7 @@ from common.agent_configuration.agent_sub_configurations import ( CustomPBAConfiguration, ScanTargetConfiguration, ) -from common.agent_events import PingScanEvent, PropagationEvent, TCPScanEvent +from common.agent_events import ExploitationEvent, PingScanEvent, PropagationEvent, TCPScanEvent from common.credentials import Credentials, LMHash, NTHash from common.types import NetworkPort from infection_monkey.exploit.log4shell_utils.ldap_server import LDAPServerFactory @@ -317,6 +317,7 @@ TCPScanEvent.port_status # TODO: Remove once #2269 is close PropagationEvent +ExploitationEvent # pydantic base models underscore_attrs_are_private