From 4268e387c4e2c965431c8d097d34cede0078c1d0 Mon Sep 17 00:00:00 2001 From: Charlie Crane Date: Wed, 26 Feb 2025 11:02:00 +0000 Subject: [PATCH 1/8] Add custom how-to guides to documentation, additional notebook around how to use dev cli --- docs/source/how_to_guides/custom_actions.rst | 50 ++ .../how_to_guides/custom_environment.rst | 26 + docs/source/how_to_guides/custom_rewards.rst | 46 ++ docs/source/how_to_guides/custom_software.rst | 78 +++ docs/source/how_to_guides/using_dev_cli.rst | 8 + .../How-To-Use-Primaite-Dev-Mode.ipynb | 488 ++++++++++++++++++ 6 files changed, 696 insertions(+) create mode 100644 docs/source/how_to_guides/custom_actions.rst create mode 100644 docs/source/how_to_guides/custom_environment.rst create mode 100644 docs/source/how_to_guides/custom_rewards.rst create mode 100644 docs/source/how_to_guides/custom_software.rst create mode 100644 docs/source/how_to_guides/using_dev_cli.rst create mode 100644 src/primaite/notebooks/How-To-Use-Primaite-Dev-Mode.ipynb diff --git a/docs/source/how_to_guides/custom_actions.rst b/docs/source/how_to_guides/custom_actions.rst new file mode 100644 index 00000000..bebabfdb --- /dev/null +++ b/docs/source/how_to_guides/custom_actions.rst @@ -0,0 +1,50 @@ +.. only:: comment + + © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK + +.. _custom_action: + +Creating Custom Actions in PrimAITE +*********************************** + +PrimAITE contains a selection of available actions that can be exercised within a training session, listed within ``actions.py``. `Note`: Agents are only able to perform the actions listed within it's action_map, defined within it's configuration YAML. See :ref:`custom_environment` for more information. + +Developing Custom Actions +============================ + +Actions within PrimAITE follow a default format, as seen below and in ``actions.py``. It's important that they have an identifier when declared, as this is used when creating the training environment. + +.. code:: Python + + class ExampleActionClass(AbstractAction, identifier="ExampleActions"): + """Example Action Class""" + + def __init__(self, manager: "ActionManager", num_nodes: int, num_folders: int, **kwargs) -> None: + super().__init(manager, num_nodes=num_nodes, num_folders=num_folders, **kwargs) + self.verb: str = "ExampleAction" + +Integration with PrimAITE ActionManager +========================================== + +Any custom actions should then be added to the `ActionManager` class, and the `act_class_identifiers` dictionary. This will map the action class to the corresponding action type string that would be passed through the PrimAITE `request_system`. + + +Interaction with the PrimAITE Request Manager +================================================ + +Where an action would cause a request to be sent through the PrimAITE RequestManager, a `form_request` method is expected to be defined within the Action Class. This should format the action into a format that can be ingested by the `RequestManager`. Examples of this include the `NodeFolderCreateAction`, which sends a formed request to create a folder on a given node (seen below). + +.. code:: Python + + def form_request(self, node_id: int, folder_name: str) -> RequestFormat: + """Return the action formatted as a request which can be ingested by the PrimAITE simulation.""" + node_name = self.manager.get_node_name_by_idx(node_id) + if node_name is None or folder_name is None: + return ["do_nothing"] + return ["network", "node", node_name, "file_system", "create", "folder", folder_name] + +Action Masking +============== + +Agents which use the `ProxyAgent` class within PrimAITE are able to use Action Masking. This allows the agent to know if the actions are valid/invalid based on the current environment. +Information on how to ensure this can be applied to your custom action can be found in :ref:`action_masking` diff --git a/docs/source/how_to_guides/custom_environment.rst b/docs/source/how_to_guides/custom_environment.rst new file mode 100644 index 00000000..8674d0fa --- /dev/null +++ b/docs/source/how_to_guides/custom_environment.rst @@ -0,0 +1,26 @@ +.. only:: comment + + © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK + +.. _custom_environment: + +Creating Custom Environments for PrimAITE +***************************************** + +PrimAITE generates it's training configuration/Environments through ingestion of YAML files. A detailed walkthrough of how to create your own environment can be found within the ``Creating-Custom-Environments`` jupyter notebook. + +You configuration file should follow the hierarchy seen below: + +.. code:: yaml + + io_settings: + ... + game: + ... + agents: + ... + simulation: + ... + + +For detailed information about each configuration item found within the configuration file, see :ref:`Configurable Items`. diff --git a/docs/source/how_to_guides/custom_rewards.rst b/docs/source/how_to_guides/custom_rewards.rst new file mode 100644 index 00000000..22b1de30 --- /dev/null +++ b/docs/source/how_to_guides/custom_rewards.rst @@ -0,0 +1,46 @@ +.. only:: comment + + © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK + +.. _custom_rewards: + +Creating Custom Rewards in PrimAITE +*********************************** + +Rewards within PrimAITE are contained within ``rewards.py``, which details the rewards available for all agents within training sessions, how they are calculated and any other specific information where necessary. + +Custom Rewards within PrimAITE should inherit from the ``AbstractReward`` class, found in ``rewards.py``. It's important to include an identifier for any class created within PrimAITE. + +.. code:: Python + + class ExampleAward(AbstractReward, identifier="ExampleAward"): + """Example Reward Class """ + + def calculate(self, state: Dict, last_action_response: "AgentHistoryItem") -> float: + """Calculate the reward for the current state.""" + return 1.0 + + @classmethod + def from_config(cls, config: dict) -> "AbstractReward": + """Create a reward function component from a config dictionary.""" + return cls() + + +Custom rewards that have been created should be added to the ``rew_class_identifiers`` dictionary within the ``RewardFunction`` class in ``rewards.py``. + +Including Custom Rewards within PrimAITE configuration +====================================================== + +Custom rewards can then be included within an agents configuration by it's inclusion within the training session configuration YAML. + +.. code:: yaml + + agents: + - ref: agent_name + reward_function: + reward_components: + - type: DUMMY + weight: 1.0 + + +More detailed information about rewards within PrimAITE can be found within :ref:`Rewards` diff --git a/docs/source/how_to_guides/custom_software.rst b/docs/source/how_to_guides/custom_software.rst new file mode 100644 index 00000000..d970755f --- /dev/null +++ b/docs/source/how_to_guides/custom_software.rst @@ -0,0 +1,78 @@ +.. only:: comment + + © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK + +Creating Custom Software for PrimAITE +************************************* + +This page aims to provide a how-to guide on how to create your own custom software for use within PrimAITE. + +PrimAITE has a base software class which should be inherited from when building custom software. Examples of this can be seen in the ``IOSoftware`` and ``Process`` classes. +It's important that any new software created within PrimAITE has the ``identifier`` attribute defined, for use when generating the environment. + +Some default attributes may need to be adjusted to align with the intended application of the custom software. + + +.. code:: Python + + from src.primaite.simulator.system.software import Software + + class CustomSoftware(Software, identifier="CustomSoftware"): + """ + An example of Custom Software within PrimAITE. + """ + + operating_state: OperatingState + "The current operating state of the Custom software" + + def describe_state(self) -> Dict: + """ + Produce a dictionary describing the current state of this object. + + :return: Current state of this object and child objects. + :rtype: Dict + """ + state = super().describe_state() + state.update({"operating_state": self.operating_state.value}) + +Default Install +############### + +Software can be set to auto-install onto a Node by adding it to the ``SYSTEM_SOFTWARE`` dictionary for the node. An example can be seen in the ``HostNode`` class, which pre-installs some key software that is expected on Nodes, such as the ``NTPClient`` and ``UserManager``. + +Requirements +############ + +Any custom software will need to provide an implementation of the ``describe_state`` method, and conform to the general Pydantic requirements. +It's a good idea, if possible, to also create a ``.show()`` method, as this can be used for visualising the software's status when developing within PrimAITE. + +Interaction with the PrimAITE Request System +############################################ + +If the software is intended to be used by an agent via a :ref:`custom_action`, then it will likely need an implementation of the ``RequestManager``. +Detailed information about the PrimAITE request system can be seen in :ref:`request_system`. An example implementation, derived from the `Application` class is seen below: + +.. code:: Python + + def _init_request_manager(self) -> RequestManager: + """ + Initialise the request manager. + + More information in user guide and docstring for SimComponent._init_request_manager. + """ + _is_application_running = Application._StateValidator(application=self, state=ApplicationOperatingState.RUNNING) + + rm = super()._init_request_manager() + rm.add_request( + "scan", + RequestType( + func=lambda request, context: RequestResponse.from_bool(self.scan()), validator=_is_application_running + ), + ) + return rm + + +Further information +################### + +For more detailed information about the implementation of software within PrimAITE, see :ref:`software`. diff --git a/docs/source/how_to_guides/using_dev_cli.rst b/docs/source/how_to_guides/using_dev_cli.rst new file mode 100644 index 00000000..139e8b58 --- /dev/null +++ b/docs/source/how_to_guides/using_dev_cli.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK + +Utilising the PrimAITE dev-mode cli +*********************************** + +A guide for utilising `primaite dev-mode` can be found within the ``How-To-Use-Primaite-Dev-Mode`` jupyter notebook, and also :ref:`Developer Tools`. diff --git a/src/primaite/notebooks/How-To-Use-Primaite-Dev-Mode.ipynb b/src/primaite/notebooks/How-To-Use-Primaite-Dev-Mode.ipynb new file mode 100644 index 00000000..3bb242d9 --- /dev/null +++ b/src/primaite/notebooks/How-To-Use-Primaite-Dev-Mode.ipynb @@ -0,0 +1,488 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PrimAITE Developer mode\n", + "\n", + "PrimAITE has built in developer tools.\n", + "\n", + "The dev-mode is designed to help make the development of PrimAITE easier.\n", + "\n", + "`NOTE: For the purposes of the notebook, the commands are preceeded by \"!\". When running the commands, run it without the \"!\".`\n", + "\n", + "To display the available dev-mode options, run the command below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode --help" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Save the current PRIMAITE_CONFIG to restore after the notebook runs\n", + "\n", + "from primaite import PRIMAITE_CONFIG\n", + "\n", + "temp_config = PRIMAITE_CONFIG.copy()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dev mode options" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### enable\n", + "\n", + "Enables the dev mode for PrimAITE.\n", + "\n", + "This will enable the developer mode for PrimAITE.\n", + "\n", + "By default, when developer mode is enabled, session logs will be generated in the PRIMAITE_ROOT/sessions folder unless configured to be generated in another location." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode enable" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### disable\n", + "\n", + "Disables the dev mode for PrimAITE.\n", + "\n", + "This will disable the developer mode for PrimAITE." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode disable" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### show\n", + "\n", + "Shows if PrimAITE is running in dev mode or production mode.\n", + "\n", + "The command will also show the developer mode configuration." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode show" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### config\n", + "\n", + "Configure the PrimAITE developer mode" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --help" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### path\n", + "\n", + "Set the path where generated session files will be output.\n", + "\n", + "By default, this value will be in PRIMAITE_ROOT/sessions.\n", + "\n", + "To reset the path to default, run:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config path -root\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config path --default" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### --sys-log-level or -slevel\n", + "\n", + "Set the system log level.\n", + "\n", + "This will override the system log level in configurations and will make PrimAITE include the set log level and above.\n", + "\n", + "Available options are:\n", + "- `DEBUG`\n", + "- `INFO`\n", + "- `WARNING`\n", + "- `ERROR`\n", + "- `CRITICAL`\n", + "\n", + "Default value is `DEBUG`\n", + "\n", + "Example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --sys-log-level DEBUG\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -slevel DEBUG" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### --agent-log-level or -alevel\n", + "\n", + "Set the agent log level.\n", + "\n", + "This will override the agent log level in configurations and will make PrimAITE include the set log level and above.\n", + "\n", + "Available options are:\n", + "- `DEBUG`\n", + "- `INFO`\n", + "- `WARNING`\n", + "- `ERROR`\n", + "- `CRITICAL`\n", + "\n", + "Default value is `DEBUG`\n", + "\n", + "Example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --agent-log-level DEBUG\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -alevel DEBUG" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### --output-sys-logs or -sys\n", + "\n", + "If enabled, developer mode will output system logs.\n", + "\n", + "Example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --output-sys-logs\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -sys" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To disable outputting sys logs:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --no-sys-logs\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -nsys" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### --output-agent-logs or -agent\n", + "\n", + "If enabled, developer mode will output agent action logs.\n", + "\n", + "Example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --output-agent-logs\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -agent" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To disable outputting agent action logs:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --no-agent-logs\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -nagent" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### --output-pcap-logs or -pcap\n", + "\n", + "If enabled, developer mode will output PCAP logs.\n", + "\n", + "Example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --output-pcap-logs\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -pcap" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To disable outputting PCAP logs:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --no-pcap-logs\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -npcap" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### --output-to-terminal or -t\n", + "\n", + "If enabled, developer mode will output logs to the terminal.\n", + "\n", + "Example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --output-to-terminal\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -t" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To disable terminal outputs:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config --no-terminal\n", + "\n", + "# or\n", + "\n", + "!primaite dev-mode config -nt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Combining commands\n", + "\n", + "It is possible to combine commands to set the configuration.\n", + "\n", + "This saves having to enter multiple commands and allows for a much more efficient setting of PrimAITE developer mode configurations." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Example of setting system log level and enabling the system logging:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config -slevel WARNING -sys" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another example where the system log and agent action log levels are set and enabled and should be printed to terminal:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!primaite dev-mode config -slevel ERROR -sys -alevel ERROR -agent -t" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Restore PRIMAITE_CONFIG\n", + "from primaite.utils.cli.primaite_config_utils import update_primaite_application_config\n", + "\n", + "\n", + "global PRIMAITE_CONFIG\n", + "PRIMAITE_CONFIG[\"developer_mode\"] = temp_config[\"developer_mode\"]\n", + "update_primaite_application_config(config=PRIMAITE_CONFIG)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 0d93981ef837573d22d50a7cbddaf5233d47e0fe Mon Sep 17 00:00:00 2001 From: Charlie Crane Date: Wed, 26 Feb 2025 12:03:00 +0000 Subject: [PATCH 2/8] Updates to documentation pages --- docs/source/how_to_guides/custom_actions.rst | 18 ++++++++++++------ ...environment.rst => custom_environments.rst} | 7 ++++++- docs/source/how_to_guides/custom_software.rst | 4 +++- .../how_to_guides/extensible_actions.rst | 2 ++ .../source/how_to_guides/extensible_agents.rst | 2 +- docs/source/how_to_guides/extensible_nodes.rst | 2 +- .../how_to_guides/extensible_rewards.rst | 2 +- ...Command-and-Control-E2E-Demonstration.ipynb | 2 +- 8 files changed, 27 insertions(+), 12 deletions(-) rename docs/source/how_to_guides/{custom_environment.rst => custom_environments.rst} (68%) diff --git a/docs/source/how_to_guides/custom_actions.rst b/docs/source/how_to_guides/custom_actions.rst index bebabfdb..ae865b3d 100644 --- a/docs/source/how_to_guides/custom_actions.rst +++ b/docs/source/how_to_guides/custom_actions.rst @@ -2,7 +2,7 @@ © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -.. _custom_action: +.. _custom_actions: Creating Custom Actions in PrimAITE *********************************** @@ -19,18 +19,24 @@ Actions within PrimAITE follow a default format, as seen below and in ``actions. class ExampleActionClass(AbstractAction, identifier="ExampleActions"): """Example Action Class""" - def __init__(self, manager: "ActionManager", num_nodes: int, num_folders: int, **kwargs) -> None: - super().__init(manager, num_nodes=num_nodes, num_folders=num_folders, **kwargs) - self.verb: str = "ExampleAction" + config: ExampleAction.ConfigSchema(AbstractAction.ConfigSchema) + + class ConfigSchema(AbstractAction.ConfigSchema) + + node_name: str + + @classmethod + def form_request(cls, config: ConfigSchema) -> RequestFormat: + return [config.node_name, "example_action"] Integration with PrimAITE ActionManager -========================================== +======================================= Any custom actions should then be added to the `ActionManager` class, and the `act_class_identifiers` dictionary. This will map the action class to the corresponding action type string that would be passed through the PrimAITE `request_system`. Interaction with the PrimAITE Request Manager -================================================ +============================================== Where an action would cause a request to be sent through the PrimAITE RequestManager, a `form_request` method is expected to be defined within the Action Class. This should format the action into a format that can be ingested by the `RequestManager`. Examples of this include the `NodeFolderCreateAction`, which sends a formed request to create a folder on a given node (seen below). diff --git a/docs/source/how_to_guides/custom_environment.rst b/docs/source/how_to_guides/custom_environments.rst similarity index 68% rename from docs/source/how_to_guides/custom_environment.rst rename to docs/source/how_to_guides/custom_environments.rst index 8674d0fa..928fc101 100644 --- a/docs/source/how_to_guides/custom_environment.rst +++ b/docs/source/how_to_guides/custom_environments.rst @@ -2,7 +2,7 @@ © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -.. _custom_environment: +.. _custom_environments: Creating Custom Environments for PrimAITE ***************************************** @@ -13,6 +13,9 @@ You configuration file should follow the hierarchy seen below: .. code:: yaml + metadata: + version: 4.0 + io_settings: ... game: @@ -22,5 +25,7 @@ You configuration file should follow the hierarchy seen below: simulation: ... +It's important to include the metadata tag within your YAML file, as this is used to ensure PrimAITE can interpret the configuration correctly. This should also include any plugins that are required for the defined environment, along with their respective version. For detailed information about each configuration item found within the configuration file, see :ref:`Configurable Items`. + diff --git a/docs/source/how_to_guides/custom_software.rst b/docs/source/how_to_guides/custom_software.rst index d970755f..fa0671d7 100644 --- a/docs/source/how_to_guides/custom_software.rst +++ b/docs/source/how_to_guides/custom_software.rst @@ -2,6 +2,8 @@ © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +.. _custom_software: + Creating Custom Software for PrimAITE ************************************* @@ -10,7 +12,7 @@ This page aims to provide a how-to guide on how to create your own custom softwa PrimAITE has a base software class which should be inherited from when building custom software. Examples of this can be seen in the ``IOSoftware`` and ``Process`` classes. It's important that any new software created within PrimAITE has the ``identifier`` attribute defined, for use when generating the environment. -Some default attributes may need to be adjusted to align with the intended application of the custom software. +Some default attributes may need to be adjusted to align with the intended application of the custom software. .. code:: Python diff --git a/docs/source/how_to_guides/extensible_actions.rst b/docs/source/how_to_guides/extensible_actions.rst index c2cc07bf..4a7ed35c 100644 --- a/docs/source/how_to_guides/extensible_actions.rst +++ b/docs/source/how_to_guides/extensible_actions.rst @@ -2,6 +2,7 @@ © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK +.. _extensible_actions: Extensible Actions ****************** @@ -48,6 +49,7 @@ When declaring a custom class, it must have a unique discriminator string, that node_name: str directory_name: str + @classmethod def form_request(cls, config: ConfigSchema) -> RequestFormat: return ["network", "node", diff --git a/docs/source/how_to_guides/extensible_agents.rst b/docs/source/how_to_guides/extensible_agents.rst index 1d765417..5225e63c 100644 --- a/docs/source/how_to_guides/extensible_agents.rst +++ b/docs/source/how_to_guides/extensible_agents.rst @@ -2,7 +2,7 @@ © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -.. _about: +.. _extensible_agents: Extensible Agents ***************** diff --git a/docs/source/how_to_guides/extensible_nodes.rst b/docs/source/how_to_guides/extensible_nodes.rst index 4819cbb2..9219ca31 100644 --- a/docs/source/how_to_guides/extensible_nodes.rst +++ b/docs/source/how_to_guides/extensible_nodes.rst @@ -2,7 +2,7 @@ © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -.. _about: +.. _extensible_nodes: Extensible Nodes diff --git a/docs/source/how_to_guides/extensible_rewards.rst b/docs/source/how_to_guides/extensible_rewards.rst index d3053a49..34a2f4fe 100644 --- a/docs/source/how_to_guides/extensible_rewards.rst +++ b/docs/source/how_to_guides/extensible_rewards.rst @@ -2,7 +2,7 @@ © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK -.. _about: +.. _extensible_rewards: Extensible Rewards ****************** diff --git a/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb b/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb index f187c8d5..7e64c3c5 100644 --- a/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb +++ b/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb @@ -1688,7 +1688,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.11" } }, "nbformat": 4, From 7fe4915f4280c4431ac83dcc1255fe6fb8707174 Mon Sep 17 00:00:00 2001 From: Charlie Crane Date: Wed, 26 Feb 2025 15:31:03 +0000 Subject: [PATCH 3/8] Revisions to make the how-to guides show in navigation pane --- .pre-commit-config.yaml | 12 +- docs/index.rst | 12 + docs/source/how_to.rst | 10 + docs/source/how_to_guides/custom_actions.rst | 12 +- .../how_to_guides/custom_environments.rst | 6 +- docs/source/how_to_guides/custom_software.rst | 2 +- .../how_to_guides/extensible_actions.rst | 3 +- ...ommand-and-Control-E2E-Demonstration.ipynb | 1780 +++++++++++++++-- ...ege-Escalation-and-Data-Loss-Example.ipynb | 407 +++- 9 files changed, 2045 insertions(+), 199 deletions(-) create mode 100644 docs/source/how_to.rst diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d004dd6c..4100f8b2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,10 @@ repos: - # - repo: local - # hooks: - # - id: ensure-copyright-clause - # name: ensure copyright clause - # entry: python copyright_clause_pre_commit_hook.py - # language: python + - repo: local + hooks: + - id: ensure-copyright-clause + name: ensure copyright clause + entry: python copyright_clause_pre_commit_hook.py + language: python - repo: http://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: diff --git a/docs/index.rst b/docs/index.rst index aa7d16e0..53d2e1b3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,6 +17,18 @@ What is PrimAITE? source/dependencies source/glossary +.. toctree:: + :maxdepth: 8 + :caption: How To + :hidden: + + source/how_to + source/how_to_guides/custom_actions + source/how_to_guides/custom_environments + source/how_to_guides/custom_rewards + source/how_to_guides/custom_software + source/how_to_guides/using_dev_cli + .. toctree:: :caption: Usage: :hidden: diff --git a/docs/source/how_to.rst b/docs/source/how_to.rst new file mode 100644 index 00000000..e6ea0d10 --- /dev/null +++ b/docs/source/how_to.rst @@ -0,0 +1,10 @@ +.. only:: comment + + © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK + +How-To Guides +============= + +These how-to guides aim to provide a starting point for development within PrimAITE, creating your own custom components and environments for use when training agents. More detailed information for each section can be found within the documentation. + +There are also some additional notebooks which provide a walkthrough of established content. It's encouraged to reference these when developing for PrimAITE. diff --git a/docs/source/how_to_guides/custom_actions.rst b/docs/source/how_to_guides/custom_actions.rst index ae865b3d..4b51e76a 100644 --- a/docs/source/how_to_guides/custom_actions.rst +++ b/docs/source/how_to_guides/custom_actions.rst @@ -7,13 +7,15 @@ Creating Custom Actions in PrimAITE *********************************** -PrimAITE contains a selection of available actions that can be exercised within a training session, listed within ``actions.py``. `Note`: Agents are only able to perform the actions listed within it's action_map, defined within it's configuration YAML. See :ref:`custom_environment` for more information. +PrimAITE contains a selection of possible actions that can be exercised within a training environment. Actions provided as a part of PrimAITE can be seen within `src/primaite/game/agent/actions`. `Note`: Agents are only able to perform the actions listed within it's action_map, defined within it's configuration YAML. See :ref:`custom_environment` for more information. Developing Custom Actions -============================ +========================= Actions within PrimAITE follow a default format, as seen below and in ``actions.py``. It's important that they have an identifier when declared, as this is used when creating the training environment. +An example of a custom action is seen below, with key information about what is required for new actions in :ref:`extensible_actions`. + .. code:: Python class ExampleActionClass(AbstractAction, identifier="ExampleActions"): @@ -24,7 +26,7 @@ Actions within PrimAITE follow a default format, as seen below and in ``actions. class ConfigSchema(AbstractAction.ConfigSchema) node_name: str - + @classmethod def form_request(cls, config: ConfigSchema) -> RequestFormat: return [config.node_name, "example_action"] @@ -36,9 +38,9 @@ Any custom actions should then be added to the `ActionManager` class, and the `a Interaction with the PrimAITE Request Manager -============================================== +============================================= -Where an action would cause a request to be sent through the PrimAITE RequestManager, a `form_request` method is expected to be defined within the Action Class. This should format the action into a format that can be ingested by the `RequestManager`. Examples of this include the `NodeFolderCreateAction`, which sends a formed request to create a folder on a given node (seen below). +Where an action would cause a request to be sent through the PrimAITE RequestManager, a `form_request` method is expected to be defined within the Action Class. This should format the action into a format that can be ingested by the `RequestManager`. Examples of this include the `NodeFolderCreateAction`, which sends a formed request to create a folder on a given node (seen below): .. code:: Python diff --git a/docs/source/how_to_guides/custom_environments.rst b/docs/source/how_to_guides/custom_environments.rst index 928fc101..23c70d85 100644 --- a/docs/source/how_to_guides/custom_environments.rst +++ b/docs/source/how_to_guides/custom_environments.rst @@ -25,7 +25,9 @@ You configuration file should follow the hierarchy seen below: simulation: ... +MetaData Tag +============ + It's important to include the metadata tag within your YAML file, as this is used to ensure PrimAITE can interpret the configuration correctly. This should also include any plugins that are required for the defined environment, along with their respective version. -For detailed information about each configuration item found within the configuration file, see :ref:`Configurable Items`. - +For detailed information about the remaining configuration items found within the configuration file, see :ref:`Configurable Items`. diff --git a/docs/source/how_to_guides/custom_software.rst b/docs/source/how_to_guides/custom_software.rst index fa0671d7..e10bcf1f 100644 --- a/docs/source/how_to_guides/custom_software.rst +++ b/docs/source/how_to_guides/custom_software.rst @@ -12,7 +12,7 @@ This page aims to provide a how-to guide on how to create your own custom softwa PrimAITE has a base software class which should be inherited from when building custom software. Examples of this can be seen in the ``IOSoftware`` and ``Process`` classes. It's important that any new software created within PrimAITE has the ``identifier`` attribute defined, for use when generating the environment. -Some default attributes may need to be adjusted to align with the intended application of the custom software. +Some default attributes may need to be adjusted to align with the intended application of the custom software. .. code:: Python diff --git a/docs/source/how_to_guides/extensible_actions.rst b/docs/source/how_to_guides/extensible_actions.rst index 4a7ed35c..fe61949b 100644 --- a/docs/source/how_to_guides/extensible_actions.rst +++ b/docs/source/how_to_guides/extensible_actions.rst @@ -7,7 +7,6 @@ Extensible Actions ****************** - Changes to Actions class Structure. =================================== @@ -33,7 +32,7 @@ The ConfigSchema sub-class of the action must contain all `configurable` variabl Unique discriminator -################# +#################### When declaring a custom class, it must have a unique discriminator string, that allows PrimAITE to generate the correct action when needed. diff --git a/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb b/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb index 7e64c3c5..9f4923df 100644 --- a/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb +++ b/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb @@ -13,9 +13,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:23,996: Performing the PrimAITE first-time setup...\n", + "2025-02-26 12:09:23,996: Building the PrimAITE app directories...\n", + "2025-02-26 12:09:23,996: Building primaite_config.yaml...\n", + "2025-02-26 12:09:23,996: Rebuilding the demo notebooks...\n", + "2025-02-26 12:09:24,029: Rebuilding the example notebooks...\n", + "2025-02-26 12:09:24,029: PrimAITE setup complete!\n" + ] + } + ], "source": [ "!primaite setup" ] @@ -36,7 +49,8 @@ "from primaite.simulator.system.applications.red_applications.c2.abstract_c2 import C2Command\n", "from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript\n", "from primaite.simulator.network.hardware.nodes.host.computer import Computer\n", - "from primaite.simulator.network.hardware.nodes.host.server import Server" + "from primaite.simulator.network.hardware.nodes.host.server import Server\n", + "from primaite.game.agent.interface import ProxyAgent" ] }, { @@ -52,7 +66,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -138,9 +152,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:31,270: PrimaiteGymEnv RNG seed = None\n" + ] + } + ], "source": [ "with open(data_manipulation_config_path()) as f:\n", " cfg = yaml.safe_load(f)\n", @@ -166,9 +188,35 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------------+\n", + "| client_1 Software Manager |\n", + "+-----------------------+-------------+-----------------+--------------+------+----------+\n", + "| Name | Type | Operating State | Health State | Port | Protocol |\n", + "+-----------------------+-------------+-----------------+--------------+------+----------+\n", + "| arp | Service | RUNNING | GOOD | 219 | udp |\n", + "| icmp | Service | RUNNING | GOOD | None | icmp |\n", + "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", + "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", + "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", + "| nmap | Application | RUNNING | GOOD | None | none |\n", + "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", + "| user-manager | Service | RUNNING | GOOD | None | none |\n", + "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", + "| ftp-client | Service | RUNNING | GOOD | 21 | tcp |\n", + "| data-manipulation-bot | Application | RUNNING | GOOD | None | none |\n", + "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", + "| c2-server | Application | RUNNING | GOOD | None | tcp |\n", + "+-----------------------+-------------+-----------------+--------------+------+----------+\n" + ] + } + ], "source": [ "client_1: Computer = env.game.simulation.network.get_node_by_hostname(\"client_1\")\n", "client_1.software_manager.install(C2Server)\n", @@ -218,9 +266,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------------------------------------------------------------------+\n", + "| web_server Software Manager |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| Name | Type | Operating State | Health State | Port | Protocol |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| arp | Service | RUNNING | GOOD | 219 | udp |\n", + "| icmp | Service | RUNNING | GOOD | None | icmp |\n", + "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", + "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", + "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", + "| nmap | Application | RUNNING | GOOD | None | none |\n", + "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", + "| user-manager | Service | RUNNING | GOOD | None | none |\n", + "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", + "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", + "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", + "| c2-beacon | Application | INSTALLING | GOOD | None | tcp |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n" + ] + } + ], "source": [ "env.step(1)\n", "web_server: Computer = env.game.simulation.network.get_node_by_hostname(\"web_server\")\n", @@ -255,9 +328,41 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------------------------------------------------------------------+\n", + "| web_server Software Manager |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| Name | Type | Operating State | Health State | Port | Protocol |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| arp | Service | RUNNING | GOOD | 219 | udp |\n", + "| icmp | Service | RUNNING | GOOD | None | icmp |\n", + "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", + "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", + "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", + "| nmap | Application | RUNNING | GOOD | None | none |\n", + "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", + "| user-manager | Service | RUNNING | GOOD | None | none |\n", + "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", + "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", + "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", + "| c2-beacon | Application | RUNNING | GOOD | None | tcp |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", + "| c2-beacon Running Status |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| False | 192.168.10.21 | 0 | 5 | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n" + ] + } + ], "source": [ "env.step(2)\n", "c2_beacon: C2Beacon = web_server.software_manager.software[\"c2-beacon\"]\n", @@ -288,18 +393,54 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "(0,\n", + " 0.0,\n", + " False,\n", + " False,\n", + " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=2, action='node-application-execute', parameters={'node_name': 'web_server', 'application_name': 'c2-beacon'}, request=['network', 'node', 'web_server', 'application', 'c2-beacon', 'execute'], response=RequestResponse(status='success', data={}), reward=0.0, reward_info={})}})" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "env.step(3)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", + "| c2-beacon Running Status |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| True | 192.168.10.21 | 1 | 5 | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "+-----------------------------------------------------------------------------------------------------+\n", + "| c2-server Running Status |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n", + "| True | 192.168.1.12 | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n" + ] + } + ], "source": [ "c2_beacon.show()\n", "c2_server.show()" @@ -354,18 +495,59 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "(0,\n", + " 0.0,\n", + " False,\n", + " False,\n", + " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=3, action='c2-server-terminal-command', parameters={'node_name': 'client_1', 'ip_address': None, 'username': 'admin', 'password': 'admin', 'commands': [['software_manager', 'application', 'install', 'ransomware-script']]}, request=['network', 'node', 'client_1', 'application', 'c2-server', 'terminal_command', {'commands': [['software_manager', 'application', 'install', 'ransomware-script']], 'ip_address': None, 'username': 'admin', 'password': 'admin'}], response=RequestResponse(status='success', data={0: RequestResponse(status='success', data={})}), reward=0.0, reward_info={})}})" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "env.step(4)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------------+\n", + "| client_1 Software Manager |\n", + "+-----------------------+-------------+-----------------+--------------+------+----------+\n", + "| Name | Type | Operating State | Health State | Port | Protocol |\n", + "+-----------------------+-------------+-----------------+--------------+------+----------+\n", + "| arp | Service | RUNNING | GOOD | 219 | udp |\n", + "| icmp | Service | RUNNING | GOOD | None | icmp |\n", + "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", + "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", + "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", + "| nmap | Application | RUNNING | GOOD | None | none |\n", + "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", + "| user-manager | Service | RUNNING | GOOD | None | none |\n", + "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", + "| ftp-client | Service | RUNNING | GOOD | 21 | tcp |\n", + "| data-manipulation-bot | Application | RUNNING | GOOD | None | none |\n", + "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", + "| c2-server | Application | RUNNING | GOOD | None | tcp |\n", + "+-----------------------+-------------+-----------------+--------------+------+----------+\n" + ] + } + ], "source": [ "client_1.software_manager.show()" ] @@ -396,18 +578,66 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "(0,\n", + " 0.0,\n", + " False,\n", + " False,\n", + " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=4, action='c2-server-ransomware-configure', parameters={'node_name': 'client_1', 'server_ip_address': '192.168.1.14', 'payload': 'ENCRYPT'}, request=['network', 'node', 'client_1', 'application', 'c2-server', 'ransomware_configure', {'server_ip_address': '192.168.1.14', 'server_password': None, 'payload': 'ENCRYPT'}], response=RequestResponse(status='success', data={}), reward=0.0, reward_info={})}})" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "env.step(5)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------------------------------------------------------------------+\n", + "| web_server Software Manager |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| Name | Type | Operating State | Health State | Port | Protocol |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| arp | Service | RUNNING | GOOD | 219 | udp |\n", + "| icmp | Service | RUNNING | GOOD | None | icmp |\n", + "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", + "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", + "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", + "| nmap | Application | RUNNING | GOOD | None | none |\n", + "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", + "| user-manager | Service | RUNNING | GOOD | None | none |\n", + "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", + "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", + "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", + "| c2-beacon | Application | RUNNING | GOOD | None | tcp |\n", + "| ransomware-script | Application | RUNNING | GOOD | None | none |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "+------------------------------------+\n", + "| ransomware-script Running Status |\n", + "+--------------------------+---------+\n", + "| Target Server IP Address | Payload |\n", + "+--------------------------+---------+\n", + "| 192.168.1.14 | ENCRYPT |\n", + "+--------------------------+---------+\n" + ] + } + ], "source": [ "ransomware_script: RansomwareScript = web_server.software_manager.software[\"ransomware-script\"]\n", "web_server.software_manager.show()\n", @@ -445,18 +675,48 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "(0,\n", + " 0.0,\n", + " False,\n", + " False,\n", + " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=5, action='c2-server-data-exfiltrate', parameters={'node_name': 'client_1', 'target_file_name': 'database.db', 'target_folder_name': 'database', 'exfiltration_folder_name': 'spoils', 'target_ip_address': '192.168.1.14', 'username': 'admin', 'password': 'admin'}, request=['network', 'node', 'client_1', 'application', 'c2-server', 'exfiltrate', {'target_file_name': 'database.db', 'target_folder_name': 'database', 'exfiltration_folder_name': 'spoils', 'target_ip_address': '192.168.1.14', 'username': 'admin', 'password': 'admin'}], response=RequestResponse(status='success', data={}), reward=0.0, reward_info={})}})" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "env.step(6)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------------------------+\n", + "| client_1 File System |\n", + "+--------------------+---------+---------------+-----------------------+---------+\n", + "| File Path | Size | Health status | Visible health status | Deleted |\n", + "+--------------------+---------+---------------+-----------------------+---------+\n", + "| root | 0 B | GOOD | NONE | False |\n", + "| spoils/database.db | 4.77 MB | GOOD | NONE | False |\n", + "+--------------------+---------+---------------+-----------------------+---------+\n" + ] + } + ], "source": [ "client_1: Computer = env.game.simulation.network.get_node_by_hostname(\"client_1\")\n", "client_1.software_manager.file_system.show(full=True)" @@ -464,9 +724,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------------------------------------------------------------+\n", + "| web_server File System |\n", + "+---------------------+---------+---------------+-----------------------+---------+\n", + "| File Path | Size | Health status | Visible health status | Deleted |\n", + "+---------------------+---------+---------------+-----------------------+---------+\n", + "| primaite/index.html | 15.0 KB | GOOD | NONE | False |\n", + "| root | 0 B | GOOD | NONE | False |\n", + "| spoils/database.db | 4.77 MB | GOOD | NONE | False |\n", + "+---------------------+---------+---------------+-----------------------+---------+\n" + ] + } + ], "source": [ "web_server: Computer = env.game.simulation.network.get_node_by_hostname(\"web_server\")\n", "web_server.software_manager.file_system.show(full=True)" @@ -496,18 +772,48 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "(0,\n", + " 0.0,\n", + " False,\n", + " False,\n", + " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=6, action='c2-server-ransomware-launch', parameters={'node_name': 'client_1'}, request=['network', 'node', 'client_1', 'application', 'c2-server', 'ransomware_launch'], response=RequestResponse(status='success', data={}), reward=0.0, reward_info={})}})" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "env.step(7)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------+\n", + "| database_server File System |\n", + "+----------------------+---------+---------------+-----------------------+---------+\n", + "| File Path | Size | Health status | Visible health status | Deleted |\n", + "+----------------------+---------+---------------+-----------------------+---------+\n", + "| database/database.db | 4.77 MB | CORRUPT | NONE | False |\n", + "| root | 0 B | GOOD | NONE | False |\n", + "+----------------------+---------+---------------+-----------------------+---------+\n" + ] + } + ], "source": [ "database_server: Server = env.game.simulation.network.get_node_by_hostname(\"database_server\")\n", "database_server.software_manager.file_system.show(full=True)" @@ -526,7 +832,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -654,9 +960,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:32,087: PrimaiteGymEnv RNG seed = None\n" + ] + } + ], "source": [ "with open(data_manipulation_config_path()) as f:\n", " cfg = yaml.safe_load(f)\n", @@ -670,7 +984,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -713,9 +1027,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:32,894: Resetting environment, episode 0, avg. reward: 0.0\n", + "2025-02-26 12:09:32,898: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_0.json\n" + ] + } + ], "source": [ "# Resetting the environment and capturing the default observation space.\n", "blue_env.reset()\n", @@ -724,9 +1047,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Setting up the C2 Suite via the simulation API.\n", "\n", @@ -747,7 +1081,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -757,9 +1091,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 2\n", + "root['nodes']['HOST0']['APPLICATIONS'][1]['operating_status']: 0 -> 1\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", + "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", + "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" + ] + } + ], "source": [ "display_obs_diffs(default_obs, c2_configuration_obs, blue_env.game.step_counter)" ] @@ -779,9 +1130,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={0: RequestResponse(status='success', data={})})" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Installing RansomwareScript via C2 Terminal Commands\n", "ransomware_install_command = {\"commands\":[[\"software_manager\", \"application\", \"install\", \"ransomware-script\"]],\n", @@ -792,9 +1154,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={})" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Configuring the RansomwareScript\n", "ransomware_config = {\"server_ip_address\": \"192.168.1.14\", \"payload\": \"ENCRYPT\"}\n", @@ -803,7 +1176,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ @@ -813,9 +1186,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 7\n", + "root['nodes']['HOST0']['APPLICATIONS'][1]['operating_status']: 0 -> 1\n", + "root['nodes']['HOST0']['APPLICATIONS'][2]['operating_status']: 0 -> 3\n", + "root['nodes']['HOST0']['users']['local_login']: 0 -> 1\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", + "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", + "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" + ] + } + ], "source": [ "display_obs_diffs(default_obs, c2_ransomware_obs, env.game.step_counter)" ] @@ -831,7 +1223,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "metadata": {}, "outputs": [], "source": [ @@ -847,16 +1239,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={})" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "c2_server.send_command(given_command=C2Command.DATA_EXFILTRATION, command_options=exfil_options)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": {}, "outputs": [], "source": [ @@ -865,9 +1268,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 7\n", + "root['nodes']['HOST0']['APPLICATIONS'][2]['operating_status']: 3 -> 1\n", + "root['nodes']['HOST1']['users']['remote_sessions']: 0 -> 1\n" + ] + } + ], "source": [ "display_obs_diffs(c2_ransomware_obs, c2_exfil_obs, env.game.step_counter)" ] @@ -883,9 +1299,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={})" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Configuring the RansomwareScript\n", "ransomware_config = {\"server_ip_address\": \"192.168.1.14\", \"payload\": \"ENCRYPT\"}\n", @@ -894,9 +1321,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={})" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Waiting for the ransomware to finish installing and then launching the RansomwareScript.\n", "blue_env.step(0)\n", @@ -905,7 +1343,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "metadata": {}, "outputs": [], "source": [ @@ -915,9 +1353,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 6\n", + "root['nodes']['HOST0']['APPLICATIONS'][2]['operating_status']: 3 -> 1\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['nodes']['HOST1']['users']['remote_sessions']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" + ] + } + ], "source": [ "display_obs_diffs(c2_ransomware_obs, c2_final_obs, blue_env.game.step_counter)" ] @@ -933,7 +1392,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 38, "metadata": {}, "outputs": [], "source": [ @@ -965,16 +1424,200 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 39, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:33,561: Resetting environment, episode 1, avg. reward: 0.0\n", + "2025-02-26 12:09:33,561: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_1.json\n" + ] + }, + { + "data": { + "text/plain": [ + "({'nodes': {'HOST0': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 1,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'HOST1': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 1,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'HOST2': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 0,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'HOST3': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 0,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'ROUTER0': {'ACL': {1: {'position': 0,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 2: {'position': 1,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 3: {'position': 2,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 4: {'position': 3,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 5: {'position': 4,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 6: {'position': 5,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 7: {'position': 6,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 8: {'position': 7,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 9: {'position': 8,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 10: {'position': 9,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0}},\n", + " 'PORTS': {1: {'operating_status': 1},\n", + " 2: {'operating_status': 1},\n", + " 3: {'operating_status': 2}},\n", + " 'users': {'local_login': 0, 'remote_sessions': 0}}},\n", + " 'LINKS': {1: {'PROTOCOLS': {'ALL': 1}},\n", + " 2: {'PROTOCOLS': {'ALL': 1}},\n", + " 3: {'PROTOCOLS': {'ALL': 0}},\n", + " 4: {'PROTOCOLS': {'ALL': 1}},\n", + " 5: {'PROTOCOLS': {'ALL': 1}},\n", + " 6: {'PROTOCOLS': {'ALL': 1}},\n", + " 7: {'PROTOCOLS': {'ALL': 1}},\n", + " 8: {'PROTOCOLS': {'ALL': 1}},\n", + " 9: {'PROTOCOLS': {'ALL': 1}},\n", + " 10: {'PROTOCOLS': {'ALL': 0}}},\n", + " 'ICS': 0},\n", + " {})" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "blue_env.reset()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 40, "metadata": {}, "outputs": [], "source": [ @@ -993,7 +1636,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 41, "metadata": {}, "outputs": [], "source": [ @@ -1010,9 +1653,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 42, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------------------------------------------------------------------+\n", + "| web_server Software Manager |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| Name | Type | Operating State | Health State | Port | Protocol |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| arp | Service | RUNNING | GOOD | 219 | udp |\n", + "| icmp | Service | RUNNING | GOOD | None | icmp |\n", + "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", + "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", + "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", + "| nmap | Application | RUNNING | GOOD | None | none |\n", + "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", + "| user-manager | Service | RUNNING | GOOD | None | none |\n", + "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", + "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", + "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n" + ] + } + ], "source": [ "blue_env.step(0)\n", "web_server.software_manager.show()" @@ -1020,9 +1687,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 43, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 3\n", + "root['nodes']['HOST0']['APPLICATIONS'][1]['operating_status']: 1 -> 0\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", + "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", + "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" + ] + } + ], "source": [ "display_obs_diffs(pre_blue_action_obs, post_blue_action_obs, blue_env.game.step_counter)" ] @@ -1036,9 +1720,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 44, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='failure', data={'Reason': 'Command sent to the C2 Beacon but no response was ever received.'})" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Attempting to install the C2 RansomwareScript\n", "ransomware_install_command = {\"commands\":[[\"software_manager\", \"application\", \"install\", \"RansomwareScript\"]],\n", @@ -1060,16 +1755,200 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 45, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:33,856: Resetting environment, episode 2, avg. reward: 0.0\n", + "2025-02-26 12:09:33,856: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_2.json\n" + ] + }, + { + "data": { + "text/plain": [ + "({'nodes': {'HOST0': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 1,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'HOST1': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 1,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'HOST2': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 0,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'HOST3': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 0,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'ROUTER0': {'ACL': {1: {'position': 0,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 2: {'position': 1,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 3: {'position': 2,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 4: {'position': 3,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 5: {'position': 4,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 6: {'position': 5,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 7: {'position': 6,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 8: {'position': 7,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 9: {'position': 8,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 10: {'position': 9,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0}},\n", + " 'PORTS': {1: {'operating_status': 1},\n", + " 2: {'operating_status': 1},\n", + " 3: {'operating_status': 2}},\n", + " 'users': {'local_login': 0, 'remote_sessions': 0}}},\n", + " 'LINKS': {1: {'PROTOCOLS': {'ALL': 1}},\n", + " 2: {'PROTOCOLS': {'ALL': 1}},\n", + " 3: {'PROTOCOLS': {'ALL': 0}},\n", + " 4: {'PROTOCOLS': {'ALL': 1}},\n", + " 5: {'PROTOCOLS': {'ALL': 1}},\n", + " 6: {'PROTOCOLS': {'ALL': 1}},\n", + " 7: {'PROTOCOLS': {'ALL': 1}},\n", + " 8: {'PROTOCOLS': {'ALL': 1}},\n", + " 9: {'PROTOCOLS': {'ALL': 1}},\n", + " 10: {'PROTOCOLS': {'ALL': 0}}},\n", + " 'ICS': 0},\n", + " {})" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "blue_env.reset()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 46, "metadata": {}, "outputs": [], "source": [ @@ -1088,7 +1967,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 47, "metadata": {}, "outputs": [], "source": [ @@ -1105,9 +1984,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 48, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "NodeOperatingState.SHUTTING_DOWN\n" + ] + } + ], "source": [ "web_server = blue_env.game.simulation.network.get_node_by_hostname(\"web_server\")\n", "print(web_server.operating_state)" @@ -1115,18 +2002,48 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 49, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 2\n", + "root['nodes']['HOST0']['operating_status']: 1 -> 4\n", + "root['nodes']['HOST0']['APPLICATIONS'][1]['operating_status']: 1 -> 0\n", + "root['nodes']['HOST0']['NICS'][1]['nic_status']: 1 -> 0\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", + "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", + "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" + ] + } + ], "source": [ "display_obs_diffs(pre_blue_action_obs, post_blue_action_obs, blue_env.game.step_counter)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 50, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='failure', data={'Reason': 'Command sent to the C2 Beacon but no response was ever received.'})" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Attempting to install the C2 RansomwareScript\n", "ransomware_install_command = {\"commands\":[\"software_manager\", \"application\", \"install\", \"RansomwareScript\"],\n", @@ -1150,16 +2067,200 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 51, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:34,093: Resetting environment, episode 3, avg. reward: 0.0\n", + "2025-02-26 12:09:34,093: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_3.json\n" + ] + }, + { + "data": { + "text/plain": [ + "({'nodes': {'HOST0': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 1,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'HOST1': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 1,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'HOST2': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 0,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'HOST3': {'APPLICATIONS': {1: {'operating_status': 0,\n", + " 'health_status': 0,\n", + " 'num_executions': 0},\n", + " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", + " 'FOLDERS': {1: {'health_status': 0,\n", + " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", + " 'NICS': {1: {'nic_status': 1,\n", + " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", + " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", + " 53: {'inbound': 0, 'outbound': 0},\n", + " 21: {'inbound': 0, 'outbound': 0}}}}},\n", + " 'num_file_creations': 0,\n", + " 'num_file_deletions': 0,\n", + " 'users': {'local_login': 0, 'remote_sessions': 0},\n", + " 'operating_status': 1},\n", + " 'ROUTER0': {'ACL': {1: {'position': 0,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 2: {'position': 1,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 3: {'position': 2,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 4: {'position': 3,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 5: {'position': 4,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 6: {'position': 5,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 7: {'position': 6,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 8: {'position': 7,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 9: {'position': 8,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0},\n", + " 10: {'position': 9,\n", + " 'permission': 0,\n", + " 'source_ip_id': 0,\n", + " 'source_wildcard_id': 0,\n", + " 'source_port_id': 0,\n", + " 'dest_ip_id': 0,\n", + " 'dest_wildcard_id': 0,\n", + " 'dest_port_id': 0,\n", + " 'protocol_id': 0}},\n", + " 'PORTS': {1: {'operating_status': 1},\n", + " 2: {'operating_status': 1},\n", + " 3: {'operating_status': 2}},\n", + " 'users': {'local_login': 0, 'remote_sessions': 0}}},\n", + " 'LINKS': {1: {'PROTOCOLS': {'ALL': 1}},\n", + " 2: {'PROTOCOLS': {'ALL': 1}},\n", + " 3: {'PROTOCOLS': {'ALL': 0}},\n", + " 4: {'PROTOCOLS': {'ALL': 1}},\n", + " 5: {'PROTOCOLS': {'ALL': 1}},\n", + " 6: {'PROTOCOLS': {'ALL': 1}},\n", + " 7: {'PROTOCOLS': {'ALL': 1}},\n", + " 8: {'PROTOCOLS': {'ALL': 1}},\n", + " 9: {'PROTOCOLS': {'ALL': 1}},\n", + " 10: {'PROTOCOLS': {'ALL': 0}}},\n", + " 'ICS': 0},\n", + " {})" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "blue_env.reset()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 52, "metadata": {}, "outputs": [], "source": [ @@ -1178,7 +2279,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 53, "metadata": {}, "outputs": [], "source": [ @@ -1195,9 +2296,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 54, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| router_1 Access Control List |\n", + "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n", + "| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |\n", + "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n", + "| 1 | DENY | ANY | 192.168.10.21 | 0.0.0.1 | 80 | 192.168.1.12 | 0.0.0.1 | 80 | 0 |\n", + "| 18 | PERMIT | ANY | ANY | ANY | 5432 | ANY | ANY | 5432 | 0 |\n", + "| 19 | PERMIT | ANY | ANY | ANY | 53 | ANY | ANY | 53 | 0 |\n", + "| 20 | PERMIT | ANY | ANY | ANY | 21 | ANY | ANY | 21 | 0 |\n", + "| 21 | PERMIT | ANY | ANY | ANY | 80 | ANY | ANY | 80 | 4 |\n", + "| 22 | PERMIT | ANY | ANY | ANY | 219 | ANY | ANY | 219 | 10 |\n", + "| 23 | PERMIT | icmp | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", + "| 24 | DENY | ANY | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", + "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n" + ] + } + ], "source": [ "router_1: Router = blue_env.game.simulation.network.get_node_by_hostname(\"router_1\")\n", "router_1.acl.show()" @@ -1212,9 +2334,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 55, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='failure', data={'Reason': 'Command sent to the C2 Beacon but no response was ever received.'})" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "blue_env.step(0)\n", "\n", @@ -1225,9 +2358,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 56, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| router_1 Access Control List |\n", + "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n", + "| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |\n", + "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n", + "| 1 | DENY | ANY | 192.168.10.21 | 0.0.0.1 | 80 | 192.168.1.12 | 0.0.0.1 | 80 | 2 |\n", + "| 18 | PERMIT | ANY | ANY | ANY | 5432 | ANY | ANY | 5432 | 0 |\n", + "| 19 | PERMIT | ANY | ANY | ANY | 53 | ANY | ANY | 53 | 0 |\n", + "| 20 | PERMIT | ANY | ANY | ANY | 21 | ANY | ANY | 21 | 0 |\n", + "| 21 | PERMIT | ANY | ANY | ANY | 80 | ANY | ANY | 80 | 4 |\n", + "| 22 | PERMIT | ANY | ANY | ANY | 219 | ANY | ANY | 219 | 10 |\n", + "| 23 | PERMIT | icmp | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", + "| 24 | DENY | ANY | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", + "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n" + ] + } + ], "source": [ "router_1.acl.show()" ] @@ -1241,18 +2395,58 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 57, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------------------------------------------------------------------+\n", + "| web_server Software Manager |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| Name | Type | Operating State | Health State | Port | Protocol |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n", + "| arp | Service | RUNNING | GOOD | 219 | udp |\n", + "| icmp | Service | RUNNING | GOOD | None | icmp |\n", + "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", + "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", + "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", + "| nmap | Application | RUNNING | GOOD | None | none |\n", + "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", + "| user-manager | Service | RUNNING | GOOD | None | none |\n", + "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", + "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", + "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", + "| c2-beacon | Application | RUNNING | GOOD | None | tcp |\n", + "+----------------------+-------------+-----------------+--------------+------+----------+\n" + ] + } + ], "source": [ "web_server.software_manager.show()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 58, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------+\n", + "| database_server File System |\n", + "+----------------------+---------+---------------+-----------------------+---------+\n", + "| File Path | Size | Health status | Visible health status | Deleted |\n", + "+----------------------+---------+---------------+-----------------------+---------+\n", + "| database/database.db | 4.77 MB | GOOD | NONE | False |\n", + "| root | 0 B | GOOD | NONE | False |\n", + "+----------------------+---------+---------------+-----------------------+---------+\n" + ] + } + ], "source": [ "database_server: Server = blue_env.game.simulation.network.get_node_by_hostname(\"database_server\")\n", "database_server.software_manager.file_system.show(full=True)" @@ -1260,9 +2454,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 59, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 3\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", + "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", + "root['nodes']['ROUTER0']['ACL'][1]['permission']: 0 -> 2\n", + "root['nodes']['ROUTER0']['ACL'][1]['source_ip_id']: 0 -> 7\n", + "root['nodes']['ROUTER0']['ACL'][1]['source_wildcard_id']: 0 -> 2\n", + "root['nodes']['ROUTER0']['ACL'][1]['source_port_id']: 0 -> 2\n", + "root['nodes']['ROUTER0']['ACL'][1]['dest_ip_id']: 0 -> 3\n", + "root['nodes']['ROUTER0']['ACL'][1]['dest_wildcard_id']: 0 -> 2\n", + "root['nodes']['ROUTER0']['ACL'][1]['dest_port_id']: 0 -> 2\n", + "root['nodes']['ROUTER0']['ACL'][1]['protocol_id']: 0 -> 1\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", + "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", + "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" + ] + } + ], "source": [ "display_obs_diffs(pre_blue_action_obs, post_blue_action_obs, blue_env.game.step_counter)" ] @@ -1328,9 +2546,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 60, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:34,725: PrimaiteGymEnv RNG seed = None\n" + ] + } + ], "source": [ "with open(data_manipulation_config_path()) as f:\n", " cfg = yaml.safe_load(f)\n", @@ -1351,7 +2577,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 61, "metadata": {}, "outputs": [], "source": [ @@ -1379,9 +2605,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 62, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", + "| c2-beacon Running Status |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| False | None | 0 | 5 | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "+-----------------------------------------------------------------------------------------------------+\n", + "| c2-server Running Status |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n", + "| False | None | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n" + ] + } + ], "source": [ "env.step(2) # Agent Action Equivalent to c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\")\n", "env.step(3) # Agent action Equivalent to c2_beacon.establish()\n", @@ -1398,9 +2645,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 63, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", + "| c2-beacon Running Status |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| False | None | 0 | 5 | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "+-----------------------------------------------------------------------------------------------------+\n", + "| c2-server Running Status |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n", + "| False | None | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n" + ] + } + ], "source": [ "env.step(9) # Equivalent of to c2_beacon.configure(c2_server_ip_address=\"192.168.10.22\")\n", "env.step(3)\n", @@ -1418,9 +2686,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 64, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-----------------------------------------------------------------------------------------------------+\n", + "| c2-server Running Status |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n", + "| False | None | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------------+-------------------------+\n" + ] + } + ], "source": [ "for i in range(6):\n", " env.step(0)\n", @@ -1443,9 +2725,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 65, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:35,057: PrimaiteGymEnv RNG seed = None\n" + ] + } + ], "source": [ "with open(data_manipulation_config_path()) as f:\n", " cfg = yaml.safe_load(f)\n", @@ -1461,7 +2751,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 66, "metadata": {}, "outputs": [], "source": [ @@ -1485,9 +2775,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 67, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", + "| c2-beacon Running Status |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| True | 192.168.10.21 | 0 | 5 | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n" + ] + } + ], "source": [ "c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\")\n", "c2_beacon.establish()\n", @@ -1505,9 +2809,72 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 68, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 4\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 5\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 6\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 7\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 8\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 9\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 10\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 11\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 12\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 13\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" + ] + } + ], "source": [ "for i in range(10):\n", " keep_alive_obs, _, _, _, _ = blue_config_env.step(0)\n", @@ -1523,9 +2890,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 69, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", + "| c2-beacon Running Status |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| True | 192.168.10.21 | 0 | 1 | tcp | 80 |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n" + ] + } + ], "source": [ "c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\", keep_alive_frequency=1)\n", "c2_beacon.establish()\n", @@ -1541,9 +2922,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 70, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 14\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 15\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" + ] + } + ], "source": [ "# Comparing the OBS of the default frequency to a timestep frequency of 1\n", "for i in range(2):\n", @@ -1562,9 +2974,52 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 71, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 16\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 17\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 18\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 19\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 20\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 21\n", + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 22\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" + ] + } + ], "source": [ "c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\", keep_alive_frequency=7)\n", "\n", @@ -1601,9 +3056,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 72, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 12:09:35,703: Resetting environment, episode 0, avg. reward: 0.0\n", + "2025-02-26 12:09:35,704: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_0.json\n" + ] + } + ], "source": [ "blue_config_env.reset()\n", "\n", @@ -1625,9 +3089,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 73, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 5\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", + "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", + "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" + ] + } + ], "source": [ "# Capturing default C2 Traffic\n", "for i in range(3):\n", @@ -1645,9 +3128,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 74, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", + "| c2-beacon Running Status |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", + "| True | 192.168.10.21 | 0 | 5 | udp | 53 |\n", + "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n" + ] + } + ], "source": [ "from primaite.utils.validation.ip_protocol import PROTOCOL_LOOKUP\n", "from primaite.utils.validation.port import PORT_LOOKUP\n", @@ -1660,9 +3157,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 75, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Observation space differences\n", + "-----------------------------\n", + "Step 10\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 1 -> 0\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 1 -> 0\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['udp'][53]['inbound']: 0 -> 1\n", + "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['udp'][53]['outbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 1 -> 0\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 1 -> 0\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['udp'][53]['inbound']: 0 -> 1\n", + "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['udp'][53]['outbound']: 0 -> 1\n" + ] + } + ], "source": [ "# Capturing UDP C2 Traffic\n", "for i in range(5):\n", diff --git a/src/primaite/notebooks/Privilege-Escalation-and-Data-Loss-Example.ipynb b/src/primaite/notebooks/Privilege-Escalation-and-Data-Loss-Example.ipynb index deb38eea..284cd9fd 100644 --- a/src/primaite/notebooks/Privilege-Escalation-and-Data-Loss-Example.ipynb +++ b/src/primaite/notebooks/Privilege-Escalation-and-Data-Loss-Example.ipynb @@ -53,16 +53,37 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\notebooks\\example_notebooks\\Privilege-Escalation-and-Data-Loss-Example.ipynb\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-26 14:11:04,193: Performing the PrimAITE first-time setup...\n", + "2025-02-26 14:11:04,193: Building the PrimAITE app directories...\n", + "2025-02-26 14:11:04,193: Building primaite_config.yaml...\n", + "2025-02-26 14:11:04,193: Rebuilding the demo notebooks...\n", + "2025-02-26 14:11:04,226: Reset example notebook: C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\notebooks\\example_notebooks\\Privilege-Escalation-and-Data-Loss-Example.ipynb\n", + "2025-02-26 14:11:04,246: Rebuilding the example notebooks...\n", + "2025-02-26 14:11:04,251: PrimAITE setup complete!\n" + ] + } + ], "source": [ "!primaite setup" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "tags": [] }, @@ -90,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "tags": [] }, @@ -113,7 +134,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "tags": [] }, @@ -140,33 +161,73 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------------+\n", + "| some_tech_storage_srv File System |\n", + "+-----------+------+---------------+-----------------------+---------+\n", + "| File Path | Size | Health status | Visible health status | Deleted |\n", + "+-----------+------+---------------+-----------------------+---------+\n", + "| root | 0 B | GOOD | NONE | False |\n", + "+-----------+------+---------------+-----------------------+---------+\n" + ] + } + ], "source": [ "some_tech_storage_srv.file_system.show(full=True)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "some_tech_db_service.backup_database()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------------------------------------------------------+\n", + "| some_tech_storage_srv File System |\n", + "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n", + "| File Path | Size | Health status | Visible health status | Deleted |\n", + "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n", + "| ed8587f2-7100-4837-bfbb-2a06bfafa8db/database.db | 4.77 MB | GOOD | NONE | False |\n", + "| root | 0 B | GOOD | NONE | False |\n", + "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n" + ] + } + ], "source": [ "some_tech_storage_srv.file_system.show(full=True)" ] @@ -180,11 +241,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'ed8587f2-7100-4837-bfbb-2a06bfafa8db'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "db_backup_folder = [folder.name for folder in some_tech_storage_srv.file_system.folders.values() if folder.name != \"root\"][0]\n", "db_backup_folder" @@ -203,11 +275,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='failure', data={})" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -227,11 +310,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={})" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "caos_action = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n", "game.simulation.apply_request(caos_action)" @@ -252,20 +346,42 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "game.get_sim_state()[\"network\"][\"nodes\"][\"some_tech_rt\"][\"services\"][\"user-session-manager\"][\"active_remote_sessions\"]" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={'ip_address': '10.10.2.1', 'username': 'admin'})" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -276,11 +392,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "['ee4b75dc-1f70-4f93-a25f-d0466afecfd9']" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "game.get_sim_state()[\"network\"][\"nodes\"][\"some_tech_rt\"][\"services\"][\"user-session-manager\"][\"active_remote_sessions\"]" ] @@ -296,22 +423,59 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------------------------------------------------------------------------------------------------+\n", + "| some_tech_rt Access Control List |\n", + "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n", + "| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |\n", + "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n", + "| 11 | PERMIT | ANY | 94.10.180.6 | 0.0.0.0 | 5432 | 10.10.1.11 | 0.0.0.0 | 5432 | 2 |\n", + "| 12 | PERMIT | ANY | 10.10.1.11 | 0.0.0.0 | 5432 | 94.10.180.6 | 0.0.0.0 | 5432 | 2 |\n", + "| 13 | DENY | ANY | 10.10.2.12 | 0.0.0.0 | 21 | 10.10.1.12 | 0.0.0.0 | 21 | 0 |\n", + "| 14 | DENY | ANY | 10.10.2.12 | 0.0.0.0 | 22 | 10.10.1.12 | 0.0.0.0 | 22 | 1 |\n", + "| 15 | PERMIT | ANY | 10.10.2.0 | 0.0.0.255 | ANY | 10.10.1.0 | 0.0.0.255 | ANY | 0 |\n", + "| 16 | PERMIT | ANY | 10.10.1.0 | 0.0.0.255 | ANY | 10.10.2.0 | 0.0.0.255 | ANY | 0 |\n", + "| 17 | PERMIT | ANY | ANY | ANY | 80 | ANY | ANY | 80 | 2 |\n", + "| 18 | PERMIT | ANY | 10.10.0.0 | 0.0.255.255 | 219 | ANY | ANY | ANY | 7 |\n", + "| 19 | PERMIT | icmp | 10.10.0.0 | 0.0.255.255 | ANY | ANY | ANY | ANY | 0 |\n", + "| 21 | PERMIT | ANY | 94.10.180.6 | 0.0.0.0 | 80 | 10.10.0.0 | 0.0.255.255 | 80 | 0 |\n", + "| 22 | PERMIT | ANY | ANY | ANY | 53 | ANY | ANY | 53 | 2 |\n", + "| 23 | PERMIT | ANY | ANY | ANY | 22 | ANY | ANY | 22 | 1 |\n", + "| 24 | DENY | ANY | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", + "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n" + ] + } + ], "source": [ "some_tech_rt.acl.show()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={})" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -340,11 +504,38 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------------------------------------------------------------------------------------------------+\n", + "| some_tech_rt Access Control List |\n", + "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n", + "| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |\n", + "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n", + "| 1 | PERMIT | tcp | 10.10.2.12 | 0.0.0.0 | 22 | 10.10.1.12 | 0.0.0.0 | 22 | 0 |\n", + "| 11 | PERMIT | ANY | 94.10.180.6 | 0.0.0.0 | 5432 | 10.10.1.11 | 0.0.0.0 | 5432 | 2 |\n", + "| 12 | PERMIT | ANY | 10.10.1.11 | 0.0.0.0 | 5432 | 94.10.180.6 | 0.0.0.0 | 5432 | 2 |\n", + "| 13 | DENY | ANY | 10.10.2.12 | 0.0.0.0 | 21 | 10.10.1.12 | 0.0.0.0 | 21 | 0 |\n", + "| 14 | DENY | ANY | 10.10.2.12 | 0.0.0.0 | 22 | 10.10.1.12 | 0.0.0.0 | 22 | 1 |\n", + "| 15 | PERMIT | ANY | 10.10.2.0 | 0.0.0.255 | ANY | 10.10.1.0 | 0.0.0.255 | ANY | 0 |\n", + "| 16 | PERMIT | ANY | 10.10.1.0 | 0.0.0.255 | ANY | 10.10.2.0 | 0.0.0.255 | ANY | 0 |\n", + "| 17 | PERMIT | ANY | ANY | ANY | 80 | ANY | ANY | 80 | 2 |\n", + "| 18 | PERMIT | ANY | 10.10.0.0 | 0.0.255.255 | 219 | ANY | ANY | ANY | 7 |\n", + "| 19 | PERMIT | icmp | 10.10.0.0 | 0.0.255.255 | ANY | ANY | ANY | ANY | 0 |\n", + "| 21 | PERMIT | ANY | 94.10.180.6 | 0.0.0.0 | 80 | 10.10.0.0 | 0.0.255.255 | 80 | 0 |\n", + "| 22 | PERMIT | ANY | ANY | ANY | 53 | ANY | ANY | 53 | 2 |\n", + "| 23 | PERMIT | ANY | ANY | ANY | 22 | ANY | ANY | 22 | 2 |\n", + "| 24 | DENY | ANY | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", + "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n" + ] + } + ], "source": [ "some_tech_rt.acl.show()" ] @@ -360,11 +551,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={})" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -382,9 +584,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "game.get_sim_state()[\"network\"][\"nodes\"][\"some_tech_rt\"][\"services\"][\"user-session-manager\"][\"active_remote_sessions\"]" ] @@ -400,9 +613,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={'ip_address': '10.10.1.12', 'username': 'admin'})" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -413,11 +637,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={})" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -441,11 +676,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------------------------------------------------------+\n", + "| some_tech_storage_srv File System |\n", + "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n", + "| File Path | Size | Health status | Visible health status | Deleted |\n", + "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n", + "| ed8587f2-7100-4837-bfbb-2a06bfafa8db/database.db | 4.77 MB | GOOD | NONE | True |\n", + "| root | 0 B | GOOD | NONE | False |\n", + "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n" + ] + } + ], "source": [ "some_tech_storage_srv.file_system.show(full=True)" ] @@ -470,11 +720,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='success', data={})" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "caos_action = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n", "game.simulation.apply_request(caos_action)" @@ -489,11 +750,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "DatabaseClientConnection(connection_id='cb712d1e-68d2-4504-94a2-8c67d3652ccd', is_active=True)" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "some_tech_jnr_dev_db_client.server_ip_address = some_tech_db_srv.network_interface[1].ip_address\n", "some_tech_jnr_dev_db_connection = some_tech_jnr_dev_db_client.get_new_connection()\n", @@ -511,11 +783,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "some_tech_jnr_dev_db_connection.query(\"DELETE\")" ] @@ -529,11 +812,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "RequestResponse(status='failure', data={})" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "caos_action = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n", "game.simulation.apply_request(caos_action)" @@ -550,11 +844,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "some_tech_db_service.restore_backup()" ] @@ -595,7 +900,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -609,7 +914,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.11" } }, "nbformat": 4, From 6b796608df4b0a881d46e942b7d47289f23f06b8 Mon Sep 17 00:00:00 2001 From: Charlie Crane Date: Wed, 26 Feb 2025 15:32:50 +0000 Subject: [PATCH 4/8] Revert commit of output in Command and Control notebook --- ...ommand-and-Control-E2E-Demonstration.ipynb | 1777 ++--------------- 1 file changed, 131 insertions(+), 1646 deletions(-) diff --git a/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb b/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb index 9f4923df..19de56bf 100644 --- a/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb +++ b/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb @@ -13,22 +13,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:23,996: Performing the PrimAITE first-time setup...\n", - "2025-02-26 12:09:23,996: Building the PrimAITE app directories...\n", - "2025-02-26 12:09:23,996: Building primaite_config.yaml...\n", - "2025-02-26 12:09:23,996: Rebuilding the demo notebooks...\n", - "2025-02-26 12:09:24,029: Rebuilding the example notebooks...\n", - "2025-02-26 12:09:24,029: PrimAITE setup complete!\n" - ] - } - ], + "outputs": [], "source": [ "!primaite setup" ] @@ -66,7 +53,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -152,17 +139,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:31,270: PrimaiteGymEnv RNG seed = None\n" - ] - } - ], + "outputs": [], "source": [ "with open(data_manipulation_config_path()) as f:\n", " cfg = yaml.safe_load(f)\n", @@ -188,35 +167,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------+\n", - "| client_1 Software Manager |\n", - "+-----------------------+-------------+-----------------+--------------+------+----------+\n", - "| Name | Type | Operating State | Health State | Port | Protocol |\n", - "+-----------------------+-------------+-----------------+--------------+------+----------+\n", - "| arp | Service | RUNNING | GOOD | 219 | udp |\n", - "| icmp | Service | RUNNING | GOOD | None | icmp |\n", - "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", - "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", - "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", - "| nmap | Application | RUNNING | GOOD | None | none |\n", - "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", - "| user-manager | Service | RUNNING | GOOD | None | none |\n", - "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", - "| ftp-client | Service | RUNNING | GOOD | 21 | tcp |\n", - "| data-manipulation-bot | Application | RUNNING | GOOD | None | none |\n", - "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", - "| c2-server | Application | RUNNING | GOOD | None | tcp |\n", - "+-----------------------+-------------+-----------------+--------------+------+----------+\n" - ] - } - ], + "outputs": [], "source": [ "client_1: Computer = env.game.simulation.network.get_node_by_hostname(\"client_1\")\n", "client_1.software_manager.install(C2Server)\n", @@ -266,34 +219,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------------------------------------------------------------------------------+\n", - "| web_server Software Manager |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| Name | Type | Operating State | Health State | Port | Protocol |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| arp | Service | RUNNING | GOOD | 219 | udp |\n", - "| icmp | Service | RUNNING | GOOD | None | icmp |\n", - "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", - "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", - "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", - "| nmap | Application | RUNNING | GOOD | None | none |\n", - "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", - "| user-manager | Service | RUNNING | GOOD | None | none |\n", - "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", - "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", - "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", - "| c2-beacon | Application | INSTALLING | GOOD | None | tcp |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n" - ] - } - ], + "outputs": [], "source": [ "env.step(1)\n", "web_server: Computer = env.game.simulation.network.get_node_by_hostname(\"web_server\")\n", @@ -328,41 +256,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------------------------------------------------------------------------------+\n", - "| web_server Software Manager |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| Name | Type | Operating State | Health State | Port | Protocol |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| arp | Service | RUNNING | GOOD | 219 | udp |\n", - "| icmp | Service | RUNNING | GOOD | None | icmp |\n", - "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", - "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", - "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", - "| nmap | Application | RUNNING | GOOD | None | none |\n", - "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", - "| user-manager | Service | RUNNING | GOOD | None | none |\n", - "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", - "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", - "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", - "| c2-beacon | Application | RUNNING | GOOD | None | tcp |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", - "| c2-beacon Running Status |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| False | 192.168.10.21 | 0 | 5 | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n" - ] - } - ], + "outputs": [], "source": [ "env.step(2)\n", "c2_beacon: C2Beacon = web_server.software_manager.software[\"c2-beacon\"]\n", @@ -393,54 +289,18 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0,\n", - " 0.0,\n", - " False,\n", - " False,\n", - " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=2, action='node-application-execute', parameters={'node_name': 'web_server', 'application_name': 'c2-beacon'}, request=['network', 'node', 'web_server', 'application', 'c2-beacon', 'execute'], response=RequestResponse(status='success', data={}), reward=0.0, reward_info={})}})" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "env.step(3)" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", - "| c2-beacon Running Status |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| True | 192.168.10.21 | 1 | 5 | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "+-----------------------------------------------------------------------------------------------------+\n", - "| c2-server Running Status |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n", - "| True | 192.168.1.12 | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n" - ] - } - ], + "outputs": [], "source": [ "c2_beacon.show()\n", "c2_server.show()" @@ -495,59 +355,18 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0,\n", - " 0.0,\n", - " False,\n", - " False,\n", - " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=3, action='c2-server-terminal-command', parameters={'node_name': 'client_1', 'ip_address': None, 'username': 'admin', 'password': 'admin', 'commands': [['software_manager', 'application', 'install', 'ransomware-script']]}, request=['network', 'node', 'client_1', 'application', 'c2-server', 'terminal_command', {'commands': [['software_manager', 'application', 'install', 'ransomware-script']], 'ip_address': None, 'username': 'admin', 'password': 'admin'}], response=RequestResponse(status='success', data={0: RequestResponse(status='success', data={})}), reward=0.0, reward_info={})}})" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "env.step(4)" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------+\n", - "| client_1 Software Manager |\n", - "+-----------------------+-------------+-----------------+--------------+------+----------+\n", - "| Name | Type | Operating State | Health State | Port | Protocol |\n", - "+-----------------------+-------------+-----------------+--------------+------+----------+\n", - "| arp | Service | RUNNING | GOOD | 219 | udp |\n", - "| icmp | Service | RUNNING | GOOD | None | icmp |\n", - "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", - "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", - "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", - "| nmap | Application | RUNNING | GOOD | None | none |\n", - "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", - "| user-manager | Service | RUNNING | GOOD | None | none |\n", - "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", - "| ftp-client | Service | RUNNING | GOOD | 21 | tcp |\n", - "| data-manipulation-bot | Application | RUNNING | GOOD | None | none |\n", - "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", - "| c2-server | Application | RUNNING | GOOD | None | tcp |\n", - "+-----------------------+-------------+-----------------+--------------+------+----------+\n" - ] - } - ], + "outputs": [], "source": [ "client_1.software_manager.show()" ] @@ -578,66 +397,18 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0,\n", - " 0.0,\n", - " False,\n", - " False,\n", - " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=4, action='c2-server-ransomware-configure', parameters={'node_name': 'client_1', 'server_ip_address': '192.168.1.14', 'payload': 'ENCRYPT'}, request=['network', 'node', 'client_1', 'application', 'c2-server', 'ransomware_configure', {'server_ip_address': '192.168.1.14', 'server_password': None, 'payload': 'ENCRYPT'}], response=RequestResponse(status='success', data={}), reward=0.0, reward_info={})}})" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "env.step(5)" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------------------------------------------------------------------------------+\n", - "| web_server Software Manager |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| Name | Type | Operating State | Health State | Port | Protocol |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| arp | Service | RUNNING | GOOD | 219 | udp |\n", - "| icmp | Service | RUNNING | GOOD | None | icmp |\n", - "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", - "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", - "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", - "| nmap | Application | RUNNING | GOOD | None | none |\n", - "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", - "| user-manager | Service | RUNNING | GOOD | None | none |\n", - "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", - "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", - "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", - "| c2-beacon | Application | RUNNING | GOOD | None | tcp |\n", - "| ransomware-script | Application | RUNNING | GOOD | None | none |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "+------------------------------------+\n", - "| ransomware-script Running Status |\n", - "+--------------------------+---------+\n", - "| Target Server IP Address | Payload |\n", - "+--------------------------+---------+\n", - "| 192.168.1.14 | ENCRYPT |\n", - "+--------------------------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "ransomware_script: RansomwareScript = web_server.software_manager.software[\"ransomware-script\"]\n", "web_server.software_manager.show()\n", @@ -675,48 +446,18 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0,\n", - " 0.0,\n", - " False,\n", - " False,\n", - " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=5, action='c2-server-data-exfiltrate', parameters={'node_name': 'client_1', 'target_file_name': 'database.db', 'target_folder_name': 'database', 'exfiltration_folder_name': 'spoils', 'target_ip_address': '192.168.1.14', 'username': 'admin', 'password': 'admin'}, request=['network', 'node', 'client_1', 'application', 'c2-server', 'exfiltrate', {'target_file_name': 'database.db', 'target_folder_name': 'database', 'exfiltration_folder_name': 'spoils', 'target_ip_address': '192.168.1.14', 'username': 'admin', 'password': 'admin'}], response=RequestResponse(status='success', data={}), reward=0.0, reward_info={})}})" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "env.step(6)" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------------------------------------------------------------------+\n", - "| client_1 File System |\n", - "+--------------------+---------+---------------+-----------------------+---------+\n", - "| File Path | Size | Health status | Visible health status | Deleted |\n", - "+--------------------+---------+---------------+-----------------------+---------+\n", - "| root | 0 B | GOOD | NONE | False |\n", - "| spoils/database.db | 4.77 MB | GOOD | NONE | False |\n", - "+--------------------+---------+---------------+-----------------------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "client_1: Computer = env.game.simulation.network.get_node_by_hostname(\"client_1\")\n", "client_1.software_manager.file_system.show(full=True)" @@ -724,25 +465,9 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------------------------------------------------------------------------+\n", - "| web_server File System |\n", - "+---------------------+---------+---------------+-----------------------+---------+\n", - "| File Path | Size | Health status | Visible health status | Deleted |\n", - "+---------------------+---------+---------------+-----------------------+---------+\n", - "| primaite/index.html | 15.0 KB | GOOD | NONE | False |\n", - "| root | 0 B | GOOD | NONE | False |\n", - "| spoils/database.db | 4.77 MB | GOOD | NONE | False |\n", - "+---------------------+---------+---------------+-----------------------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "web_server: Computer = env.game.simulation.network.get_node_by_hostname(\"web_server\")\n", "web_server.software_manager.file_system.show(full=True)" @@ -772,48 +497,18 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0,\n", - " 0.0,\n", - " False,\n", - " False,\n", - " {'agent_actions': {'CustomC2Agent': AgentHistoryItem(timestep=6, action='c2-server-ransomware-launch', parameters={'node_name': 'client_1'}, request=['network', 'node', 'client_1', 'application', 'c2-server', 'ransomware_launch'], response=RequestResponse(status='success', data={}), reward=0.0, reward_info={})}})" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "env.step(7)" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------+\n", - "| database_server File System |\n", - "+----------------------+---------+---------------+-----------------------+---------+\n", - "| File Path | Size | Health status | Visible health status | Deleted |\n", - "+----------------------+---------+---------------+-----------------------+---------+\n", - "| database/database.db | 4.77 MB | CORRUPT | NONE | False |\n", - "| root | 0 B | GOOD | NONE | False |\n", - "+----------------------+---------+---------------+-----------------------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "database_server: Server = env.game.simulation.network.get_node_by_hostname(\"database_server\")\n", "database_server.software_manager.file_system.show(full=True)" @@ -832,7 +527,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -960,17 +655,9 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:32,087: PrimaiteGymEnv RNG seed = None\n" - ] - } - ], + "outputs": [], "source": [ "with open(data_manipulation_config_path()) as f:\n", " cfg = yaml.safe_load(f)\n", @@ -984,7 +671,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1027,18 +714,9 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:32,894: Resetting environment, episode 0, avg. reward: 0.0\n", - "2025-02-26 12:09:32,898: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_0.json\n" - ] - } - ], + "outputs": [], "source": [ "# Resetting the environment and capturing the default observation space.\n", "blue_env.reset()\n", @@ -1047,20 +725,9 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Setting up the C2 Suite via the simulation API.\n", "\n", @@ -1081,7 +748,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1091,26 +758,9 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 2\n", - "root['nodes']['HOST0']['APPLICATIONS'][1]['operating_status']: 0 -> 1\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", - "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", - "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" - ] - } - ], + "outputs": [], "source": [ "display_obs_diffs(default_obs, c2_configuration_obs, blue_env.game.step_counter)" ] @@ -1130,20 +780,9 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={0: RequestResponse(status='success', data={})})" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Installing RansomwareScript via C2 Terminal Commands\n", "ransomware_install_command = {\"commands\":[[\"software_manager\", \"application\", \"install\", \"ransomware-script\"]],\n", @@ -1154,20 +793,9 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={})" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Configuring the RansomwareScript\n", "ransomware_config = {\"server_ip_address\": \"192.168.1.14\", \"payload\": \"ENCRYPT\"}\n", @@ -1176,7 +804,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1186,28 +814,9 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 7\n", - "root['nodes']['HOST0']['APPLICATIONS'][1]['operating_status']: 0 -> 1\n", - "root['nodes']['HOST0']['APPLICATIONS'][2]['operating_status']: 0 -> 3\n", - "root['nodes']['HOST0']['users']['local_login']: 0 -> 1\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", - "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", - "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" - ] - } - ], + "outputs": [], "source": [ "display_obs_diffs(default_obs, c2_ransomware_obs, env.game.step_counter)" ] @@ -1223,7 +832,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1239,27 +848,16 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={})" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "c2_server.send_command(given_command=C2Command.DATA_EXFILTRATION, command_options=exfil_options)" ] }, { "cell_type": "code", - "execution_count": 32, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1268,22 +866,9 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 7\n", - "root['nodes']['HOST0']['APPLICATIONS'][2]['operating_status']: 3 -> 1\n", - "root['nodes']['HOST1']['users']['remote_sessions']: 0 -> 1\n" - ] - } - ], + "outputs": [], "source": [ "display_obs_diffs(c2_ransomware_obs, c2_exfil_obs, env.game.step_counter)" ] @@ -1299,20 +884,9 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={})" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Configuring the RansomwareScript\n", "ransomware_config = {\"server_ip_address\": \"192.168.1.14\", \"payload\": \"ENCRYPT\"}\n", @@ -1321,20 +895,9 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={})" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Waiting for the ransomware to finish installing and then launching the RansomwareScript.\n", "blue_env.step(0)\n", @@ -1343,7 +906,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1353,30 +916,9 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 6\n", - "root['nodes']['HOST0']['APPLICATIONS'][2]['operating_status']: 3 -> 1\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['nodes']['HOST1']['users']['remote_sessions']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" - ] - } - ], + "outputs": [], "source": [ "display_obs_diffs(c2_ransomware_obs, c2_final_obs, blue_env.game.step_counter)" ] @@ -1392,7 +934,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1424,200 +966,16 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:33,561: Resetting environment, episode 1, avg. reward: 0.0\n", - "2025-02-26 12:09:33,561: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_1.json\n" - ] - }, - { - "data": { - "text/plain": [ - "({'nodes': {'HOST0': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 1,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'HOST1': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 1,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'HOST2': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 0,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'HOST3': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 0,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'ROUTER0': {'ACL': {1: {'position': 0,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 2: {'position': 1,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 3: {'position': 2,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 4: {'position': 3,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 5: {'position': 4,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 6: {'position': 5,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 7: {'position': 6,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 8: {'position': 7,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 9: {'position': 8,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 10: {'position': 9,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0}},\n", - " 'PORTS': {1: {'operating_status': 1},\n", - " 2: {'operating_status': 1},\n", - " 3: {'operating_status': 2}},\n", - " 'users': {'local_login': 0, 'remote_sessions': 0}}},\n", - " 'LINKS': {1: {'PROTOCOLS': {'ALL': 1}},\n", - " 2: {'PROTOCOLS': {'ALL': 1}},\n", - " 3: {'PROTOCOLS': {'ALL': 0}},\n", - " 4: {'PROTOCOLS': {'ALL': 1}},\n", - " 5: {'PROTOCOLS': {'ALL': 1}},\n", - " 6: {'PROTOCOLS': {'ALL': 1}},\n", - " 7: {'PROTOCOLS': {'ALL': 1}},\n", - " 8: {'PROTOCOLS': {'ALL': 1}},\n", - " 9: {'PROTOCOLS': {'ALL': 1}},\n", - " 10: {'PROTOCOLS': {'ALL': 0}}},\n", - " 'ICS': 0},\n", - " {})" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "blue_env.reset()" ] }, { "cell_type": "code", - "execution_count": 40, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1636,7 +994,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1653,33 +1011,9 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------------------------------------------------------------------------------+\n", - "| web_server Software Manager |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| Name | Type | Operating State | Health State | Port | Protocol |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| arp | Service | RUNNING | GOOD | 219 | udp |\n", - "| icmp | Service | RUNNING | GOOD | None | icmp |\n", - "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", - "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", - "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", - "| nmap | Application | RUNNING | GOOD | None | none |\n", - "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", - "| user-manager | Service | RUNNING | GOOD | None | none |\n", - "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", - "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", - "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n" - ] - } - ], + "outputs": [], "source": [ "blue_env.step(0)\n", "web_server.software_manager.show()" @@ -1687,26 +1021,9 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 3\n", - "root['nodes']['HOST0']['APPLICATIONS'][1]['operating_status']: 1 -> 0\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", - "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", - "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" - ] - } - ], + "outputs": [], "source": [ "display_obs_diffs(pre_blue_action_obs, post_blue_action_obs, blue_env.game.step_counter)" ] @@ -1720,20 +1037,9 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='failure', data={'Reason': 'Command sent to the C2 Beacon but no response was ever received.'})" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Attempting to install the C2 RansomwareScript\n", "ransomware_install_command = {\"commands\":[[\"software_manager\", \"application\", \"install\", \"RansomwareScript\"]],\n", @@ -1755,200 +1061,16 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:33,856: Resetting environment, episode 2, avg. reward: 0.0\n", - "2025-02-26 12:09:33,856: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_2.json\n" - ] - }, - { - "data": { - "text/plain": [ - "({'nodes': {'HOST0': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 1,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'HOST1': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 1,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'HOST2': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 0,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'HOST3': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 0,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'ROUTER0': {'ACL': {1: {'position': 0,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 2: {'position': 1,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 3: {'position': 2,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 4: {'position': 3,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 5: {'position': 4,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 6: {'position': 5,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 7: {'position': 6,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 8: {'position': 7,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 9: {'position': 8,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 10: {'position': 9,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0}},\n", - " 'PORTS': {1: {'operating_status': 1},\n", - " 2: {'operating_status': 1},\n", - " 3: {'operating_status': 2}},\n", - " 'users': {'local_login': 0, 'remote_sessions': 0}}},\n", - " 'LINKS': {1: {'PROTOCOLS': {'ALL': 1}},\n", - " 2: {'PROTOCOLS': {'ALL': 1}},\n", - " 3: {'PROTOCOLS': {'ALL': 0}},\n", - " 4: {'PROTOCOLS': {'ALL': 1}},\n", - " 5: {'PROTOCOLS': {'ALL': 1}},\n", - " 6: {'PROTOCOLS': {'ALL': 1}},\n", - " 7: {'PROTOCOLS': {'ALL': 1}},\n", - " 8: {'PROTOCOLS': {'ALL': 1}},\n", - " 9: {'PROTOCOLS': {'ALL': 1}},\n", - " 10: {'PROTOCOLS': {'ALL': 0}}},\n", - " 'ICS': 0},\n", - " {})" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "blue_env.reset()" ] }, { "cell_type": "code", - "execution_count": 46, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1967,7 +1089,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1984,17 +1106,9 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NodeOperatingState.SHUTTING_DOWN\n" - ] - } - ], + "outputs": [], "source": [ "web_server = blue_env.game.simulation.network.get_node_by_hostname(\"web_server\")\n", "print(web_server.operating_state)" @@ -2002,48 +1116,18 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 2\n", - "root['nodes']['HOST0']['operating_status']: 1 -> 4\n", - "root['nodes']['HOST0']['APPLICATIONS'][1]['operating_status']: 1 -> 0\n", - "root['nodes']['HOST0']['NICS'][1]['nic_status']: 1 -> 0\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", - "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", - "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" - ] - } - ], + "outputs": [], "source": [ "display_obs_diffs(pre_blue_action_obs, post_blue_action_obs, blue_env.game.step_counter)" ] }, { "cell_type": "code", - "execution_count": 50, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='failure', data={'Reason': 'Command sent to the C2 Beacon but no response was ever received.'})" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Attempting to install the C2 RansomwareScript\n", "ransomware_install_command = {\"commands\":[\"software_manager\", \"application\", \"install\", \"RansomwareScript\"],\n", @@ -2067,200 +1151,16 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:34,093: Resetting environment, episode 3, avg. reward: 0.0\n", - "2025-02-26 12:09:34,093: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_3.json\n" - ] - }, - { - "data": { - "text/plain": [ - "({'nodes': {'HOST0': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 1,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'HOST1': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 1,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'HOST2': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 0,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'HOST3': {'APPLICATIONS': {1: {'operating_status': 0,\n", - " 'health_status': 0,\n", - " 'num_executions': 0},\n", - " 2: {'operating_status': 0, 'health_status': 0, 'num_executions': 0}},\n", - " 'FOLDERS': {1: {'health_status': 0,\n", - " 'FILES': {1: {'health_status': 0, 'num_access': 0}}}},\n", - " 'NICS': {1: {'nic_status': 1,\n", - " 'TRAFFIC': {'icmp': {'inbound': 0, 'outbound': 0},\n", - " 'tcp': {80: {'inbound': 0, 'outbound': 0},\n", - " 53: {'inbound': 0, 'outbound': 0},\n", - " 21: {'inbound': 0, 'outbound': 0}}}}},\n", - " 'num_file_creations': 0,\n", - " 'num_file_deletions': 0,\n", - " 'users': {'local_login': 0, 'remote_sessions': 0},\n", - " 'operating_status': 1},\n", - " 'ROUTER0': {'ACL': {1: {'position': 0,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 2: {'position': 1,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 3: {'position': 2,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 4: {'position': 3,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 5: {'position': 4,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 6: {'position': 5,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 7: {'position': 6,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 8: {'position': 7,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 9: {'position': 8,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0},\n", - " 10: {'position': 9,\n", - " 'permission': 0,\n", - " 'source_ip_id': 0,\n", - " 'source_wildcard_id': 0,\n", - " 'source_port_id': 0,\n", - " 'dest_ip_id': 0,\n", - " 'dest_wildcard_id': 0,\n", - " 'dest_port_id': 0,\n", - " 'protocol_id': 0}},\n", - " 'PORTS': {1: {'operating_status': 1},\n", - " 2: {'operating_status': 1},\n", - " 3: {'operating_status': 2}},\n", - " 'users': {'local_login': 0, 'remote_sessions': 0}}},\n", - " 'LINKS': {1: {'PROTOCOLS': {'ALL': 1}},\n", - " 2: {'PROTOCOLS': {'ALL': 1}},\n", - " 3: {'PROTOCOLS': {'ALL': 0}},\n", - " 4: {'PROTOCOLS': {'ALL': 1}},\n", - " 5: {'PROTOCOLS': {'ALL': 1}},\n", - " 6: {'PROTOCOLS': {'ALL': 1}},\n", - " 7: {'PROTOCOLS': {'ALL': 1}},\n", - " 8: {'PROTOCOLS': {'ALL': 1}},\n", - " 9: {'PROTOCOLS': {'ALL': 1}},\n", - " 10: {'PROTOCOLS': {'ALL': 0}}},\n", - " 'ICS': 0},\n", - " {})" - ] - }, - "execution_count": 51, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "blue_env.reset()" ] }, { "cell_type": "code", - "execution_count": 52, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2279,7 +1179,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2296,30 +1196,9 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+------------------------------------------------------------------------------------------------------------------------+\n", - "| router_1 Access Control List |\n", - "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n", - "| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |\n", - "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n", - "| 1 | DENY | ANY | 192.168.10.21 | 0.0.0.1 | 80 | 192.168.1.12 | 0.0.0.1 | 80 | 0 |\n", - "| 18 | PERMIT | ANY | ANY | ANY | 5432 | ANY | ANY | 5432 | 0 |\n", - "| 19 | PERMIT | ANY | ANY | ANY | 53 | ANY | ANY | 53 | 0 |\n", - "| 20 | PERMIT | ANY | ANY | ANY | 21 | ANY | ANY | 21 | 0 |\n", - "| 21 | PERMIT | ANY | ANY | ANY | 80 | ANY | ANY | 80 | 4 |\n", - "| 22 | PERMIT | ANY | ANY | ANY | 219 | ANY | ANY | 219 | 10 |\n", - "| 23 | PERMIT | icmp | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", - "| 24 | DENY | ANY | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", - "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "router_1: Router = blue_env.game.simulation.network.get_node_by_hostname(\"router_1\")\n", "router_1.acl.show()" @@ -2334,20 +1213,9 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='failure', data={'Reason': 'Command sent to the C2 Beacon but no response was ever received.'})" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "blue_env.step(0)\n", "\n", @@ -2358,30 +1226,9 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+------------------------------------------------------------------------------------------------------------------------+\n", - "| router_1 Access Control List |\n", - "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n", - "| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |\n", - "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n", - "| 1 | DENY | ANY | 192.168.10.21 | 0.0.0.1 | 80 | 192.168.1.12 | 0.0.0.1 | 80 | 2 |\n", - "| 18 | PERMIT | ANY | ANY | ANY | 5432 | ANY | ANY | 5432 | 0 |\n", - "| 19 | PERMIT | ANY | ANY | ANY | 53 | ANY | ANY | 53 | 0 |\n", - "| 20 | PERMIT | ANY | ANY | ANY | 21 | ANY | ANY | 21 | 0 |\n", - "| 21 | PERMIT | ANY | ANY | ANY | 80 | ANY | ANY | 80 | 4 |\n", - "| 22 | PERMIT | ANY | ANY | ANY | 219 | ANY | ANY | 219 | 10 |\n", - "| 23 | PERMIT | icmp | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", - "| 24 | DENY | ANY | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", - "+-------+--------+----------+---------------+--------------+----------+--------------+--------------+----------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "router_1.acl.show()" ] @@ -2395,58 +1242,18 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------------------------------------------------------------------------------+\n", - "| web_server Software Manager |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| Name | Type | Operating State | Health State | Port | Protocol |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n", - "| arp | Service | RUNNING | GOOD | 219 | udp |\n", - "| icmp | Service | RUNNING | GOOD | None | icmp |\n", - "| dns-client | Service | RUNNING | GOOD | 53 | tcp |\n", - "| ntp-client | Service | RUNNING | GOOD | 123 | udp |\n", - "| web-browser | Application | RUNNING | GOOD | 80 | tcp |\n", - "| nmap | Application | RUNNING | GOOD | None | none |\n", - "| user-session-manager | Service | RUNNING | GOOD | None | none |\n", - "| user-manager | Service | RUNNING | GOOD | None | none |\n", - "| terminal | Service | RUNNING | GOOD | 22 | tcp |\n", - "| web-server | Service | RUNNING | GOOD | 80 | tcp |\n", - "| database-client | Application | RUNNING | GOOD | 5432 | tcp |\n", - "| c2-beacon | Application | RUNNING | GOOD | None | tcp |\n", - "+----------------------+-------------+-----------------+--------------+------+----------+\n" - ] - } - ], + "outputs": [], "source": [ "web_server.software_manager.show()" ] }, { "cell_type": "code", - "execution_count": 58, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------+\n", - "| database_server File System |\n", - "+----------------------+---------+---------------+-----------------------+---------+\n", - "| File Path | Size | Health status | Visible health status | Deleted |\n", - "+----------------------+---------+---------------+-----------------------+---------+\n", - "| database/database.db | 4.77 MB | GOOD | NONE | False |\n", - "| root | 0 B | GOOD | NONE | False |\n", - "+----------------------+---------+---------------+-----------------------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "database_server: Server = blue_env.game.simulation.network.get_node_by_hostname(\"database_server\")\n", "database_server.software_manager.file_system.show(full=True)" @@ -2454,33 +1261,9 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 3\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['inbound']: 1 -> 0\n", - "root['nodes']['HOST1']['NICS'][1]['TRAFFIC']['tcp'][21]['outbound']: 4 -> 0\n", - "root['nodes']['ROUTER0']['ACL'][1]['permission']: 0 -> 2\n", - "root['nodes']['ROUTER0']['ACL'][1]['source_ip_id']: 0 -> 7\n", - "root['nodes']['ROUTER0']['ACL'][1]['source_wildcard_id']: 0 -> 2\n", - "root['nodes']['ROUTER0']['ACL'][1]['source_port_id']: 0 -> 2\n", - "root['nodes']['ROUTER0']['ACL'][1]['dest_ip_id']: 0 -> 3\n", - "root['nodes']['ROUTER0']['ACL'][1]['dest_wildcard_id']: 0 -> 2\n", - "root['nodes']['ROUTER0']['ACL'][1]['dest_port_id']: 0 -> 2\n", - "root['nodes']['ROUTER0']['ACL'][1]['protocol_id']: 0 -> 1\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 1 -> 0\n", - "root['LINKS'][5]['PROTOCOLS']['ALL']: 4 -> 0\n", - "root['LINKS'][6]['PROTOCOLS']['ALL']: 4 -> 0\n" - ] - } - ], + "outputs": [], "source": [ "display_obs_diffs(pre_blue_action_obs, post_blue_action_obs, blue_env.game.step_counter)" ] @@ -2546,17 +1329,9 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:34,725: PrimaiteGymEnv RNG seed = None\n" - ] - } - ], + "outputs": [], "source": [ "with open(data_manipulation_config_path()) as f:\n", " cfg = yaml.safe_load(f)\n", @@ -2577,7 +1352,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2605,30 +1380,9 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", - "| c2-beacon Running Status |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| False | None | 0 | 5 | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "+-----------------------------------------------------------------------------------------------------+\n", - "| c2-server Running Status |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n", - "| False | None | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n" - ] - } - ], + "outputs": [], "source": [ "env.step(2) # Agent Action Equivalent to c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\")\n", "env.step(3) # Agent action Equivalent to c2_beacon.establish()\n", @@ -2645,30 +1399,9 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", - "| c2-beacon Running Status |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| False | None | 0 | 5 | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "+-----------------------------------------------------------------------------------------------------+\n", - "| c2-server Running Status |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n", - "| False | None | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n" - ] - } - ], + "outputs": [], "source": [ "env.step(9) # Equivalent of to c2_beacon.configure(c2_server_ip_address=\"192.168.10.22\")\n", "env.step(3)\n", @@ -2686,23 +1419,9 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+-----------------------------------------------------------------------------------------------------+\n", - "| c2-server Running Status |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n", - "| False | None | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------------+-------------------------+\n" - ] - } - ], + "outputs": [], "source": [ "for i in range(6):\n", " env.step(0)\n", @@ -2725,17 +1444,9 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:35,057: PrimaiteGymEnv RNG seed = None\n" - ] - } - ], + "outputs": [], "source": [ "with open(data_manipulation_config_path()) as f:\n", " cfg = yaml.safe_load(f)\n", @@ -2751,7 +1462,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2775,23 +1486,9 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", - "| c2-beacon Running Status |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| True | 192.168.10.21 | 0 | 5 | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n" - ] - } - ], + "outputs": [], "source": [ "c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\")\n", "c2_beacon.establish()\n", @@ -2809,72 +1506,9 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 4\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 5\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 6\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 7\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 8\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 9\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 10\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 11\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 12\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 13\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" - ] - } - ], + "outputs": [], "source": [ "for i in range(10):\n", " keep_alive_obs, _, _, _, _ = blue_config_env.step(0)\n", @@ -2890,23 +1524,9 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", - "| c2-beacon Running Status |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| True | 192.168.10.21 | 0 | 1 | tcp | 80 |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n" - ] - } - ], + "outputs": [], "source": [ "c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\", keep_alive_frequency=1)\n", "c2_beacon.establish()\n", @@ -2922,40 +1542,9 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 14\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 15\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" - ] - } - ], + "outputs": [], "source": [ "# Comparing the OBS of the default frequency to a timestep frequency of 1\n", "for i in range(2):\n", @@ -2974,52 +1563,9 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 16\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 17\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 18\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 19\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 20\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 21\n", - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 22\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" - ] - } - ], + "outputs": [], "source": [ "c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\", keep_alive_frequency=7)\n", "\n", @@ -3056,18 +1602,9 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 12:09:35,703: Resetting environment, episode 0, avg. reward: 0.0\n", - "2025-02-26 12:09:35,704: Saving agent action log to C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\sessions\\2025-02-26\\12-09-25\\agent_actions\\episode_0.json\n" - ] - } - ], + "outputs": [], "source": [ "blue_config_env.reset()\n", "\n", @@ -3089,28 +1626,9 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 5\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 0 -> 1\n", - "root['LINKS'][1]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][2]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][4]['PROTOCOLS']['ALL']: 0 -> 1\n", - "root['LINKS'][8]['PROTOCOLS']['ALL']: 0 -> 1\n" - ] - } - ], + "outputs": [], "source": [ "# Capturing default C2 Traffic\n", "for i in range(3):\n", @@ -3128,23 +1646,9 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------------------------------------------------------------------+\n", - "| c2-beacon Running Status |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| C2 Connection Active | C2 Remote Connection | Keep Alive Inactivity | Keep Alive Frequency | Current Masquerade Protocol | Current Masquerade Port |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n", - "| True | 192.168.10.21 | 0 | 5 | udp | 53 |\n", - "+----------------------+----------------------+-----------------------+----------------------+-----------------------------+-------------------------+\n" - ] - } - ], + "outputs": [], "source": [ "from primaite.utils.validation.ip_protocol import PROTOCOL_LOOKUP\n", "from primaite.utils.validation.port import PORT_LOOKUP\n", @@ -3157,28 +1661,9 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Observation space differences\n", - "-----------------------------\n", - "Step 10\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 1 -> 0\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 1 -> 0\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['udp'][53]['inbound']: 0 -> 1\n", - "root['nodes']['HOST0']['NICS'][1]['TRAFFIC']['udp'][53]['outbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['inbound']: 1 -> 0\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['tcp'][80]['outbound']: 1 -> 0\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['udp'][53]['inbound']: 0 -> 1\n", - "root['nodes']['HOST2']['NICS'][1]['TRAFFIC']['udp'][53]['outbound']: 0 -> 1\n" - ] - } - ], + "outputs": [], "source": [ "# Capturing UDP C2 Traffic\n", "for i in range(5):\n", From 891467d1d3291a4d778b30f8c5eab460cda91d11 Mon Sep 17 00:00:00 2001 From: Charlie Crane Date: Wed, 26 Feb 2025 15:44:06 +0000 Subject: [PATCH 5/8] Revert changes to Command & control and Privilege jupyter notebooks --- ...ommand-and-Control-E2E-Demonstration.ipynb | 3 +- ...ege-Escalation-and-Data-Loss-Example.ipynb | 403 +++--------------- .../_primaite/_game/_agent/test_agent.py | 1 + 3 files changed, 51 insertions(+), 356 deletions(-) diff --git a/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb b/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb index 19de56bf..7e64c3c5 100644 --- a/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb +++ b/src/primaite/notebooks/Command-and-Control-E2E-Demonstration.ipynb @@ -36,8 +36,7 @@ "from primaite.simulator.system.applications.red_applications.c2.abstract_c2 import C2Command\n", "from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript\n", "from primaite.simulator.network.hardware.nodes.host.computer import Computer\n", - "from primaite.simulator.network.hardware.nodes.host.server import Server\n", - "from primaite.game.agent.interface import ProxyAgent" + "from primaite.simulator.network.hardware.nodes.host.server import Server" ] }, { diff --git a/src/primaite/notebooks/Privilege-Escalation-and-Data-Loss-Example.ipynb b/src/primaite/notebooks/Privilege-Escalation-and-Data-Loss-Example.ipynb index 284cd9fd..4b4e253d 100644 --- a/src/primaite/notebooks/Privilege-Escalation-and-Data-Loss-Example.ipynb +++ b/src/primaite/notebooks/Privilege-Escalation-and-Data-Loss-Example.ipynb @@ -53,37 +53,16 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\notebooks\\example_notebooks\\Privilege-Escalation-and-Data-Loss-Example.ipynb\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2025-02-26 14:11:04,193: Performing the PrimAITE first-time setup...\n", - "2025-02-26 14:11:04,193: Building the PrimAITE app directories...\n", - "2025-02-26 14:11:04,193: Building primaite_config.yaml...\n", - "2025-02-26 14:11:04,193: Rebuilding the demo notebooks...\n", - "2025-02-26 14:11:04,226: Reset example notebook: C:\\Users\\CharlieCrane\\primaite\\4.0.0a1-dev\\notebooks\\example_notebooks\\Privilege-Escalation-and-Data-Loss-Example.ipynb\n", - "2025-02-26 14:11:04,246: Rebuilding the example notebooks...\n", - "2025-02-26 14:11:04,251: PrimAITE setup complete!\n" - ] - } - ], + "outputs": [], "source": [ "!primaite setup" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "tags": [] }, @@ -111,7 +90,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "tags": [] }, @@ -134,7 +113,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "tags": [] }, @@ -161,73 +140,33 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------------------------------------------------------+\n", - "| some_tech_storage_srv File System |\n", - "+-----------+------+---------------+-----------------------+---------+\n", - "| File Path | Size | Health status | Visible health status | Deleted |\n", - "+-----------+------+---------------+-----------------------+---------+\n", - "| root | 0 B | GOOD | NONE | False |\n", - "+-----------+------+---------------+-----------------------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "some_tech_storage_srv.file_system.show(full=True)" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "some_tech_db_service.backup_database()" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------------------------------------------------------------------------------------------------+\n", - "| some_tech_storage_srv File System |\n", - "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n", - "| File Path | Size | Health status | Visible health status | Deleted |\n", - "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n", - "| ed8587f2-7100-4837-bfbb-2a06bfafa8db/database.db | 4.77 MB | GOOD | NONE | False |\n", - "| root | 0 B | GOOD | NONE | False |\n", - "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "some_tech_storage_srv.file_system.show(full=True)" ] @@ -241,22 +180,11 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "'ed8587f2-7100-4837-bfbb-2a06bfafa8db'" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "db_backup_folder = [folder.name for folder in some_tech_storage_srv.file_system.folders.values() if folder.name != \"root\"][0]\n", "db_backup_folder" @@ -275,22 +203,11 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='failure', data={})" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -310,22 +227,11 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={})" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "caos_action = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n", "game.simulation.apply_request(caos_action)" @@ -346,42 +252,20 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "game.get_sim_state()[\"network\"][\"nodes\"][\"some_tech_rt\"][\"services\"][\"user-session-manager\"][\"active_remote_sessions\"]" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={'ip_address': '10.10.2.1', 'username': 'admin'})" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -392,22 +276,11 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "['ee4b75dc-1f70-4f93-a25f-d0466afecfd9']" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "game.get_sim_state()[\"network\"][\"nodes\"][\"some_tech_rt\"][\"services\"][\"user-session-manager\"][\"active_remote_sessions\"]" ] @@ -423,59 +296,22 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------------------------------------------------------------------------------------------------------------+\n", - "| some_tech_rt Access Control List |\n", - "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n", - "| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |\n", - "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n", - "| 11 | PERMIT | ANY | 94.10.180.6 | 0.0.0.0 | 5432 | 10.10.1.11 | 0.0.0.0 | 5432 | 2 |\n", - "| 12 | PERMIT | ANY | 10.10.1.11 | 0.0.0.0 | 5432 | 94.10.180.6 | 0.0.0.0 | 5432 | 2 |\n", - "| 13 | DENY | ANY | 10.10.2.12 | 0.0.0.0 | 21 | 10.10.1.12 | 0.0.0.0 | 21 | 0 |\n", - "| 14 | DENY | ANY | 10.10.2.12 | 0.0.0.0 | 22 | 10.10.1.12 | 0.0.0.0 | 22 | 1 |\n", - "| 15 | PERMIT | ANY | 10.10.2.0 | 0.0.0.255 | ANY | 10.10.1.0 | 0.0.0.255 | ANY | 0 |\n", - "| 16 | PERMIT | ANY | 10.10.1.0 | 0.0.0.255 | ANY | 10.10.2.0 | 0.0.0.255 | ANY | 0 |\n", - "| 17 | PERMIT | ANY | ANY | ANY | 80 | ANY | ANY | 80 | 2 |\n", - "| 18 | PERMIT | ANY | 10.10.0.0 | 0.0.255.255 | 219 | ANY | ANY | ANY | 7 |\n", - "| 19 | PERMIT | icmp | 10.10.0.0 | 0.0.255.255 | ANY | ANY | ANY | ANY | 0 |\n", - "| 21 | PERMIT | ANY | 94.10.180.6 | 0.0.0.0 | 80 | 10.10.0.0 | 0.0.255.255 | 80 | 0 |\n", - "| 22 | PERMIT | ANY | ANY | ANY | 53 | ANY | ANY | 53 | 2 |\n", - "| 23 | PERMIT | ANY | ANY | ANY | 22 | ANY | ANY | 22 | 1 |\n", - "| 24 | DENY | ANY | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", - "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "some_tech_rt.acl.show()" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={})" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -504,38 +340,11 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------------------------------------------------------------------------------------------------------------+\n", - "| some_tech_rt Access Control List |\n", - "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n", - "| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |\n", - "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n", - "| 1 | PERMIT | tcp | 10.10.2.12 | 0.0.0.0 | 22 | 10.10.1.12 | 0.0.0.0 | 22 | 0 |\n", - "| 11 | PERMIT | ANY | 94.10.180.6 | 0.0.0.0 | 5432 | 10.10.1.11 | 0.0.0.0 | 5432 | 2 |\n", - "| 12 | PERMIT | ANY | 10.10.1.11 | 0.0.0.0 | 5432 | 94.10.180.6 | 0.0.0.0 | 5432 | 2 |\n", - "| 13 | DENY | ANY | 10.10.2.12 | 0.0.0.0 | 21 | 10.10.1.12 | 0.0.0.0 | 21 | 0 |\n", - "| 14 | DENY | ANY | 10.10.2.12 | 0.0.0.0 | 22 | 10.10.1.12 | 0.0.0.0 | 22 | 1 |\n", - "| 15 | PERMIT | ANY | 10.10.2.0 | 0.0.0.255 | ANY | 10.10.1.0 | 0.0.0.255 | ANY | 0 |\n", - "| 16 | PERMIT | ANY | 10.10.1.0 | 0.0.0.255 | ANY | 10.10.2.0 | 0.0.0.255 | ANY | 0 |\n", - "| 17 | PERMIT | ANY | ANY | ANY | 80 | ANY | ANY | 80 | 2 |\n", - "| 18 | PERMIT | ANY | 10.10.0.0 | 0.0.255.255 | 219 | ANY | ANY | ANY | 7 |\n", - "| 19 | PERMIT | icmp | 10.10.0.0 | 0.0.255.255 | ANY | ANY | ANY | ANY | 0 |\n", - "| 21 | PERMIT | ANY | 94.10.180.6 | 0.0.0.0 | 80 | 10.10.0.0 | 0.0.255.255 | 80 | 0 |\n", - "| 22 | PERMIT | ANY | ANY | ANY | 53 | ANY | ANY | 53 | 2 |\n", - "| 23 | PERMIT | ANY | ANY | ANY | 22 | ANY | ANY | 22 | 2 |\n", - "| 24 | DENY | ANY | ANY | ANY | ANY | ANY | ANY | ANY | 0 |\n", - "+-------+--------+----------+-------------+--------------+----------+-------------+--------------+----------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "some_tech_rt.acl.show()" ] @@ -551,22 +360,11 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={})" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -584,20 +382,9 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "game.get_sim_state()[\"network\"][\"nodes\"][\"some_tech_rt\"][\"services\"][\"user-session-manager\"][\"active_remote_sessions\"]" ] @@ -613,20 +400,9 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={'ip_address': '10.10.1.12', 'username': 'admin'})" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -637,22 +413,11 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={})" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "caos_action = [\n", " \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n", @@ -676,26 +441,11 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------------------------------------------------------------------------------------------------+\n", - "| some_tech_storage_srv File System |\n", - "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n", - "| File Path | Size | Health status | Visible health status | Deleted |\n", - "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n", - "| ed8587f2-7100-4837-bfbb-2a06bfafa8db/database.db | 4.77 MB | GOOD | NONE | True |\n", - "| root | 0 B | GOOD | NONE | False |\n", - "+--------------------------------------------------+---------+---------------+-----------------------+---------+\n" - ] - } - ], + "outputs": [], "source": [ "some_tech_storage_srv.file_system.show(full=True)" ] @@ -720,22 +470,11 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='success', data={})" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "caos_action = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n", "game.simulation.apply_request(caos_action)" @@ -750,22 +489,11 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "DatabaseClientConnection(connection_id='cb712d1e-68d2-4504-94a2-8c67d3652ccd', is_active=True)" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "some_tech_jnr_dev_db_client.server_ip_address = some_tech_db_srv.network_interface[1].ip_address\n", "some_tech_jnr_dev_db_connection = some_tech_jnr_dev_db_client.get_new_connection()\n", @@ -783,22 +511,11 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "some_tech_jnr_dev_db_connection.query(\"DELETE\")" ] @@ -812,22 +529,11 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "RequestResponse(status='failure', data={})" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "caos_action = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n", "game.simulation.apply_request(caos_action)" @@ -844,22 +550,11 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "some_tech_db_service.restore_backup()" ] diff --git a/tests/unit_tests/_primaite/_game/_agent/test_agent.py b/tests/unit_tests/_primaite/_game/_agent/test_agent.py index b555f1b2..a185ae42 100644 --- a/tests/unit_tests/_primaite/_game/_agent/test_agent.py +++ b/tests/unit_tests/_primaite/_game/_agent/test_agent.py @@ -1,3 +1,4 @@ +# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK from primaite.game.agent.observations.file_system_observations import FileObservation from primaite.game.agent.observations.observation_manager import NullObservation from primaite.game.agent.scripted_agents.random_agent import RandomAgent From 1f6f0079417774e38a3f5e232b32f377ad8e515d Mon Sep 17 00:00:00 2001 From: Charlie Crane Date: Thu, 27 Feb 2025 18:16:45 +0000 Subject: [PATCH 6/8] Updates to documentation and inclusion of how-to guides --- CHANGELOG.md | 1 + docs/index.rst | 4 ++ .../how_to_guides/custom_environments.rst | 16 +++++++- docs/source/how_to_guides/custom_rewards.rst | 2 + .../how_to_guides/extensible_actions.rst | 2 +- .../network/base_hardware.rst | 32 ++++++++------- .../simulation_components/network/network.rst | 28 +++++++------ .../system/applications/c2_suite.rst | 8 ++-- .../applications/data_manipulation_bot.rst | 13 +++--- .../system/applications/database_client.rst | 13 +++--- .../system/applications/dos_bot.rst | 13 +++--- .../system/applications/nmap.rst | 40 ++++++++++--------- .../system/applications/ransomware_script.rst | 13 +++--- .../system/applications/web_browser.rst | 13 +++--- .../system/services/database_service.rst | 13 +++--- .../system/services/dns_client.rst | 13 +++--- .../system/services/dns_server.rst | 13 +++--- .../system/services/ftp_client.rst | 13 +++--- .../system/services/ftp_server.rst | 13 +++--- .../system/services/ntp_client.rst | 13 +++--- .../system/services/ntp_server.rst | 13 +++--- .../system/services/terminal.rst | 29 +++++++------- .../system/services/web_server.rst | 13 +++--- .../simulation_components/system/software.rst | 2 +- .../Data-Manipulation-E2E-Demonstration.ipynb | 4 +- 25 files changed, 188 insertions(+), 149 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f87f54e..e4fb0172 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated tests that don't use YAMLs to still use the new action and agent schemas - Nodes now use a config schema and are extensible, allowing for plugin support. - Node tests have been updated to use the new node config schemas when not using YAML files. +- Documentation has been updated to include details of extensability with PrimAITE. ### Fixed - DNS client no longer fails to check its cache if a DNS server address is missing. diff --git a/docs/index.rst b/docs/index.rst index 53d2e1b3..00ace007 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -28,6 +28,10 @@ What is PrimAITE? source/how_to_guides/custom_rewards source/how_to_guides/custom_software source/how_to_guides/using_dev_cli + source/how_to_guides/extensible_actions + source/how_to_guides/extensible_agents + source/how_to_guides/extensible_nodes + source/how_to_guides/extensible_rewards .. toctree:: :caption: Usage: diff --git a/docs/source/how_to_guides/custom_environments.rst b/docs/source/how_to_guides/custom_environments.rst index 23c70d85..f4d49810 100644 --- a/docs/source/how_to_guides/custom_environments.rst +++ b/docs/source/how_to_guides/custom_environments.rst @@ -16,6 +16,10 @@ You configuration file should follow the hierarchy seen below: metadata: version: 4.0 + required_plugins: + - name: Example_Plugin + version: 1.0 + io_settings: ... game: @@ -25,9 +29,17 @@ You configuration file should follow the hierarchy seen below: simulation: ... -MetaData Tag -============ +MetaData +======== It's important to include the metadata tag within your YAML file, as this is used to ensure PrimAITE can interpret the configuration correctly. This should also include any plugins that are required for the defined environment, along with their respective version. +Required Plugins +================ + +Should your custom environment need any additional PrimAITE plugins, each must be specified under the `required_plugins` tab, as seen in the above example. + +Configuration Items +=================== + For detailed information about the remaining configuration items found within the configuration file, see :ref:`Configurable Items`. diff --git a/docs/source/how_to_guides/custom_rewards.rst b/docs/source/how_to_guides/custom_rewards.rst index 22b1de30..93bea700 100644 --- a/docs/source/how_to_guides/custom_rewards.rst +++ b/docs/source/how_to_guides/custom_rewards.rst @@ -9,6 +9,8 @@ Creating Custom Rewards in PrimAITE Rewards within PrimAITE are contained within ``rewards.py``, which details the rewards available for all agents within training sessions, how they are calculated and any other specific information where necessary. +Rewards within PrimAITE have been updated to facilitate extensability and the creation of plugins with the release of PrimAITE version 4.0. Additional information about this is covered within :ref:`extensible_rewards`. + Custom Rewards within PrimAITE should inherit from the ``AbstractReward`` class, found in ``rewards.py``. It's important to include an identifier for any class created within PrimAITE. .. code:: Python diff --git a/docs/source/how_to_guides/extensible_actions.rst b/docs/source/how_to_guides/extensible_actions.rst index fe61949b..5649428d 100644 --- a/docs/source/how_to_guides/extensible_actions.rst +++ b/docs/source/how_to_guides/extensible_actions.rst @@ -65,4 +65,4 @@ The above action would fail pydantic validation as the discriminator "node-folde form_request method ################### -PrimAITE actions need to have a `form_request` method, which can be passed to the `RequestManager` for processing. This allows the custom action to be actioned within the simulation environment. +PrimAITE actions need to have a `form_request` method, which can be passed to the `RequestManager` for processing. This allows the custom action to be actioned within the simulation environment. Further information and an example of this can be seen in :ref:`custom_actions`. diff --git a/docs/source/simulation_components/network/base_hardware.rst b/docs/source/simulation_components/network/base_hardware.rst index 8b325ffc..e60831e2 100644 --- a/docs/source/simulation_components/network/base_hardware.rst +++ b/docs/source/simulation_components/network/base_hardware.rst @@ -42,7 +42,7 @@ Example code where a node is turned on: from primaite.simulator.network.hardware.base import Node from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState - node = Node(hostname="pc_a") + node = Node(config={"hostname":"pc_a"}) assert node.operating_state is NodeOperatingState.OFF # By default, node is instantiated in an OFF state @@ -65,7 +65,7 @@ If the node needs to be instantiated in an on state: from primaite.simulator.network.hardware.base import Node from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState - node = Node(hostname="pc_a", operating_state=NodeOperatingState.ON) + node = Node(config={"hostname":"pc_a", "operating_state":NodeOperatingState.ON}) assert node.operating_state is NodeOperatingState.ON # node is in ON state @@ -76,7 +76,7 @@ Setting ``start_up_duration`` and/or ``shut_down_duration`` to ``0`` will allow from primaite.simulator.network.hardware.base import Node from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState - node = Node(hostname="pc_a", start_up_duration=0, shut_down_duration=0) + node = Node(config={"hostname":"pc_a", "start_up_duration":0, "shut_down_duration":0}) assert node.operating_state is NodeOperatingState.OFF # node is in OFF state @@ -196,21 +196,23 @@ Setting up a Client-Server Network def client_server_network() -> Tuple[Computer, Server, Network]: network = Network() - client = Computer( - hostname="client", - ip_address="192.168.1.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + client = Computer(config={ + "hostname":"client", + "ip_address":"192.168.1.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) client.power_on() - server = Server( - hostname="server", - ip_address="192.168.1.3", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + server = Server(config = { + "hostname":"server", + "ip_address":"192.168.1.3", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) server.power_on() diff --git a/docs/source/simulation_components/network/network.rst b/docs/source/simulation_components/network/network.rst index 152b74b8..95bfb9fe 100644 --- a/docs/source/simulation_components/network/network.rst +++ b/docs/source/simulation_components/network/network.rst @@ -48,7 +48,7 @@ we'll use the following Network that has a client, server, two switches, and a r .. code-block:: python - router_1 = Router(hostname="router_1", num_ports=3) + router_1 = Router(config={"hostname":"router_1", "num_ports":3}) router_1.power_on() router_1.configure_port(port=1, ip_address="192.168.1.1", subnet_mask="255.255.255.0") router_1.configure_port(port=2, ip_address="192.168.2.1", subnet_mask="255.255.255.0") @@ -57,9 +57,9 @@ we'll use the following Network that has a client, server, two switches, and a r .. code-block:: python - switch_1 = Switch(hostname="switch_1", num_ports=6) + switch_1 = Switch(config={"hostname":"switch_1", "num_ports":6}) switch_1.power_on() - switch_2 = Switch(hostname="switch_2", num_ports=6) + switch_2 = Switch(config={"hostname":"switch_2", "num_ports":6}) switch_2.power_on() 5. Connect the Switches to the Router @@ -75,18 +75,20 @@ we'll use the following Network that has a client, server, two switches, and a r .. code-block:: python - client_1 = Computer( - hostname="client_1", - ip_address="192.168.2.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.2.1" + client_1 = Computer(config = { + "hostname":"client_1", + "ip_address":"192.168.2.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.2.1", + } ) client_1.power_on() - server_1 = Server( - hostname="server_1", - ip_address="192.168.1.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1" + server_1 = Server(config= { + "hostname":"server_1", + "ip_address":"192.168.1.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + } ) server_1.power_on() diff --git a/docs/source/simulation_components/system/applications/c2_suite.rst b/docs/source/simulation_components/system/applications/c2_suite.rst index 34175fc3..ce083406 100644 --- a/docs/source/simulation_components/system/applications/c2_suite.rst +++ b/docs/source/simulation_components/system/applications/c2_suite.rst @@ -128,19 +128,19 @@ Python network = Network() - switch = Switch(hostname="switch", start_up_duration=0, num_ports=4) + switch = Switch(config={"hostname":"switch", "start_up_duration":0, "num_ports":4}) switch.power_on() - node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) + node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_a.power_on() network.connect(node_a.network_interface[1], switch.network_interface[1]) - node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) + node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_b.power_on() network.connect(node_b.network_interface[1], switch.network_interface[2]) - node_c = Computer(hostname="node_c", ip_address="192.168.0.12", subnet_mask="255.255.255.0", start_up_duration=0) + node_c = Computer(config={"hostname":"node_c", "ip_address":"192.168.0.12", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_c.power_on() network.connect(node_c.network_interface[1], switch.network_interface[3]) diff --git a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst index 8e008504..053ad8d7 100644 --- a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst +++ b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst @@ -67,12 +67,13 @@ Python from primaite.simulator.system.applications.red_applications.data_manipulation_bot import DataManipulationBot from primaite.simulator.system.applications.database_client import DatabaseClient - client_1 = Computer( - hostname="client_1", - ip_address="192.168.10.21", - subnet_mask="255.255.255.0", - default_gateway="192.168.10.1", - operating_state=NodeOperatingState.ON # initialise the computer in an ON state + client_1 = Computer(config={ + "hostname":"client_1", + "ip_address":"192.168.10.21", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.10.1", + "operating_state":NodeOperatingState.ON # initialise the computer in an ON state + } ) network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.network_interface[1]) client_1.software_manager.install(DatabaseClient) diff --git a/docs/source/simulation_components/system/applications/database_client.rst b/docs/source/simulation_components/system/applications/database_client.rst index 7087dedf..341876fe 100644 --- a/docs/source/simulation_components/system/applications/database_client.rst +++ b/docs/source/simulation_components/system/applications/database_client.rst @@ -48,12 +48,13 @@ Python from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.system.applications.database_client import DatabaseClient - client = Computer( - hostname="client", - ip_address="192.168.10.21", - subnet_mask="255.255.255.0", - default_gateway="192.168.10.1", - operating_state=NodeOperatingState.ON # initialise the computer in an ON state + client_1 = Computer(config={ + "hostname":"client_1", + "ip_address":"192.168.10.21", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.10.1", + "operating_state":NodeOperatingState.ON # initialise the computer in an ON state + } ) # install DatabaseClient diff --git a/docs/source/simulation_components/system/applications/dos_bot.rst b/docs/source/simulation_components/system/applications/dos_bot.rst index 47b72be7..e6e03cfe 100644 --- a/docs/source/simulation_components/system/applications/dos_bot.rst +++ b/docs/source/simulation_components/system/applications/dos_bot.rst @@ -45,12 +45,13 @@ Python from primaite.simulator.system.applications.red_applications.dos_bot import dos-bot # Create Computer - computer = Computer( - hostname="computer", - ip_address="192.168.1.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + computer = Computer(config={ + "hostname":"computer", + "ip_address":"192.168.1.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) computer.power_on() diff --git a/docs/source/simulation_components/system/applications/nmap.rst b/docs/source/simulation_components/system/applications/nmap.rst index a82735c8..06badf7e 100644 --- a/docs/source/simulation_components/system/applications/nmap.rst +++ b/docs/source/simulation_components/system/applications/nmap.rst @@ -70,39 +70,41 @@ The network we use for these examples is defined below: router.configure_port(port=1, ip_address="192.168.1.1", subnet_mask="255.255.255.0") # Set up PC 1 - pc_1 = Computer( - hostname="pc_1", - ip_address="192.168.1.11", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0 + pc_1 = Computer(config = { + "hostname":"pc_1", + "ip_address":"192.168.1.11", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) pc_1.power_on() # Set up PC 2 - pc_2 = Computer( - hostname="pc_2", - ip_address="192.168.1.12", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0 + pc_2 = Computer(config = { + "hostname":"pc_2", + "ip_address":"192.168.1.12", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) pc_2.power_on() pc_2.software_manager.install(DatabaseService) pc_2.software_manager.software["DatabaseService"].start() # start the postgres server # Set up PC 3 - pc_3 = Computer( - hostname="pc_3", - ip_address="192.168.1.13", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0 + pc_3 = Computer(config = { + "hostname";"pc_3", + "ip_address":"192.168.1.13", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0 ) # Don't power on PC 3 # Set up the switch - switch = Switch(hostname="switch", start_up_duration=0) + switch = Switch(config={"hostname":"switch", "start_up_duration":0}) switch.power_on() # Connect devices diff --git a/docs/source/simulation_components/system/applications/ransomware_script.rst b/docs/source/simulation_components/system/applications/ransomware_script.rst index 192618fc..517167fd 100644 --- a/docs/source/simulation_components/system/applications/ransomware_script.rst +++ b/docs/source/simulation_components/system/applications/ransomware_script.rst @@ -52,12 +52,13 @@ Python from primaite.simulator.system.applications.red_applications.RansomwareScript import RansomwareScript from primaite.simulator.system.applications.database_client import DatabaseClient - client_1 = Computer( - hostname="client_1", - ip_address="192.168.10.21", - subnet_mask="255.255.255.0", - default_gateway="192.168.10.1", - operating_state=NodeOperatingState.ON # initialise the computer in an ON state + client_1 = Computer(config={ + "hostname":"client_1", + "ip_address":"192.168.10.21", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.10.1", + "operating_state":NodeOperatingState.ON # initialise the computer in an ON state + } ) network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.network_interface[1]) client_1.software_manager.install(DatabaseClient) diff --git a/docs/source/simulation_components/system/applications/web_browser.rst b/docs/source/simulation_components/system/applications/web_browser.rst index c04e60af..36290235 100644 --- a/docs/source/simulation_components/system/applications/web_browser.rst +++ b/docs/source/simulation_components/system/applications/web_browser.rst @@ -50,12 +50,13 @@ The :ref:`DNSClient` must be configured to use the :ref:`DNSServer`. The :ref:`D from primaite.simulator.system.applications.web_browser import WebBrowser # Create Computer - computer = Computer( - hostname="computer", - ip_address="192.168.1.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + computer = Computer(config={ + "hostname":"computer", + "ip_address":"192.168.1.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) computer.power_on() diff --git a/docs/source/simulation_components/system/services/database_service.rst b/docs/source/simulation_components/system/services/database_service.rst index 961f2e45..d071a5c4 100644 --- a/docs/source/simulation_components/system/services/database_service.rst +++ b/docs/source/simulation_components/system/services/database_service.rst @@ -55,12 +55,13 @@ Python from primaite.simulator.system.services.database.database_service import DatabaseService # Create Server - server = Server( - hostname="server", - ip_address="192.168.2.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + server = Server(config = { + "hostname":"server", + "ip_address":"192.168.2.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) server.power_on() diff --git a/docs/source/simulation_components/system/services/dns_client.rst b/docs/source/simulation_components/system/services/dns_client.rst index 17a1ed25..aa99bc0e 100644 --- a/docs/source/simulation_components/system/services/dns_client.rst +++ b/docs/source/simulation_components/system/services/dns_client.rst @@ -45,12 +45,13 @@ Python from primaite.simulator.system.services.dns.dns_client import DNSClient # Create Server - server = Server( - hostname="server", - ip_address="192.168.2.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + server = Server(config = { + "hostname":"server", + "ip_address":"192.168.2.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) server.power_on() diff --git a/docs/source/simulation_components/system/services/dns_server.rst b/docs/source/simulation_components/system/services/dns_server.rst index 633221d5..787b2a70 100644 --- a/docs/source/simulation_components/system/services/dns_server.rst +++ b/docs/source/simulation_components/system/services/dns_server.rst @@ -42,12 +42,13 @@ Python from primaite.simulator.system.services.dns.dns_server import DNSServer # Create Server - server = Server( - hostname="server", - ip_address="192.168.2.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + server = Server(config = { + "hostname":"server", + "ip_address":"192.168.2.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) server.power_on() diff --git a/docs/source/simulation_components/system/services/ftp_client.rst b/docs/source/simulation_components/system/services/ftp_client.rst index d4375069..b8b493bd 100644 --- a/docs/source/simulation_components/system/services/ftp_client.rst +++ b/docs/source/simulation_components/system/services/ftp_client.rst @@ -49,12 +49,13 @@ Python from primaite.simulator.system.services.ftp.ftp_client import FTPClient # Create Server - server = Server( - hostname="server", - ip_address="192.168.2.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.10", - start_up_duration=0, + server = Server(config = { + "hostname":"server", + "ip_address":"192.168.2.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.10", + "start_up_duration":0, + } ) server.power_on() diff --git a/docs/source/simulation_components/system/services/ftp_server.rst b/docs/source/simulation_components/system/services/ftp_server.rst index a5ad32fe..df080125 100644 --- a/docs/source/simulation_components/system/services/ftp_server.rst +++ b/docs/source/simulation_components/system/services/ftp_server.rst @@ -44,12 +44,13 @@ Python from primaite.simulator.system.services.ftp.ftp_server import FTPServer # Create Server - server = Server( - hostname="server", - ip_address="192.168.2.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + server = Server(config = { + "hostname":"server", + "ip_address":"192.168.2.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.10", + "start_up_duration":0, + } ) server.power_on() diff --git a/docs/source/simulation_components/system/services/ntp_client.rst b/docs/source/simulation_components/system/services/ntp_client.rst index 8c011cad..22ae4516 100644 --- a/docs/source/simulation_components/system/services/ntp_client.rst +++ b/docs/source/simulation_components/system/services/ntp_client.rst @@ -42,12 +42,13 @@ Python from primaite.simulator.system.services.ntp.ntp_client import NTPClient # Create Server - server = Server( - hostname="server", - ip_address="192.168.2.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + server = Server(config = { + "hostname":"server", + "ip_address":"192.168.2.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.10", + "start_up_duration":0, + } ) server.power_on() diff --git a/docs/source/simulation_components/system/services/ntp_server.rst b/docs/source/simulation_components/system/services/ntp_server.rst index c1d16d61..784aac0c 100644 --- a/docs/source/simulation_components/system/services/ntp_server.rst +++ b/docs/source/simulation_components/system/services/ntp_server.rst @@ -44,12 +44,13 @@ Python from primaite.simulator.system.services.ntp.ntp_server import NTPServer # Create Server - server = Server( - hostname="server", - ip_address="192.168.2.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + server = Server(config = { + "hostname":"server", + "ip_address":"192.168.2.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.10", + "start_up_duration":0, + } ) server.power_on() diff --git a/docs/source/simulation_components/system/services/terminal.rst b/docs/source/simulation_components/system/services/terminal.rst index bc5cee48..1fec3b53 100644 --- a/docs/source/simulation_components/system/services/terminal.rst +++ b/docs/source/simulation_components/system/services/terminal.rst @@ -57,12 +57,13 @@ Python from primaite.simulator.system.services.terminal.terminal import Terminal from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState - client = Computer( - hostname="client", - ip_address="192.168.10.21", - subnet_mask="255.255.255.0", - default_gateway="192.168.10.1", - operating_state=NodeOperatingState.ON, + client = Computer(config= { + "hostname":"client", + "ip_address":"192.168.10.21", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.10.1", + "operating_state":NodeOperatingState.ON, + } ) terminal: Terminal = client.software_manager.software.get("Terminal") @@ -80,9 +81,9 @@ Creating Remote Terminal Connection network = Network() - node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) + node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_a.power_on() - node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) + node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_b.power_on() network.connect(node_a.network_interface[1], node_b.network_interface[1]) @@ -106,9 +107,9 @@ Executing a basic application install command network = Network() - node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) + node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_a.power_on() - node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) + node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_b.power_on() network.connect(node_a.network_interface[1], node_b.network_interface[1]) @@ -134,9 +135,9 @@ Creating a folder on a remote node network = Network() - node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) + node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_a.power_on() - node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) + node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_b.power_on() network.connect(node_a.network_interface[1], node_b.network_interface[1]) @@ -161,9 +162,9 @@ Disconnect from Remote Node network = Network() - node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) + node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_a.power_on() - node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) + node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0}) node_b.power_on() network.connect(node_a.network_interface[1], node_b.network_interface[1]) diff --git a/docs/source/simulation_components/system/services/web_server.rst b/docs/source/simulation_components/system/services/web_server.rst index bce42791..dc7ebd4b 100644 --- a/docs/source/simulation_components/system/services/web_server.rst +++ b/docs/source/simulation_components/system/services/web_server.rst @@ -45,12 +45,13 @@ Python from primaite.simulator.system.services.web_server.web_server import WebServer # Create Server - server = Server( - hostname="server", - ip_address="192.168.2.2", - subnet_mask="255.255.255.0", - default_gateway="192.168.1.1", - start_up_duration=0, + server = Server(config = { + "hostname":"server", + "ip_address":"192.168.2.2", + "subnet_mask":"255.255.255.0", + "default_gateway":"192.168.1.1", + "start_up_duration":0, + } ) server.power_on() diff --git a/docs/source/simulation_components/system/software.rst b/docs/source/simulation_components/system/software.rst index d28815bb..be284af1 100644 --- a/docs/source/simulation_components/system/software.rst +++ b/docs/source/simulation_components/system/software.rst @@ -23,7 +23,7 @@ See :ref:`Node Start up and Shut down` from primaite.simulator.system.services.service import ServiceOperatingState from primaite.simulator.system.services.web_server.web_server import WebServer - node = Node(hostname="pc_a", start_up_duration=0, shut_down_duration=0) + node = Node(config={"hostname":"pc_a", "start_up_duration":0, "shut_down_duration":0}) node.power_on() assert node.operating_state is NodeOperatingState.ON diff --git a/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb b/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb index 31e1f9d3..9d9fb654 100644 --- a/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb +++ b/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb @@ -703,7 +703,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -717,7 +717,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.11" } }, "nbformat": 4, From 5609dc8d0772bed1a6dfbca080bdcd4de0c1df24 Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Fri, 28 Feb 2025 11:13:23 +0000 Subject: [PATCH 7/8] Appease precommit --- .../configuration_file_parsing/test_node_file_system_config.py | 2 +- .../game_layer/actions/test_user_account_actions.py | 2 +- .../game_layer/observations/test_obs_data_capture.py | 2 +- tests/integration_tests/system/test_arp.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/integration_tests/configuration_file_parsing/test_node_file_system_config.py b/tests/integration_tests/configuration_file_parsing/test_node_file_system_config.py index 4c99a39f..f4f96a7a 100644 --- a/tests/integration_tests/configuration_file_parsing/test_node_file_system_config.py +++ b/tests/integration_tests/configuration_file_parsing/test_node_file_system_config.py @@ -1,4 +1,4 @@ -# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK +# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK from pathlib import Path from typing import Union diff --git a/tests/integration_tests/game_layer/actions/test_user_account_actions.py b/tests/integration_tests/game_layer/actions/test_user_account_actions.py index 26b871db..340a093a 100644 --- a/tests/integration_tests/game_layer/actions/test_user_account_actions.py +++ b/tests/integration_tests/game_layer/actions/test_user_account_actions.py @@ -1,4 +1,4 @@ -# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK +# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK import pytest from primaite.simulator.network.hardware.nodes.host.computer import Computer diff --git a/tests/integration_tests/game_layer/observations/test_obs_data_capture.py b/tests/integration_tests/game_layer/observations/test_obs_data_capture.py index e8bdea22..f0143281 100644 --- a/tests/integration_tests/game_layer/observations/test_obs_data_capture.py +++ b/tests/integration_tests/game_layer/observations/test_obs_data_capture.py @@ -1,4 +1,4 @@ -# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK +# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK import json from primaite.session.environment import PrimaiteGymEnv diff --git a/tests/integration_tests/system/test_arp.py b/tests/integration_tests/system/test_arp.py index b9a92255..85fa3abd 100644 --- a/tests/integration_tests/system/test_arp.py +++ b/tests/integration_tests/system/test_arp.py @@ -1,4 +1,4 @@ -# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK +# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router, RouterARP from primaite.simulator.system.services.arp.arp import ARP from primaite.utils.validation.port import PORT_LOOKUP From 92af387e564b1e6636855cf7af3d15166293c910 Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Fri, 28 Feb 2025 15:35:06 +0000 Subject: [PATCH 8/8] Remove buggy autoreload from notebook --- .../Data-Manipulation-E2E-Demonstration.ipynb | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb b/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb index d9ca6411..41bbf569 100644 --- a/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb +++ b/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb @@ -380,18 +380,6 @@ "!primaite setup" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, { "cell_type": "code", "execution_count": null, @@ -712,7 +700,7 @@ ], "metadata": { "kernelspec": { - "display_name": ".venv", + "display_name": "venv2", "language": "python", "name": "python3" }, @@ -726,7 +714,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.11" + "version": "3.11.10" } }, "nbformat": 4,