Merged PR 589: Extensible Agents and Actions
## Summary This PR is a follow-on from Charlie's two branches, one for agents and one for actions. This list of changes describes work done by both Charlie and myself - Agents are now extensible - Refactored observation manager, action manager, and reward function to inherit from BaseModel - Added a config schema to observation manager, action manager, and reward function - Streamlined the way agents are created from config - Agent config no longer requires a dummy action space if the action space is empty, the same applies for observation space and reward function - Actions are now extensible - Actions now support a config schema, to allow yaml data validation and default parameter values - Action parameters are no longer defined through IDs, instead meaningful data is expected directly in the action map - Test and example YAMLs have been updated to match the new agent and action schemas, such as: - Removed empty action spaces, observation spaces, or reward spaces for agent which didn't use them - Relabeled action parameters to match the new action config schemas, and updated the values to no longer rely on indices - Removed action space options which were previously used for assigning meaning to action space IDs - Updated tests that don't use YAMLs to still use the new action and agent schemas - I haven't checked the notebooks run and there's a couple places where find-and-replace issues persist. I will fix but we can start review in the meantime if you're bored ## Test process unit test ## Checklist - [X] PR is linked to a **work item** - [ ] **acceptance criteria** of linked ticket are met - [X] performed **self-review** of the code - [X] written **tests** for any new functionality added with this PR - [ ] updated the **documentation** if this PR changes or adds functionality - [ ] written/updated **design docs** if this PR implements new functionality - [X] updated the **change log** - [X] ran **pre-commit** checks for code style - [ ] attended to any **TO-DOs** left in the code Related work items: #2869, #2912
This commit is contained in:
@@ -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:
|
||||
|
||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [4.0.0] = TBC
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
- Agents now follow a common configuration format, simplifying the configuration of agents and their extensibilty.
|
||||
- Actions within PrimAITE are now extensible, allowing for plugin support.
|
||||
- Added a config schema to `ObservationManager`, `ActionManager`, and `RewardFunction`.
|
||||
- Streamlined the way agents are created from config
|
||||
- Agent config no longer requires a dummy action space if the action space is empty, the same applies for observation space and reward function
|
||||
- Actions now support a config schema, to allow yaml data validation and default parameter values
|
||||
- Action parameters are no longer defined through IDs, instead meaningful data is provided directly in the action map
|
||||
- Test and example YAMLs have been updated to match the new agent and action schemas, such as:
|
||||
- Removed empty action spaces, observation spaces, or reward spaces for agent which didn't use them
|
||||
- Relabeled action parameters to match the new action config schemas, and updated the values to no longer rely on indices
|
||||
- Removed action space options which were previously used for assigning meaning to action space IDs
|
||||
- Updated tests that don't use YAMLs to still use the new action and agent schemas
|
||||
|
||||
## [3.3.0] - 2024-09-04
|
||||
|
||||
### Added
|
||||
|
||||
@@ -70,7 +70,7 @@ PrimAITE incorporates the following features:
|
||||
|
||||
- Architected with a separate Simulation layer and Game layer. This separation of concerns defines a clear path towards transfer learning with environments of differing fidelity;
|
||||
- Ability to reconfigure an RL reward function based on (a) the ability to counter the modelled adversarial cyber-attack, and (b) the ability to ensure success for green agents;
|
||||
- Access Control List (ACL) functions for network devices (routers and firewalls), following standard ACL rule format (e.g., DENY / ALLOW, source / destination IP addresses, protocol and port);
|
||||
- Access Control List (ACL) functions for network devices (routers and firewalls), following standard ACL rule format (e.g., DENY / PERMIT, source / destination IP addresses, protocol and port);
|
||||
- Application of traffic to the links of the system laydown adheres to the ACL rulesets and routing tables contained within each network device;
|
||||
- Provides RL environments adherent to the Farama Foundation Gymnasium (Previously OpenAI Gym) API, allowing integration with any compliant RL Agent frameworks;
|
||||
- Provides RL environments adherent to Ray RLlib environment specifications for single-agent and multi-agent scenarios;
|
||||
|
||||
@@ -184,7 +184,7 @@ Head over to the :ref:`getting-started` page to install and setup PrimAITE!
|
||||
- 192.168.1.5
|
||||
- ANY
|
||||
- ANY
|
||||
All ACL rules are considered when applying an IER. Logic follows the order of rules, so a DENY or ALLOW for the same parameters will override an earlier entry.
|
||||
All ACL rules are considered when applying an IER. Logic follows the order of rules, so a DENY or PERMIT for the same parameters will override an earlier entry.
|
||||
Observation Spaces
|
||||
******************
|
||||
The observation space provides the blue agent with information about the current status of nodes and links.
|
||||
@@ -331,7 +331,7 @@ Head over to the :ref:`getting-started` page to install and setup PrimAITE!
|
||||
* Dictionary item {... ,1: [x1, x2, x3, x4, x5, x6] ...}
|
||||
The placeholders inside the list under the key '1' mean the following:
|
||||
* [0, 2] - Action (0 = do nothing, 1 = create rule, 2 = delete rule)
|
||||
* [0, 1] - Permission (0 = DENY, 1 = ALLOW)
|
||||
* [0, 1] - Permission (0 = DENY, 1 = PERMIT)
|
||||
* [0, num nodes] - Source IP (0 = any, then 1 -> x resolving to IP addresses)
|
||||
* [0, num nodes] - Dest IP (0 = any, then 1 -> x resolving to IP addresses)
|
||||
* [0, num services] - Protocol (0 = any, then 1 -> x resolving to protocol)
|
||||
|
||||
@@ -23,123 +23,117 @@ The following logic is applied:
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| Action | Action Mask Logic |
|
||||
+==========================================+=====================================================================+
|
||||
| **DONOTHING** | Always Possible. |
|
||||
| **do_nothing** | Always Possible. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SERVICE_SCAN** | Node is on. Service is running. |
|
||||
| **node_service_scan** | Node is on. Service is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SERVICE_STOP** | Node is on. Service is running. |
|
||||
| **node_service_stop** | Node is on. Service is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SERVICE_START** | Node is on. Service is stopped. |
|
||||
| **node_service_start** | Node is on. Service is stopped. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SERVICE_PAUSE** | Node is on. Service is running. |
|
||||
| **node_service_pause** | Node is on. Service is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SERVICE_RESUME** | Node is on. Service is paused. |
|
||||
| **node_service_resume** | Node is on. Service is paused. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SERVICE_RESTART** | Node is on. Service is running. |
|
||||
| **node_service_restart** | Node is on. Service is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SERVICE_DISABLE** | Node is on. |
|
||||
| **node_service_disable** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SERVICE_ENABLE** | Node is on. Service is disabled. |
|
||||
| **node_service_enable** | Node is on. Service is disabled. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SERVICE_FIX** | Node is on. Service is running. |
|
||||
| **node_service_fix** | Node is on. Service is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_APPLICATION_EXECUTE** | Node is on. |
|
||||
| **node_application_execute** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_APPLICATION_SCAN** | Node is on. Application is running. |
|
||||
| **node_application_scan** | Node is on. Application is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_APPLICATION_CLOSE** | Node is on. Application is running. |
|
||||
| **node_application_close** | Node is on. Application is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_APPLICATION_FIX** | Node is on. Application is running. |
|
||||
| **node_application_fix** | Node is on. Application is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_APPLICATION_INSTALL** | Node is on. |
|
||||
| **node_application_install** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_APPLICATION_REMOVE** | Node is on. |
|
||||
| **node_application_remove** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FILE_SCAN** | Node is on. File exists. File not deleted. |
|
||||
| **node_file_scan** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FILE_CREATE** | Node is on. |
|
||||
| **node_file_create** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FILE_CHECKHASH** | Node is on. File exists. File not deleted. |
|
||||
| **node_file_checkhash** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FILE_DELETE** | Node is on. File exists. |
|
||||
| **node_file_delete** | Node is on. File exists. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FILE_REPAIR** | Node is on. File exists. File not deleted. |
|
||||
| **node_file_repair** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FILE_RESTORE** | Node is on. File exists. File is deleted. |
|
||||
| **node_file_restore** | Node is on. File exists. File is deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FILE_CORRUPT** | Node is on. File exists. File not deleted. |
|
||||
| **node_file_corrupt** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FILE_ACCESS** | Node is on. File exists. File not deleted. |
|
||||
| **node_file_access** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FOLDER_CREATE** | Node is on. |
|
||||
| **node_folder_create** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FOLDER_SCAN** | Node is on. Folder exists. Folder not deleted. |
|
||||
| **node_folder_scan** | Node is on. Folder exists. Folder not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FOLDER_CHECKHASH** | Node is on. Folder exists. Folder not deleted. |
|
||||
| **node_folder_checkhash** | Node is on. Folder exists. Folder not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FOLDER_REPAIR** | Node is on. Folder exists. Folder not deleted. |
|
||||
| **node_folder_repair** | Node is on. Folder exists. Folder not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_FOLDER_RESTORE** | Node is on. Folder exists. Folder is deleted. |
|
||||
| **node_folder_restore** | Node is on. Folder exists. Folder is deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_OS_SCAN** | Node is on. |
|
||||
| **node_os_scan** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **HOST_NIC_ENABLE** | NIC is disabled. Node is on. |
|
||||
| **host_nic_enable** | NIC is disabled. Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **HOST_NIC_DISABLE** | NIC is enabled. Node is on. |
|
||||
| **host_nic_disable** | NIC is enabled. Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SHUTDOWN** | Node is on. |
|
||||
| **node_shutdown** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_STARTUP** | Node is off. |
|
||||
| **node_startup** | Node is off. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_RESET** | Node is on. |
|
||||
| **node_reset** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_NMAP_PING_SCAN** | Node is on. |
|
||||
| **node_nmap_ping_scan** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_NMAP_PORT_SCAN** | Node is on. |
|
||||
| **node_nmap_port_scan** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_NMAP_NETWORK_SERVICE_RECON** | Node is on. |
|
||||
| **node_network_service_recon** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NETWORK_PORT_ENABLE** | Node is on. Router is on. |
|
||||
| **network_port_enable** | Node is on. Router is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NETWORK_PORT_DISABLE** | Router is on. |
|
||||
| **network_port_disable** | Router is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **ROUTER_ACL_ADDRULE** | Router is on. |
|
||||
| **router_acl_addrule** | Router is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **ROUTER_ACL_REMOVERULE** | Router is on. |
|
||||
| **router_acl_removerule** | Router is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **FIREWALL_ACL_ADDRULE** | Firewall is on. |
|
||||
| **firewall_acl_addrule** | Firewall is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **FIREWALL_ACL_REMOVERULE** | Firewall is on. |
|
||||
| **firewall_acl_removerule** | Firewall is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_NMAP_PING_SCAN** | Node is on. |
|
||||
| **configure_database_client** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_NMAP_PORT_SCAN** | Node is on. |
|
||||
| **configure_ransomware_script** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_NMAP_NETWORK_SERVICE_RECON** | Node is on. |
|
||||
| **c2_server_ransomware_configure** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **CONFIGURE_DATABASE_CLIENT** | Node is on. |
|
||||
| **configure_dos_bot** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **CONFIGURE_RANSOMWARE_SCRIPT** | Node is on. |
|
||||
| **configure_c2_beacon** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **CONFIGURE_DOSBOT** | Node is on. |
|
||||
| **c2_server_ransomware_launch** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **CONFIGURE_C2_BEACON** | Node is on. |
|
||||
| **c2_server_terminal_command** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **C2_SERVER_RANSOMWARE_LAUNCH** | Node is on. |
|
||||
| **c2_server_data_exfiltrate** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **C2_SERVER_RANSOMWARE_CONFIGURE** | Node is on. |
|
||||
| **node_account_change_password** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **C2_SERVER_TERMINAL_COMMAND** | Node is on. |
|
||||
| **node_session_remote_login** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **C2_SERVER_DATA_EXFILTRATE** | Node is on. |
|
||||
| **node_session_remote_logoff** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_ACCOUNTS_CHANGE_PASSWORD** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **SSH_TO_REMOTE** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **SESSIONS_REMOTE_LOGOFF** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **NODE_SEND_REMOTE_COMMAND** | Node is on. |
|
||||
| **node_send_remote_command** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
|
||||
|
||||
|
||||
@@ -23,19 +23,6 @@ Agents can be scripted (deterministic and stochastic), or controlled by a reinfo
|
||||
observation_space:
|
||||
type: UC2GreenObservation
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
@@ -91,10 +78,6 @@ For more information see :py:mod:`primaite.game.agent.observations`
|
||||
|
||||
The action space is configured to be made up of individual action types. Once configured, the agent can select an action type and some optional action parameters at every step. For example: The ``NODE_SERVICE_SCAN`` action takes the parameters ``node_id`` and ``service_id``.
|
||||
|
||||
``action_list``
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
A list of action modules. The options are listed in the :py:mod:`primaite.game.agent.actions.ActionManager.act_class_identifiers` module.
|
||||
|
||||
``action_map``
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
67
docs/source/how_to_guides/extensible_actions.rst
Normal file
67
docs/source/how_to_guides/extensible_actions.rst
Normal file
@@ -0,0 +1,67 @@
|
||||
.. only:: comment
|
||||
|
||||
© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
|
||||
Extensible Actions
|
||||
******************
|
||||
|
||||
|
||||
Changes to Actions class Structure.
|
||||
===================================
|
||||
|
||||
Actions within PrimAITE have been updated to inherit from a base class, AbstractAction, standardising their format and allowing for easier creation of custom actions. Actions now use a ``ConfigSchema`` to define the possible configuration variables, and use pydantic to enforce correct parameters are passed through.
|
||||
|
||||
|
||||
Developing Custom Actions.
|
||||
==========================
|
||||
|
||||
Custom actions within PrimAITE must be a sub-class of `AbstractAction`, and contain 3 key items:
|
||||
|
||||
#. ConfigSchema class
|
||||
|
||||
#. Unique Identifier
|
||||
|
||||
#. `form_request` method.
|
||||
|
||||
|
||||
ConfigSchema
|
||||
############
|
||||
|
||||
The ConfigSchema sub-class of the action must contain all `configurable` variables within the action, that would be specified within the environments configuration YAML file.
|
||||
|
||||
|
||||
Unique Identifier
|
||||
#################
|
||||
|
||||
When declaring a custom class, it must have a unique identifier string, that allows PrimAITE to generate the correct action when needed.
|
||||
|
||||
.. code:: Python
|
||||
|
||||
class CreateDirectoryAction(AbstractAction, identifier="node_folder_create")
|
||||
|
||||
config: CreateDirectoryAction.ConfigSchema
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
|
||||
verb: ClassVar[str] = "create"
|
||||
node_name: str
|
||||
directory_name: str
|
||||
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
return ["network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"file_system",
|
||||
config.verb,
|
||||
"folder",
|
||||
config.directory_name,
|
||||
]
|
||||
|
||||
The above action would fail pydantic validation as the identifier "node_folder_create" is already used by the `NodeFolderCreateAction`, and would create a duplicate listing within `AbstractAction._registry`.
|
||||
|
||||
|
||||
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.
|
||||
78
docs/source/how_to_guides/extensible_agents.rst
Normal file
78
docs/source/how_to_guides/extensible_agents.rst
Normal file
@@ -0,0 +1,78 @@
|
||||
.. only:: comment
|
||||
|
||||
© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _about:
|
||||
|
||||
Extensible Agents
|
||||
*****************
|
||||
|
||||
Agents defined within PrimAITE have been updated to allow for easier creation of new bespoke agents for use in custom environments.
|
||||
|
||||
|
||||
Developing Agents for PrimAITE
|
||||
==============================
|
||||
|
||||
All agent types within PrimAITE must be subclassed from ``AbstractAgent`` in order to be used from configuration YAML files. This then allows you to implement any custom agent logic for the new agent in your training scenario. Examples of implementing custom agent logic can be seen in pre-existing agents, such as the ``DataManipulationBot`` and ``RandomAgent``.
|
||||
|
||||
The core features that should be implemented in any new agent are detailed below:
|
||||
|
||||
#. **ConfigSchema**:
|
||||
|
||||
Configurable items within a new agent within PrimAITE should contain a ``ConfigSchema`` which holds all configurable variables of the agent. This should not include parameters related to its *state*, these would be listed seperately.
|
||||
Agent generation will fail pydantic checks if incorrect or invalid parameters are passed to the ConfigSchema of the chosen Agent.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ExampleAgent(AbstractAgent, identifier = "ExampleAgent"):
|
||||
"""An example agent for demonstration purposes."""
|
||||
|
||||
config: "ExampleAgent.ConfigSchema" = Field(default_factory= lambda: ExampleAgent.ConfigSchema())
|
||||
"""Agent configuration"""
|
||||
num_executions: int = 0
|
||||
"""Number of action executions by agent"""
|
||||
|
||||
class ConfigSchema(AbstractAgent.ConfigSchema):
|
||||
"""ExampleAgent configuration schema"""
|
||||
|
||||
type: str = "ExampleAgent
|
||||
"""Name of agent"""
|
||||
starting_host: int
|
||||
"""Host node that this agent should start from in the given environment."""
|
||||
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- ref: example_green_agent
|
||||
team: GREEN
|
||||
type: ExampleAgent
|
||||
|
||||
action_space:
|
||||
action_map:
|
||||
0:
|
||||
action: do_nothing
|
||||
options: {}
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
starting_host: "Server_1"
|
||||
|
||||
|
||||
#. **Identifiers**:
|
||||
|
||||
All agent classes should have an ``identifier`` attribute, a unique kebab-case string, for when they are added to the base ``AbstractAgent`` registry. This is then specified in your configuration YAML, and used by PrimAITE to generate the correct Agent.
|
||||
|
||||
Changes to YAML file
|
||||
====================
|
||||
|
||||
PrimAITE v4.0.0 introduces some breaking changes to how environment configuration yaml files are created. YAML files created for Primaite versions 3.3.0 should be compatible through a translation function, though it is encouraged that these are updated to reflect the updated format of 4.0.0+.
|
||||
|
||||
Agents now follow a more standardised settings definition, so should be more consistent across YAML files and the available agent types with PrimAITE.
|
||||
|
||||
All configurable items for agents sit under the ``agent_settings`` heading within your YAML files. There is no need for the inclusion of a ``start_settings``. Please see the above YAML example for full changes to agents.
|
||||
@@ -113,18 +113,6 @@ If not using the data manipulation bot manually, it needs to be used with a data
|
||||
folders: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_ref: data_manipulation_bot
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
@@ -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 subprocess
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
@@ -30,35 +30,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_2
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_2
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -79,35 +66,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -128,33 +102,12 @@ agents:
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
agent_settings:
|
||||
possible_start_nodes: [client_1, client_2]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
@@ -235,490 +188,426 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
action: node_service_scan
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
action: node_service_stop
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
action: "node_service_start"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
action: "node_service_pause"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
action: "node_service_resume"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
action: "node_service_restart"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
action: "node_service_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
action: "node_service_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
action: "node_file_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
10:
|
||||
action: "NODE_FILE_CHECKHASH" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
action: "node_file_scan" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
action: "node_file_delete"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
action: "node_file_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
action: "node_service_fix"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
node_name: database_server
|
||||
service_name: DatabaseService
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
action: "node_folder_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
15:
|
||||
action: "NODE_FOLDER_CHECKHASH" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
action: "node_folder_scan" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
action: "node_folder_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
action: "node_folder_restore"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
19:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
20:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
21:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
22:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
23:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
24:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
25:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
26: # old action num: 18
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
27:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
28:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
29:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
30:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
31:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
32:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
33:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
34:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
35:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
36:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
37:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
38:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
39: # old action num: 19 # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
40: # old action num: 20
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
41: # old action num: 21
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
42:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
43:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
44:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
45:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
|
||||
46: # old action num: 22 # "ACL: ADDRULE - Block outgoing traffic from client 1"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
47: # old action num: 23 # "ACL: ADDRULE - Block outgoing traffic from client 2"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
48: # old action num: 24 # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
49: # old action num: 25 # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
50: # old action num: 26
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
51: # old action num: 27
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
52: # old action num: 28
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 0
|
||||
53: # old action num: 29
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
54: # old action num: 30
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
55: # old action num: 31
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
56: # old action num: 32
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
57: # old action num: 33
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
58: # old action num: 34
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
59: # old action num: 35
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 7
|
||||
60: # old action num: 36
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 8
|
||||
61: # old action num: 37
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 9
|
||||
62: # old action num: 38
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
63: # old action num: 39
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
64: # old action num: 40
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
65: # old action num: 41
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
66: # old action num: 42
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
67: # old action num: 43
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
68: # old action num: 44
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
69: # old action num: 45
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
70: # old action num: 46
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
71: # old action num: 47
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
72: # old action num: 48
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
73: # old action num: 49
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
74: # old action num: 50
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
75: # old action num: 51
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
76: # old action num: 52
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
77: # old action num: 53
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
- node_name: web_server
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
services:
|
||||
- service_name: WebServer
|
||||
- node_name: database_server
|
||||
folders:
|
||||
- folder_name: database
|
||||
files:
|
||||
- file_name: database.db
|
||||
services:
|
||||
- service_name: DatabaseService
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,68 +6,48 @@ game:
|
||||
agents:
|
||||
- ref: RL_Agent
|
||||
type: ProxyAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_SHUTDOWN
|
||||
action: node_shutdown
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: client_1
|
||||
2:
|
||||
action: NODE_SHUTDOWN
|
||||
action: node_shutdown
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: server
|
||||
3:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: client_1
|
||||
4:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: server
|
||||
5:
|
||||
action: HOST_NIC_DISABLE
|
||||
action: host_nic_disable
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
6:
|
||||
action: HOST_NIC_DISABLE
|
||||
action: host_nic_disable
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: server
|
||||
nic_num: 1
|
||||
7:
|
||||
action: HOST_NIC_ENABLE
|
||||
action: host_nic_enable
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
8:
|
||||
action: HOST_NIC_ENABLE
|
||||
action: host_nic_enable
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
- node_name: server
|
||||
max_folders_per_node: 0
|
||||
max_files_per_folder: 0
|
||||
max_services_per_node: 0
|
||||
max_nics_per_node: 1
|
||||
max_acl_rules: 0
|
||||
ip_list:
|
||||
- 192.168.1.2
|
||||
- 192.168.1.3
|
||||
reward_function:
|
||||
reward_components: []
|
||||
node_name: server
|
||||
nic_num: 1
|
||||
|
||||
simulation:
|
||||
network:
|
||||
|
||||
@@ -6,25 +6,17 @@ agents: &greens
|
||||
action_probabilities:
|
||||
0: 0.2
|
||||
1: 0.8
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -6,25 +6,17 @@ agents: &greens
|
||||
action_probabilities:
|
||||
0: 0.95
|
||||
1: 0.05
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -3,24 +3,9 @@ reds: &reds
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 10
|
||||
frequency: 10
|
||||
variance: 0
|
||||
possible_start_nodes: [client,]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 10
|
||||
frequency: 10
|
||||
variance: 0
|
||||
|
||||
@@ -3,24 +3,9 @@ reds: &reds
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 3
|
||||
frequency: 2
|
||||
variance: 1
|
||||
possible_start_nodes: [client_1]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 3
|
||||
frequency: 2
|
||||
variance: 1
|
||||
|
||||
@@ -54,65 +54,46 @@ agents:
|
||||
- server:eth-1<->switch_1:eth-2
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_SHUTDOWN
|
||||
action: node_shutdown
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: client_1
|
||||
2:
|
||||
action: NODE_SHUTDOWN
|
||||
action: node_shutdown
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: server
|
||||
3:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: client_1
|
||||
4:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: server
|
||||
5:
|
||||
action: HOST_NIC_DISABLE
|
||||
action: host_nic_disable
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
6:
|
||||
action: HOST_NIC_DISABLE
|
||||
action: host_nic_disable
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: server
|
||||
nic_num: 1
|
||||
7:
|
||||
action: HOST_NIC_ENABLE
|
||||
action: host_nic_enable
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
8:
|
||||
action: HOST_NIC_ENABLE
|
||||
action: host_nic_enable
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
- node_name: server
|
||||
|
||||
max_folders_per_node: 0
|
||||
max_files_per_folder: 0
|
||||
max_services_per_node: 0
|
||||
max_nics_per_node: 1
|
||||
max_acl_rules: 0
|
||||
ip_list:
|
||||
- 192.168.1.2
|
||||
- 192.168.1.3
|
||||
node_name: server
|
||||
nic_num: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
33
src/primaite/game/agent/actions/__init__.py
Normal file
33
src/primaite/game/agent/actions/__init__.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
from primaite.game.agent.actions import (
|
||||
abstract,
|
||||
acl,
|
||||
application,
|
||||
file,
|
||||
folder,
|
||||
host_nic,
|
||||
manager,
|
||||
network,
|
||||
node,
|
||||
service,
|
||||
session,
|
||||
software,
|
||||
)
|
||||
from primaite.game.agent.actions.manager import ActionManager
|
||||
|
||||
__all__ = (
|
||||
"abstract",
|
||||
"acl",
|
||||
"application",
|
||||
"software",
|
||||
"file",
|
||||
"folder",
|
||||
"host_nic",
|
||||
"manager",
|
||||
"network",
|
||||
"node",
|
||||
"service",
|
||||
"session",
|
||||
"ActionManager",
|
||||
)
|
||||
36
src/primaite/game/agent/actions/abstract.py
Normal file
36
src/primaite/game/agent/actions/abstract.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC
|
||||
from typing import Any, ClassVar, Dict, Optional, Type
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
|
||||
class AbstractAction(BaseModel, ABC):
|
||||
"""Base class for actions."""
|
||||
|
||||
config: "AbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(BaseModel, ABC):
|
||||
"""Base configuration schema for Actions."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
type: str = ""
|
||||
|
||||
_registry: ClassVar[Dict[str, Type[AbstractAction]]] = {}
|
||||
|
||||
def __init_subclass__(cls, identifier: Optional[str] = None, **kwargs: Any) -> None:
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier is None:
|
||||
return
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Cannot create new action under reserved name {identifier}")
|
||||
cls._registry[identifier] = cls
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
pass
|
||||
157
src/primaite/game/agent/actions/acl.py
Normal file
157
src/primaite/game/agent/actions/acl.py
Normal file
@@ -0,0 +1,157 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC
|
||||
from typing import Literal, Union
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
from primaite.utils.validation.ip_protocol import IPProtocol
|
||||
from primaite.utils.validation.ipv4_address import IPV4Address
|
||||
from primaite.utils.validation.port import Port
|
||||
|
||||
__all__ = (
|
||||
"RouterACLAddRuleAction",
|
||||
"RouterACLRemoveRuleAction",
|
||||
"FirewallACLAddRuleAction",
|
||||
"FirewallACLRemoveRuleAction",
|
||||
)
|
||||
|
||||
|
||||
class ACLAddRuleAbstractAction(AbstractAction, ABC):
|
||||
"""Base abstract class for ACL add rule actions."""
|
||||
|
||||
config: ConfigSchema = "ACLAddRuleAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Configuration Schema base for ACL add rule abstract actions."""
|
||||
|
||||
src_ip: IPV4Address
|
||||
protocol_name: Union[IPProtocol, Literal["ALL"]]
|
||||
permission: Literal["PERMIT", "DENY"]
|
||||
position: int
|
||||
dst_ip: Union[IPV4Address, Literal["ALL"]]
|
||||
src_port: Union[Port, Literal["ALL"]]
|
||||
dst_port: Union[Port, Literal["ALL"]]
|
||||
src_wildcard: Union[IPV4Address, Literal["NONE"]]
|
||||
dst_wildcard: Union[IPV4Address, Literal["NONE"]]
|
||||
|
||||
|
||||
class ACLRemoveRuleAbstractAction(AbstractAction, identifier="acl_remove_rule_abstract_action"):
|
||||
"""Base abstract class for ACL remove rule actions."""
|
||||
|
||||
config: ConfigSchema = "ACLRemoveRuleAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Configuration Schema base for ACL remove rule abstract actions."""
|
||||
|
||||
position: int
|
||||
|
||||
|
||||
class RouterACLAddRuleAction(ACLAddRuleAbstractAction, identifier="router_acl_add_rule"):
|
||||
"""Action which adds a rule to a router's ACL."""
|
||||
|
||||
config: "RouterACLAddRuleAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(ACLAddRuleAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for RouterACLAddRuleAction."""
|
||||
|
||||
target_router: str
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.target_router,
|
||||
"acl",
|
||||
"add_rule",
|
||||
config.permission,
|
||||
config.protocol_name,
|
||||
str(config.src_ip),
|
||||
str(config.src_wildcard),
|
||||
config.src_port,
|
||||
str(config.dst_ip),
|
||||
str(config.dst_wildcard),
|
||||
config.dst_port,
|
||||
config.position,
|
||||
]
|
||||
|
||||
|
||||
class RouterACLRemoveRuleAction(ACLRemoveRuleAbstractAction, identifier="router_acl_remove_rule"):
|
||||
"""Action which removes a rule from a router's ACL."""
|
||||
|
||||
config: "RouterACLRemoveRuleAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(ACLRemoveRuleAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for RouterACLRemoveRuleAction."""
|
||||
|
||||
target_router: str
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return ["network", "node", config.target_router, "acl", "remove_rule", config.position]
|
||||
|
||||
|
||||
class FirewallACLAddRuleAction(ACLAddRuleAbstractAction, identifier="firewall_acl_add_rule"):
|
||||
"""Action which adds a rule to a firewall port's ACL."""
|
||||
|
||||
config: "FirewallACLAddRuleAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(ACLAddRuleAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for FirewallACLAddRuleAction."""
|
||||
|
||||
target_firewall_nodename: str
|
||||
firewall_port_name: str
|
||||
firewall_port_direction: str
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.target_firewall_nodename,
|
||||
config.firewall_port_name,
|
||||
config.firewall_port_direction,
|
||||
"acl",
|
||||
"add_rule",
|
||||
config.permission,
|
||||
config.protocol_name,
|
||||
str(config.src_ip),
|
||||
str(config.src_wildcard),
|
||||
config.src_port,
|
||||
str(config.dst_ip),
|
||||
str(config.dst_wildcard),
|
||||
config.dst_port,
|
||||
config.position,
|
||||
]
|
||||
|
||||
|
||||
class FirewallACLRemoveRuleAction(ACLRemoveRuleAbstractAction, identifier="firewall_acl_remove_rule"):
|
||||
"""Action which removes a rule from a firewall port's ACL."""
|
||||
|
||||
config: "FirewallACLRemoveRuleAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(ACLRemoveRuleAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for FirewallACLRemoveRuleAction."""
|
||||
|
||||
target_firewall_nodename: str
|
||||
firewall_port_name: str
|
||||
firewall_port_direction: str
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.target_firewall_nodename,
|
||||
config.firewall_port_name,
|
||||
config.firewall_port_direction,
|
||||
"acl",
|
||||
"remove_rule",
|
||||
config.position,
|
||||
]
|
||||
137
src/primaite/game/agent/actions/application.py
Normal file
137
src/primaite/game/agent/actions/application.py
Normal file
@@ -0,0 +1,137 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
from primaite.game.agent.actions.abstract import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
__all__ = (
|
||||
"NodeApplicationExecuteAction",
|
||||
"NodeApplicationScanAction",
|
||||
"NodeApplicationCloseAction",
|
||||
"NodeApplicationFixAction",
|
||||
"NodeApplicationInstallAction",
|
||||
"NodeApplicationRemoveAction",
|
||||
)
|
||||
|
||||
|
||||
class NodeApplicationAbstractAction(AbstractAction, ABC):
|
||||
"""
|
||||
Base class for application actions.
|
||||
|
||||
Any action which applies to an application and uses node_name and application_name as its only two parameters can
|
||||
inherit from this base class.
|
||||
"""
|
||||
|
||||
config: "NodeApplicationAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Base Configuration schema for Node Application actions."""
|
||||
|
||||
node_name: str
|
||||
application_name: str
|
||||
verb: ClassVar[str]
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"application",
|
||||
config.application_name,
|
||||
config.verb,
|
||||
]
|
||||
|
||||
|
||||
class NodeApplicationExecuteAction(NodeApplicationAbstractAction, identifier="node_application_execute"):
|
||||
"""Action which executes an application."""
|
||||
|
||||
config: "NodeApplicationExecuteAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeApplicationAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeApplicationExecuteAction."""
|
||||
|
||||
verb: str = "execute"
|
||||
|
||||
|
||||
class NodeApplicationScanAction(NodeApplicationAbstractAction, identifier="node_application_scan"):
|
||||
"""Action which scans an application."""
|
||||
|
||||
config: "NodeApplicationScanAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeApplicationAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeApplicationScanAction."""
|
||||
|
||||
verb: str = "scan"
|
||||
|
||||
|
||||
class NodeApplicationCloseAction(NodeApplicationAbstractAction, identifier="node_application_close"):
|
||||
"""Action which closes an application."""
|
||||
|
||||
config: "NodeApplicationCloseAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeApplicationAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeApplicationCloseAction."""
|
||||
|
||||
verb: str = "close"
|
||||
|
||||
|
||||
class NodeApplicationFixAction(NodeApplicationAbstractAction, identifier="node_application_fix"):
|
||||
"""Action which fixes an application."""
|
||||
|
||||
config: "NodeApplicationFixAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeApplicationAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeApplicationFixAction."""
|
||||
|
||||
verb: str = "fix"
|
||||
|
||||
|
||||
class NodeApplicationInstallAction(NodeApplicationAbstractAction, identifier="node_application_install"):
|
||||
"""Action which installs an application."""
|
||||
|
||||
config: "NodeApplicationInstallAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeApplicationAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeApplicationInstallAction."""
|
||||
|
||||
verb: str = "install"
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"software_manager",
|
||||
"application",
|
||||
config.verb,
|
||||
config.application_name,
|
||||
]
|
||||
|
||||
|
||||
class NodeApplicationRemoveAction(NodeApplicationAbstractAction, identifier="node_application_remove"):
|
||||
"""Action which removes/uninstalls an application."""
|
||||
|
||||
config: "NodeApplicationRemoveAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeApplicationAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeApplicationRemoveAction."""
|
||||
|
||||
verb: str = "uninstall"
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"software_manager",
|
||||
"application",
|
||||
config.verb,
|
||||
config.application_name,
|
||||
]
|
||||
189
src/primaite/game/agent/actions/file.py
Normal file
189
src/primaite/game/agent/actions/file.py
Normal file
@@ -0,0 +1,189 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
__all__ = (
|
||||
"NodeFileCreateAction",
|
||||
"NodeFileScanAction",
|
||||
"NodeFileDeleteAction",
|
||||
"NodeFileRestoreAction",
|
||||
"NodeFileCorruptAction",
|
||||
"NodeFileAccessAction",
|
||||
"NodeFileCheckhashAction",
|
||||
"NodeFileRepairAction",
|
||||
)
|
||||
|
||||
|
||||
class NodeFileAbstractAction(AbstractAction, ABC):
|
||||
"""Abstract base class for file actions.
|
||||
|
||||
Any action which applies to a file and uses node_name, folder_name, and file_name as its
|
||||
only three parameters can inherit from this base class.
|
||||
"""
|
||||
|
||||
config: "NodeFileAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeFileAbstractAction."""
|
||||
|
||||
node_name: str
|
||||
folder_name: str
|
||||
file_name: str
|
||||
verb: ClassVar[str]
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.node_name is None or config.folder_name is None or config.file_name is None:
|
||||
return ["do_nothing"]
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"file_system",
|
||||
"folder",
|
||||
config.folder_name,
|
||||
"file",
|
||||
config.file_name,
|
||||
config.verb,
|
||||
]
|
||||
|
||||
|
||||
class NodeFileCreateAction(NodeFileAbstractAction, identifier="node_file_create"):
|
||||
"""Action which creates a new file in a given folder."""
|
||||
|
||||
config: "NodeFileCreateAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFileAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFileCreateAction."""
|
||||
|
||||
verb: ClassVar[str] = "create"
|
||||
force: bool = False
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.node_name is None or config.folder_name is None or config.file_name is None:
|
||||
return ["do_nothing"]
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"file_system",
|
||||
config.verb,
|
||||
"file",
|
||||
config.folder_name,
|
||||
config.file_name,
|
||||
config.verb,
|
||||
]
|
||||
|
||||
|
||||
class NodeFileScanAction(NodeFileAbstractAction, identifier="node_file_scan"):
|
||||
"""Action which scans a file."""
|
||||
|
||||
config: "NodeFileScanAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFileAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFileScanAction."""
|
||||
|
||||
verb: ClassVar[str] = "scan"
|
||||
|
||||
|
||||
class NodeFileDeleteAction(NodeFileAbstractAction, identifier="node_file_delete"):
|
||||
"""Action which deletes a file."""
|
||||
|
||||
config: "NodeFileDeleteAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFileAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFileDeleteAction."""
|
||||
|
||||
verb: ClassVar[str] = "delete"
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.node_name is None or config.folder_name is None or config.file_name is None:
|
||||
return ["do_nothing"]
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"file_system",
|
||||
config.verb,
|
||||
"file",
|
||||
config.folder_name,
|
||||
config.file_name,
|
||||
]
|
||||
|
||||
|
||||
class NodeFileRestoreAction(NodeFileAbstractAction, identifier="node_file_restore"):
|
||||
"""Action which restores a file."""
|
||||
|
||||
config: "NodeFileRestoreAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFileAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFileRestoreAction."""
|
||||
|
||||
verb: ClassVar[str] = "restore"
|
||||
|
||||
|
||||
class NodeFileCorruptAction(NodeFileAbstractAction, identifier="node_file_corrupt"):
|
||||
"""Action which corrupts a file."""
|
||||
|
||||
config: "NodeFileCorruptAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFileAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFileCorruptAction."""
|
||||
|
||||
verb: ClassVar[str] = "corrupt"
|
||||
|
||||
|
||||
class NodeFileAccessAction(NodeFileAbstractAction, identifier="node_file_access"):
|
||||
"""Action which increases a file's access count."""
|
||||
|
||||
config: "NodeFileAccessAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFileAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFileAccessAction."""
|
||||
|
||||
verb: ClassVar[str] = "access"
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.node_name is None or config.folder_name is None or config.file_name is None:
|
||||
return ["do_nothing"]
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"file_system",
|
||||
config.verb,
|
||||
config.folder_name,
|
||||
config.file_name,
|
||||
]
|
||||
|
||||
|
||||
class NodeFileCheckhashAction(NodeFileAbstractAction, identifier="node_file_checkhash"):
|
||||
"""Action which checks the hash of a file."""
|
||||
|
||||
config: "NodeFileCheckhashAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFileAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFileCheckhashAction."""
|
||||
|
||||
verb: ClassVar[str] = "checkhash"
|
||||
|
||||
|
||||
class NodeFileRepairAction(NodeFileAbstractAction, identifier="node_file_repair"):
|
||||
"""Action which repairs a file."""
|
||||
|
||||
config: "NodeFileRepairAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFileAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeFileRepairAction."""
|
||||
|
||||
verb: ClassVar[str] = "repair"
|
||||
117
src/primaite/game/agent/actions/folder.py
Normal file
117
src/primaite/game/agent/actions/folder.py
Normal file
@@ -0,0 +1,117 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
__all__ = (
|
||||
"NodeFolderScanAction",
|
||||
"NodeFolderCheckhashAction",
|
||||
"NodeFolderRepairAction",
|
||||
"NodeFolderRestoreAction",
|
||||
"NodeFolderCreateAction",
|
||||
)
|
||||
|
||||
|
||||
class NodeFolderAbstractAction(AbstractAction, ABC):
|
||||
"""
|
||||
Base class for folder actions.
|
||||
|
||||
Any action which applies to a folder and uses node_name and folder_name as its only two parameters can inherit from
|
||||
this base class.
|
||||
"""
|
||||
|
||||
config: "NodeFolderAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Base configuration schema for NodeFolder actions."""
|
||||
|
||||
node_name: str
|
||||
folder_name: str
|
||||
verb: ClassVar[str]
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.node_name is None or config.folder_name is None:
|
||||
return ["do_nothing"]
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"file_system",
|
||||
"folder",
|
||||
config.folder_name,
|
||||
config.verb,
|
||||
]
|
||||
|
||||
|
||||
class NodeFolderScanAction(NodeFolderAbstractAction, identifier="node_folder_scan"):
|
||||
"""Action which scans a folder."""
|
||||
|
||||
config: "NodeFolderScanAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFolderAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFolderScanAction."""
|
||||
|
||||
verb: ClassVar[str] = "scan"
|
||||
|
||||
|
||||
class NodeFolderCheckhashAction(NodeFolderAbstractAction, identifier="node_folder_checkhash"):
|
||||
"""Action which checks the hash of a folder."""
|
||||
|
||||
config: "NodeFolderCheckhashAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFolderAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFolderCheckhashAction."""
|
||||
|
||||
verb: ClassVar[str] = "checkhash"
|
||||
|
||||
|
||||
class NodeFolderRepairAction(NodeFolderAbstractAction, identifier="node_folder_repair"):
|
||||
"""Action which repairs a folder."""
|
||||
|
||||
config: "NodeFolderRepairAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFolderAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFolderRepairAction."""
|
||||
|
||||
verb: ClassVar[str] = "repair"
|
||||
|
||||
|
||||
class NodeFolderRestoreAction(NodeFolderAbstractAction, identifier="node_folder_restore"):
|
||||
"""Action which restores a folder."""
|
||||
|
||||
config: "NodeFolderRestoreAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFolderAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFolderRestoreAction."""
|
||||
|
||||
verb: ClassVar[str] = "restore"
|
||||
|
||||
|
||||
class NodeFolderCreateAction(NodeFolderAbstractAction, identifier="node_folder_create"):
|
||||
"""Action which creates a new folder."""
|
||||
|
||||
config: "NodeFolderCreateAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeFolderAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeFolderCreateAction."""
|
||||
|
||||
verb: ClassVar[str] = "create"
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.node_name is None or config.folder_name is None:
|
||||
return ["do_nothing"]
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"file_system",
|
||||
config.verb,
|
||||
"folder",
|
||||
config.folder_name,
|
||||
]
|
||||
62
src/primaite/game/agent/actions/host_nic.py
Normal file
62
src/primaite/game/agent/actions/host_nic.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
__all__ = ("HostNICEnableAction", "HostNICDisableAction")
|
||||
|
||||
|
||||
class HostNICAbstractAction(AbstractAction, ABC):
|
||||
"""
|
||||
Abstract base class for NIC actions.
|
||||
|
||||
Any action which applies to a NIC and uses node_name and nic_num as its only two parameters can inherit from this
|
||||
base class.
|
||||
"""
|
||||
|
||||
config: "HostNICAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Base Configuration schema for HostNIC actions."""
|
||||
|
||||
node_name: str
|
||||
nic_num: int
|
||||
verb: ClassVar[str]
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.node_name is None or config.nic_num is None:
|
||||
return ["do_nothing"]
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"network_interface",
|
||||
config.nic_num,
|
||||
config.verb,
|
||||
]
|
||||
|
||||
|
||||
class HostNICEnableAction(HostNICAbstractAction, identifier="host_nic_enable"):
|
||||
"""Action which enables a NIC."""
|
||||
|
||||
config: "HostNICEnableAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(HostNICAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for HostNICEnableAction."""
|
||||
|
||||
verb: ClassVar[str] = "enable"
|
||||
|
||||
|
||||
class HostNICDisableAction(HostNICAbstractAction, identifier="host_nic_disable"):
|
||||
"""Action which disables a NIC."""
|
||||
|
||||
config: "HostNICDisableAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(HostNICAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for HostNICDisableAction."""
|
||||
|
||||
verb: ClassVar[str] = "disable"
|
||||
108
src/primaite/game/agent/actions/manager.py
Normal file
108
src/primaite/game/agent/actions/manager.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""yaml example.
|
||||
|
||||
agents:
|
||||
- name: agent_1
|
||||
action_space:
|
||||
actions:
|
||||
- do_nothing
|
||||
- node_service_start
|
||||
- node_service_stop
|
||||
action_map:
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from gymnasium import spaces
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
from primaite.game.agent.actions.abstract import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
__all__ = ("DoNothingAction", "ActionManager")
|
||||
|
||||
|
||||
class DoNothingAction(AbstractAction, identifier="do_nothing"):
|
||||
"""Do Nothing Action."""
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for do_nothingAction."""
|
||||
|
||||
type: str = "do_nothing"
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return ["do_nothing"]
|
||||
|
||||
|
||||
class _ActionMapItem(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
action: str
|
||||
options: Dict
|
||||
|
||||
|
||||
class ActionManager(BaseModel):
|
||||
"""Class which manages the action space for an agent."""
|
||||
|
||||
class ConfigSchema(BaseModel):
|
||||
"""Config Schema for ActionManager."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
action_map: Dict[int, _ActionMapItem] = {}
|
||||
"""Mapping between integer action choices and CAOS actions."""
|
||||
|
||||
@field_validator("action_map", mode="after")
|
||||
def consecutive_action_nums(cls, v: Dict) -> Dict:
|
||||
"""Make sure all numbers between 0 and N are represented as dict keys in action map."""
|
||||
assert all([i in v.keys() for i in range(len(v))])
|
||||
return v
|
||||
|
||||
config: ActionManager.ConfigSchema = Field(default_factory=lambda: ActionManager.ConfigSchema())
|
||||
|
||||
action_map: Dict[int, Tuple[str, Dict]] = {}
|
||||
"""Init as empty, populate after model validation."""
|
||||
|
||||
def __init__(self, **kwargs) -> None:
|
||||
super().__init__(**kwargs)
|
||||
self.action_map = {n: (v.action, v.options) for n, v in self.config.action_map.items()}
|
||||
|
||||
def get_action(self, action: int) -> Tuple[str, Dict]:
|
||||
"""
|
||||
Produce action in CAOS format.
|
||||
|
||||
The agent chooses an action (as an integer), this is converted into an action in CAOS format
|
||||
The CAOS format is basically an action identifier, followed by parameters stored in a dictionary.
|
||||
"""
|
||||
act_identifier, act_options = self.action_map[action]
|
||||
return act_identifier, act_options
|
||||
|
||||
def form_request(self, action_identifier: str, action_options: Dict) -> RequestFormat:
|
||||
"""Take action in CAOS format and use the execution definition to change it into PrimAITE request format."""
|
||||
act_class = AbstractAction._registry[action_identifier]
|
||||
config = act_class.ConfigSchema(**action_options)
|
||||
return act_class.form_request(config=config)
|
||||
|
||||
@property
|
||||
def space(self) -> spaces.Space:
|
||||
"""Return the gymnasium action space for this agent."""
|
||||
return spaces.Discrete(len(self.action_map))
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, cfg: Dict) -> "ActionManager":
|
||||
"""
|
||||
Construct an ActionManager from a config dictionary.
|
||||
|
||||
The action space config supports must contain the following key:
|
||||
``action_map`` - List of actions available to the agent, formatted as a dictionary where the key is the
|
||||
action number between 0 - N, and the value is the CAOS-formatted action.
|
||||
|
||||
:param cfg: The action space config.
|
||||
:type cfg: Dict
|
||||
:return: The constructed ActionManager.
|
||||
:rtype: ActionManager
|
||||
"""
|
||||
return cls(**cfg.get("options", {}), act_map=cfg.get("action_map"))
|
||||
57
src/primaite/game/agent/actions/network.py
Normal file
57
src/primaite/game/agent/actions/network.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
from typing import ClassVar
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
__all__ = ("NetworkPortEnableAction", "NetworkPortDisableAction")
|
||||
|
||||
|
||||
class NetworkPortAbstractAction(AbstractAction, identifier="network_port_abstract"):
|
||||
"""Base class for Network port actions."""
|
||||
|
||||
config: "NetworkPortAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Base configuration schema for NetworkPort actions."""
|
||||
|
||||
target_nodename: str
|
||||
port_num: int
|
||||
verb: ClassVar[str]
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.target_nodename is None or config.port_num is None:
|
||||
return ["do_nothing"]
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.target_nodename,
|
||||
"network_interface",
|
||||
config.port_num,
|
||||
config.verb,
|
||||
]
|
||||
|
||||
|
||||
class NetworkPortEnableAction(NetworkPortAbstractAction, identifier="network_port_enable"):
|
||||
"""Action which enables are port on a router or a firewall."""
|
||||
|
||||
config: "NetworkPortEnableAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NetworkPortAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NetworkPortEnableAction."""
|
||||
|
||||
verb: ClassVar[str] = "enable"
|
||||
|
||||
|
||||
class NetworkPortDisableAction(NetworkPortAbstractAction, identifier="network_port_disable"):
|
||||
"""Action which disables are port on a router or a firewall."""
|
||||
|
||||
config: "NetworkPortDisableAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NetworkPortAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NetworkPortDisableAction."""
|
||||
|
||||
verb: ClassVar[str] = "disable"
|
||||
186
src/primaite/game/agent/actions/node.py
Normal file
186
src/primaite/game/agent/actions/node.py
Normal file
@@ -0,0 +1,186 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from abc import abstractmethod
|
||||
from typing import ClassVar, List, Optional, Union
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
from primaite.utils.validation.ip_protocol import IPProtocol
|
||||
from primaite.utils.validation.port import Port
|
||||
|
||||
__all__ = (
|
||||
"NodeOSScanAction",
|
||||
"NodeShutdownAction",
|
||||
"NodeStartupAction",
|
||||
"NodeResetAction",
|
||||
"NodeNMAPPingScanAction",
|
||||
"NodeNMAPPortScanAction",
|
||||
"NodeNetworkServiceReconAction",
|
||||
)
|
||||
|
||||
|
||||
class NodeAbstractAction(AbstractAction, identifier="node_abstract"):
|
||||
"""
|
||||
Abstract base class for node actions.
|
||||
|
||||
Any action which applies to a node and uses node_name as its only parameter can inherit from this base class.
|
||||
"""
|
||||
|
||||
config: "NodeAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Base Configuration schema for Node actions."""
|
||||
|
||||
node_name: str
|
||||
verb: ClassVar[str]
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
print(config)
|
||||
return ["network", "node", config.node_name, config.verb]
|
||||
|
||||
|
||||
class NodeOSScanAction(NodeAbstractAction, identifier="node_os_scan"):
|
||||
"""Action which scans a node's OS."""
|
||||
|
||||
config: "NodeOSScanAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeOSScanAction."""
|
||||
|
||||
verb: ClassVar[str] = "scan"
|
||||
|
||||
|
||||
class NodeShutdownAction(NodeAbstractAction, identifier="node_shutdown"):
|
||||
"""Action which shuts down a node."""
|
||||
|
||||
config: "NodeShutdownAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeShutdownAction."""
|
||||
|
||||
verb: ClassVar[str] = "shutdown"
|
||||
|
||||
|
||||
class NodeStartupAction(NodeAbstractAction, identifier="node_startup"):
|
||||
"""Action which starts up a node."""
|
||||
|
||||
config: "NodeStartupAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeStartupAction."""
|
||||
|
||||
verb: ClassVar[str] = "startup"
|
||||
|
||||
|
||||
class NodeResetAction(NodeAbstractAction, identifier="node_reset"):
|
||||
"""Action which resets a node."""
|
||||
|
||||
config: "NodeResetAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeResetAction."""
|
||||
|
||||
verb: ClassVar[str] = "reset"
|
||||
|
||||
|
||||
class NodeNMAPAbstractAction(AbstractAction, identifier="node_nmap_abstract_action"):
|
||||
"""Base class for NodeNMAP actions."""
|
||||
|
||||
config: "NodeNMAPAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Base Configuration Schema for NodeNMAP actions."""
|
||||
|
||||
target_ip_address: Union[str, List[str]]
|
||||
show: bool = False
|
||||
source_node: str
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
# NMAP action requests don't share a common format for their requests
|
||||
# This is just a placeholder to ensure the method is defined.
|
||||
pass
|
||||
|
||||
|
||||
class NodeNMAPPingScanAction(NodeNMAPAbstractAction, identifier="node_nmap_ping_scan"):
|
||||
"""Action which performs an NMAP ping scan."""
|
||||
|
||||
config: "NodeNMAPPingScanAction.ConfigSchema"
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: "NodeNMAPPingScanAction.ConfigSchema") -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.source_node,
|
||||
"application",
|
||||
"NMAP",
|
||||
"ping_scan",
|
||||
{"target_ip_address": config.target_ip_address, "show": config.show},
|
||||
]
|
||||
|
||||
|
||||
class NodeNMAPPortScanAction(NodeNMAPAbstractAction, identifier="node_nmap_port_scan"):
|
||||
"""Action which performs an NMAP port scan."""
|
||||
|
||||
config: "NodeNMAPPortScanAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeNMAPAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeNMAPPortScanAction."""
|
||||
|
||||
source_node: str
|
||||
target_protocol: Optional[Union[IPProtocol, List[IPProtocol]]] = None
|
||||
target_port: Optional[Union[Port, List[Port]]] = None
|
||||
show: Optional[bool] = (False,)
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.source_node,
|
||||
"application",
|
||||
"NMAP",
|
||||
"port_scan",
|
||||
{
|
||||
"target_ip_address": config.target_ip_address,
|
||||
"target_port": config.target_port,
|
||||
"target_protocol": config.target_protocol,
|
||||
"show": config.show,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class NodeNetworkServiceReconAction(NodeNMAPAbstractAction, identifier="node_network_service_recon"):
|
||||
"""Action which performs an NMAP network service recon (ping scan followed by port scan)."""
|
||||
|
||||
config: "NodeNetworkServiceReconAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeNMAPAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeNetworkServiceReconAction."""
|
||||
|
||||
target_protocol: Optional[Union[IPProtocol, List[IPProtocol]]] = None
|
||||
target_port: Optional[Union[Port, List[Port]]] = None
|
||||
show: Optional[bool] = (False,)
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.source_node,
|
||||
"application",
|
||||
"NMAP",
|
||||
"network_service_recon",
|
||||
{
|
||||
"target_ip_address": config.target_ip_address,
|
||||
"target_port": config.target_port,
|
||||
"target_protocol": config.target_protocol,
|
||||
"show": config.show,
|
||||
},
|
||||
]
|
||||
135
src/primaite/game/agent/actions/service.py
Normal file
135
src/primaite/game/agent/actions/service.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from typing import ClassVar
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
__all__ = (
|
||||
"NodeServiceScanAction",
|
||||
"NodeServiceStopAction",
|
||||
"NodeServiceStartAction",
|
||||
"NodeServicePauseAction",
|
||||
"NodeServiceResumeAction",
|
||||
"NodeServiceRestartAction",
|
||||
"NodeServiceDisableAction",
|
||||
"NodeServiceEnableAction",
|
||||
"NodeServiceFixAction",
|
||||
)
|
||||
|
||||
|
||||
class NodeServiceAbstractAction(AbstractAction, identifier="node_service_abstract"):
|
||||
"""Abstract Action for Node Service related actions.
|
||||
|
||||
Any actions which use node_name and service_name can inherit from this class.
|
||||
"""
|
||||
|
||||
config: "NodeServiceAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
node_name: str
|
||||
service_name: str
|
||||
verb: ClassVar[str]
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return ["network", "node", config.node_name, "service", config.service_name, config.verb]
|
||||
|
||||
|
||||
class NodeServiceScanAction(NodeServiceAbstractAction, identifier="node_service_scan"):
|
||||
"""Action which scans a service."""
|
||||
|
||||
config: "NodeServiceScanAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeServiceAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeServiceScanAction."""
|
||||
|
||||
verb: ClassVar[str] = "scan"
|
||||
|
||||
|
||||
class NodeServiceStopAction(NodeServiceAbstractAction, identifier="node_service_stop"):
|
||||
"""Action which stops a service."""
|
||||
|
||||
config: "NodeServiceStopAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeServiceAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeServiceStopAction."""
|
||||
|
||||
verb: ClassVar[str] = "stop"
|
||||
|
||||
|
||||
class NodeServiceStartAction(NodeServiceAbstractAction, identifier="node_service_start"):
|
||||
"""Action which starts a service."""
|
||||
|
||||
config: "NodeServiceStartAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeServiceAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeServiceStartAction."""
|
||||
|
||||
verb: ClassVar[str] = "start"
|
||||
|
||||
|
||||
class NodeServicePauseAction(NodeServiceAbstractAction, identifier="node_service_pause"):
|
||||
"""Action which pauses a service."""
|
||||
|
||||
config: "NodeServicePauseAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeServiceAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeServicePauseAction."""
|
||||
|
||||
verb: ClassVar[str] = "pause"
|
||||
|
||||
|
||||
class NodeServiceResumeAction(NodeServiceAbstractAction, identifier="node_service_resume"):
|
||||
"""Action which resumes a service."""
|
||||
|
||||
config: "NodeServiceResumeAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeServiceAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeServiceResumeAction."""
|
||||
|
||||
verb: ClassVar[str] = "resume"
|
||||
|
||||
|
||||
class NodeServiceRestartAction(NodeServiceAbstractAction, identifier="node_service_restart"):
|
||||
"""Action which restarts a service."""
|
||||
|
||||
config: "NodeServiceRestartAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeServiceAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeServiceRestartAction."""
|
||||
|
||||
verb: ClassVar[str] = "restart"
|
||||
|
||||
|
||||
class NodeServiceDisableAction(NodeServiceAbstractAction, identifier="node_service_disable"):
|
||||
"""Action which disables a service."""
|
||||
|
||||
config: "NodeServiceDisableAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeServiceAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeServiceDisableAction."""
|
||||
|
||||
verb: ClassVar[str] = "disable"
|
||||
|
||||
|
||||
class NodeServiceEnableAction(NodeServiceAbstractAction, identifier="node_service_enable"):
|
||||
"""Action which enables a service."""
|
||||
|
||||
config: "NodeServiceEnableAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeServiceAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeServiceEnableAction."""
|
||||
|
||||
verb: ClassVar[str] = "enable"
|
||||
|
||||
|
||||
class NodeServiceFixAction(NodeServiceAbstractAction, identifier="node_service_fix"):
|
||||
"""Action which fixes a service."""
|
||||
|
||||
config: "NodeServiceFixAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeServiceAbstractAction.ConfigSchema):
|
||||
"""Configuration Schema for NodeServiceFixAction."""
|
||||
|
||||
verb: ClassVar[str] = "fix"
|
||||
108
src/primaite/game/agent/actions/session.py
Normal file
108
src/primaite/game/agent/actions/session.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from abc import abstractmethod
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
__all__ = (
|
||||
"NodeSessionsRemoteLoginAction",
|
||||
"NodeSessionsRemoteLogoutAction",
|
||||
"NodeAccountChangePasswordAction",
|
||||
)
|
||||
|
||||
|
||||
class NodeSessionAbstractAction(AbstractAction, identifier="node_session_abstract"):
|
||||
"""Base class for NodeSession actions."""
|
||||
|
||||
config: "NodeSessionAbstractAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Base configuration schema for NodeSessionAbstractActions."""
|
||||
|
||||
node_name: str
|
||||
remote_ip: str
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""
|
||||
Abstract method for request forming.
|
||||
|
||||
Should return the action formatted as a request which can be ingested by the PrimAITE simulation.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class NodeSessionsRemoteLoginAction(NodeSessionAbstractAction, identifier="node_session_remote_login"):
|
||||
"""Action which performs a remote session login."""
|
||||
|
||||
config: "NodeSessionsRemoteLoginAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeSessionAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeSessionsRemoteLoginAction."""
|
||||
|
||||
username: str
|
||||
password: str
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.node_name is None or config.remote_ip is None:
|
||||
return ["do_nothing"]
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"service",
|
||||
"Terminal",
|
||||
"node_session_remote_login",
|
||||
config.username,
|
||||
config.password,
|
||||
config.remote_ip,
|
||||
]
|
||||
|
||||
|
||||
class NodeSessionsRemoteLogoutAction(NodeSessionAbstractAction, identifier="node_session_remote_logoff"):
|
||||
"""Action which performs a remote session logout."""
|
||||
|
||||
config: "NodeSessionsRemoteLogoutAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeSessionAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeSessionsRemoteLogoutAction."""
|
||||
|
||||
verb: str = "remote_logoff"
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
if config.node_name is None or config.remote_ip is None:
|
||||
return ["do_nothing"]
|
||||
return ["network", "node", config.node_name, "service", "Terminal", config.verb, config.remote_ip]
|
||||
|
||||
|
||||
class NodeAccountChangePasswordAction(NodeSessionAbstractAction, identifier="node_account_change_password"):
|
||||
"""Action which changes the password for a user."""
|
||||
|
||||
config: "NodeAccountChangePasswordAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(NodeSessionAbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeAccountsChangePasswordAction."""
|
||||
|
||||
username: str
|
||||
current_password: str
|
||||
new_password: str
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"service",
|
||||
"UserManager",
|
||||
"change_password",
|
||||
config.username,
|
||||
config.current_password,
|
||||
config.new_password,
|
||||
]
|
||||
241
src/primaite/game/agent/actions/software.py
Normal file
241
src/primaite/game/agent/actions/software.py
Normal file
@@ -0,0 +1,241 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pydantic import ConfigDict, Field
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
from primaite.interface.request import RequestFormat
|
||||
|
||||
__all__ = (
|
||||
"ConfigureRansomwareScriptAction",
|
||||
"ConfigureDoSBotAction",
|
||||
"ConfigureC2BeaconAction",
|
||||
"NodeSendRemoteCommandAction",
|
||||
"TerminalC2ServerAction",
|
||||
"RansomwareLaunchC2ServerAction",
|
||||
"ExfiltrationC2ServerAction",
|
||||
"ConfigureDatabaseClientAction",
|
||||
)
|
||||
|
||||
|
||||
class ConfigureRansomwareScriptAction(AbstractAction, identifier="configure_ransomware_script"):
|
||||
"""Action which sets config parameters for a ransomware script on a node."""
|
||||
|
||||
config: "ConfigureRansomwareScriptAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Configuration schema for ConfigureRansomwareScriptAction."""
|
||||
|
||||
node_name: str
|
||||
server_ip_address: Optional[str] = None
|
||||
server_password: Optional[str] = None
|
||||
payload: Optional[str] = None
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request that can be ingested by the simulation."""
|
||||
if config.node_name is None:
|
||||
return ["do_nothing"]
|
||||
data = dict(
|
||||
server_ip_address=config.server_ip_address,
|
||||
server_password=config.server_password,
|
||||
payload=config.payload,
|
||||
)
|
||||
return ["network", "node", config.node_name, "application", "RansomwareScript", "configure", data]
|
||||
|
||||
|
||||
class RansomwareConfigureC2ServerAction(ConfigureRansomwareScriptAction, identifier="c2_server_ransomware_configure"):
|
||||
"""Action which causes a C2 server to send a command to set options on a ransomware script remotely."""
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigureRansomwareScriptAction.ConfigSchema) -> RequestFormat:
|
||||
data = dict(
|
||||
server_ip_address=config.server_ip_address, server_password=config.server_password, payload=config.payload
|
||||
)
|
||||
return ["network", "node", config.node_name, "application", "C2Server", "ransomware_configure", data]
|
||||
|
||||
|
||||
class ConfigureDoSBotAction(AbstractAction, identifier="configure_dos_bot"):
|
||||
"""Action which sets config parameters for a DoS bot on a node."""
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Schema for options that can be passed to this action."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
node_name: str
|
||||
target_ip_address: Optional[str] = None
|
||||
target_port: Optional[str] = None
|
||||
payload: Optional[str] = None
|
||||
repeat: Optional[bool] = None
|
||||
port_scan_p_of_success: Optional[float] = None
|
||||
dos_intensity: Optional[float] = None
|
||||
max_sessions: Optional[int] = None
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request that can be ingested by the simulation."""
|
||||
data = dict(
|
||||
target_ip_address=config.target_ip_address,
|
||||
target_port=config.target_port,
|
||||
payload=config.payload,
|
||||
repeat=config.repeat,
|
||||
port_scan_p_of_success=config.port_scan_p_of_success,
|
||||
dos_intensity=config.dos_intensity,
|
||||
max_sessions=config.max_sessions,
|
||||
)
|
||||
data = {k: v for k, v in data.items() if v is not None}
|
||||
return ["network", "node", config.node_name, "application", "DoSBot", "configure", data]
|
||||
|
||||
|
||||
class ConfigureC2BeaconAction(AbstractAction, identifier="configure_c2_beacon"):
|
||||
"""Action which configures a C2 Beacon based on the parameters given."""
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Configuration schema for ConfigureC2BeaconAction."""
|
||||
|
||||
node_name: str
|
||||
c2_server_ip_address: str
|
||||
keep_alive_frequency: int = Field(default=5, ge=1)
|
||||
masquerade_protocol: str = Field(default="TCP")
|
||||
masquerade_port: str = Field(default="HTTP")
|
||||
|
||||
@classmethod
|
||||
def form_request(self, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request that can be ingested by the simulation."""
|
||||
data = dict(
|
||||
c2_server_ip_address=config.c2_server_ip_address,
|
||||
keep_alive_frequency=config.keep_alive_frequency,
|
||||
masquerade_protocol=config.masquerade_protocol,
|
||||
masquerade_port=config.masquerade_port,
|
||||
)
|
||||
return ["network", "node", config.node_name, "application", "C2Beacon", "configure", data]
|
||||
|
||||
|
||||
class NodeSendRemoteCommandAction(AbstractAction, identifier="node_send_remote_command"):
|
||||
"""Action which sends a terminal command to a remote node via SSH."""
|
||||
|
||||
config: "NodeSendRemoteCommandAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Configuration schema for NodeSendRemoteCommandAction."""
|
||||
|
||||
node_name: str
|
||||
remote_ip: str
|
||||
command: RequestFormat
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request which can be ingested by the PrimAITE simulation."""
|
||||
return [
|
||||
"network",
|
||||
"node",
|
||||
config.node_name,
|
||||
"service",
|
||||
"Terminal",
|
||||
"send_remote_command",
|
||||
config.remote_ip,
|
||||
{"command": config.command},
|
||||
]
|
||||
|
||||
|
||||
class TerminalC2ServerAction(AbstractAction, identifier="c2_server_terminal_command"):
|
||||
"""Action which causes the C2 Server to send a command to the C2 Beacon to execute the terminal command passed."""
|
||||
|
||||
config: "TerminalC2ServerAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Schema for options that can be passed to this action."""
|
||||
|
||||
node_name: str
|
||||
commands: Union[List[RequestFormat], RequestFormat]
|
||||
ip_address: Optional[str]
|
||||
username: Optional[str]
|
||||
password: Optional[str]
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request that can be ingested by the simulation."""
|
||||
if config.node_name is None:
|
||||
return ["do_nothing"]
|
||||
|
||||
command_model = {
|
||||
"commands": config.commands,
|
||||
"ip_address": config.ip_address,
|
||||
"username": config.username,
|
||||
"password": config.password,
|
||||
}
|
||||
return ["network", "node", config.node_name, "application", "C2Server", "terminal_command", command_model]
|
||||
|
||||
|
||||
class RansomwareLaunchC2ServerAction(AbstractAction, identifier="c2_server_ransomware_launch"):
|
||||
"""Action which causes the C2 Server to send a command to the C2 Beacon to launch the RansomwareScript."""
|
||||
|
||||
config: "RansomwareLaunchC2ServerAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Configuration schema for RansomwareLaunchC2ServerAction."""
|
||||
|
||||
node_name: str
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request that can be ingested by the simulation."""
|
||||
if config.node_name is None:
|
||||
return ["do_nothing"]
|
||||
# This action currently doesn't require any further configuration options.
|
||||
return ["network", "node", config.node_name, "application", "C2Server", "ransomware_launch"]
|
||||
|
||||
|
||||
class ExfiltrationC2ServerAction(AbstractAction, identifier="c2_server_data_exfiltrate"):
|
||||
"""Action which exfiltrates a target file from a certain node onto the C2 beacon and then the C2 Server."""
|
||||
|
||||
config: "ExfiltrationC2ServerAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Schema for options that can be passed to this action."""
|
||||
|
||||
node_name: str
|
||||
username: Optional[str]
|
||||
password: Optional[str]
|
||||
target_ip_address: str
|
||||
target_file_name: str
|
||||
target_folder_name: str
|
||||
exfiltration_folder_name: Optional[str]
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request that can be ingested by the simulation."""
|
||||
if config.node_name is None:
|
||||
return ["do_nothing"]
|
||||
|
||||
command_model = {
|
||||
"target_file_name": config.target_file_name,
|
||||
"target_folder_name": config.target_folder_name,
|
||||
"exfiltration_folder_name": config.exfiltration_folder_name,
|
||||
"target_ip_address": config.target_ip_address,
|
||||
"username": config.username,
|
||||
"password": config.password,
|
||||
}
|
||||
return ["network", "node", config.node_name, "application", "C2Server", "exfiltrate", command_model]
|
||||
|
||||
|
||||
class ConfigureDatabaseClientAction(AbstractAction, identifier="configure_database_client"):
|
||||
"""Action which sets config parameters for a database client on a node."""
|
||||
|
||||
config: "ConfigureDatabaseClientAction.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractAction.ConfigSchema):
|
||||
"""Schema for options that can be passed to this action."""
|
||||
|
||||
node_name: str
|
||||
server_ip_address: Optional[str] = None
|
||||
server_password: Optional[str] = None
|
||||
|
||||
@classmethod
|
||||
def form_request(cls, config: ConfigSchema) -> RequestFormat:
|
||||
"""Return the action formatted as a request that can be ingested by the simulation."""
|
||||
if config.node_name is None:
|
||||
return ["do_nothing"]
|
||||
data = {"server_ip_address": config.server_ip_address, "server_password": config.server_password}
|
||||
return ["network", "node", config.node_name, "application", "DatabaseClient", "configure", data]
|
||||
@@ -1,6 +1,7 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from prettytable import MARKDOWN, PrettyTable
|
||||
|
||||
@@ -20,20 +21,22 @@ class _NotJSONFilter(logging.Filter):
|
||||
|
||||
class AgentLog:
|
||||
"""
|
||||
A Agent Log class is a simple logger dedicated to managing and writing logging updates and information for an agent.
|
||||
An Agent Log class is a simple logger dedicated to managing and writing updates and information for an agent.
|
||||
|
||||
Each log message is written to a file located at: <simulation output directory>/agent_name/agent_name.log
|
||||
Each log message is written to a file located at:
|
||||
<simulation output directory>/agent_name/agent_name.log
|
||||
"""
|
||||
|
||||
def __init__(self, agent_name: str):
|
||||
def __init__(self, agent_name: Optional[str]):
|
||||
"""
|
||||
Constructs a Agent Log instance for a given hostname.
|
||||
|
||||
:param hostname: The hostname associated with the system logs being recorded.
|
||||
:param agent_name: The agent_name associated with the system logs being recorded.
|
||||
"""
|
||||
self.agent_name = agent_name
|
||||
self.current_episode: int = 1
|
||||
super().__init__()
|
||||
self.agent_name = agent_name if agent_name else "unnamed_agent"
|
||||
self.current_timestep: int = 0
|
||||
self.current_episode: int = 1
|
||||
self.setup_logger()
|
||||
|
||||
@property
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Interface for agents."""
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING
|
||||
from typing import Any, ClassVar, Dict, List, Literal, Optional, Tuple, Type, TYPE_CHECKING
|
||||
|
||||
from gymnasium.core import ActType, ObsType
|
||||
from pydantic import BaseModel, model_validator
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
from primaite.game.agent.actions import ActionManager
|
||||
from primaite.game.agent.agent_log import AgentLog
|
||||
@@ -15,6 +17,8 @@ from primaite.interface.request import RequestFormat, RequestResponse
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
__all__ = ("AgentHistoryItem", "AbstractAgent", "AbstractScriptedAgent", "ProxyAgent")
|
||||
|
||||
|
||||
class AgentHistoryItem(BaseModel):
|
||||
"""One entry of an agent's action log - what the agent did and how the simulator responded in 1 step."""
|
||||
@@ -39,89 +43,56 @@ class AgentHistoryItem(BaseModel):
|
||||
reward_info: Dict[str, Any] = {}
|
||||
|
||||
|
||||
class AgentStartSettings(BaseModel):
|
||||
"""Configuration values for when an agent starts performing actions."""
|
||||
|
||||
start_step: int = 5
|
||||
"The timestep at which an agent begins performing it's actions"
|
||||
frequency: int = 5
|
||||
"The number of timesteps to wait between performing actions"
|
||||
variance: int = 0
|
||||
"The amount the frequency can randomly change to"
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_variance_lt_frequency(self) -> "AgentStartSettings":
|
||||
"""
|
||||
Make sure variance is equal to or lower than frequency.
|
||||
|
||||
This is because the calculation for the next execution time is now + (frequency +- variance). If variance were
|
||||
greater than frequency, sometimes the bracketed term would be negative and the attack would never happen again.
|
||||
"""
|
||||
if self.variance > self.frequency:
|
||||
raise ValueError(
|
||||
f"Agent start settings error: variance must be lower than frequency "
|
||||
f"{self.variance=}, {self.frequency=}"
|
||||
)
|
||||
return self
|
||||
|
||||
|
||||
class AgentSettings(BaseModel):
|
||||
"""Settings for configuring the operation of an agent."""
|
||||
|
||||
start_settings: Optional[AgentStartSettings] = None
|
||||
"Configuration for when an agent begins performing it's actions"
|
||||
flatten_obs: bool = True
|
||||
"Whether to flatten the observation space before passing it to the agent. True by default."
|
||||
action_masking: bool = False
|
||||
"Whether to return action masks at each step."
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, config: Optional[Dict]) -> "AgentSettings":
|
||||
"""Construct agent settings from a config dictionary.
|
||||
|
||||
:param config: A dict of options for the agent settings.
|
||||
:type config: Dict
|
||||
:return: The agent settings.
|
||||
:rtype: AgentSettings
|
||||
"""
|
||||
if config is None:
|
||||
return cls()
|
||||
|
||||
return cls(**config)
|
||||
|
||||
|
||||
class AbstractAgent(ABC):
|
||||
class AbstractAgent(BaseModel, ABC):
|
||||
"""Base class for scripted and RL agents."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent_name: Optional[str],
|
||||
action_space: Optional[ActionManager],
|
||||
observation_space: Optional[ObservationManager],
|
||||
reward_function: Optional[RewardFunction],
|
||||
agent_settings: Optional[AgentSettings] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an agent.
|
||||
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
|
||||
|
||||
:param agent_name: Unique string identifier for the agent, for reporting and multi-agent purposes.
|
||||
:type agent_name: Optional[str]
|
||||
:param action_space: Action space for the agent.
|
||||
:type action_space: Optional[ActionManager]
|
||||
:param observation_space: Observation space for the agent.
|
||||
:type observation_space: Optional[ObservationSpace]
|
||||
:param reward_function: Reward function for the agent.
|
||||
:type reward_function: Optional[RewardFunction]
|
||||
:param agent_settings: Configurable Options for Abstracted Agents
|
||||
:type agent_settings: Optional[AgentSettings]
|
||||
"""
|
||||
self.agent_name: str = agent_name or "unnamed_agent"
|
||||
self.action_manager: Optional[ActionManager] = action_space
|
||||
self.observation_manager: Optional[ObservationManager] = observation_space
|
||||
self.reward_function: Optional[RewardFunction] = reward_function
|
||||
self.agent_settings = agent_settings or AgentSettings()
|
||||
self.history: List[AgentHistoryItem] = []
|
||||
self.logger = AgentLog(agent_name)
|
||||
class AgentSettingsSchema(BaseModel, ABC):
|
||||
"""Schema for the 'agent_settings' key."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
class ConfigSchema(BaseModel, ABC):
|
||||
"""Configuration Schema for AbstractAgents."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
|
||||
type: str
|
||||
ref: str = ""
|
||||
"""name of the agent."""
|
||||
team: Optional[Literal["BLUE", "GREEN", "RED"]] = None
|
||||
agent_settings: AbstractAgent.AgentSettingsSchema = Field(default=lambda: AbstractAgent.AgentSettingsSchema())
|
||||
action_space: ActionManager.ConfigSchema = Field(default_factory=lambda: ActionManager.ConfigSchema())
|
||||
observation_space: ObservationManager.ConfigSchema = Field(
|
||||
default_factory=lambda: ObservationManager.ConfigSchema()
|
||||
)
|
||||
reward_function: RewardFunction.ConfigSchema = Field(default_factory=lambda: RewardFunction.ConfigSchema())
|
||||
|
||||
config: "AbstractAgent.ConfigSchema" = Field(default_factory=lambda: AbstractAgent.ConfigSchema())
|
||||
|
||||
logger: AgentLog = AgentLog(agent_name="Abstract_Agent")
|
||||
history: List[AgentHistoryItem] = []
|
||||
|
||||
action_manager: ActionManager = Field(default_factory=lambda: ActionManager())
|
||||
observation_manager: ObservationManager = Field(default_factory=lambda: ObservationManager())
|
||||
reward_function: RewardFunction = Field(default_factory=lambda: RewardFunction())
|
||||
|
||||
_registry: ClassVar[Dict[str, Type[AbstractAgent]]] = {}
|
||||
|
||||
def __init_subclass__(cls, identifier: Optional[str] = None, **kwargs: Any) -> None:
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier is None:
|
||||
return
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Cannot create a new agent under reserved name {identifier}")
|
||||
cls._registry[identifier] = cls
|
||||
|
||||
def model_post_init(self, __context: Any) -> None:
|
||||
"""Overwrite the default empty action, observation, and rewards with ones defined through the config."""
|
||||
self.action_manager = ActionManager(config=self.config.action_space)
|
||||
self.observation_manager = ObservationManager(config=self.config.observation_space)
|
||||
self.reward_function = RewardFunction(config=self.config.reward_function)
|
||||
return super().model_post_init(__context)
|
||||
|
||||
def update_observation(self, state: Dict) -> ObsType:
|
||||
"""
|
||||
@@ -159,9 +130,9 @@ class AbstractAgent(ABC):
|
||||
"""
|
||||
# in RL agent, this method will send CAOS observation to RL agent, then receive a int 0-39,
|
||||
# then use a bespoke conversion to take 1-40 int back into CAOS action
|
||||
return ("DO_NOTHING", {})
|
||||
return ("do_nothing", {})
|
||||
|
||||
def format_request(self, action: Tuple[str, Dict], options: Dict[str, int]) -> List[str]:
|
||||
def format_request(self, action: Tuple[str, Dict], options: Dict[str, int]) -> RequestFormat:
|
||||
# this will take something like APPLICATION.EXECUTE and add things like target_ip_address in simulator.
|
||||
# therefore the execution definition needs to be a mapping from CAOS into SIMULATOR
|
||||
"""Format action into format expected by the simulator, and apply execution definition if applicable."""
|
||||
@@ -182,36 +153,47 @@ class AbstractAgent(ABC):
|
||||
"""Update the most recent history item with the reward value."""
|
||||
self.history[-1].reward = self.reward_function.current_reward
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, config: Dict) -> AbstractAgent:
|
||||
"""Grab the relevant agent class and construct an instance from a config dict."""
|
||||
agent_type = config["type"]
|
||||
agent_class = cls._registry[agent_type]
|
||||
return agent_class(config=config)
|
||||
|
||||
class AbstractScriptedAgent(AbstractAgent):
|
||||
|
||||
class AbstractScriptedAgent(AbstractAgent, identifier="AbstractScriptedAgent"):
|
||||
"""Base class for actors which generate their own behaviour."""
|
||||
|
||||
config: "AbstractScriptedAgent.ConfigSchema" = Field(default_factory=lambda: AbstractScriptedAgent.ConfigSchema())
|
||||
|
||||
class ConfigSchema(AbstractAgent.ConfigSchema):
|
||||
"""Configuration Schema for AbstractScriptedAgents."""
|
||||
|
||||
type: str = "AbstractScriptedAgent"
|
||||
|
||||
@abstractmethod
|
||||
def get_action(self, obs: ObsType, timestep: int = 0) -> Tuple[str, Dict]:
|
||||
"""Return an action to be taken in the environment."""
|
||||
return super().get_action(obs=obs, timestep=timestep)
|
||||
|
||||
|
||||
class ProxyAgent(AbstractAgent):
|
||||
class ProxyAgent(AbstractAgent, identifier="ProxyAgent"):
|
||||
"""Agent that sends observations to an RL model and receives actions from that model."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent_name: Optional[str],
|
||||
action_space: Optional[ActionManager],
|
||||
observation_space: Optional[ObservationManager],
|
||||
reward_function: Optional[RewardFunction],
|
||||
agent_settings: Optional[AgentSettings] = None,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
agent_name=agent_name,
|
||||
action_space=action_space,
|
||||
observation_space=observation_space,
|
||||
reward_function=reward_function,
|
||||
)
|
||||
self.most_recent_action: ActType
|
||||
self.flatten_obs: bool = agent_settings.flatten_obs if agent_settings else False
|
||||
self.action_masking: bool = agent_settings.action_masking if agent_settings else False
|
||||
config: "ProxyAgent.ConfigSchema" = Field(default_factory=lambda: ProxyAgent.ConfigSchema())
|
||||
most_recent_action: ActType = None
|
||||
|
||||
class AgentSettingsSchema(AbstractAgent.AgentSettingsSchema):
|
||||
"""Schema for the `agent_settings` part of the agent config."""
|
||||
|
||||
flatten_obs: bool = False
|
||||
action_masking: bool = False
|
||||
|
||||
class ConfigSchema(AbstractAgent.ConfigSchema):
|
||||
"""Configuration Schema for Proxy Agent."""
|
||||
|
||||
type: str = "Proxy_Agent"
|
||||
agent_settings: ProxyAgent.AgentSettingsSchema = Field(default_factory=lambda: ProxyAgent.AgentSettingsSchema())
|
||||
|
||||
def get_action(self, obs: ObsType, timestep: int = 0) -> Tuple[str, Dict]:
|
||||
"""
|
||||
@@ -233,3 +215,8 @@ class ProxyAgent(AbstractAgent):
|
||||
The environment is responsible for calling this method when it receives an action from the agent policy.
|
||||
"""
|
||||
self.most_recent_action = action
|
||||
|
||||
@property
|
||||
def flatten_obs(self) -> bool:
|
||||
"""Return agent flatten_obs param."""
|
||||
return self.config.agent_settings.flatten_obs
|
||||
|
||||
@@ -17,5 +17,5 @@ from primaite.game.agent.observations.software_observation import ApplicationObs
|
||||
__all__ = [
|
||||
"ACLObservation", "FileObservation", "FolderObservation", "FirewallObservation", "HostObservation",
|
||||
"LinksObservation", "NICObservation", "PortObservation", "NodesObservation", "NestedObservation",
|
||||
"ObservationManager", "ApplicationObservation", "ServiceObservation",]
|
||||
"ObservationManager", "ApplicationObservation", "ServiceObservation", "RouterObservation", "LinkObservation",]
|
||||
# fmt: on
|
||||
|
||||
@@ -72,7 +72,6 @@ class FirewallObservation(AbstractObservation, identifier="FIREWALL"):
|
||||
self.ports: List[PortObservation] = [
|
||||
PortObservation(where=self.where + ["NICs", port_num]) for port_num in (1, 2, 3)
|
||||
]
|
||||
# TODO: check what the port nums are for firewall.
|
||||
|
||||
self.internal_inbound_acl = ACLObservation(
|
||||
where=self.where + ["internal_inbound_acl", "acl"],
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import cached_property
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from gymnasium import spaces
|
||||
from gymnasium.core import ObsType
|
||||
from pydantic import BaseModel, ConfigDict, model_validator, ValidationError
|
||||
from pydantic import BaseModel, computed_field, ConfigDict, Field, model_validator, ValidationError
|
||||
|
||||
from primaite.game.agent.observations.observations import AbstractObservation, WhereType
|
||||
|
||||
@@ -140,7 +141,7 @@ class NullObservation(AbstractObservation, identifier="NONE"):
|
||||
return cls()
|
||||
|
||||
|
||||
class ObservationManager:
|
||||
class ObservationManager(BaseModel):
|
||||
"""
|
||||
Manage the observations of an Agent.
|
||||
|
||||
@@ -150,15 +151,66 @@ class ObservationManager:
|
||||
3. Formatting this information so an agent can use it to make decisions.
|
||||
"""
|
||||
|
||||
def __init__(self, obs: AbstractObservation) -> None:
|
||||
"""Initialise observation space.
|
||||
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
|
||||
|
||||
:param observation: Observation object
|
||||
:type observation: AbstractObservation
|
||||
"""
|
||||
self.obs: AbstractObservation = obs
|
||||
self.current_observation: ObsType
|
||||
"""Cached copy of the observation at the time it was most recently calculated."""
|
||||
class ConfigSchema(BaseModel):
|
||||
"""Config Schema for Observation Manager."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
type: str = "NONE"
|
||||
"""Identifier name for the top-level observation."""
|
||||
options: AbstractObservation.ConfigSchema = Field(
|
||||
default_factory=lambda: NullObservation.ConfigSchema(), validate_default=True
|
||||
)
|
||||
"""Options to pass into the top-level observation during creation."""
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def resolve_obs_options_type(cls, data: Any) -> Any:
|
||||
"""
|
||||
When constructing the model from a dict, resolve the correct observation class based on `type` field.
|
||||
|
||||
Workaround: The `options` field is statically typed as AbstractObservation. Therefore, it falls over when
|
||||
passing in data that adheres to a subclass schema rather than the plain AbstractObservation schema. There is
|
||||
a way to do this properly using discriminated union, but most advice on the internet assumes that the full
|
||||
list of types between which to discriminate is known ahead-of-time. That is not the case for us, because of
|
||||
our plugin architecture.
|
||||
|
||||
We may be able to revisit and implement a better solution when needed using the following resources as
|
||||
research starting points:
|
||||
https://docs.pydantic.dev/latest/concepts/unions/#discriminated-unions
|
||||
https://github.com/pydantic/pydantic/issues/7366
|
||||
https://github.com/pydantic/pydantic/issues/7462
|
||||
https://github.com/pydantic/pydantic/pull/7983
|
||||
"""
|
||||
if not isinstance(data, dict):
|
||||
return data
|
||||
|
||||
# (TODO: duplicate default definition between here and the actual model)
|
||||
obs_type = data["type"] if "type" in data else "NONE"
|
||||
obs_class = AbstractObservation._registry[obs_type]
|
||||
|
||||
# if no options are passed in, try to create a default schema. Only works if there are no mandatory fields
|
||||
if "options" not in data:
|
||||
data["options"] = obs_class.ConfigSchema()
|
||||
|
||||
# if options passed as a dict, validate against schema
|
||||
elif isinstance(data["options"], dict):
|
||||
data["options"] = obs_class.ConfigSchema(**data["options"])
|
||||
|
||||
return data
|
||||
|
||||
config: ConfigSchema = Field(default_factory=lambda: ObservationManager.ConfigSchema())
|
||||
|
||||
current_observation: ObsType = 0
|
||||
|
||||
@computed_field
|
||||
@cached_property
|
||||
def obs(self) -> AbstractObservation:
|
||||
"""Create the main observation component for the observation manager from the config."""
|
||||
obs_class = AbstractObservation._registry[self.config.type]
|
||||
obs_instance = obs_class.from_config(config=self.config.options)
|
||||
return obs_instance
|
||||
|
||||
def update(self, state: Dict) -> Dict:
|
||||
"""
|
||||
|
||||
@@ -31,7 +31,7 @@ class AbstractObservation(ABC):
|
||||
"""Initialise an observation. This method must be overwritten."""
|
||||
self.default_observation: ObsType
|
||||
|
||||
def __init_subclass__(cls, identifier: str, **kwargs: Any) -> None:
|
||||
def __init_subclass__(cls, identifier: Optional[str] = None, **kwargs: Any) -> None:
|
||||
"""
|
||||
Register an observation type.
|
||||
|
||||
@@ -40,6 +40,8 @@ class AbstractObservation(ABC):
|
||||
:raises ValueError: When attempting to create a component with a name that is already in use.
|
||||
"""
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier is None:
|
||||
return
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Duplicate observation component type {identifier}")
|
||||
cls._registry[identifier] = cls
|
||||
|
||||
@@ -30,7 +30,7 @@ the structure:
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Callable, ClassVar, Dict, Iterable, List, Optional, Tuple, Type, TYPE_CHECKING, Union
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
from typing_extensions import Never
|
||||
|
||||
from primaite import getLogger
|
||||
@@ -48,21 +48,17 @@ class AbstractReward(BaseModel):
|
||||
|
||||
config: "AbstractReward.ConfigSchema"
|
||||
|
||||
# def __init__(self, schema_name, **kwargs):
|
||||
# super.__init__(self, **kwargs)
|
||||
# # Create ConfigSchema class
|
||||
# self.config_class = type(schema_name, (BaseModel, ABC), **kwargs)
|
||||
# self.config = self.config_class()
|
||||
|
||||
class ConfigSchema(BaseModel, ABC):
|
||||
"""Config schema for AbstractReward."""
|
||||
|
||||
type: str
|
||||
type: str = ""
|
||||
|
||||
_registry: ClassVar[Dict[str, Type["AbstractReward"]]] = {}
|
||||
|
||||
def __init_subclass__(cls, identifier: str, **kwargs: Any) -> None:
|
||||
def __init_subclass__(cls, identifier: Optional[str] = None, **kwargs: Any) -> None:
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier is None:
|
||||
return
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Duplicate reward {identifier}")
|
||||
cls._registry[identifier] = cls
|
||||
@@ -381,14 +377,19 @@ class SharedReward(AbstractReward, identifier="SHARED_REWARD"):
|
||||
|
||||
|
||||
class ActionPenalty(AbstractReward, identifier="ACTION_PENALTY"):
|
||||
"""Apply a negative reward when taking any action except DONOTHING."""
|
||||
"""Apply a negative reward when taking any action except do_nothing."""
|
||||
|
||||
config: "ActionPenalty.ConfigSchema"
|
||||
|
||||
class ConfigSchema(AbstractReward.ConfigSchema):
|
||||
"""Config schema for ActionPenalty."""
|
||||
"""Config schema for ActionPenalty.
|
||||
|
||||
:param action_penalty: Reward to give agents for taking any action except do_nothing
|
||||
:type action_penalty: float
|
||||
:param do_nothing_penalty: Reward to give agent for taking the do_nothing action
|
||||
:type do_nothing_penalty: float
|
||||
"""
|
||||
|
||||
type: str = "ACTION_PENALTY"
|
||||
action_penalty: float = -1.0
|
||||
do_nothing_penalty: float = 0.0
|
||||
|
||||
@@ -402,21 +403,81 @@ class ActionPenalty(AbstractReward, identifier="ACTION_PENALTY"):
|
||||
:return: Reward value
|
||||
:rtype: float
|
||||
"""
|
||||
if last_action_response.action == "DONOTHING":
|
||||
if last_action_response.action == "do_nothing":
|
||||
return self.config.do_nothing_penalty
|
||||
|
||||
else:
|
||||
return self.config.action_penalty
|
||||
|
||||
|
||||
class RewardFunction:
|
||||
class _SingleComponentConfig(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
type: str
|
||||
options: AbstractReward.ConfigSchema
|
||||
weight: float = 1.0
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def resolve_obs_options_type(cls, data: Any) -> Any:
|
||||
"""
|
||||
When constructing the model from a dict, resolve the correct reward class based on `type` field.
|
||||
|
||||
Workaround: The `options` field is statically typed as AbstractReward. Therefore, it falls over when
|
||||
passing in data that adheres to a subclass schema rather than the plain AbstractReward schema. There is
|
||||
a way to do this properly using discriminated union, but most advice on the internet assumes that the full
|
||||
list of types between which to discriminate is known ahead-of-time. That is not the case for us, because of
|
||||
our plugin architecture.
|
||||
|
||||
We may be able to revisit and implement a better solution when needed using the following resources as
|
||||
research starting points:
|
||||
https://docs.pydantic.dev/latest/concepts/unions/#discriminated-unions
|
||||
https://github.com/pydantic/pydantic/issues/7366
|
||||
https://github.com/pydantic/pydantic/issues/7462
|
||||
https://github.com/pydantic/pydantic/pull/7983
|
||||
"""
|
||||
if not isinstance(data, dict):
|
||||
return data
|
||||
|
||||
assert "type" in data, ValueError('Reward component definition is missing the "type" key.')
|
||||
rew_type = data["type"]
|
||||
rew_class = AbstractReward._registry[rew_type]
|
||||
|
||||
# if no options are passed in, try to create a default schema. Only works if there are no mandatory fields.
|
||||
if "options" not in data:
|
||||
data["options"] = rew_class.ConfigSchema()
|
||||
|
||||
# if options are passed as a dict, validate against schema
|
||||
elif isinstance(data["options"], dict):
|
||||
data["options"] = rew_class.ConfigSchema(**data["options"])
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class RewardFunction(BaseModel):
|
||||
"""Manages the reward function for the agent."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialise the reward function object."""
|
||||
self.reward_components: List[Tuple[AbstractReward, float]] = []
|
||||
"attribute reward_components keeps track of reward components and the weights assigned to each."
|
||||
self.current_reward: float = 0.0
|
||||
self.total_reward: float = 0.0
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
class ConfigSchema(BaseModel):
|
||||
"""Config Schema for RewardFunction."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
reward_components: Iterable[_SingleComponentConfig] = []
|
||||
|
||||
config: ConfigSchema = Field(default_factory=lambda: RewardFunction.ConfigSchema())
|
||||
|
||||
reward_components: List[Tuple[AbstractReward, float]] = []
|
||||
|
||||
current_reward: float = 0.0
|
||||
total_reward: float = 0.0
|
||||
|
||||
def __init__(self, **kwargs) -> None:
|
||||
super().__init__(**kwargs)
|
||||
for rew_config in self.config.reward_components:
|
||||
rew_class = AbstractReward._registry[rew_config.type]
|
||||
rew_instance = rew_class(config=rew_config.options)
|
||||
self.register_component(component=rew_instance, weight=rew_config.weight)
|
||||
|
||||
def register_component(self, component: AbstractReward, weight: float = 1.0) -> None:
|
||||
"""Add a reward component to the reward function.
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
from primaite.game.agent import interface
|
||||
from primaite.game.agent.scripted_agents import abstract_tap, data_manipulation_bot, probabilistic_agent, random_agent
|
||||
|
||||
__all__ = ("abstract_tap", "data_manipulation_bot", "interface", "probabilistic_agent", "random_agent")
|
||||
|
||||
61
src/primaite/game/agent/scripted_agents/abstract_tap.py
Normal file
61
src/primaite/game/agent/scripted_agents/abstract_tap.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from abc import abstractmethod
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from gymnasium.core import ObsType
|
||||
from pydantic import Field
|
||||
|
||||
from primaite.game.agent.scripted_agents.random_agent import PeriodicAgent
|
||||
|
||||
__all__ = "AbstractTAPAgent"
|
||||
|
||||
|
||||
class AbstractTAPAgent(PeriodicAgent, identifier="AbstractTAP"):
|
||||
"""Base class for TAP agents to inherit from."""
|
||||
|
||||
config: "AbstractTAPAgent.ConfigSchema" = Field(default_factory=lambda: AbstractTAPAgent.ConfigSchema())
|
||||
next_execution_timestep: int = 0
|
||||
|
||||
class AgentSettingsSchema(PeriodicAgent.AgentSettingsSchema):
|
||||
"""Schema for the `agent_settings` part of the agent config."""
|
||||
|
||||
possible_starting_nodes: List[str] = Field(default_factory=list)
|
||||
|
||||
class ConfigSchema(PeriodicAgent.ConfigSchema):
|
||||
"""Configuration schema for Abstract TAP agents."""
|
||||
|
||||
type: str = "AbstractTAP"
|
||||
agent_settings: AbstractTAPAgent.AgentSettingsSchema = Field(
|
||||
default_factory=lambda: AbstractTAPAgent.AgentSettingsSchema()
|
||||
)
|
||||
|
||||
starting_node: Optional[str] = None
|
||||
|
||||
@abstractmethod
|
||||
def get_action(self, obs: ObsType, timestep: int = 0) -> Tuple[str, Dict]:
|
||||
"""Return an action to be taken in the environment."""
|
||||
return super().get_action(obs=obs, timestep=timestep)
|
||||
|
||||
@abstractmethod
|
||||
def setup_agent(self) -> None:
|
||||
"""Set up agent."""
|
||||
pass
|
||||
|
||||
def _set_next_execution_timestep(self, timestep: int) -> None:
|
||||
"""Set the next execution timestep with a configured random variance.
|
||||
|
||||
:param timestep: The timestep to add variance to.
|
||||
"""
|
||||
random_timestep_increment = random.randint(
|
||||
-self.config.agent_settings.variance, self.config.agent_settings.variance
|
||||
)
|
||||
self.next_execution_timestep = timestep + random_timestep_increment
|
||||
|
||||
def _select_start_node(self) -> None:
|
||||
"""Set the starting starting node of the agent to be a random node from this agent's action manager."""
|
||||
# we are assuming that every node in the node manager has a data manipulation application at idx 0
|
||||
self.starting_node = random.choice(self.config.agent_settings.possible_starting_nodes)
|
||||
self.logger.debug(f"Selected starting node: {self.starting_node}")
|
||||
@@ -1,31 +1,35 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
import random
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from gymnasium.core import ObsType
|
||||
from pydantic import Field
|
||||
|
||||
from primaite.game.agent.interface import AbstractScriptedAgent
|
||||
from primaite.game.agent.scripted_agents.random_agent import PeriodicAgent
|
||||
|
||||
__all__ = "DataManipulationAgent"
|
||||
|
||||
|
||||
class DataManipulationAgent(AbstractScriptedAgent):
|
||||
class DataManipulationAgent(PeriodicAgent, identifier="RedDatabaseCorruptingAgent"):
|
||||
"""Agent that uses a DataManipulationBot to perform an SQL injection attack."""
|
||||
|
||||
next_execution_timestep: int = 0
|
||||
starting_node_idx: int = 0
|
||||
class AgentSettingsSchema(PeriodicAgent.AgentSettingsSchema):
|
||||
"""Schema for the `agent_settings` part of the agent config."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.setup_agent()
|
||||
target_application: str = "DataManipulationBot"
|
||||
|
||||
def _set_next_execution_timestep(self, timestep: int) -> None:
|
||||
"""Set the next execution timestep with a configured random variance.
|
||||
class ConfigSchema(PeriodicAgent.ConfigSchema):
|
||||
"""Configuration Schema for DataManipulationAgent."""
|
||||
|
||||
:param timestep: The timestep to add variance to.
|
||||
"""
|
||||
random_timestep_increment = random.randint(
|
||||
-self.agent_settings.start_settings.variance, self.agent_settings.start_settings.variance
|
||||
type: str = "RedDatabaseCorruptingAgent"
|
||||
agent_settings: "DataManipulationAgent.AgentSettingsSchema" = Field(
|
||||
default_factory=lambda: DataManipulationAgent.AgentSettingsSchema()
|
||||
)
|
||||
self.next_execution_timestep = timestep + random_timestep_increment
|
||||
|
||||
config: "DataManipulationAgent.ConfigSchema" = Field(default_factory=lambda: DataManipulationAgent.ConfigSchema())
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._set_next_execution_timestep(timestep=self.config.agent_settings.start_step, variance=0)
|
||||
|
||||
def get_action(self, obs: ObsType, timestep: int) -> Tuple[str, Dict]:
|
||||
"""Waits until a specific timestep, then attempts to execute its data manipulation application.
|
||||
@@ -38,21 +42,14 @@ class DataManipulationAgent(AbstractScriptedAgent):
|
||||
:rtype: Tuple[str, Dict]
|
||||
"""
|
||||
if timestep < self.next_execution_timestep:
|
||||
self.logger.debug(msg="Performing do NOTHING")
|
||||
return "DONOTHING", {}
|
||||
self.logger.debug(msg="Performing do nothing action")
|
||||
return "do_nothing", {}
|
||||
|
||||
self._set_next_execution_timestep(timestep + self.agent_settings.start_settings.frequency)
|
||||
self._set_next_execution_timestep(
|
||||
timestep=timestep + self.config.agent_settings.frequency, variance=self.config.agent_settings.variance
|
||||
)
|
||||
self.logger.info(msg="Performing a data manipulation attack!")
|
||||
return "NODE_APPLICATION_EXECUTE", {"node_id": self.starting_node_idx, "application_id": 0}
|
||||
|
||||
def setup_agent(self) -> None:
|
||||
"""Set the next execution timestep when the episode resets."""
|
||||
self._select_start_node()
|
||||
self._set_next_execution_timestep(self.agent_settings.start_settings.start_step)
|
||||
|
||||
def _select_start_node(self) -> None:
|
||||
"""Set the starting starting node of the agent to be a random node from this agent's action manager."""
|
||||
# we are assuming that every node in the node manager has a data manipulation application at idx 0
|
||||
num_nodes = len(self.action_manager.node_names)
|
||||
self.starting_node_idx = random.randint(0, num_nodes - 1)
|
||||
self.logger.debug(msg=f"Select Start Node ID: {self.starting_node_idx}")
|
||||
return "node_application_execute", {
|
||||
"node_name": self.start_node,
|
||||
"application_name": self.config.agent_settings.target_application,
|
||||
}
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Agents with predefined behaviours."""
|
||||
from typing import Dict, Optional, Tuple
|
||||
from typing import Dict, Tuple
|
||||
|
||||
import numpy as np
|
||||
import pydantic
|
||||
from gymnasium.core import ObsType
|
||||
from numpy.random import Generator
|
||||
from pydantic import Field
|
||||
|
||||
from primaite.game.agent.actions import ActionManager
|
||||
from primaite.game.agent.interface import AbstractScriptedAgent
|
||||
from primaite.game.agent.observations.observation_manager import ObservationManager
|
||||
from primaite.game.agent.rewards import RewardFunction
|
||||
|
||||
__all__ = "ProbabilisticAgent"
|
||||
|
||||
|
||||
class ProbabilisticAgent(AbstractScriptedAgent):
|
||||
class ProbabilisticAgent(AbstractScriptedAgent, identifier="ProbabilisticAgent"):
|
||||
"""Scripted agent which randomly samples its action space with prescribed probabilities for each action."""
|
||||
|
||||
class Settings(pydantic.BaseModel):
|
||||
"""Config schema for Probabilistic agent settings."""
|
||||
rng: Generator = Field(default_factory=lambda: np.random.default_rng(np.random.randint(0, 65535)))
|
||||
|
||||
model_config = pydantic.ConfigDict(extra="forbid")
|
||||
"""Strict validation."""
|
||||
action_probabilities: Dict[int, float]
|
||||
class AgentSettingsSchema(AbstractScriptedAgent.AgentSettingsSchema):
|
||||
"""Schema for the `agent_settings` part of the agent config."""
|
||||
|
||||
action_probabilities: Dict[int, float] = None
|
||||
"""Probability to perform each action in the action map. The sum of probabilities should sum to 1."""
|
||||
# TODO: give the option to still set a random seed, but have it vary each episode in a predictable way
|
||||
# for example if the user sets seed 123, have it be 123 + episode_num, so that each ep it's the next seed.
|
||||
|
||||
@pydantic.field_validator("action_probabilities", mode="after")
|
||||
@classmethod
|
||||
@@ -44,31 +43,20 @@ class ProbabilisticAgent(AbstractScriptedAgent):
|
||||
)
|
||||
return v
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent_name: str,
|
||||
action_space: Optional[ActionManager],
|
||||
observation_space: Optional[ObservationManager],
|
||||
reward_function: Optional[RewardFunction],
|
||||
settings: Dict = {},
|
||||
) -> None:
|
||||
# If the action probabilities are not specified, create equal probabilities for all actions
|
||||
if "action_probabilities" not in settings:
|
||||
num_actions = len(action_space.action_map)
|
||||
settings = {"action_probabilities": {i: 1 / num_actions for i in range(num_actions)}}
|
||||
class ConfigSchema(AbstractScriptedAgent.ConfigSchema):
|
||||
"""Configuration schema for Probabilistic Agent."""
|
||||
|
||||
# The random number seed for np.random is dependent on whether a random number seed is set
|
||||
# in the config file. If there is one it is processed by set_random_seed() in environment.py
|
||||
# and as a consequence the the sequence of rng_seed's used here will be repeatable.
|
||||
self.settings = ProbabilisticAgent.Settings(**settings)
|
||||
rng_seed = np.random.randint(0, 65535)
|
||||
self.rng = np.random.default_rng(rng_seed)
|
||||
type: str = "ProbabilisticAgent"
|
||||
agent_settings: "ProbabilisticAgent.AgentSettingsSchema" = Field(
|
||||
default_factory=lambda: ProbabilisticAgent.AgentSettingsSchema()
|
||||
)
|
||||
|
||||
# convert probabilities from
|
||||
self.probabilities = np.asarray(list(self.settings.action_probabilities.values()))
|
||||
config: "ProbabilisticAgent.ConfigSchema" = Field(default_factory=lambda: ProbabilisticAgent.ConfigSchema())
|
||||
|
||||
super().__init__(agent_name, action_space, observation_space, reward_function)
|
||||
self.logger.debug(f"ProbabilisticAgent RNG seed: {rng_seed}")
|
||||
@property
|
||||
def probabilities(self) -> Dict[str, int]:
|
||||
"""Convenience method to view the probabilities of the Agent."""
|
||||
return np.asarray(list(self.config.agent_settings.action_probabilities.values()))
|
||||
|
||||
def get_action(self, obs: ObsType, timestep: int = 0) -> Tuple[str, Dict]:
|
||||
"""
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
import random
|
||||
from typing import Dict, Optional, Tuple
|
||||
from functools import cached_property
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
from gymnasium.core import ObsType
|
||||
from pydantic import BaseModel
|
||||
from pydantic import computed_field, Field, model_validator
|
||||
|
||||
from primaite.game.agent.actions import ActionManager
|
||||
from primaite.game.agent.interface import AbstractScriptedAgent
|
||||
from primaite.game.agent.observations.observation_manager import ObservationManager
|
||||
from primaite.game.agent.rewards import RewardFunction
|
||||
|
||||
__all__ = ("RandomAgent", "PeriodicAgent")
|
||||
|
||||
|
||||
class RandomAgent(AbstractScriptedAgent):
|
||||
class RandomAgent(AbstractScriptedAgent, identifier="RandomAgent"):
|
||||
"""Agent that ignores its observation and acts completely at random."""
|
||||
|
||||
def get_action(self, obs: ObsType, timestep: int = 0) -> Tuple[str, Dict]:
|
||||
config: "RandomAgent.ConfigSchema" = Field(default_factory=lambda: RandomAgent.ConfigSchema())
|
||||
|
||||
class ConfigSchema(AbstractScriptedAgent.ConfigSchema):
|
||||
"""Configuration Schema for Random Agents."""
|
||||
|
||||
type: str = "RandomAgent"
|
||||
|
||||
def get_action(self) -> Tuple[str, Dict]:
|
||||
"""Sample the action space randomly.
|
||||
|
||||
:param obs: Current observation for this agent, not used in RandomAgent
|
||||
@@ -27,41 +34,60 @@ class RandomAgent(AbstractScriptedAgent):
|
||||
return self.action_manager.get_action(self.action_manager.space.sample())
|
||||
|
||||
|
||||
class PeriodicAgent(AbstractScriptedAgent):
|
||||
class PeriodicAgent(AbstractScriptedAgent, identifier="PeriodicAgent"):
|
||||
"""Agent that does nothing most of the time, but executes application at regular intervals (with variance)."""
|
||||
|
||||
class Settings(BaseModel):
|
||||
"""Configuration values for when an agent starts performing actions."""
|
||||
config: "PeriodicAgent.ConfigSchema" = Field(default_factory=lambda: PeriodicAgent.ConfigSchema())
|
||||
|
||||
start_step: int = 20
|
||||
"The timestep at which an agent begins performing it's actions."
|
||||
start_variance: int = 5
|
||||
"Deviation around the start step."
|
||||
class AgentSettingsSchema(AbstractScriptedAgent.AgentSettingsSchema):
|
||||
"""Schema for the `agent_settings` part of the agent config."""
|
||||
|
||||
start_step: int = 5
|
||||
"The timestep at which an agent begins performing it's actions"
|
||||
frequency: int = 5
|
||||
"The number of timesteps to wait between performing actions."
|
||||
"The number of timesteps to wait between performing actions"
|
||||
variance: int = 0
|
||||
"The amount the frequency can randomly change to."
|
||||
max_executions: int = 999999
|
||||
"Maximum number of times the agent can execute its action."
|
||||
"The amount the frequency can randomly change to"
|
||||
possible_start_nodes: List[str]
|
||||
target_application: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent_name: str,
|
||||
action_space: ActionManager,
|
||||
observation_space: ObservationManager,
|
||||
reward_function: RewardFunction,
|
||||
settings: Optional[Settings] = None,
|
||||
) -> None:
|
||||
"""Initialise PeriodicAgent."""
|
||||
super().__init__(
|
||||
agent_name=agent_name,
|
||||
action_space=action_space,
|
||||
observation_space=observation_space,
|
||||
reward_function=reward_function,
|
||||
@model_validator(mode="after")
|
||||
def check_variance_lt_frequency(self) -> "PeriodicAgent.ConfigSchema":
|
||||
"""
|
||||
Make sure variance is equal to or lower than frequency.
|
||||
|
||||
This is because the calculation for the next execution time is now + (frequency +- variance).
|
||||
If variance were greater than frequency, sometimes the bracketed term would be negative
|
||||
and the attack would never happen again.
|
||||
"""
|
||||
if self.variance >= self.frequency:
|
||||
raise ValueError(
|
||||
f"Agent start settings error: variance must be lower than frequency "
|
||||
f"{self.variance=}, {self.frequency=}"
|
||||
)
|
||||
return self
|
||||
|
||||
class ConfigSchema(AbstractScriptedAgent.ConfigSchema):
|
||||
"""Configuration Schema for Periodic Agent."""
|
||||
|
||||
type: str = "PeriodicAgent"
|
||||
"""Name of the agent."""
|
||||
agent_settings: "PeriodicAgent.AgentSettingsSchema" = Field(
|
||||
default_factory=lambda: PeriodicAgent.AgentSettingsSchema()
|
||||
)
|
||||
self.settings = settings or PeriodicAgent.Settings()
|
||||
self._set_next_execution_timestep(timestep=self.settings.start_step, variance=self.settings.start_variance)
|
||||
self.num_executions = 0
|
||||
|
||||
max_executions: int = 999999
|
||||
"Maximum number of times the agent can execute its action."
|
||||
num_executions: int = 0
|
||||
"""Number of times the agent has executed an action."""
|
||||
next_execution_timestep: int = 0
|
||||
"""Timestep of the next action execution by the agent."""
|
||||
|
||||
@computed_field
|
||||
@cached_property
|
||||
def start_node(self) -> str:
|
||||
"""On instantiation, randomly select a start node."""
|
||||
return random.choice(self.config.agent_settings.possible_start_nodes)
|
||||
|
||||
def _set_next_execution_timestep(self, timestep: int, variance: int) -> None:
|
||||
"""Set the next execution timestep with a configured random variance.
|
||||
@@ -76,9 +102,14 @@ class PeriodicAgent(AbstractScriptedAgent):
|
||||
|
||||
def get_action(self, obs: ObsType, timestep: int) -> Tuple[str, Dict]:
|
||||
"""Do nothing, unless the current timestep is the next execution timestep, in which case do the action."""
|
||||
if timestep == self.next_execution_timestep and self.num_executions < self.settings.max_executions:
|
||||
if timestep == self.next_execution_timestep and self.num_executions < self.max_executions:
|
||||
self.num_executions += 1
|
||||
self._set_next_execution_timestep(timestep + self.settings.frequency, self.settings.variance)
|
||||
return "NODE_APPLICATION_EXECUTE", {"node_id": 0, "application_id": 0}
|
||||
self._set_next_execution_timestep(
|
||||
timestep + self.config.agent_settings.frequency, self.config.agent_settings.variance
|
||||
)
|
||||
return "node_application_execute", {
|
||||
"node_name": self.start_node,
|
||||
"application_name": self.config.agent_settings.target_application,
|
||||
}
|
||||
|
||||
return "DONOTHING", {}
|
||||
return "do_nothing", {}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
import random
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from gymnasium.core import ObsType
|
||||
|
||||
from primaite.game.agent.interface import AbstractScriptedAgent
|
||||
|
||||
|
||||
class TAP001(AbstractScriptedAgent):
|
||||
"""
|
||||
TAP001 | Mobile Malware -- Ransomware Variant.
|
||||
|
||||
Scripted Red Agent. Capable of one action; launching the kill-chain (Ransomware Application)
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.setup_agent()
|
||||
|
||||
next_execution_timestep: int = 0
|
||||
starting_node_idx: int = 0
|
||||
installed: bool = False
|
||||
|
||||
def _set_next_execution_timestep(self, timestep: int) -> None:
|
||||
"""Set the next execution timestep with a configured random variance.
|
||||
|
||||
:param timestep: The timestep to add variance to.
|
||||
"""
|
||||
random_timestep_increment = random.randint(
|
||||
-self.agent_settings.start_settings.variance, self.agent_settings.start_settings.variance
|
||||
)
|
||||
self.next_execution_timestep = timestep + random_timestep_increment
|
||||
|
||||
def get_action(self, obs: ObsType, timestep: int) -> Tuple[str, Dict]:
|
||||
"""Waits until a specific timestep, then attempts to execute the ransomware application.
|
||||
|
||||
This application acts a wrapper around the kill-chain, similar to green-analyst and
|
||||
the previous UC2 data manipulation bot.
|
||||
|
||||
:param obs: Current observation for this agent.
|
||||
:type obs: ObsType
|
||||
:param timestep: The current simulation timestep, used for scheduling actions
|
||||
:type timestep: int
|
||||
:return: Action formatted in CAOS format
|
||||
:rtype: Tuple[str, Dict]
|
||||
"""
|
||||
if timestep < self.next_execution_timestep:
|
||||
return "DONOTHING", {}
|
||||
|
||||
self._set_next_execution_timestep(timestep + self.agent_settings.start_settings.frequency)
|
||||
|
||||
if not self.installed:
|
||||
self.installed = True
|
||||
return "NODE_APPLICATION_INSTALL", {
|
||||
"node_id": self.starting_node_idx,
|
||||
"application_name": "RansomwareScript",
|
||||
}
|
||||
|
||||
return "NODE_APPLICATION_EXECUTE", {"node_id": self.starting_node_idx, "application_id": 0}
|
||||
|
||||
def setup_agent(self) -> None:
|
||||
"""Set the next execution timestep when the episode resets."""
|
||||
self._select_start_node()
|
||||
self._set_next_execution_timestep(self.agent_settings.start_settings.start_step)
|
||||
for n, act in self.action_manager.action_map.items():
|
||||
if not act[0] == "NODE_APPLICATION_INSTALL":
|
||||
continue
|
||||
if act[1]["node_id"] == self.starting_node_idx:
|
||||
self.ip_address = act[1]["ip_address"]
|
||||
return
|
||||
raise RuntimeError("TAP001 agent could not find database server ip address in action map")
|
||||
|
||||
def _select_start_node(self) -> None:
|
||||
"""Set the starting starting node of the agent to be a random node from this agent's action manager."""
|
||||
# we are assuming that every node in the node manager has a data manipulation application at idx 0
|
||||
num_nodes = len(self.action_manager.node_names)
|
||||
self.starting_node_idx = random.randint(0, num_nodes - 1)
|
||||
@@ -7,14 +7,8 @@ import numpy as np
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
from primaite import DEFAULT_BANDWIDTH, getLogger
|
||||
from primaite.game.agent.actions import ActionManager
|
||||
from primaite.game.agent.interface import AbstractAgent, AgentSettings, ProxyAgent
|
||||
from primaite.game.agent.observations.observation_manager import ObservationManager
|
||||
from primaite.game.agent.rewards import RewardFunction, SharedReward
|
||||
from primaite.game.agent.scripted_agents.data_manipulation_bot import DataManipulationAgent
|
||||
from primaite.game.agent.scripted_agents.probabilistic_agent import ProbabilisticAgent
|
||||
from primaite.game.agent.scripted_agents.random_agent import PeriodicAgent
|
||||
from primaite.game.agent.scripted_agents.tap001 import TAP001
|
||||
from primaite.game.agent.interface import AbstractAgent, ProxyAgent
|
||||
from primaite.game.agent.rewards import SharedReward
|
||||
from primaite.game.science import graph_has_cycle, topological_sort
|
||||
from primaite.simulator import SIM_OUTPUT
|
||||
from primaite.simulator.network.creation import NetworkNodeAdder
|
||||
@@ -477,76 +471,10 @@ class PrimaiteGame:
|
||||
agents_cfg = cfg.get("agents", [])
|
||||
|
||||
for agent_cfg in agents_cfg:
|
||||
agent_ref = agent_cfg["ref"] # noqa: F841
|
||||
agent_type = agent_cfg["type"]
|
||||
action_space_cfg = agent_cfg["action_space"]
|
||||
observation_space_cfg = agent_cfg["observation_space"]
|
||||
reward_function_cfg = agent_cfg["reward_function"]
|
||||
|
||||
# CREATE OBSERVATION SPACE
|
||||
obs_space = ObservationManager.from_config(observation_space_cfg)
|
||||
|
||||
# CREATE ACTION SPACE
|
||||
action_space = ActionManager.from_config(game, action_space_cfg)
|
||||
|
||||
# CREATE REWARD FUNCTION
|
||||
reward_function = RewardFunction.from_config(reward_function_cfg)
|
||||
|
||||
# CREATE AGENT
|
||||
if agent_type == "ProbabilisticAgent":
|
||||
# TODO: implement non-random agents and fix this parsing
|
||||
settings = agent_cfg.get("agent_settings", {})
|
||||
new_agent = ProbabilisticAgent(
|
||||
agent_name=agent_cfg["ref"],
|
||||
action_space=action_space,
|
||||
observation_space=obs_space,
|
||||
reward_function=reward_function,
|
||||
settings=settings,
|
||||
)
|
||||
elif agent_type == "PeriodicAgent":
|
||||
settings = PeriodicAgent.Settings(**agent_cfg.get("settings", {}))
|
||||
new_agent = PeriodicAgent(
|
||||
agent_name=agent_cfg["ref"],
|
||||
action_space=action_space,
|
||||
observation_space=obs_space,
|
||||
reward_function=reward_function,
|
||||
settings=settings,
|
||||
)
|
||||
|
||||
elif agent_type == "ProxyAgent":
|
||||
agent_settings = AgentSettings.from_config(agent_cfg.get("agent_settings"))
|
||||
new_agent = ProxyAgent(
|
||||
agent_name=agent_cfg["ref"],
|
||||
action_space=action_space,
|
||||
observation_space=obs_space,
|
||||
reward_function=reward_function,
|
||||
agent_settings=agent_settings,
|
||||
)
|
||||
game.rl_agents[agent_cfg["ref"]] = new_agent
|
||||
elif agent_type == "RedDatabaseCorruptingAgent":
|
||||
agent_settings = AgentSettings.from_config(agent_cfg.get("agent_settings"))
|
||||
|
||||
new_agent = DataManipulationAgent(
|
||||
agent_name=agent_cfg["ref"],
|
||||
action_space=action_space,
|
||||
observation_space=obs_space,
|
||||
reward_function=reward_function,
|
||||
agent_settings=agent_settings,
|
||||
)
|
||||
elif agent_type == "TAP001":
|
||||
agent_settings = AgentSettings.from_config(agent_cfg.get("agent_settings"))
|
||||
new_agent = TAP001(
|
||||
agent_name=agent_cfg["ref"],
|
||||
action_space=action_space,
|
||||
observation_space=obs_space,
|
||||
reward_function=reward_function,
|
||||
agent_settings=agent_settings,
|
||||
)
|
||||
else:
|
||||
msg = f"Configuration error: {agent_type} is not a valid agent type."
|
||||
_LOGGER.error(msg)
|
||||
raise ValueError(msg)
|
||||
new_agent = AbstractAgent.from_config(agent_cfg)
|
||||
game.agents[agent_cfg["ref"]] = new_agent
|
||||
if isinstance(new_agent, ProxyAgent):
|
||||
game.rl_agents[agent_cfg["ref"]] = new_agent
|
||||
|
||||
# Validate that if any agents are sharing rewards, they aren't forming an infinite loop.
|
||||
game.setup_reward_sharing()
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"source": [
|
||||
"from primaite.session.environment import PrimaiteGymEnv\n",
|
||||
"from primaite.config.load import data_manipulation_config_path\n",
|
||||
"from prettytable import PrettyTable\n"
|
||||
"from prettytable import PrettyTable"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -195,7 +195,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "venv",
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@@ -209,7 +209,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
"version": "3.10.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -51,24 +51,15 @@
|
||||
" - ref: CustomC2Agent\n",
|
||||
" team: RED\n",
|
||||
" type: ProxyAgent\n",
|
||||
" observation_space: null\n",
|
||||
"\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" - type: DONOTHING\n",
|
||||
" - type: NODE_APPLICATION_INSTALL\n",
|
||||
" - type: NODE_APPLICATION_EXECUTE\n",
|
||||
" - type: CONFIGURE_C2_BEACON\n",
|
||||
" - type: C2_SERVER_RANSOMWARE_LAUNCH\n",
|
||||
" - type: C2_SERVER_RANSOMWARE_CONFIGURE\n",
|
||||
" - type: C2_SERVER_TERMINAL_COMMAND\n",
|
||||
" - type: C2_SERVER_DATA_EXFILTRATE\n",
|
||||
" options:\n",
|
||||
" nodes:\n",
|
||||
" - node_name: web_server\n",
|
||||
" applications: \n",
|
||||
" applications:\n",
|
||||
" - application_name: C2Beacon\n",
|
||||
" - node_name: client_1\n",
|
||||
" applications: \n",
|
||||
" applications:\n",
|
||||
" - application_name: C2Server\n",
|
||||
" max_folders_per_node: 1\n",
|
||||
" max_files_per_folder: 1\n",
|
||||
@@ -82,15 +73,15 @@
|
||||
" - 0.0.0.1\n",
|
||||
" action_map:\n",
|
||||
" 0:\n",
|
||||
" action: DONOTHING\n",
|
||||
" action: do_nothing\n",
|
||||
" options: {}\n",
|
||||
" 1:\n",
|
||||
" action: NODE_APPLICATION_INSTALL\n",
|
||||
" action: node_application_install\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" application_name: C2Beacon\n",
|
||||
" 2:\n",
|
||||
" action: CONFIGURE_C2_BEACON\n",
|
||||
" action: configure_c2_beacon\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" config:\n",
|
||||
@@ -99,12 +90,12 @@
|
||||
" masquerade_protocol:\n",
|
||||
" masquerade_port:\n",
|
||||
" 3:\n",
|
||||
" action: NODE_APPLICATION_EXECUTE\n",
|
||||
" action: node_application_execute\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" application_id: 0 \n",
|
||||
" application_id: 0\n",
|
||||
" 4:\n",
|
||||
" action: C2_SERVER_TERMINAL_COMMAND\n",
|
||||
" action: c2_server_terminal_command\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" ip_address:\n",
|
||||
@@ -112,20 +103,20 @@
|
||||
" username: admin\n",
|
||||
" password: admin\n",
|
||||
" commands:\n",
|
||||
" - \n",
|
||||
" -\n",
|
||||
" - software_manager\n",
|
||||
" - application\n",
|
||||
" - install\n",
|
||||
" - RansomwareScript\n",
|
||||
" 5:\n",
|
||||
" action: C2_SERVER_RANSOMWARE_CONFIGURE\n",
|
||||
" action: c2_server_ransomware_configure\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" config:\n",
|
||||
" server_ip_address: 192.168.1.14\n",
|
||||
" payload: ENCRYPT\n",
|
||||
" 6:\n",
|
||||
" action: C2_SERVER_DATA_EXFILTRATE\n",
|
||||
" action: c2_server_data_exfiltrate\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" target_file_name: \"database.db\"\n",
|
||||
@@ -134,14 +125,14 @@
|
||||
" target_ip_address: 192.168.1.14\n",
|
||||
" account:\n",
|
||||
" username: admin\n",
|
||||
" password: admin \n",
|
||||
" password: admin\n",
|
||||
"\n",
|
||||
" 7:\n",
|
||||
" action: C2_SERVER_RANSOMWARE_LAUNCH\n",
|
||||
" action: c2_server_ransomware_launch\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" 8:\n",
|
||||
" action: CONFIGURE_C2_BEACON\n",
|
||||
" action: configure_c2_beacon\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" config:\n",
|
||||
@@ -150,7 +141,7 @@
|
||||
" masquerade_protocol: TCP\n",
|
||||
" masquerade_port: DNS\n",
|
||||
" 9:\n",
|
||||
" action: CONFIGURE_C2_BEACON\n",
|
||||
" action: configure_c2_beacon\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" config:\n",
|
||||
@@ -177,7 +168,7 @@
|
||||
" # removing all agents & adding the custom agent.\n",
|
||||
" cfg['agents'] = {}\n",
|
||||
" cfg['agents'] = c2_agent_yaml\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"env = PrimaiteGymEnv(env_config=cfg)"
|
||||
]
|
||||
@@ -222,7 +213,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Beacon Actions | NODE_APPLICATION_INSTALL\n",
|
||||
"### **Command and Control** | C2 Beacon Actions | node_application_install\n",
|
||||
"\n",
|
||||
"The custom proxy red agent defined at the start of this notebook has been configured to install the C2 Beacon as action ``1`` in it's action map. \n",
|
||||
"\n",
|
||||
@@ -230,10 +221,6 @@
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: NODE_APPLICATION_INSTALL\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" - node_name: web_server\n",
|
||||
@@ -243,7 +230,7 @@
|
||||
" ...\n",
|
||||
" action_map:\n",
|
||||
" 1:\n",
|
||||
" action: NODE_APPLICATION_INSTALL \n",
|
||||
" action: node_application_install \n",
|
||||
" options:\n",
|
||||
" node_id: 0 # Index 0 at the node list.\n",
|
||||
" application_name: C2Beacon\n",
|
||||
@@ -265,7 +252,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Beacon Actions | CONFIGURE_C2_BEACON \n",
|
||||
"### **Command and Control** | C2 Beacon Actions | configure_c2_beacon \n",
|
||||
"\n",
|
||||
"The custom proxy red agent defined at the start of this notebook can configure the C2 Beacon via action ``2`` in it's action map. \n",
|
||||
"\n",
|
||||
@@ -273,10 +260,6 @@
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: CONFIGURE_C2_BEACON\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" - node_name: web_server\n",
|
||||
@@ -285,7 +268,7 @@
|
||||
" action_map:\n",
|
||||
" ...\n",
|
||||
" 2:\n",
|
||||
" action: CONFIGURE_C2_BEACON\n",
|
||||
" action: configure_c2_beacon\n",
|
||||
" options:\n",
|
||||
" node_id: 0 # Node Index\n",
|
||||
" config: # Further information about these config options can be found at the bottom of this notebook.\n",
|
||||
@@ -312,18 +295,14 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Beacon Actions | NODE_APPLICATION_EXECUTE\n",
|
||||
"### **Command and Control** | C2 Beacon Actions | node_application_execute\n",
|
||||
"\n",
|
||||
"The final action is ``NODE_APPLICATION_EXECUTE`` which is used to establish a connection for the C2 application. This action can be called by the Red Agent via action ``3`` in it's action map. \n",
|
||||
"The final action is ``node_application_execute`` which is used to establish a connection for the C2 application. This action can be called by the Red Agent via action ``3`` in it's action map. \n",
|
||||
"\n",
|
||||
"The yaml snippet below shows all the relevant agent options for this action:\n",
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: NODE_APPLICATION_EXECUTE\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" - node_name: web_server\n",
|
||||
@@ -334,7 +313,7 @@
|
||||
" action_map:\n",
|
||||
" ...\n",
|
||||
" 3:\n",
|
||||
" action: NODE_APPLICATION_EXECUTE\n",
|
||||
" action: node_application_execute\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" application_id: 0\n",
|
||||
@@ -347,7 +326,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(3) "
|
||||
"env.step(3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -390,10 +369,6 @@
|
||||
"\n",
|
||||
"``` yaml\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: C2_SERVER_TERMINAL_COMMAND\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" ...\n",
|
||||
@@ -441,7 +416,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Server Actions | C2_SERVER_RANSOMWARE_CONFIGURE\n",
|
||||
"### **Command and Control** | C2 Server Actions | c2_server_ransomware_configure\n",
|
||||
"\n",
|
||||
"Another action the C2 Server grants is the ability for a Red Agent to configure the RansomwareScript via the C2 Server rather than the note directly.\n",
|
||||
"\n",
|
||||
@@ -451,10 +426,6 @@
|
||||
"\n",
|
||||
"``` yaml\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: C2_SERVER_RANSOMWARE_CONFIGURE\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" ...\n",
|
||||
@@ -464,7 +435,7 @@
|
||||
" ...\n",
|
||||
" action_map:\n",
|
||||
" 5:\n",
|
||||
" action: C2_SERVER_RANSOMWARE_CONFIG\n",
|
||||
" action: c2_server_ransomware_configure\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" config:\n",
|
||||
@@ -497,9 +468,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Server Actions | C2_SERVER_DATA_EXFILTRATE\n",
|
||||
"### **Command and Control** | C2 Server Actions | c2_server_data_exfiltrate\n",
|
||||
"\n",
|
||||
"The second to last action available is the ``C2_SERVER_DATA_EXFILTRATE`` which is indexed as action ``6`` in the action map.\n",
|
||||
"The second to last action available is the ``c2_server_data_exfiltrate`` which is indexed as action ``6`` in the action map.\n",
|
||||
"\n",
|
||||
"This action can be used to exfiltrate a target file on a remote node to the C2 Beacon and the C2 Server's host file system via the ``FTP`` services.\n",
|
||||
"\n",
|
||||
@@ -507,10 +478,6 @@
|
||||
"\n",
|
||||
"``` yaml\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: C2_SERVER_DATA_EXFILTRATE\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" ...\n",
|
||||
@@ -520,7 +487,7 @@
|
||||
" ...\n",
|
||||
" action_map:\n",
|
||||
" 6:\n",
|
||||
" action: C2_SERVER_DATA_EXFILTRATE\n",
|
||||
" action: c2_server_data_exfiltrate\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" target_file_name: \"database.db\"\n",
|
||||
@@ -567,9 +534,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Server Actions | C2_SERVER_RANSOMWARE_LAUNCH\n",
|
||||
"### **Command and Control** | C2 Server Actions | c2_server_ransomware_launch\n",
|
||||
"\n",
|
||||
"Finally, the last available action is for the C2_SERVER_RANSOMWARE_LAUNCH to start the ransomware script installed on the same node as the C2 beacon.\n",
|
||||
"Finally, the last available action is for the c2_server_ransomware_launch to start the ransomware script installed on the same node as the C2 beacon.\n",
|
||||
"\n",
|
||||
"This action is indexed as action ``7``.\n",
|
||||
"\n",
|
||||
@@ -577,10 +544,6 @@
|
||||
"\n",
|
||||
"``` yaml\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: C2_SERVER_RANSOMWARE_LAUNCH\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" ...\n",
|
||||
@@ -590,7 +553,7 @@
|
||||
" ...\n",
|
||||
" action_map:\n",
|
||||
" 7:\n",
|
||||
" action: C2_SERVER_RANSOMWARE_LAUNCH\n",
|
||||
" action: c2_server_ransomware_launch\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
"```\n"
|
||||
@@ -632,7 +595,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"custom_blue_agent_yaml = \"\"\" \n",
|
||||
"custom_blue_agent_yaml = \"\"\"\n",
|
||||
" - ref: defender\n",
|
||||
" team: BLUE\n",
|
||||
" type: ProxyAgent\n",
|
||||
@@ -715,28 +678,23 @@
|
||||
" - type: \"NONE\"\n",
|
||||
" label: ICS\n",
|
||||
" options: {}\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" - type: NODE_APPLICATION_REMOVE\n",
|
||||
" - type: NODE_SHUTDOWN\n",
|
||||
" - type: ROUTER_ACL_ADDRULE\n",
|
||||
" - type: DONOTHING\n",
|
||||
" action_map:\n",
|
||||
" 0:\n",
|
||||
" action: DONOTHING\n",
|
||||
" action: do_nothing\n",
|
||||
" options: {}\n",
|
||||
" 1:\n",
|
||||
" action: NODE_APPLICATION_REMOVE\n",
|
||||
" action: node_application_remove\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" application_name: C2Beacon\n",
|
||||
" 2:\n",
|
||||
" action: NODE_SHUTDOWN\n",
|
||||
" action: node_shutdown\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" 3:\n",
|
||||
" action: ROUTER_ACL_ADDRULE\n",
|
||||
" action: router_acl_add_rule\n",
|
||||
" options:\n",
|
||||
" target_router: router_1\n",
|
||||
" position: 1\n",
|
||||
@@ -747,7 +705,7 @@
|
||||
" dest_port_id: 2\n",
|
||||
" protocol_id: 1\n",
|
||||
" source_wildcard_id: 0\n",
|
||||
" dest_wildcard_id: 0 \n",
|
||||
" dest_wildcard_id: 0\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" options:\n",
|
||||
@@ -796,7 +754,7 @@
|
||||
" # removing all agents & adding the custom agent.\n",
|
||||
" cfg['agents'] = {}\n",
|
||||
" cfg['agents'] = custom_blue\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"blue_env = PrimaiteGymEnv(env_config=cfg)"
|
||||
]
|
||||
@@ -1121,7 +1079,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The code cell below uses the custom blue agent defined at the start of this section perform a NODE_APPLICATION_REMOVE on the C2 beacon:"
|
||||
"The code cell below uses the custom blue agent defined at the start of this section perform a node_application_remove on the C2 beacon:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1130,7 +1088,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Using CAOS ACTION: NODE_APPLICATION_REMOVE & capturing the OBS\n",
|
||||
"# Using CAOS ACTION: node_application_remove & capturing the OBS\n",
|
||||
"post_blue_action_obs, _, _, _, _ = blue_env.step(1)"
|
||||
]
|
||||
},
|
||||
@@ -1216,7 +1174,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The code cell below uses the custom blue agent defined at the start of this section to perform a ``NODE_SHUT_DOWN`` action on the web server."
|
||||
"The code cell below uses the custom blue agent defined at the start of this section to perform a ``node_shut_down`` action on the web server."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1225,7 +1183,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Using CAOS ACTION: NODE_SHUT_DOWN & capturing the OBS\n",
|
||||
"# Using CAOS ACTION: node_shut_down & capturing the OBS\n",
|
||||
"post_blue_action_obs, _, _, _, _ = blue_env.step(2)"
|
||||
]
|
||||
},
|
||||
@@ -1306,7 +1264,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The code cell below uses the custom blue agent defined at the start of this section to perform a ROUTER_ACL_ADDRULE on router 1."
|
||||
"The code cell below uses the custom blue agent defined at the start of this section to perform a router_acl_add_rule on router 1."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1315,7 +1273,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Using CAOS ACTION: ROUTER_ACL_ADDRULE & capturing the OBS\n",
|
||||
"# Using CAOS ACTION: router_acl_add_rule & capturing the OBS\n",
|
||||
"post_blue_action_obs, _, _, _, _ = blue_env.step(3)"
|
||||
]
|
||||
},
|
||||
@@ -1429,11 +1387,11 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"As demonstrated earlier, red agents can use the ``CONFIGURE_C2_BEACON`` action to configure these settings mid episode through the configuration options:\n",
|
||||
"As demonstrated earlier, red agents can use the ``configure_c2_beacon`` action to configure these settings mid episode through the configuration options:\n",
|
||||
"\n",
|
||||
"``` YAML\n",
|
||||
"...\n",
|
||||
" action: CONFIGURE_C2_BEACON\n",
|
||||
" action: configure_c2_beacon\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" config:\n",
|
||||
@@ -1468,7 +1426,7 @@
|
||||
" # removing all agents & adding the custom agent.\n",
|
||||
" cfg['agents'] = {}\n",
|
||||
" cfg['agents'] = c2_agent_yaml\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"c2_config_env = PrimaiteGymEnv(env_config=cfg)"
|
||||
]
|
||||
@@ -1555,7 +1513,7 @@
|
||||
"source": [
|
||||
"for i in range(6):\n",
|
||||
" env.step(0)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"c2_server_1.show()"
|
||||
]
|
||||
},
|
||||
@@ -1676,7 +1634,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Comparing the OBS of the default frequency to a timestep frequency of 1 \n",
|
||||
"# Comparing the OBS of the default frequency to a timestep frequency of 1\n",
|
||||
"for i in range(2):\n",
|
||||
" keep_alive_obs, _, _, _, _ = blue_config_env.step(0)\n",
|
||||
" display_obs_diffs(default_obs, keep_alive_obs, blue_config_env.game.step_counter)"
|
||||
@@ -1760,7 +1718,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Capturing default C2 Traffic \n",
|
||||
"# Capturing default C2 Traffic\n",
|
||||
"for i in range(3):\n",
|
||||
" tcp_c2_obs, _, _, _, _ = blue_config_env.step(0)\n",
|
||||
"\n",
|
||||
|
||||
@@ -67,9 +67,9 @@
|
||||
" # parse the info dict form step output and write out what the red agent is doing\n",
|
||||
" red_info : AgentHistoryItem = info['agent_actions']['data_manipulation_attacker']\n",
|
||||
" red_action = red_info.action\n",
|
||||
" if red_action == 'DONOTHING':\n",
|
||||
" if red_action == 'do_nothing':\n",
|
||||
" red_str = 'DO NOTHING'\n",
|
||||
" elif red_action == 'NODE_APPLICATION_EXECUTE':\n",
|
||||
" elif red_action == 'node_application_execute':\n",
|
||||
" client = \"client 1\" if red_info.parameters['node_id'] == 0 else \"client 2\"\n",
|
||||
" red_str = f\"ATTACK from {client}\"\n",
|
||||
" return red_str"
|
||||
@@ -147,12 +147,7 @@
|
||||
" nodes: {}\n",
|
||||
"\n",
|
||||
" action_space:\n",
|
||||
"\n",
|
||||
" # The agent has two action choices, either do nothing, or execute a pre-scripted attack by using \n",
|
||||
" action_list:\n",
|
||||
" - type: DONOTHING\n",
|
||||
" - type: NODE_APPLICATION_EXECUTE\n",
|
||||
"\n",
|
||||
" \n",
|
||||
" # The agent has access to the DataManipulationBoth on clients 1 and 2.\n",
|
||||
" options:\n",
|
||||
" nodes:\n",
|
||||
@@ -306,19 +301,9 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"change = yaml.safe_load(\"\"\"\n",
|
||||
"action_space:\n",
|
||||
" action_list:\n",
|
||||
" - type: DONOTHING\n",
|
||||
" - type: NODE_APPLICATION_EXECUTE\n",
|
||||
" options:\n",
|
||||
" nodes:\n",
|
||||
" - node_name: client_1\n",
|
||||
" applications:\n",
|
||||
" - application_name: DataManipulationBot\n",
|
||||
" max_folders_per_node: 1\n",
|
||||
" max_files_per_folder: 1\n",
|
||||
" max_services_per_node: 1\n",
|
||||
"# TODO:\n",
|
||||
"\"\"\")\n",
|
||||
"#TODO 2869 fix\n",
|
||||
"\n",
|
||||
"with open(data_manipulation_config_path(), 'r') as f:\n",
|
||||
" cfg = yaml.safe_load(f)\n",
|
||||
@@ -444,7 +429,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "venv",
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
|
||||
@@ -165,13 +165,13 @@
|
||||
"\n",
|
||||
"| node_id | node name |\n",
|
||||
"|---------|------------------|\n",
|
||||
"| 1 | domain_controller|\n",
|
||||
"| 2 | web_server |\n",
|
||||
"| 3 | database_server |\n",
|
||||
"| 4 | backup_server |\n",
|
||||
"| 5 | security_suite |\n",
|
||||
"| 6 | client_1 |\n",
|
||||
"| 7 | client_2 |\n",
|
||||
"| 0 | domain_controller|\n",
|
||||
"| 1 | web_server |\n",
|
||||
"| 2 | database_server |\n",
|
||||
"| 3 | backup_server |\n",
|
||||
"| 4 | security_suite |\n",
|
||||
"| 5 | client_1 |\n",
|
||||
"| 6 | client_2 |\n",
|
||||
"\n",
|
||||
"Service 1 on node 2 (web_server) corresponds to the Web Server service. Other services are only there for padding to ensure that each node's observation space has the same shape. They are filled with zeroes.\n",
|
||||
"\n",
|
||||
@@ -449,9 +449,9 @@
|
||||
" # parse the info dict form step output and write out what the red agent is doing\n",
|
||||
" red_info : AgentHistoryItem = info['agent_actions']['data_manipulation_attacker']\n",
|
||||
" red_action = red_info.action\n",
|
||||
" if red_action == 'DONOTHING':\n",
|
||||
" if red_action == 'do_nothing':\n",
|
||||
" red_str = 'DO NOTHING'\n",
|
||||
" elif red_action == 'NODE_APPLICATION_EXECUTE':\n",
|
||||
" elif red_action == 'node_application_execute':\n",
|
||||
" client = \"client 1\" if red_info.parameters['node_id'] == 0 else \"client 2\"\n",
|
||||
" red_str = f\"ATTACK from {client}\"\n",
|
||||
" return red_str"
|
||||
@@ -547,7 +547,7 @@
|
||||
"\n",
|
||||
"The reward will increase slightly as soon as the file finishes restoring. Then, the reward will increase to 0.9 when both green agents make successful requests.\n",
|
||||
"\n",
|
||||
"Run the following cell until the green action is `NODE_APPLICATION_EXECUTE` for application 0, then the reward should increase. If you run it enough times, another red attack will happen and the reward will drop again."
|
||||
"Run the following cell until the green action is `node_application_execute` for application 0, then the reward should increase. If you run it enough times, another red attack will happen and the reward will drop again."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -201,7 +201,7 @@
|
||||
"source": [
|
||||
"caos_action = [\n",
|
||||
" \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n",
|
||||
" \"service\", \"Terminal\", \"ssh_to_remote\", \"admin\", \"admin\", str(some_tech_storage_srv.network_interface[1].ip_address)\n",
|
||||
" \"service\", \"Terminal\", \"node_session_remote_login\", \"admin\", \"admin\", str(some_tech_storage_srv.network_interface[1].ip_address)\n",
|
||||
"]\n",
|
||||
"game.simulation.apply_request(caos_action)"
|
||||
]
|
||||
@@ -259,7 +259,7 @@
|
||||
"source": [
|
||||
"caos_action = [\n",
|
||||
" \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n",
|
||||
" \"service\", \"Terminal\", \"ssh_to_remote\", \"admin\", \"admin\", str(some_tech_rt.network_interface[4].ip_address)\n",
|
||||
" \"service\", \"Terminal\", \"node_session_remote_login\", \"admin\", \"admin\", str(some_tech_rt.network_interface[4].ip_address)\n",
|
||||
"]\n",
|
||||
"game.simulation.apply_request(caos_action)"
|
||||
]
|
||||
@@ -396,7 +396,7 @@
|
||||
"source": [
|
||||
"caos_action = [\n",
|
||||
" \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n",
|
||||
" \"service\", \"Terminal\", \"ssh_to_remote\", \"admin\", \"admin\", str(some_tech_storage_srv.network_interface[1].ip_address)\n",
|
||||
" \"service\", \"Terminal\", \"node_session_remote_login\", \"admin\", \"admin\", str(some_tech_storage_srv.network_interface[1].ip_address)\n",
|
||||
"]\n",
|
||||
"game.simulation.apply_request(caos_action)"
|
||||
]
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "venv",
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@@ -109,7 +109,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
"version": "3.10.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@@ -182,7 +182,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.8"
|
||||
"version": "3.10.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -238,7 +238,7 @@
|
||||
"### Episode 2\n",
|
||||
"When we reset the environment again, it moves onto episode 2, where it will bring in greens_1 and reds_1 for green and red agent definitions. Let's verify the agent names and that they take actions at the defined frequency.\n",
|
||||
"\n",
|
||||
"Most green actions will be `NODE_APPLICATION_EXECUTE` while red will `DONOTHING` except at steps 10 and 20."
|
||||
"Most green actions will be `node_application_execute` while red will `DONOTHING` except at steps 10 and 20."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -269,7 +269,7 @@
|
||||
"### Episode 3\n",
|
||||
"When we reset the environment again, it moves onto episode 3, where it will bring in greens_2 and reds_2 for green and red agent definitions. Let's verify the agent names and that they take actions at the defined frequency.\n",
|
||||
"\n",
|
||||
"Now, green will perform `NODE_APPLICATION_EXECUTE` only 5% of the time, while red will perform `NODE_APPLICATION_EXECUTE` more frequently than before."
|
||||
"Now, green will perform `node_application_execute` only 5% of the time, while red will perform `node_application_execute` more frequently than before."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -89,7 +89,7 @@ class PrimaiteGymEnv(gymnasium.Env):
|
||||
:return: Action mask
|
||||
:rtype: List[bool]
|
||||
"""
|
||||
if not self.agent.action_masking:
|
||||
if not self.agent.config.agent_settings.action_masking:
|
||||
return np.asarray([True] * len(self.agent.action_manager.action_map))
|
||||
else:
|
||||
return self.game.action_mask(self._agent_name)
|
||||
|
||||
@@ -44,7 +44,7 @@ class PrimaiteRayMARLEnv(MultiAgentEnv):
|
||||
)
|
||||
for agent_name in self._agent_ids:
|
||||
agent = self.game.rl_agents[agent_name]
|
||||
if agent.action_masking:
|
||||
if agent.config.agent_settings.action_masking:
|
||||
self.observation_space[agent_name] = spaces.Dict(
|
||||
{
|
||||
"action_mask": spaces.MultiBinary(agent.action_manager.space.n),
|
||||
@@ -143,7 +143,7 @@ class PrimaiteRayMARLEnv(MultiAgentEnv):
|
||||
unflat_space = agent.observation_manager.space
|
||||
unflat_obs = agent.observation_manager.current_observation
|
||||
obs = gymnasium.spaces.flatten(unflat_space, unflat_obs)
|
||||
if agent.action_masking:
|
||||
if agent.config.agent_settings.action_masking:
|
||||
all_obs[agent_name] = {"action_mask": self.game.action_mask(agent_name), "observations": obs}
|
||||
else:
|
||||
all_obs[agent_name] = obs
|
||||
@@ -168,7 +168,7 @@ class PrimaiteRayEnv(gymnasium.Env):
|
||||
self.env = PrimaiteGymEnv(env_config=env_config)
|
||||
# self.env.episode_counter -= 1
|
||||
self.action_space = self.env.action_space
|
||||
if self.env.agent.action_masking:
|
||||
if self.env.agent.config.agent_settings.action_masking:
|
||||
self.observation_space = spaces.Dict(
|
||||
{"action_mask": spaces.MultiBinary(self.env.action_space.n), "observations": self.env.observation_space}
|
||||
)
|
||||
@@ -178,7 +178,7 @@ class PrimaiteRayEnv(gymnasium.Env):
|
||||
def reset(self, *, seed: int = None, options: dict = None) -> Tuple[ObsType, Dict]:
|
||||
"""Reset the environment."""
|
||||
super().reset() # Ensure PRNG seed is set everywhere
|
||||
if self.env.agent.action_masking:
|
||||
if self.env.agent.config.agent_settings.action_masking:
|
||||
obs, *_ = self.env.reset(seed=seed)
|
||||
new_obs = {"action_mask": self.env.action_masks(), "observations": obs}
|
||||
return new_obs, *_
|
||||
@@ -187,7 +187,7 @@ class PrimaiteRayEnv(gymnasium.Env):
|
||||
def step(self, action: ActType) -> Tuple[ObsType, SupportsFloat, bool, bool, Dict]:
|
||||
"""Perform a step in the environment."""
|
||||
# if action masking is enabled, intercept the step method and add action mask to observation
|
||||
if self.env.agent.action_masking:
|
||||
if self.env.agent.config.agent_settings.action_masking:
|
||||
obs, *_ = self.env.step(action)
|
||||
new_obs = {"action_mask": self.game.action_mask(self.env._agent_name), "observations": obs}
|
||||
return new_obs, *_
|
||||
|
||||
@@ -264,7 +264,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
"version": "3.10.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -664,7 +664,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
"version": "3.10.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -130,8 +130,8 @@ class File(FileSystemItemABC):
|
||||
|
||||
Return False if corruption is detected, otherwise True
|
||||
"""
|
||||
warnings.warn("NODE_FILE_CHECKHASH is currently not implemented.")
|
||||
self.sys_log.warning("NODE_FILE_CHECKHASH is currently not implemented.")
|
||||
warnings.warn("node_file_checkhash is currently not implemented.")
|
||||
self.sys_log.warning("node_file_checkhash is currently not implemented.")
|
||||
return False
|
||||
|
||||
if self.deleted:
|
||||
|
||||
@@ -387,8 +387,8 @@ class Folder(FileSystemItemABC):
|
||||
|
||||
Return False if corruption is detected, otherwise True
|
||||
"""
|
||||
warnings.warn("NODE_FOLDER_CHECKHASH is currently not implemented.")
|
||||
self.sys_log.error("NODE_FOLDER_CHECKHASH is currently not implemented.")
|
||||
warnings.warn("node_folder_checkhash is currently not implemented.")
|
||||
self.sys_log.error("node_folder_checkhash is currently not implemented.")
|
||||
return False
|
||||
|
||||
if self.deleted:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from abc import ABC, abstractmethod
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Any, ClassVar, Dict, Literal, Type
|
||||
from typing import Any, ClassVar, Dict, Literal, Optional, Type
|
||||
|
||||
from pydantic import BaseModel, model_validator
|
||||
|
||||
@@ -49,7 +49,7 @@ class NetworkNodeAdder(BaseModel):
|
||||
|
||||
_registry: ClassVar[Dict[str, Type["NetworkNodeAdder"]]] = {}
|
||||
|
||||
def __init_subclass__(cls, identifier: str, **kwargs: Any) -> None:
|
||||
def __init_subclass__(cls, identifier: Optional[str], **kwargs: Any) -> None:
|
||||
"""
|
||||
Register a network node adder class.
|
||||
|
||||
@@ -58,6 +58,8 @@ class NetworkNodeAdder(BaseModel):
|
||||
:raises ValueError: When attempting to register a name that is already reserved.
|
||||
"""
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier is None:
|
||||
return
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Duplicate node adder {identifier}")
|
||||
cls._registry[identifier] = cls
|
||||
|
||||
@@ -1559,7 +1559,7 @@ class Node(SimComponent):
|
||||
_identifier: ClassVar[str] = "unknown"
|
||||
"""Identifier for this particular class, used for printing and logging. Each subclass redefines this."""
|
||||
|
||||
def __init_subclass__(cls, identifier: str = "default", **kwargs: Any) -> None:
|
||||
def __init_subclass__(cls, identifier: Optional[str] = None, **kwargs: Any) -> None:
|
||||
"""
|
||||
Register a node type.
|
||||
|
||||
@@ -1567,10 +1567,10 @@ class Node(SimComponent):
|
||||
:type identifier: str
|
||||
:raises ValueError: When attempting to register an node with a name that is already allocated.
|
||||
"""
|
||||
if identifier == "default":
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier is None:
|
||||
return
|
||||
identifier = identifier.lower()
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Tried to define new node {identifier}, but this name is already reserved.")
|
||||
cls._registry[identifier] = cls
|
||||
|
||||
@@ -61,9 +61,9 @@ class Application(IOSoftware, ABC):
|
||||
:type identifier: Optional[str]
|
||||
:raises ValueError: When attempting to register an application with a name that is already allocated.
|
||||
"""
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier is None:
|
||||
return
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Tried to define new application {identifier}, but this name is already reserved.")
|
||||
cls._registry[identifier] = cls
|
||||
|
||||
@@ -61,7 +61,7 @@ class Service(IOSoftware):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def __init_subclass__(cls, identifier: str = "default", **kwargs: Any) -> None:
|
||||
def __init_subclass__(cls, identifier: Optional[str] = None, **kwargs: Any) -> None:
|
||||
"""
|
||||
Register a hostnode type.
|
||||
|
||||
@@ -69,11 +69,11 @@ class Service(IOSoftware):
|
||||
:type identifier: str
|
||||
:raises ValueError: When attempting to register an hostnode with a name that is already allocated.
|
||||
"""
|
||||
if identifier == "default":
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier is None:
|
||||
return
|
||||
# Enforce lowercase registry entries because it makes comparisons everywhere else much easier.
|
||||
identifier = identifier.lower()
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Tried to define new hostnode {identifier}, but this name is already reserved.")
|
||||
cls._registry[identifier] = cls
|
||||
|
||||
@@ -186,7 +186,7 @@ class Terminal(Service, identifier="Terminal"):
|
||||
return RequestResponse(status="failure", data={})
|
||||
|
||||
rm.add_request(
|
||||
"ssh_to_remote",
|
||||
"node_session_remote_login",
|
||||
request_type=RequestType(func=_remote_login),
|
||||
)
|
||||
|
||||
@@ -286,7 +286,6 @@ class Terminal(Service, identifier="Terminal"):
|
||||
:param password: Password for login.
|
||||
:return: boolean, True if successful, else False
|
||||
"""
|
||||
# TODO: Un-comment this when UserSessionManager is merged.
|
||||
connection_uuid = self.parent.user_session_manager.local_login(username=username, password=password)
|
||||
if connection_uuid:
|
||||
self.sys_log.info(f"{self.name}: Login request authorised, connection uuid: {connection_uuid}")
|
||||
@@ -413,7 +412,6 @@ class Terminal(Service, identifier="Terminal"):
|
||||
if isinstance(payload, SSHPacket):
|
||||
if payload.transport_message == SSHTransportMessage.SSH_MSG_USERAUTH_REQUEST:
|
||||
# validate & add connection
|
||||
# TODO: uncomment this as part of 2781
|
||||
username = payload.user_account.username
|
||||
password = payload.user_account.password
|
||||
connection_id = self.parent.user_session_manager.remote_login(
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
raise DeprecationWarning(
|
||||
"Benchmarking depends on deprecated functionality and it has not been updated to primaite v3 yet."
|
||||
)
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Tuple, Union
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
raise DeprecationWarning(
|
||||
"Benchmarking depends on deprecated functionality and it has not been updated to primaite v3 yet."
|
||||
)
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
import csv
|
||||
from logging import Logger
|
||||
from typing import Final, List, Tuple, TYPE_CHECKING, Union
|
||||
|
||||
@@ -31,7 +31,7 @@ def ipv4_validator(v: Any) -> IPv4Address:
|
||||
|
||||
IPV4Address: Final[Annotated] = Annotated[IPv4Address, BeforeValidator(ipv4_validator)]
|
||||
"""
|
||||
IPv4Address with with IPv4Address with with pre-validation and auto-conversion from str using ipv4_validator..
|
||||
IPv4Address with pre-validation and auto-conversion from str using ipv4_validator..
|
||||
|
||||
This type is essentially an IPv4Address from the standard library's ipaddress module,
|
||||
but with added validation logic. If you use this custom type, the ipv4_validator function
|
||||
|
||||
@@ -96,490 +96,423 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
action: node_service_scan
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
action: node_service_stop
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
action: "node_service_start"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
action: "node_service_pause"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
action: "node_service_resume"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
action: "node_service_restart"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
action: "node_service_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
action: "node_service_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
action: "node_file_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
10:
|
||||
action: "NODE_FILE_CHECKHASH"
|
||||
action: "node_file_scan" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
action: "node_file_delete"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
action: "node_file_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
action: "node_service_fix"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
node_name: database_server
|
||||
service_name: DatabaseService
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
action: "node_folder_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
15:
|
||||
action: "NODE_FOLDER_CHECKHASH"
|
||||
action: "node_folder_scan" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
action: "node_folder_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
action: "node_folder_restore"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
19:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
20:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
21:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
22:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
23:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
24:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
25:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
26: # old action num: 18
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
27:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
28:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
29:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
30:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
31:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
32:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
33:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
34:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
35:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
36:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
37:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
38:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
39: # old action num: 19 # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
40: # old action num: 20
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
41: # old action num: 21
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
42:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
43:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
44:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
45:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
|
||||
46: # old action num: 22 # "ACL: ADDRULE - Block outgoing traffic from client 1"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
47: # old action num: 23 # "ACL: ADDRULE - Block outgoing traffic from client 2"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
48: # old action num: 24 # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
49: # old action num: 25 # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
50: # old action num: 26
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
51: # old action num: 27
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
52: # old action num: 28
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 0
|
||||
53: # old action num: 29
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 1
|
||||
54: # old action num: 30
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 2
|
||||
55: # old action num: 31
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 3
|
||||
56: # old action num: 32
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 4
|
||||
57: # old action num: 33
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 5
|
||||
58: # old action num: 34
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 6
|
||||
59: # old action num: 35
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 7
|
||||
60: # old action num: 36
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 8
|
||||
61: # old action num: 37
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
target_router: router_1
|
||||
position: 9
|
||||
62: # old action num: 38
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
63: # old action num: 39
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
64: # old action num: 40
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
65: # old action num: 41
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
66: # old action num: 42
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
67: # old action num: 43
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
68: # old action num: 44
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
69: # old action num: 45
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
70: # old action num: 46
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
71: # old action num: 47
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
72: # old action num: 48
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
73: # old action num: 49
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
74: # old action num: 50
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
75: # old action num: 51
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
76: # old action num: 52
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
77: # old action num: 53
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
- node_name: web_server
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
services:
|
||||
- service_name: WebServer
|
||||
- node_name: database_server
|
||||
folders:
|
||||
- folder_name: database
|
||||
files:
|
||||
- file_name: database.db
|
||||
services:
|
||||
- service_name: DatabaseService
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -13,60 +13,19 @@ agents:
|
||||
- ref: client_2_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_nics_per_node: 2
|
||||
max_acl_rules: 10
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
action_probabilities:
|
||||
0: 1.0
|
||||
|
||||
- ref: data_manipulation_attacker
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_CORRUPT
|
||||
- type: NODE_OS_SCAN
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
possible_start_nodes: [client_1,]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
@@ -142,381 +101,327 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
action: node_service_scan
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
action: node_service_stop
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
action: "node_service_start"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
action: "node_service_pause"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
action: "node_service_resume"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
action: "node_service_restart"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
action: "node_service_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
action: "node_service_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
action: "node_file_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
10:
|
||||
action: "NODE_FILE_CHECKHASH"
|
||||
action: "node_file_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
action: "node_file_delete"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
action: "node_file_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
action: "node_service_fix"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
node_name: database_server
|
||||
service_name: DatabaseService
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
action: "node_folder_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
15:
|
||||
action: "NODE_FOLDER_CHECKHASH"
|
||||
action: "node_folder_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
action: "node_folder_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
action: "node_folder_restore"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
19: # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
20:
|
||||
action: "NODE_STARTUP"
|
||||
action: "node_startup"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
21:
|
||||
action: "NODE_RESET"
|
||||
action: "node_reset"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
22: # "ACL: ADDRULE - Block outgoing traffic from client 1" (not supported in Primaite)
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
23: # "ACL: ADDRULE - Block outgoing traffic from client 2" (not supported in Primaite)
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
24: # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
25: # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
26:
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
27:
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
28:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 0
|
||||
29:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
30:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
31:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
32:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
33:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
34:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
35:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 7
|
||||
36:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 8
|
||||
37:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 9
|
||||
38:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
39:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
40:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
41:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
42:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
43:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
44:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
45:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
46:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
47:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
48:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
49:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
50:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
51:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
52:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
53:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
- node_name: web_server
|
||||
- node_name: database_server
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -27,39 +27,22 @@ agents:
|
||||
- ref: client_2_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
node_name: client_2
|
||||
application_name: WebBrowser
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
action_probabilities:
|
||||
0: 0.4
|
||||
1: 0.6
|
||||
|
||||
simulation:
|
||||
network:
|
||||
|
||||
@@ -30,41 +30,26 @@ agents:
|
||||
- ref: client_2_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
node_name: client_2
|
||||
application_name: WebBrowser
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
|
||||
|
||||
action_probabilities:
|
||||
0: 0.4
|
||||
1: 0.6
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
@@ -122,28 +107,10 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
options:
|
||||
nodes:
|
||||
- node_name: switch
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
- node_name: client_3
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.23
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -30,35 +30,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_2
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_2
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -79,35 +66,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -127,34 +101,12 @@ agents:
|
||||
- ref: data_manipulation_attacker
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
possible_start_nodes: [client_1, client_2]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
@@ -235,490 +187,423 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
action: node_service_scan
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
action: node_service_stop
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
action: "node_service_start"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
action: "node_service_pause"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
action: "node_service_resume"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
action: "node_service_restart"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
action: "node_service_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
action: "node_service_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
action: "node_file_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
10:
|
||||
action: "NODE_FILE_CHECKHASH" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
action: "node_file_scan" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
action: "node_file_delete"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
action: "node_file_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
action: "node_service_fix"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
node_name: database_server
|
||||
service_name: DatabaseService
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
action: "node_folder_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
15:
|
||||
action: "NODE_FOLDER_CHECKHASH" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
action: "node_folder_scan" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
action: "node_folder_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
action: "node_folder_restore"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
19:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
20:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
21:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
22:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
23:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
24:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
25:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
26: # old action num: 18
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
27:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
28:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
29:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
30:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
31:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
32:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
33:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
34:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
35:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
36:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
37:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
38:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
39: # old action num: 19 # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
40: # old action num: 20
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
41: # old action num: 21
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
42:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
43:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
44:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
45:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
|
||||
46: # old action num: 22 # "ACL: ADDRULE - Block outgoing traffic from client 1"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
47: # old action num: 23 # "ACL: ADDRULE - Block outgoing traffic from client 2"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
48: # old action num: 24 # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
49: # old action num: 25 # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
50: # old action num: 26
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
51: # old action num: 27
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
52: # old action num: 28
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 0
|
||||
53: # old action num: 29
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
54: # old action num: 30
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
55: # old action num: 31
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
56: # old action num: 32
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
57: # old action num: 33
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
58: # old action num: 34
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
59: # old action num: 35
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 7
|
||||
60: # old action num: 36
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 8
|
||||
61: # old action num: 37
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 9
|
||||
62: # old action num: 38
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
63: # old action num: 39
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
64: # old action num: 40
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
65: # old action num: 41
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
66: # old action num: 42
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
67: # old action num: 43
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
68: # old action num: 44
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
69: # old action num: 45
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
70: # old action num: 46
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
71: # old action num: 47
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
72: # old action num: 48
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
73: # old action num: 49
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
74: # old action num: 50
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
75: # old action num: 51
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
76: # old action num: 52
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
77: # old action num: 53
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
- node_name: web_server
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
services:
|
||||
- service_name: WebServer
|
||||
- node_name: database_server
|
||||
folders:
|
||||
- folder_name: database
|
||||
files:
|
||||
- file_name: database.db
|
||||
services:
|
||||
- service_name: DatabaseService
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -52,39 +52,22 @@ agents:
|
||||
- ref: client_1_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
action_probabilities:
|
||||
0: 0.4
|
||||
1: 0.6
|
||||
|
||||
|
||||
simulation:
|
||||
|
||||
@@ -13,72 +13,47 @@ agents:
|
||||
- ref: client_2_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_nics_per_node: 2
|
||||
max_acl_rules: 10
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
action_probabilities:
|
||||
0: 1.0
|
||||
|
||||
- ref: data_manipulation_attacker
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_CORRUPT
|
||||
- type: NODE_OS_SCAN
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
node_name: client_1
|
||||
application_name: DataManipulationBot
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
possible_start_nodes: [client_1,]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
@@ -154,381 +129,327 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
action: node_service_scan
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
action: node_service_stop
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
action: "node_service_start"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
action: "node_service_pause"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
action: "node_service_resume"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
action: "node_service_restart"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
action: "node_service_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
action: "node_service_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
action: "node_file_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
10:
|
||||
action: "NODE_FILE_CHECKHASH"
|
||||
action: "node_file_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
action: "node_file_delete"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
action: "node_file_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
action: "node_service_fix"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
node_name: database_server
|
||||
service_name: DatabaseService
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
action: "node_folder_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
15:
|
||||
action: "NODE_FOLDER_CHECKHASH"
|
||||
action: "node_folder_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
action: "node_folder_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
action: "node_folder_restore"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 1
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
19: # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
20:
|
||||
action: "NODE_STARTUP"
|
||||
action: "node_startup"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
21:
|
||||
action: "NODE_RESET"
|
||||
action: "node_reset"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
22: # "ACL: ADDRULE - Block outgoing traffic from client 1" (not supported in Primaite)
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
23: # "ACL: ADDRULE - Block outgoing traffic from client 2" (not supported in Primaite)
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
24: # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
25: # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
26:
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
27:
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
28:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 0
|
||||
29:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
30:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
31:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
32:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
33:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
34:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
35:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 7
|
||||
36:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 8
|
||||
37:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 9
|
||||
38:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
39:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
40:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
41:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
42:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
43:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
44:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
45:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
46:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
47:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
48:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
49:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
50:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
51:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
52:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
53:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
- node_name: web_server
|
||||
- node_name: database_server
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -30,35 +30,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_2
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_2
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -79,35 +66,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_1
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -128,33 +102,12 @@ agents:
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
possible_start_nodes: [client_1, client_2]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
@@ -235,491 +188,426 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
action: node_service_scan
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
action: node_service_stop
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
action: "node_service_start"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
action: "node_service_pause"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
action: "node_service_resume"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
action: "node_service_restart"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
action: "node_service_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
action: "node_service_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
action: "node_file_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
10:
|
||||
action: "NODE_FILE_CHECKHASH" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
action: "node_file_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
action: "node_file_delete"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
action: "node_file_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
action: "node_service_fix"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
node_name: database_server
|
||||
service_name: DatabaseService
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
action: "node_folder_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
15:
|
||||
action: "NODE_FOLDER_CHECKHASH" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
action: "node_folder_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
action: "node_folder_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
action: "node_folder_restore"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
19:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
20:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
21:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
22:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
23:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
24:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
25:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
26: # old action num: 18
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
27:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
28:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
29:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
30:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
31:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
32:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
33:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
34:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
35:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
36:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
37:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
38:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
39: # old action num: 19 # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
40: # old action num: 20
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
41: # old action num: 21
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
42:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
43:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
44:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
45:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
|
||||
46: # old action num: 22 # "ACL: ADDRULE - Block outgoing traffic from client 1"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
47: # old action num: 23 # "ACL: ADDRULE - Block outgoing traffic from client 2"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
48: # old action num: 24 # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
49: # old action num: 25 # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
50: # old action num: 26
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
51: # old action num: 27
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
52: # old action num: 28
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 0
|
||||
53: # old action num: 29
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
54: # old action num: 30
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
55: # old action num: 31
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
56: # old action num: 32
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
57: # old action num: 33
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
58: # old action num: 34
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
59: # old action num: 35
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 7
|
||||
60: # old action num: 36
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 8
|
||||
61: # old action num: 37
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 9
|
||||
62: # old action num: 38
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
63: # old action num: 39
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
64: # old action num: 40
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
65: # old action num: 41
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
66: # old action num: 42
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
67: # old action num: 43
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
68: # old action num: 44
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
69: # old action num: 45
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
70: # old action num: 46
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
71: # old action num: 47
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
72: # old action num: 48
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
73: # old action num: 49
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
74: # old action num: 50
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
75: # old action num: 51
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
76: # old action num: 52
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
77: # old action num: 53
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
- node_name: web_server
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
services:
|
||||
- service_name: WebServer
|
||||
- node_name: database_server
|
||||
folders:
|
||||
- folder_name: database
|
||||
files:
|
||||
- file_name: database.db
|
||||
services:
|
||||
- service_name: DatabaseService
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DATABASE_FILE_INTEGRITY
|
||||
|
||||
@@ -95,181 +95,156 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: FIREWALL_ACL_ADDRULE
|
||||
- type: FIREWALL_ACL_REMOVERULE
|
||||
- type: NETWORK_PORT_DISABLE
|
||||
- type: NETWORK_PORT_ENABLE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: FIREWALL_ACL_ADDRULE
|
||||
action: firewall_acl_add_rule
|
||||
options:
|
||||
type: firewall_acl_add_rule
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: internal
|
||||
firewall_port_direction: inbound
|
||||
position: 1
|
||||
permission: 1
|
||||
source_ip_id: 2 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: PERMIT
|
||||
src_ip: 192.168.0.10
|
||||
dst_ip: ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
2:
|
||||
action: FIREWALL_ACL_REMOVERULE
|
||||
action: firewall_acl_remove_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: internal
|
||||
firewall_port_direction: inbound
|
||||
position: 1
|
||||
3:
|
||||
action: FIREWALL_ACL_ADDRULE
|
||||
action: firewall_acl_add_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: internal
|
||||
firewall_port_direction: outbound
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 2 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 2
|
||||
dest_port_id: 3
|
||||
protocol_id: 2
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.0.10 # client 1
|
||||
dst_ip: ALL
|
||||
src_port: ARP
|
||||
dst_port: DNS
|
||||
protocol_name: ICMP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
4:
|
||||
action: FIREWALL_ACL_REMOVERULE
|
||||
action: firewall_acl_remove_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: internal
|
||||
firewall_port_direction: outbound
|
||||
position: 1
|
||||
5:
|
||||
action: FIREWALL_ACL_ADDRULE
|
||||
action: firewall_acl_add_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: dmz
|
||||
firewall_port_direction: inbound
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 3 # dmz_server
|
||||
dest_ip_id: 2 # client_1
|
||||
source_port_id: 4
|
||||
dest_port_id: 4
|
||||
protocol_id: 4
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.10 # dmz_server
|
||||
dst_ip: 192.168.0.10 # client_1
|
||||
src_port: HTTP
|
||||
dst_port: HTTP
|
||||
protocol_name: UDP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
6:
|
||||
action: FIREWALL_ACL_REMOVERULE
|
||||
action: firewall_acl_remove_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: dmz
|
||||
firewall_port_direction: inbound
|
||||
position: 1
|
||||
7:
|
||||
action: FIREWALL_ACL_ADDRULE
|
||||
action: firewall_acl_add_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: dmz
|
||||
firewall_port_direction: outbound
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 3 # dmz_server
|
||||
dest_ip_id: 2 # client_1
|
||||
source_port_id: 4
|
||||
dest_port_id: 4
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.10 # dmz_server
|
||||
dst_ip: 192.168.0.10 # client_1
|
||||
src_port: HTTP
|
||||
dst_port: HTTP
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
8:
|
||||
action: FIREWALL_ACL_REMOVERULE
|
||||
action: firewall_acl_remove_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: dmz
|
||||
firewall_port_direction: outbound
|
||||
position: 2
|
||||
9:
|
||||
action: FIREWALL_ACL_ADDRULE
|
||||
action: firewall_acl_add_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: external
|
||||
firewall_port_direction: inbound
|
||||
position: 10
|
||||
permission: 2
|
||||
source_ip_id: 4 # external_computer
|
||||
dest_ip_id: 3 # dmz
|
||||
source_port_id: 5
|
||||
dest_port_id: 5
|
||||
protocol_id: 2
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.20.10 # external_computer
|
||||
dst_ip: 192.168.10.10 # dmz
|
||||
src_port: POSTGRES_SERVER
|
||||
dst_port: POSTGRES_SERVER
|
||||
protocol_name: ICMP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
10:
|
||||
action: FIREWALL_ACL_REMOVERULE
|
||||
action: firewall_acl_remove_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: external
|
||||
firewall_port_direction: inbound
|
||||
position: 10
|
||||
11:
|
||||
action: FIREWALL_ACL_ADDRULE
|
||||
action: firewall_acl_add_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: external
|
||||
firewall_port_direction: outbound
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 4 # external_computer
|
||||
dest_ip_id: 2 # client_1
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.20.10 # external_computer
|
||||
dst_ip: 192.168.0.10 # client_1
|
||||
src_port: NONE
|
||||
dst_port: NONE
|
||||
protocol_name: none
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
12:
|
||||
action: FIREWALL_ACL_REMOVERULE
|
||||
action: firewall_acl_remove_rule
|
||||
options:
|
||||
target_firewall_nodename: firewall
|
||||
firewall_port_name: external
|
||||
firewall_port_direction: outbound
|
||||
position: 1
|
||||
13:
|
||||
action: NETWORK_PORT_DISABLE
|
||||
action: network_port_disable
|
||||
options:
|
||||
type: network_port_disable
|
||||
target_nodename: firewall
|
||||
port_id: 3
|
||||
port_num: 3
|
||||
14:
|
||||
action: NETWORK_PORT_ENABLE
|
||||
action: network_port_enable
|
||||
options:
|
||||
type: network_port_enable
|
||||
target_nodename: firewall
|
||||
port_id: 3
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
- node_name: dmz_server
|
||||
- node_name: external_computer
|
||||
ip_list:
|
||||
- 192.168.0.10
|
||||
- 192.168.10.10
|
||||
- 192.168.20.10
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
port_num: 3
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -27,40 +27,21 @@ agents:
|
||||
- ref: client_2_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
|
||||
action_probabilities:
|
||||
0: 0.4
|
||||
1: 0.6
|
||||
|
||||
|
||||
- ref: defender
|
||||
@@ -119,28 +100,10 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
options:
|
||||
nodes:
|
||||
- node_name: switch
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
- node_name: client_3
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.23
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -18,80 +18,63 @@ agents:
|
||||
team: BLUE
|
||||
type: ProxyAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_INSTALL
|
||||
- type: CONFIGURE_DATABASE_CLIENT
|
||||
- type: CONFIGURE_DOSBOT
|
||||
- type: CONFIGURE_RANSOMWARE_SCRIPT
|
||||
- type: NODE_APPLICATION_REMOVE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_INSTALL
|
||||
action: node_application_install
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: client_1
|
||||
application_name: DatabaseClient
|
||||
2:
|
||||
action: NODE_APPLICATION_INSTALL
|
||||
action: node_application_install
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: client_2
|
||||
application_name: RansomwareScript
|
||||
3:
|
||||
action: NODE_APPLICATION_INSTALL
|
||||
action: node_application_install
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: client_3
|
||||
application_name: DoSBot
|
||||
4:
|
||||
action: CONFIGURE_DATABASE_CLIENT
|
||||
action: configure_database_client
|
||||
options:
|
||||
node_id: 0
|
||||
config:
|
||||
server_ip_address: 10.0.0.5
|
||||
node_name: client_1
|
||||
server_ip_address: 10.0.0.5
|
||||
5:
|
||||
action: CONFIGURE_DATABASE_CLIENT
|
||||
action: configure_database_client
|
||||
options:
|
||||
node_id: 0
|
||||
config:
|
||||
server_password: correct_password
|
||||
node_name: client_1
|
||||
server_password: correct_password
|
||||
6:
|
||||
action: CONFIGURE_RANSOMWARE_SCRIPT
|
||||
action: configure_ransomware_script
|
||||
options:
|
||||
node_id: 1
|
||||
config:
|
||||
server_ip_address: 10.0.0.5
|
||||
server_password: correct_password
|
||||
payload: ENCRYPT
|
||||
node_name: client_2
|
||||
server_ip_address: 10.0.0.5
|
||||
server_password: correct_password
|
||||
payload: ENCRYPT
|
||||
7:
|
||||
action: CONFIGURE_DOSBOT
|
||||
action: configure_dos_bot
|
||||
options:
|
||||
node_id: 2
|
||||
config:
|
||||
target_ip_address: 10.0.0.5
|
||||
target_port: POSTGRES_SERVER
|
||||
payload: DELETE
|
||||
repeat: true
|
||||
port_scan_p_of_success: 1.0
|
||||
dos_intensity: 1.0
|
||||
max_sessions: 1000
|
||||
node_name: client_3
|
||||
target_ip_address: 10.0.0.5
|
||||
target_port: POSTGRES_SERVER
|
||||
payload: DELETE
|
||||
repeat: true
|
||||
port_scan_p_of_success: 1.0
|
||||
dos_intensity: 1.0
|
||||
max_sessions: 1000
|
||||
8:
|
||||
action: NODE_APPLICATION_INSTALL
|
||||
action: node_application_install
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: client_2
|
||||
application_name: DatabaseClient
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
- node_name: client_3
|
||||
ip_list: []
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
agent_settings:
|
||||
flatten_obs: True
|
||||
action_masking: False
|
||||
|
||||
simulation:
|
||||
network:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,32 +22,17 @@ agents:
|
||||
- ref: client_1_red_nmap
|
||||
team: RED
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: NMAP
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
action_list:
|
||||
- type: NODE_NMAP_NETWORK_SERVICE_RECON
|
||||
action_map:
|
||||
0:
|
||||
action: NODE_NMAP_NETWORK_SERVICE_RECON
|
||||
action: node_network_service_recon
|
||||
options:
|
||||
source_node: client_1
|
||||
target_ip_address: 192.168.10.0/24
|
||||
target_port: 80
|
||||
target_protocol: tcp
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
show: false
|
||||
agent_settings:
|
||||
action_probabilities:
|
||||
0: 1.0
|
||||
|
||||
@@ -22,29 +22,15 @@ agents:
|
||||
- ref: client_1_red_nmap
|
||||
team: RED
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: NMAP
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
action_list:
|
||||
- type: NODE_NMAP_PING_SCAN
|
||||
action_map:
|
||||
0:
|
||||
action: NODE_NMAP_PING_SCAN
|
||||
action: node_nmap_ping_scan
|
||||
options:
|
||||
source_node: client_1
|
||||
target_ip_address: 192.168.1.0/24
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
show: False
|
||||
|
||||
agent_settings:
|
||||
action_probabilities:
|
||||
|
||||
@@ -22,22 +22,11 @@ agents:
|
||||
- ref: client_1_red_nmap
|
||||
team: RED
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: NMAP
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
action_list:
|
||||
- type: NODE_NMAP_PORT_SCAN
|
||||
action_map:
|
||||
0:
|
||||
action: NODE_NMAP_PORT_SCAN
|
||||
action: node_nmap_port_scan
|
||||
options:
|
||||
source_node: client_1
|
||||
target_ip_address: 192.168.10.0/24
|
||||
@@ -47,10 +36,7 @@ agents:
|
||||
- 80
|
||||
- 123
|
||||
- 219
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
show: false
|
||||
|
||||
agent_settings:
|
||||
action_probabilities:
|
||||
|
||||
@@ -6,25 +6,17 @@ agents: &greens
|
||||
action_probabilities:
|
||||
0: 0.2
|
||||
1: 0.8
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -6,25 +6,17 @@ agents: &greens
|
||||
action_probabilities:
|
||||
0: 0.95
|
||||
1: 0.05
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -3,24 +3,9 @@ reds: &reds
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 10
|
||||
frequency: 10
|
||||
variance: 0
|
||||
possible_start_nodes: [client,]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 10
|
||||
frequency: 10
|
||||
variance: 0
|
||||
|
||||
@@ -2,25 +2,9 @@ reds: &reds
|
||||
- ref: red_B
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 3
|
||||
frequency: 2
|
||||
variance: 1
|
||||
possible_start_nodes: [client_1,]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 3
|
||||
frequency: 2
|
||||
variance: 1
|
||||
|
||||
@@ -54,65 +54,46 @@ agents:
|
||||
- server:eth-1<->switch_1:eth-2
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_SHUTDOWN
|
||||
action: node_shutdown
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: client
|
||||
2:
|
||||
action: NODE_SHUTDOWN
|
||||
action: node_shutdown
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: server
|
||||
3:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: client
|
||||
4:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: server
|
||||
5:
|
||||
action: HOST_NIC_DISABLE
|
||||
action: host_nic_disable
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: client
|
||||
nic_num: 1
|
||||
6:
|
||||
action: HOST_NIC_DISABLE
|
||||
action: host_nic_disable
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: server
|
||||
nic_num: 1
|
||||
7:
|
||||
action: HOST_NIC_ENABLE
|
||||
action: host_nic_enable
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: client
|
||||
nic_num: 1
|
||||
8:
|
||||
action: HOST_NIC_ENABLE
|
||||
action: host_nic_enable
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client
|
||||
- node_name: server
|
||||
|
||||
max_folders_per_node: 0
|
||||
max_files_per_folder: 0
|
||||
max_services_per_node: 0
|
||||
max_nics_per_node: 1
|
||||
max_acl_rules: 0
|
||||
ip_list:
|
||||
- 192.168.1.2
|
||||
- 192.168.1.3
|
||||
node_name: server
|
||||
nic_num: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -29,35 +29,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_2
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_2
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -78,35 +65,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_1
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -123,33 +97,12 @@ agents:
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
possible_start_nodes: [client_1, client_2]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
@@ -225,490 +178,423 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
action: node_service_scan
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
action: node_service_stop
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
action: "node_service_start"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
action: "node_service_pause"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
action: "node_service_resume"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
action: "node_service_restart"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
action: "node_service_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
action: "node_service_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
action: "node_file_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
10:
|
||||
action: "NODE_FILE_CHECKHASH"
|
||||
action: "node_file_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
action: "node_file_delete"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
action: "node_file_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
action: "node_service_fix"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
node_name: database_server
|
||||
service_name: DatabaseService
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
action: "node_folder_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
15:
|
||||
action: "NODE_FOLDER_CHECKHASH"
|
||||
action: "node_folder_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
action: "node_folder_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
action: "node_folder_restore"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
19:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
20:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
21:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
22:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
23:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
24:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
25:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
26: # old action num: 18
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
27:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
28:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
29:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
30:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
31:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
32:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
33:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
34:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
35:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
36:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
37:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
38:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
39: # old action num: 19 # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
40: # old action num: 20
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
41: # old action num: 21
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
42:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
43:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
44:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
45:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
|
||||
46: # old action num: 22 # "ACL: ADDRULE - Block outgoing traffic from client 1"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
47: # old action num: 23 # "ACL: ADDRULE - Block outgoing traffic from client 2"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
48: # old action num: 24 # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
49: # old action num: 25 # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
50: # old action num: 26
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
51: # old action num: 27
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
52: # old action num: 28
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 0
|
||||
53: # old action num: 29
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
54: # old action num: 30
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
55: # old action num: 31
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
56: # old action num: 32
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
57: # old action num: 33
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
58: # old action num: 34
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
59: # old action num: 35
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 7
|
||||
60: # old action num: 36
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 8
|
||||
61: # old action num: 37
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 9
|
||||
62: # old action num: 38
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
63: # old action num: 39
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
64: # old action num: 40
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
65: # old action num: 41
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
66: # old action num: 42
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
67: # old action num: 43
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
68: # old action num: 44
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
69: # old action num: 45
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
70: # old action num: 46
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
71: # old action num: 47
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
72: # old action num: 48
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
73: # old action num: 49
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
74: # old action num: 50
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
75: # old action num: 51
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
76: # old action num: 52
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
77: # old action num: 53
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
- node_name: web_server
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
services:
|
||||
- service_name: WebServer
|
||||
- node_name: database_server
|
||||
folders:
|
||||
- folder_name: database
|
||||
files:
|
||||
- file_name: database.db
|
||||
services:
|
||||
- service_name: DatabaseService
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -27,40 +27,21 @@ agents:
|
||||
- ref: client_2_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
node_name: client_2
|
||||
application_name: WebBrowser
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
|
||||
action_probabilities:
|
||||
0: 0.4
|
||||
1: 0.6
|
||||
|
||||
|
||||
- ref: defender
|
||||
@@ -119,28 +100,10 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
options:
|
||||
nodes:
|
||||
- node_name: switch
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
- node_name: client_3
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.23
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -29,35 +29,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_2
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_2
|
||||
application_name: DatabaseClient
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -78,35 +65,22 @@ agents:
|
||||
0: 0.3
|
||||
1: 0.6
|
||||
2: 0.1
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
- application_name: DatabaseClient
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 2
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
2:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 1
|
||||
node_name: client_1
|
||||
application_name: WebBrowser
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
@@ -127,33 +101,12 @@ agents:
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
possible_start_nodes: [client_1, client_2]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
@@ -229,524 +182,449 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
- type: NODE_APPLICATION_INSTALL
|
||||
- type: NODE_APPLICATION_REMOVE
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
- type: CONFIGURE_DOSBOT
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
action: node_service_scan
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
action: node_service_stop
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
action: "node_service_start"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
action: "node_service_pause"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
action: "node_service_resume"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
action: "node_service_restart"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
action: "node_service_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
action: "node_service_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
action: "node_file_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
10:
|
||||
action: "NODE_FILE_SCAN" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
action: "node_file_scan" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
action: "node_file_delete"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
action: "node_file_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
action: "node_service_fix"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
node_name: database_server
|
||||
service_name: DatabaseService
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
action: "node_folder_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
15:
|
||||
action: "NODE_FOLDER_SCAN" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
action: "node_folder_scan" # CHECKHASH replaced by SCAN - but the behaviour is the same in this context.
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
action: "node_folder_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
action: "node_folder_restore"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
19:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
20:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
21:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
22:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
23:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
24:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
25:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 1
|
||||
node_name: web_server
|
||||
26: # old action num: 18
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
27:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
28:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
29:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
30:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
31:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
32:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
33:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 3
|
||||
node_name: backup_server
|
||||
34:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
35:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
36:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
37:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 4
|
||||
node_name: security_suite
|
||||
38:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
39: # old action num: 19 # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
40: # old action num: 20
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
41: # old action num: 21
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
42:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
43:
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
44:
|
||||
action: NODE_STARTUP
|
||||
action: node_startup
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
45:
|
||||
action: NODE_RESET
|
||||
action: node_reset
|
||||
options:
|
||||
node_id: 6
|
||||
node_name: client_2
|
||||
|
||||
46: # old action num: 22 # "ACL: ADDRULE - Block outgoing traffic from client 1"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
47: # old action num: 23 # "ACL: ADDRULE - Block outgoing traffic from client 2"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
48: # old action num: 24 # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
49: # old action num: 25 # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
50: # old action num: 26
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
51: # old action num: 27
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
52: # old action num: 28
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 0
|
||||
53: # old action num: 29
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 1
|
||||
54: # old action num: 30
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 2
|
||||
55: # old action num: 31
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 3
|
||||
56: # old action num: 32
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 4
|
||||
57: # old action num: 33
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 5
|
||||
58: # old action num: 34
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 6
|
||||
59: # old action num: 35
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 7
|
||||
60: # old action num: 36
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 8
|
||||
61: # old action num: 37
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router_hostname: router_1
|
||||
target_router: router_1
|
||||
position: 9
|
||||
62: # old action num: 38
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
63: # old action num: 39
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
64: # old action num: 40
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
65: # old action num: 41
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
66: # old action num: 42
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
67: # old action num: 43
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
68: # old action num: 44
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
69: # old action num: 45
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
70: # old action num: 46
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
71: # old action num: 47
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
72: # old action num: 48
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
73: # old action num: 49
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
74: # old action num: 50
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
75: # old action num: 51
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
76: # old action num: 52
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
77: # old action num: 53
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
78:
|
||||
action: NODE_APPLICATION_INSTALL
|
||||
action: node_application_install
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
application_name: DoSBot
|
||||
79:
|
||||
action: NODE_APPLICATION_REMOVE
|
||||
action: node_application_remove
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
application_name: DoSBot
|
||||
80:
|
||||
action: NODE_APPLICATION_REMOVE
|
||||
action: node_application_remove
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: domain_controller
|
||||
application_name: WebBrowser
|
||||
81:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
node_name: domain_controller
|
||||
application_name: DoSBot
|
||||
82:
|
||||
action: CONFIGURE_DOSBOT
|
||||
action: configure_dos_bot
|
||||
options:
|
||||
node_id: 0
|
||||
config:
|
||||
target_ip_address: 192.168.1.14
|
||||
target_port: POSTGRES_SERVER
|
||||
|
||||
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
applications:
|
||||
- application_name: DoSBot
|
||||
- node_name: web_server
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
services:
|
||||
- service_name: WebServer
|
||||
- node_name: database_server
|
||||
folders:
|
||||
- folder_name: database
|
||||
files:
|
||||
- file_name: database.db
|
||||
services:
|
||||
- service_name: DatabaseService
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
|
||||
node_name: domain_controller
|
||||
target_ip_address: 192.168.1.14
|
||||
target_port: POSTGRES_SERVER
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -21,73 +21,40 @@ agents:
|
||||
- ref: client_2_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_nics_per_node: 2
|
||||
max_acl_rules: 10
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
action_probabilities:
|
||||
0: 1.0
|
||||
|
||||
- ref: data_manipulation_attacker
|
||||
team: RED
|
||||
type: RedDatabaseCorruptingAgent
|
||||
|
||||
observation_space: null
|
||||
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_CORRUPT
|
||||
- type: NODE_OS_SCAN
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
action: node_application_execute
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
applications:
|
||||
- application_name: DataManipulationBot
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
node_name: client_1
|
||||
application_name: DataManipulationBot
|
||||
|
||||
agent_settings: # options specific to this particular agent type, basically args of __init__(self)
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
possible_start_nodes: [client_1,]
|
||||
target_application: DataManipulationBot
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
@@ -163,391 +130,326 @@ agents:
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
action: do_nothing
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
action: node_service_scan
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
action: node_service_stop
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
action: "node_service_start"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
action: "node_service_pause"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
action: "node_service_resume"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
action: "node_service_restart"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
action: "node_service_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
action: "node_service_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
node_name: web_server
|
||||
service_name: WebServer
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
action: "node_file_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
10:
|
||||
action: "NODE_FILE_CHECKHASH"
|
||||
action: "node_file_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
action: "node_file_delete"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
action: "node_file_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
action: "node_service_fix"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
node_name: database_server
|
||||
service_name: DatabaseService
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
action: "node_folder_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
15:
|
||||
action: "NODE_FOLDER_CHECKHASH"
|
||||
action: "node_folder_checkhash"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
action: "node_folder_repair"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
action: "node_folder_restore"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
node_name: database_server
|
||||
folder_name: database
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
action: "node_os_scan"
|
||||
options:
|
||||
node_id: 2
|
||||
node_name: database_server
|
||||
19: # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
action: "node_shutdown"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
20:
|
||||
action: "NODE_STARTUP"
|
||||
action: "node_startup"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
21:
|
||||
action: "NODE_RESET"
|
||||
action: "node_reset"
|
||||
options:
|
||||
node_id: 5
|
||||
node_name: client_1
|
||||
22: # "ACL: ADDRULE - Block outgoing traffic from client 1" (not supported in Primaite)
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
23: # "ACL: ADDRULE - Block outgoing traffic from client 2" (not supported in Primaite)
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: ALL
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
24: # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
25: # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
26:
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
27:
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
action: "router_acl_add_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
src_port: ALL
|
||||
dst_port: ALL
|
||||
protocol_name: TCP
|
||||
src_wildcard: NONE
|
||||
dst_wildcard: NONE
|
||||
28:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 0
|
||||
29:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
30:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
31:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
32:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
33:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
34:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
35:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 7
|
||||
36:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 8
|
||||
37:
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
action: "router_acl_remove_rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 9
|
||||
38:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
39:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
node_name: domain_controller
|
||||
nic_num: 1
|
||||
40:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
41:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
node_name: web_server
|
||||
nic_num: 1
|
||||
42:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
43:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
node_name: database_server
|
||||
nic_num: 1
|
||||
44:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
45:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
node_name: backup_server
|
||||
nic_num: 1
|
||||
46:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
47:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
node_name: security_suite
|
||||
nic_num: 1
|
||||
48:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
49:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
node_name: security_suite
|
||||
nic_num: 2
|
||||
50:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
51:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
node_name: client_1
|
||||
nic_num: 1
|
||||
52:
|
||||
action: "HOST_NIC_DISABLE"
|
||||
action: "host_nic_disable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
53:
|
||||
action: "HOST_NIC_ENABLE"
|
||||
action: "host_nic_enable"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
- node_name: web_server
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
services:
|
||||
- service_name: WebServer
|
||||
- node_name: database_server
|
||||
folders:
|
||||
- folder_name: database
|
||||
files:
|
||||
- file_name: database.db
|
||||
services:
|
||||
- service_name: DatabaseService
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
node_name: client_2
|
||||
nic_num: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
from typing import Any, Dict, Tuple
|
||||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
@@ -11,6 +11,7 @@ from primaite.game.agent.actions import ActionManager
|
||||
from primaite.game.agent.interface import AbstractAgent
|
||||
from primaite.game.agent.observations.observation_manager import NestedObservation, ObservationManager
|
||||
from primaite.game.agent.rewards import RewardFunction
|
||||
from primaite.game.agent.scripted_agents.probabilistic_agent import ProbabilisticAgent
|
||||
from primaite.game.game import PrimaiteGame
|
||||
from primaite.simulator.file_system.file_system import FileSystem
|
||||
from primaite.simulator.network.container import Network
|
||||
@@ -279,23 +280,16 @@ def example_network() -> Network:
|
||||
return network
|
||||
|
||||
|
||||
class ControlledAgent(AbstractAgent):
|
||||
class ControlledAgent(AbstractAgent, identifier="ControlledAgent"):
|
||||
"""Agent that can be controlled by the tests."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent_name: str,
|
||||
action_space: ActionManager,
|
||||
observation_space: ObservationManager,
|
||||
reward_function: RewardFunction,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
agent_name=agent_name,
|
||||
action_space=action_space,
|
||||
observation_space=observation_space,
|
||||
reward_function=reward_function,
|
||||
)
|
||||
self.most_recent_action: Tuple[str, Dict]
|
||||
config: "ControlledAgent.ConfigSchema" = Field(default_factory=lambda: ControlledAgent.ConfigSchema())
|
||||
most_recent_action: Optional[Tuple[str, Dict]] = None
|
||||
|
||||
class ConfigSchema(AbstractAgent.ConfigSchema):
|
||||
"""Configuration Schema for Abstract Agent used in tests."""
|
||||
|
||||
type: str = "ControlledAgent"
|
||||
|
||||
def get_action(self, obs: None, timestep: int = 0) -> Tuple[str, Dict]:
|
||||
"""Return the agent's most recent action, formatted in CAOS format."""
|
||||
@@ -390,6 +384,7 @@ def install_stuff_to_sim(sim: Simulation):
|
||||
# 5: Assert that the simulation starts off in the state that we expect
|
||||
assert len(sim.network.nodes) == 6
|
||||
assert len(sim.network.links) == 5
|
||||
|
||||
# 5.1: Assert the router is correctly configured
|
||||
r = sim.network.router_nodes[0]
|
||||
for i, acl_rule in enumerate(r.acl.acl):
|
||||
@@ -433,97 +428,13 @@ def game_and_agent():
|
||||
sim = game.simulation
|
||||
install_stuff_to_sim(sim)
|
||||
|
||||
actions = [
|
||||
{"type": "DONOTHING"},
|
||||
{"type": "NODE_SERVICE_SCAN"},
|
||||
{"type": "NODE_SERVICE_STOP"},
|
||||
{"type": "NODE_SERVICE_START"},
|
||||
{"type": "NODE_SERVICE_PAUSE"},
|
||||
{"type": "NODE_SERVICE_RESUME"},
|
||||
{"type": "NODE_SERVICE_RESTART"},
|
||||
{"type": "NODE_SERVICE_DISABLE"},
|
||||
{"type": "NODE_SERVICE_ENABLE"},
|
||||
{"type": "NODE_SERVICE_FIX"},
|
||||
{"type": "NODE_APPLICATION_EXECUTE"},
|
||||
{"type": "NODE_APPLICATION_SCAN"},
|
||||
{"type": "NODE_APPLICATION_CLOSE"},
|
||||
{"type": "NODE_APPLICATION_FIX"},
|
||||
{"type": "NODE_APPLICATION_INSTALL"},
|
||||
{"type": "NODE_APPLICATION_REMOVE"},
|
||||
{"type": "NODE_FILE_CREATE"},
|
||||
{"type": "NODE_FILE_SCAN"},
|
||||
{"type": "NODE_FILE_CHECKHASH"},
|
||||
{"type": "NODE_FILE_DELETE"},
|
||||
{"type": "NODE_FILE_REPAIR"},
|
||||
{"type": "NODE_FILE_RESTORE"},
|
||||
{"type": "NODE_FILE_CORRUPT"},
|
||||
{"type": "NODE_FILE_ACCESS"},
|
||||
{"type": "NODE_FOLDER_CREATE"},
|
||||
{"type": "NODE_FOLDER_SCAN"},
|
||||
{"type": "NODE_FOLDER_CHECKHASH"},
|
||||
{"type": "NODE_FOLDER_REPAIR"},
|
||||
{"type": "NODE_FOLDER_RESTORE"},
|
||||
{"type": "NODE_OS_SCAN"},
|
||||
{"type": "NODE_SHUTDOWN"},
|
||||
{"type": "NODE_STARTUP"},
|
||||
{"type": "NODE_RESET"},
|
||||
{"type": "ROUTER_ACL_ADDRULE"},
|
||||
{"type": "ROUTER_ACL_REMOVERULE"},
|
||||
{"type": "HOST_NIC_ENABLE"},
|
||||
{"type": "HOST_NIC_DISABLE"},
|
||||
{"type": "NETWORK_PORT_ENABLE"},
|
||||
{"type": "NETWORK_PORT_DISABLE"},
|
||||
{"type": "CONFIGURE_C2_BEACON"},
|
||||
{"type": "C2_SERVER_RANSOMWARE_LAUNCH"},
|
||||
{"type": "C2_SERVER_RANSOMWARE_CONFIGURE"},
|
||||
{"type": "C2_SERVER_TERMINAL_COMMAND"},
|
||||
{"type": "C2_SERVER_DATA_EXFILTRATE"},
|
||||
{"type": "NODE_ACCOUNTS_CHANGE_PASSWORD"},
|
||||
{"type": "SSH_TO_REMOTE"},
|
||||
{"type": "SESSIONS_REMOTE_LOGOFF"},
|
||||
{"type": "NODE_SEND_REMOTE_COMMAND"},
|
||||
]
|
||||
config = {
|
||||
"type": "ControlledAgent",
|
||||
"ref": "test_agent",
|
||||
"team": "BLUE",
|
||||
}
|
||||
|
||||
action_space = ActionManager(
|
||||
actions=actions, # ALL POSSIBLE ACTIONS
|
||||
nodes=[
|
||||
{
|
||||
"node_name": "client_1",
|
||||
"applications": [
|
||||
{"application_name": "WebBrowser"},
|
||||
{"application_name": "DoSBot"},
|
||||
{"application_name": "C2Server"},
|
||||
],
|
||||
"folders": [{"folder_name": "downloads", "files": [{"file_name": "cat.png"}]}],
|
||||
},
|
||||
{
|
||||
"node_name": "server_1",
|
||||
"services": [{"service_name": "DNSServer"}],
|
||||
"applications": [{"application_name": "C2Beacon"}],
|
||||
},
|
||||
{"node_name": "server_2", "services": [{"service_name": "WebServer"}]},
|
||||
{"node_name": "router"},
|
||||
],
|
||||
max_folders_per_node=2,
|
||||
max_files_per_folder=2,
|
||||
max_services_per_node=2,
|
||||
max_applications_per_node=3,
|
||||
max_nics_per_node=2,
|
||||
max_acl_rules=10,
|
||||
protocols=["TCP", "UDP", "ICMP"],
|
||||
ports=["HTTP", "DNS", "ARP"],
|
||||
ip_list=["10.0.1.1", "10.0.1.2", "10.0.2.1", "10.0.2.2", "10.0.2.3"],
|
||||
act_map={},
|
||||
)
|
||||
observation_space = ObservationManager(NestedObservation(components={}))
|
||||
reward_function = RewardFunction()
|
||||
|
||||
test_agent = ControlledAgent(
|
||||
agent_name="test_agent",
|
||||
action_space=action_space,
|
||||
observation_space=observation_space,
|
||||
reward_function=reward_function,
|
||||
)
|
||||
test_agent = ControlledAgent(config=config)
|
||||
|
||||
game.agents["test_agent"] = test_agent
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ def test_application_install_uninstall_on_uc2():
|
||||
cfg = yaml.safe_load(f)
|
||||
|
||||
env = PrimaiteGymEnv(env_config=cfg)
|
||||
env.agent.flatten_obs = False
|
||||
env.agent.config.agent_settings.flatten_obs = False
|
||||
env.reset()
|
||||
|
||||
_, _, _, _, _ = env.step(0)
|
||||
|
||||
@@ -33,22 +33,22 @@ def test_application_cannot_perform_actions_unless_running(game_and_agent_fixtur
|
||||
browser.close()
|
||||
assert browser.operating_state == ApplicationOperatingState.CLOSED
|
||||
|
||||
action = ("NODE_APPLICATION_SCAN", {"node_id": 0, "application_id": 0})
|
||||
action = ("node_application_scan", {"node_name": "client_1", "application_name": "WebBrowser"})
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
assert browser.operating_state == ApplicationOperatingState.CLOSED
|
||||
|
||||
action = ("NODE_APPLICATION_CLOSE", {"node_id": 0, "application_id": 0})
|
||||
action = ("node_application_close", {"node_name": "client_1", "application_name": "WebBrowser"})
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
assert browser.operating_state == ApplicationOperatingState.CLOSED
|
||||
|
||||
action = ("NODE_APPLICATION_FIX", {"node_id": 0, "application_id": 0})
|
||||
action = ("node_application_fix", {"node_name": "client_1", "application_name": "WebBrowser"})
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
assert browser.operating_state == ApplicationOperatingState.CLOSED
|
||||
|
||||
action = ("NODE_APPLICATION_EXECUTE", {"node_id": 0, "application_id": 0})
|
||||
action = ("node_application_execute", {"node_name": "client_1", "application_name": "WebBrowser"})
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
assert browser.operating_state == ApplicationOperatingState.CLOSED
|
||||
|
||||
@@ -46,23 +46,21 @@ def test_c2_beacon_default(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAgen
|
||||
server_1: Server = game.simulation.network.get_node_by_hostname("server_1")
|
||||
|
||||
action = (
|
||||
"NODE_APPLICATION_INSTALL",
|
||||
{"node_id": 1, "application_name": "C2Beacon"},
|
||||
"node_application_install",
|
||||
{"node_name": "server_1", "application_name": "C2Beacon"},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
assert agent.history[-1].response.status == "success"
|
||||
|
||||
action = (
|
||||
"CONFIGURE_C2_BEACON",
|
||||
"configure_c2_beacon",
|
||||
{
|
||||
"node_id": 1,
|
||||
"config": {
|
||||
"c2_server_ip_address": "10.0.1.2",
|
||||
"keep_alive_frequency": 5,
|
||||
"masquerade_protocol": "TCP",
|
||||
"masquerade_port": "HTTP",
|
||||
},
|
||||
"node_name": "server_1",
|
||||
"c2_server_ip_address": "10.0.1.2",
|
||||
"keep_alive_frequency": 5,
|
||||
"masquerade_protocol": "TCP",
|
||||
"masquerade_port": "HTTP",
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -70,8 +68,8 @@ def test_c2_beacon_default(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAgen
|
||||
assert agent.history[-1].response.status == "success"
|
||||
|
||||
action = (
|
||||
"NODE_APPLICATION_EXECUTE",
|
||||
{"node_id": 1, "application_id": 0},
|
||||
"node_application_execute",
|
||||
{"node_name": "server_1", "application_name": "C2Beacon"},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
@@ -103,14 +101,12 @@ def test_c2_server_ransomware(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyA
|
||||
# C2 Action 1: Installing the RansomwareScript & Database client via Terminal
|
||||
|
||||
action = (
|
||||
"C2_SERVER_TERMINAL_COMMAND",
|
||||
"c2_server_terminal_command",
|
||||
{
|
||||
"node_id": 0,
|
||||
"node_name": "client_1",
|
||||
"ip_address": None,
|
||||
"account": {
|
||||
"username": "admin",
|
||||
"password": "admin",
|
||||
},
|
||||
"username": "admin",
|
||||
"password": "admin",
|
||||
"commands": [
|
||||
["software_manager", "application", "install", "RansomwareScript"],
|
||||
["software_manager", "application", "install", "DatabaseClient"],
|
||||
@@ -122,10 +118,11 @@ def test_c2_server_ransomware(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyA
|
||||
assert agent.history[-1].response.status == "success"
|
||||
|
||||
action = (
|
||||
"C2_SERVER_RANSOMWARE_CONFIGURE",
|
||||
"c2_server_ransomware_configure",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {"server_ip_address": "10.0.2.3", "payload": "ENCRYPT"},
|
||||
"node_name": "client_1",
|
||||
"server_ip_address": "10.0.2.3",
|
||||
"payload": "ENCRYPT",
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -134,16 +131,16 @@ def test_c2_server_ransomware(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyA
|
||||
|
||||
# Stepping a few timesteps to allow for the RansowmareScript to finish installing.
|
||||
|
||||
action = ("DONOTHING", {})
|
||||
action = ("do_nothing", {})
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
game.step()
|
||||
game.step()
|
||||
|
||||
action = (
|
||||
"C2_SERVER_RANSOMWARE_LAUNCH",
|
||||
"c2_server_ransomware_launch",
|
||||
{
|
||||
"node_id": 0,
|
||||
"node_name": "client_1",
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -181,17 +178,15 @@ def test_c2_server_data_exfiltration(game_and_agent_fixture: Tuple[PrimaiteGame,
|
||||
# C2 Action: Data exfiltrate.
|
||||
|
||||
action = (
|
||||
"C2_SERVER_DATA_EXFILTRATE",
|
||||
"c2_server_data_exfiltrate",
|
||||
{
|
||||
"node_id": 0,
|
||||
"node_name": "client_1",
|
||||
"target_file_name": "database.db",
|
||||
"target_folder_name": "database",
|
||||
"exfiltration_folder_name": "spoils",
|
||||
"target_ip_address": "10.0.2.3",
|
||||
"account": {
|
||||
"username": "admin",
|
||||
"password": "admin",
|
||||
},
|
||||
"username": "admin",
|
||||
"password": "admin",
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
|
||||
@@ -4,7 +4,7 @@ from ipaddress import IPv4Address
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from primaite.game.agent.actions import (
|
||||
from primaite.game.agent.actions.software import (
|
||||
ConfigureDatabaseClientAction,
|
||||
ConfigureDoSBotAction,
|
||||
ConfigureRansomwareScriptAction,
|
||||
@@ -27,7 +27,6 @@ class TestConfigureDatabaseAction:
|
||||
def test_configure_ip_password(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_DATABASE_CLIENT"] = ConfigureDatabaseClientAction(agent.action_manager)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
@@ -35,13 +34,11 @@ class TestConfigureDatabaseAction:
|
||||
db_client: DatabaseClient = client_1.software_manager.software["DatabaseClient"]
|
||||
|
||||
action = (
|
||||
"CONFIGURE_DATABASE_CLIENT",
|
||||
"configure_database_client",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {
|
||||
"server_ip_address": "192.168.1.99",
|
||||
"server_password": "admin123",
|
||||
},
|
||||
"node_name": "client_1",
|
||||
"server_ip_address": "192.168.1.99",
|
||||
"server_password": "admin123",
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -53,7 +50,6 @@ class TestConfigureDatabaseAction:
|
||||
def test_configure_ip(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_DATABASE_CLIENT"] = ConfigureDatabaseClientAction(agent.action_manager)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
@@ -61,12 +57,10 @@ class TestConfigureDatabaseAction:
|
||||
db_client: DatabaseClient = client_1.software_manager.software["DatabaseClient"]
|
||||
|
||||
action = (
|
||||
"CONFIGURE_DATABASE_CLIENT",
|
||||
"configure_database_client",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {
|
||||
"server_ip_address": "192.168.1.99",
|
||||
},
|
||||
"node_name": "client_1",
|
||||
"server_ip_address": "192.168.1.99",
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -78,7 +72,6 @@ class TestConfigureDatabaseAction:
|
||||
def test_configure_password(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_DATABASE_CLIENT"] = ConfigureDatabaseClientAction(agent.action_manager)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
@@ -87,12 +80,10 @@ class TestConfigureDatabaseAction:
|
||||
old_ip = db_client.server_ip_address
|
||||
|
||||
action = (
|
||||
"CONFIGURE_DATABASE_CLIENT",
|
||||
"configure_database_client",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {
|
||||
"server_password": "admin123",
|
||||
},
|
||||
"node_name": "client_1",
|
||||
"server_password": "admin123",
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -120,9 +111,6 @@ class TestConfigureRansomwareScriptAction:
|
||||
def test_configure_ip_password(self, game_and_agent, config):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_RANSOMWARE_SCRIPT"] = ConfigureRansomwareScriptAction(
|
||||
agent.action_manager
|
||||
)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
@@ -134,8 +122,8 @@ class TestConfigureRansomwareScriptAction:
|
||||
old_payload = ransomware_script.payload
|
||||
|
||||
action = (
|
||||
"CONFIGURE_RANSOMWARE_SCRIPT",
|
||||
{"node_id": 0, "config": config},
|
||||
"configure_ransomware_script",
|
||||
{"node_name": "client_1", **config},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
@@ -151,18 +139,15 @@ class TestConfigureRansomwareScriptAction:
|
||||
def test_invalid_config(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_RANSOMWARE_SCRIPT"] = ConfigureRansomwareScriptAction(
|
||||
agent.action_manager
|
||||
)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
client_1.software_manager.install(RansomwareScript)
|
||||
ransomware_script: RansomwareScript = client_1.software_manager.software["RansomwareScript"]
|
||||
action = (
|
||||
"CONFIGURE_RANSOMWARE_SCRIPT",
|
||||
"configure_ransomware_script",
|
||||
{
|
||||
"node_id": 0,
|
||||
"node_name": "client_1",
|
||||
"config": {"server_password": "admin123", "bad_option": 70},
|
||||
},
|
||||
)
|
||||
@@ -172,28 +157,25 @@ class TestConfigureRansomwareScriptAction:
|
||||
|
||||
|
||||
class TestConfigureDoSBot:
|
||||
def test_configure_DoSBot(self, game_and_agent):
|
||||
def test_configure_dos_bot(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_DOSBOT"] = ConfigureDoSBotAction(agent.action_manager)
|
||||
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
client_1.software_manager.install(DoSBot)
|
||||
dos_bot: DoSBot = client_1.software_manager.software["DoSBot"]
|
||||
|
||||
action = (
|
||||
"CONFIGURE_DOSBOT",
|
||||
"configure_dos_bot",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {
|
||||
"target_ip_address": "192.168.1.99",
|
||||
"target_port": "POSTGRES_SERVER",
|
||||
"payload": "HACC",
|
||||
"repeat": False,
|
||||
"port_scan_p_of_success": 0.875,
|
||||
"dos_intensity": 0.75,
|
||||
"max_sessions": 50,
|
||||
},
|
||||
"node_name": "client_1",
|
||||
"target_ip_address": "192.168.1.99",
|
||||
"target_port": "POSTGRES_SERVER",
|
||||
"payload": "HACC",
|
||||
"repeat": False,
|
||||
"port_scan_p_of_success": 0.875,
|
||||
"dos_intensity": 0.75,
|
||||
"max_sessions": 50,
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -239,7 +221,7 @@ class TestConfigureYAML:
|
||||
assert db_client.server_password == "correct_password"
|
||||
assert db_client.connect()
|
||||
|
||||
def test_configure_ransomware_script(self):
|
||||
def test_c2_server_ransomware_configure(self):
|
||||
env = PrimaiteGymEnv(env_config=APP_CONFIG_YAML)
|
||||
client_2 = env.game.simulation.network.get_node_by_hostname("client_2")
|
||||
assert client_2.software_manager.software.get("RansomwareScript") is None
|
||||
|
||||
@@ -33,8 +33,8 @@ def test_create_file(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAgent]):
|
||||
assert client_1.file_system.get_file(folder_name=random_folder, file_name=random_file) is None
|
||||
|
||||
action = (
|
||||
"NODE_FILE_CREATE",
|
||||
{"node_id": 0, "folder_name": random_folder, "file_name": random_file},
|
||||
"node_file_create",
|
||||
{"node_name": "client_1", "folder_name": random_folder, "file_name": random_file},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
@@ -51,8 +51,8 @@ def test_file_delete_action(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAge
|
||||
assert file.deleted is False
|
||||
|
||||
action = (
|
||||
"NODE_FILE_DELETE",
|
||||
{"node_id": 0, "folder_id": 0, "file_id": 0},
|
||||
"node_file_delete",
|
||||
{"node_name": "client_1", "folder_name": "downloads", "file_name": "cat.png"},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
@@ -72,8 +72,8 @@ def test_file_scan_action(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAgent
|
||||
assert file.visible_health_status == FileSystemItemHealthStatus.GOOD
|
||||
|
||||
action = (
|
||||
"NODE_FILE_SCAN",
|
||||
{"node_id": 0, "folder_id": 0, "file_id": 0},
|
||||
"node_file_scan",
|
||||
{"node_name": "client_1", "folder_name": "downloads", "file_name": "cat.png"},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
@@ -93,8 +93,8 @@ def test_file_repair_action(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAge
|
||||
assert file.health_status == FileSystemItemHealthStatus.CORRUPT
|
||||
|
||||
action = (
|
||||
"NODE_FILE_REPAIR",
|
||||
{"node_id": 0, "folder_id": 0, "file_id": 0},
|
||||
"node_file_repair",
|
||||
{"node_name": "client_1", "folder_name": "downloads", "file_name": "cat.png"},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
@@ -113,8 +113,8 @@ def test_file_restore_action(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAg
|
||||
assert file.health_status == FileSystemItemHealthStatus.CORRUPT
|
||||
|
||||
action = (
|
||||
"NODE_FILE_RESTORE",
|
||||
{"node_id": 0, "folder_id": 0, "file_id": 0},
|
||||
"node_file_restore",
|
||||
{"node_name": "client_1", "folder_name": "downloads", "file_name": "cat.png"},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
@@ -132,8 +132,8 @@ def test_file_corrupt_action(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAg
|
||||
assert file.health_status == FileSystemItemHealthStatus.GOOD
|
||||
|
||||
action = (
|
||||
"NODE_FILE_CORRUPT",
|
||||
{"node_id": 0, "folder_id": 0, "file_id": 0},
|
||||
"node_file_corrupt",
|
||||
{"node_name": "client_1", "folder_name": "downloads", "file_name": "cat.png"},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
@@ -150,8 +150,8 @@ def test_file_access_action(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAge
|
||||
assert file.num_access == 0
|
||||
|
||||
action = (
|
||||
"NODE_FILE_ACCESS",
|
||||
{"node_id": 0, "folder_name": file.folder_name, "file_name": file.name},
|
||||
"node_file_access",
|
||||
{"node_name": "client_1", "folder_name": file.folder_name, "file_name": file.name},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
|
||||
@@ -32,9 +32,9 @@ def test_create_folder(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAgent]):
|
||||
assert client_1.file_system.get_folder(folder_name=random_folder) is None
|
||||
|
||||
action = (
|
||||
"NODE_FOLDER_CREATE",
|
||||
"node_folder_create",
|
||||
{
|
||||
"node_id": 0,
|
||||
"node_name": "client_1",
|
||||
"folder_name": random_folder,
|
||||
},
|
||||
)
|
||||
@@ -60,10 +60,10 @@ def test_folder_scan_action(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyAge
|
||||
assert folder.visible_health_status == FileSystemItemHealthStatus.GOOD
|
||||
|
||||
action = (
|
||||
"NODE_FOLDER_SCAN",
|
||||
"node_folder_scan",
|
||||
{
|
||||
"node_id": 0, # client_1,
|
||||
"folder_id": 0, # downloads
|
||||
"node_name": "client_1", # client_1,
|
||||
"folder_name": "downloads", # downloads
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -87,10 +87,10 @@ def test_folder_repair_action(game_and_agent_fixture: Tuple[PrimaiteGame, ProxyA
|
||||
assert folder.health_status == FileSystemItemHealthStatus.CORRUPT
|
||||
|
||||
action = (
|
||||
"NODE_FOLDER_REPAIR",
|
||||
"node_folder_repair",
|
||||
{
|
||||
"node_id": 0, # client_1,
|
||||
"folder_id": 0, # downloads
|
||||
"node_name": "client_1", # client_1,
|
||||
"folder_name": "downloads", # downloads
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -111,10 +111,10 @@ def test_folder_restore_action(game_and_agent_fixture: Tuple[PrimaiteGame, Proxy
|
||||
assert folder.health_status == FileSystemItemHealthStatus.CORRUPT
|
||||
|
||||
action = (
|
||||
"NODE_FOLDER_RESTORE",
|
||||
"node_folder_restore",
|
||||
{
|
||||
"node_id": 0, # client_1,
|
||||
"folder_id": 0, # downloads
|
||||
"node_name": "client_1", # client_1,
|
||||
"folder_name": "downloads", # downloads
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
|
||||
@@ -29,10 +29,10 @@ def test_nic_cannot_be_turned_off_if_not_on(game_and_agent_fixture: Tuple[Primai
|
||||
assert nic.enabled is False
|
||||
|
||||
action = (
|
||||
"HOST_NIC_DISABLE",
|
||||
"host_nic_disable",
|
||||
{
|
||||
"node_id": 0, # client_1
|
||||
"nic_id": 0, # the only nic (eth-1)
|
||||
"node_name": "client_1", # client_1
|
||||
"nic_num": 1, # the only nic (eth-1)
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -50,10 +50,10 @@ def test_nic_cannot_be_turned_on_if_already_on(game_and_agent_fixture: Tuple[Pri
|
||||
assert nic.enabled
|
||||
|
||||
action = (
|
||||
"HOST_NIC_ENABLE",
|
||||
"host_nic_enable",
|
||||
{
|
||||
"node_id": 0, # client_1
|
||||
"nic_id": 0, # the only nic (eth-1)
|
||||
"node_name": "client_1", # client_1
|
||||
"nic_num": 1, # the only nic (eth-1)
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -71,10 +71,10 @@ def test_that_a_nic_can_be_enabled_and_disabled(game_and_agent_fixture: Tuple[Pr
|
||||
assert nic.enabled
|
||||
|
||||
action = (
|
||||
"HOST_NIC_DISABLE",
|
||||
"host_nic_disable",
|
||||
{
|
||||
"node_id": 0, # client_1
|
||||
"nic_id": 0, # the only nic (eth-1)
|
||||
"node_name": "client_1", # client_1
|
||||
"nic_num": 1, # the only nic (eth-1)
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
@@ -83,10 +83,10 @@ def test_that_a_nic_can_be_enabled_and_disabled(game_and_agent_fixture: Tuple[Pr
|
||||
assert nic.enabled is False
|
||||
|
||||
action = (
|
||||
"HOST_NIC_ENABLE",
|
||||
"host_nic_enable",
|
||||
{
|
||||
"node_id": 0, # client_1
|
||||
"nic_id": 0, # the only nic (eth-1)
|
||||
"node_name": "client_1", # client_1
|
||||
"nic_num": 1, # the only nic (eth-1)
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user