Merged PR 630: Documentation changes.
Update docs Related work items: #3110, #3111
This commit is contained in:
4
.github/workflows/build-sphinx.yml
vendored
4
.github/workflows/build-sphinx.yml
vendored
@@ -1,8 +1,8 @@
|
||||
name: build-sphinx-to-github-pages
|
||||
|
||||
env:
|
||||
GITHUB_ACTOR: {todo:fill in URL}
|
||||
GITHUB_REPOSITORY: {todo:fill in URL}/PrimAITE
|
||||
GITHUB_ACTOR: Autonomous-Resilient-Cyber-Defence
|
||||
GITHUB_REPOSITORY: Autonomous-Resilient-Cyber-Defence/PrimAITE
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN}}
|
||||
|
||||
on:
|
||||
|
||||
@@ -39,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Updated tests that don't use YAMLs to still use the new action and agent schemas
|
||||
- Nodes now use a config schema and are extensible, allowing for plugin support.
|
||||
- Node tests have been updated to use the new node config schemas when not using YAML files.
|
||||
- Documentation has been updated to include details of extensability with PrimAITE.
|
||||
- Documentation has been updated to include details of extensibility with PrimAITE.
|
||||
- Software is created in the GOOD health state instead of UNUSED.
|
||||
- Standardised naming convention for YAML config files using kebab-case.
|
||||
This naming convention is used for configuring software, observations, actions and node types.
|
||||
|
||||
@@ -4,17 +4,17 @@
|
||||
### **Did you find a bug?**
|
||||
|
||||
|
||||
* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/{todo:fill in URL}/PrimAITE/issues).
|
||||
* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/{todo:fill in URL}/PrimAITE/issues/new?assignees=&labels=bug&projects=&template=bug_report.md&title=%5BBUG%5D+-+%3Cbug+title+goes+here%3E). Be sure to follow our bug report template with the headers **Describe the bug**, **To Reproduce**, **Expected behaviour**, **Screenshots/Outputs**, **Environment**, and **Additional context**
|
||||
* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE/issues).
|
||||
* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE/issues/new?assignees=&labels=bug&projects=&template=bug_report.md&title=%5BBUG%5D+-+%3Cbug+title+goes+here%3E). Be sure to follow our bug report template with the headers **Describe the bug**, **To Reproduce**, **Expected behaviour**, **Screenshots/Outputs**, **Environment**, and **Additional context**
|
||||
|
||||
|
||||
### **Do you have a solution to fix the bug?**
|
||||
|
||||
* [Fork the repository](https://github.com/{todo:fill in URL}/PrimAITE/fork).
|
||||
* [Fork the repository](https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE/fork).
|
||||
* Install the pre-commit hook with `pre-commit install`.
|
||||
* Implement the bug fix.
|
||||
* Commit the bug fix to the dev branch on your fork. If the bug has an open issue under [Issues](https://github.com/{todo:fill in URL}/PrimAITE/issues), reference the issue in the commit message (e.g. #1 references issue 1).
|
||||
* Submit a pull request from your dev branch to the {todo:fill in URL}/PrimAITE dev branch. Again, if the bug has an open issue under [Issues](https://github.com/{todo:fill in URL}/PrimAITE/issues), reference the issue in the pull request description.
|
||||
* Commit the bug fix to the dev branch on your fork. If the bug has an open issue under [Issues](https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE/issues), reference the issue in the commit message (e.g. #1 references issue 1).
|
||||
* Submit a pull request from your dev branch to the Autonomous-Resilient-Cyber-Defence/PrimAITE dev branch. Again, if the bug has an open issue under [Issues](https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE/issues), reference the issue in the pull request description.
|
||||
|
||||
### **Did you fix whitespace, format code, or make a purely cosmetic patch?**
|
||||
|
||||
@@ -22,7 +22,7 @@ Changes that are cosmetic in nature and do not add anything substantial to the s
|
||||
|
||||
### **Do you intend to add a new feature or change an existing one?**
|
||||
|
||||
* Submit a [feature request issue](https://github.com/{todo:fill in URL}/PrimAITE/issues/new?assignees=&labels=feature_request&projects=&template=feature_request.md&title=%5BREQUEST%5D+-+%3Crequest+title+goes+here%3E).
|
||||
* Submit a [feature request issue](https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE/issues/new?assignees=&labels=feature_request&projects=&template=feature_request.md&title=%5BREQUEST%5D+-+%3Crequest+title+goes+here%3E).
|
||||
* Know how to implement the new feature or change? Follow the same steps in the bug fix section above to fork, build, document, test, commit, and submit a pull request.
|
||||
|
||||
### **Do you have questions about the source code?**
|
||||
|
||||
13
LICENSE
13
LICENSE
@@ -4,24 +4,21 @@ MIT License Conditions
|
||||
|
||||
These MIT License conditions confirm the provision of the following artefacts as MIT License by Defence Science and Technology
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
request to the QQ or FNC mailbox):
|
||||
in the Software without restriction, including without limitation the rights
|
||||
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
- Use Case Release Packs
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
Suppliers are required to read and confirm acceptance of the {todo:fill in URL} Foundry SyOPs (https://github.com/{todo:fill in URL}/foundry-syops) before being admitted access to material hosted on the {todo:fill in URL} Foundry GitHub site.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
||||
The material is supplied in confidence to QQ / FNC and their subcontractors under SERAPIS, and is issued to inform only those
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
of DSTL. The material must be stored and protected appropriately. All material must be destroyed at the end of the task.
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ To make your own changes to PrimAITE, perform the install from source (developer
|
||||
|
||||
#### 1. Clone the PrimAITE repository
|
||||
``` unix
|
||||
git clone git@github.com:{todo:fill in URL}/PrimAITE.git
|
||||
git clone git@github.com:Autonomous-Resilient-Cyber-Defence/PrimAITE.git
|
||||
```
|
||||
|
||||
#### 2. CD into the repo directory
|
||||
|
||||
@@ -8,16 +8,18 @@ SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
AUTOSUMMARY="source/_autosummary"
|
||||
NOTEBOOKS="source/notebooks/notebooks"
|
||||
|
||||
# Remove command is different depending on OS
|
||||
ifdef OS
|
||||
RM = IF exist $(AUTOSUMMARY) ( RMDIR $(AUTOSUMMARY) /s /q )
|
||||
RM = IF exist $(AUTOSUMMARY) (RMDIR $(AUTOSUMMARY) /s /q) & IF exist $(NOTEBOOKS) (RMDIR $(NOTEBOOKS) /s /q)
|
||||
else
|
||||
ifeq ($(shell uname), Linux)
|
||||
RM = rm -rf $(AUTOSUMMARY)
|
||||
RM = rm -rf $(AUTOSUMMARY) $(NOTEBOOKS)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
17
docs/_templates/custom-class-template.rst
vendored
17
docs/_templates/custom-class-template.rst
vendored
@@ -12,7 +12,8 @@
|
||||
.. autoclass:: {{ objname }}
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
:inherited-members: BaseModel
|
||||
:exclude-members: model_computed_fields, model_config, model_fields
|
||||
:special-members: __init__, __call__, __add__, __mul__
|
||||
|
||||
{% block methods %}
|
||||
@@ -22,7 +23,14 @@
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
{% for item in methods %}
|
||||
{%- if not item.startswith('_') %}
|
||||
{%- if not item.startswith('_') and item not in [
|
||||
'construct', 'copy', 'dict', 'from_orm', 'json', 'model_construct',
|
||||
'model_copy', 'model_dump', 'model_dump_json', 'model_json_schema',
|
||||
'model_parametrized_name', 'model_post_init', 'model_rebuild', '',
|
||||
'model_validate', 'model_validate_json', 'model_validate_strings',
|
||||
'parse_file', 'parse_obj', 'parse_raw', 'schema', 'schema_json',
|
||||
'update_forward_refs', 'validate',
|
||||
] %}
|
||||
~{{ name }}.{{ item }}
|
||||
{%- endif -%}
|
||||
{%- endfor %}
|
||||
@@ -35,7 +43,12 @@
|
||||
|
||||
.. autosummary::
|
||||
{% for item in attributes %}
|
||||
{%- if not item.startswith('_') and item not in [
|
||||
'model_computed_fields', 'model_config', 'model_extra', 'model_fields',
|
||||
'model_fields_set',
|
||||
] %}
|
||||
~{{ name }}.{{ item }}
|
||||
{%- endif -%}
|
||||
{%- endfor %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -43,7 +43,7 @@ touch .nojekyll
|
||||
# Add README
|
||||
cat > README.md <<EOF
|
||||
# README for the Sphinx Docs GitHub Pages Branch
|
||||
This branch is simply a cache for the website served from https://{todo:fill in URL}.github.io/PrimAITE/,
|
||||
This branch is simply a cache for the website served from https://Autonomous-Resilient-Cyber-Defence.github.io/PrimAITE/,
|
||||
and is not intended to be viewed on github.com.
|
||||
For more information on how this site is built using Sphinx, Read the Docs, GitHub Actions/Pages, and demo
|
||||
implementation from https://github.com/annegentle, see:
|
||||
|
||||
@@ -32,6 +32,7 @@ What is PrimAITE?
|
||||
source/how_to_guides/extensible_agents
|
||||
source/how_to_guides/extensible_nodes
|
||||
source/how_to_guides/extensible_rewards
|
||||
source/how_to_guides/primaite_yaml_migration_guide
|
||||
|
||||
.. toctree::
|
||||
:caption: Usage:
|
||||
@@ -42,7 +43,6 @@ What is PrimAITE?
|
||||
source/simulation
|
||||
source/config
|
||||
source/rewards
|
||||
source/customising_scenarios
|
||||
source/varying_config_files
|
||||
source/environment
|
||||
source/action_masking
|
||||
|
||||
@@ -39,14 +39,15 @@ PrimAITE provides a training and evaluation capability to AI agents in the conte
|
||||
|
||||
Scenarios can be constructed to reflect network / system laydowns consisting of any configuration of nodes (e.g., PCs, servers etc.) and the networking equipment and links between them.
|
||||
|
||||
All nodes can be configured to contain applications, services, folders and files (and their status).
|
||||
All nodes can be configured to contain applications, services, folders, and files (and their status), including a powerful terminal simulation for SSH tunnelling and remote command execution.
|
||||
|
||||
Traffic flows between services and applications as directed by an ‘execution definition’, with the traffic flow on the network governed by the network equipment (switches, routers and firewalls) and the ACL rules and routing tables they employ.
|
||||
Realistic network traffic generated by software or by users. Packets move through the network devices (switches, routers, firewalls, network interfaces) in accordance to control rules such as: internet protocols, Access control lists (ACLs), and routing tables.
|
||||
|
||||
Highlights of PrimAITE’s training and evaluation capability are:
|
||||
Highlights of PrimAITE's training and evaluation capability are:
|
||||
|
||||
- The scenario is not bound to a representation of any platform, system, or technology;
|
||||
- Fully configurable (network / system laydown, green pattern-of-life, red personas, reward function, ACL rules for each device, number of episodes / steps, action / observation space) and repeatable to suit the requirements of AI agents;
|
||||
- Domain randomisation through stochastic agent behaviour and the ability to switch between scenario variants between environment episodes.
|
||||
- Extensible through plugins to model any network behaviour.
|
||||
- Can integrate with any Gymnasium / Ray RLlib compliant AI agent.
|
||||
|
||||
|
||||
@@ -56,303 +57,16 @@ What is PrimAITE built with
|
||||
---------------------------
|
||||
|
||||
* `Gymnasium <https://gymnasium.farama.org/>`_ is used as the basis for AI blue agent interaction with the PrimAITE environment
|
||||
* `Networkx <https://github.com/networkx/networkx>`_ is used as the underlying data structure used for the PrimAITE environment
|
||||
* `Stable Baselines 3 <https://github.com/DLR-RM/stable-baselines3>`_ is used as a default source of RL algorithms (although PrimAITE is not limited to SB3 agents)
|
||||
* `Ray RLlib <https://github.com/ray-project/ray>`_ is used as an additional source of RL algorithms
|
||||
* `Typer <https://github.com/tiangolo/typer>`_ is used for building CLIs (Command Line Interface applications)
|
||||
* `Pydantic <https://docs.pydantic.dev/latest/>`_ is used for data validation
|
||||
* `Platformdirs <https://github.com/platformdirs/platformdirs>`_ is used for storing user data and configuration correctly between platforms
|
||||
* `Typer <https://github.com/tiangolo/typer>`_ is used for the Command Line Interface
|
||||
* `Jupyterlab <https://github.com/jupyterlab/jupyterlab>`_ is used as an extensible environment for interactive and reproducible computing, based on the Jupyter Notebook Architecture
|
||||
* `Platformdirs <https://github.com/platformdirs/platformdirs>`_ is used for finding the right location to store user data and configuration but varies per platform
|
||||
* `Plotly <https://github.com/plotly/plotly.py>`_ is used for building high level charts
|
||||
* `Stable Baselines 3 <https://github.com/DLR-RM/stable-baselines3>`_ is used for ensuring compatibility with RL libraries
|
||||
* `Ray RLlib <https://github.com/ray-project/ray>`_ is also used for ensuring compatibility with RL libraries
|
||||
|
||||
|
||||
Getting Started with PrimAITE
|
||||
-----------------------------
|
||||
|
||||
Head over to the :ref:`getting-started` page to install and setup PrimAITE!
|
||||
|
||||
..
|
||||
Architecture - Nodes and Links
|
||||
******************************
|
||||
**Nodes**
|
||||
An inheritance model has been adopted in order to model nodes. All nodes have the following base attributes (Class: Node):
|
||||
* ID
|
||||
* Name
|
||||
* Type (e.g. computer, switch, RTU - enumeration)
|
||||
* Priority (P1, P2, P3, P4 or P5 - enumeration)
|
||||
* Hardware State (ON, OFF, RESETTING, SHUTTING_DOWN, BOOTING - enumeration)
|
||||
Active Nodes also have the following attributes (Class: Active Node):
|
||||
* IP Address
|
||||
* Software State (GOOD, FIXING, COMPROMISED - enumeration)
|
||||
* File System State (GOOD, CORRUPT, DESTROYED, REPAIRING, RESTORING - enumeration)
|
||||
Service Nodes also have the following attributes (Class: Service Node):
|
||||
* List of Services (where service is composed of service name and port). There is no theoretical limit on the number of services that can be modelled. Services and protocols are currently intrinsically linked (i.e. a service is an application on a node transmitting traffic of this protocol type)
|
||||
* Service state (GOOD, FIXING, COMPROMISED, OVERWHELMED - enumeration)
|
||||
Passive Nodes are currently not used (but may be employed for non IP-based components such as machinery actuators in future releases).
|
||||
**Links**
|
||||
Links are modelled both as network edges (networkx) and as Python classes, in order to extend their functionality. Links include the following attributes:
|
||||
* ID
|
||||
* Name
|
||||
* Bandwidth (bits/s)
|
||||
* Source node ID
|
||||
* Destination node ID
|
||||
* Protocol list (containing the loading of protocols currently running on the link)
|
||||
When the simulation runs, IERs are applied to the links in order to model traffic loading, individually assigned to each protocol. This allows green (background) and red agent behaviour to be modelled, and defensive agents to identify suspicious traffic patterns at a protocol / traffic loading level of fidelity.
|
||||
Information Exchange Requirements (IERs)
|
||||
****************************************
|
||||
PrimAITE adopts the concept of Information Exchange Requirements (IERs) to model both green agent (background) and red agent (adversary) behaviour. IERs are used to initiate modelling of traffic loading on the network, and have the following attributes:
|
||||
* ID
|
||||
* Start step (i.e. which step in the training episode should the IER start)
|
||||
* End step (i.e. which step in the training episode should the IER end)
|
||||
* Source node ID
|
||||
* Destination node ID
|
||||
* Load (bits/s)
|
||||
* Protocol
|
||||
* Port
|
||||
* Running status (i.e. on / off)
|
||||
The application of green agent IERs between a source and destination follows a number of rules. Specifically:
|
||||
1. Does the current simulation time step fall between IER start and end step
|
||||
2. Is the source node operational (both physically and at an O/S level), and is the service (protocol / port) associated with the IER (a) present on this node, and (b) in an operational state (i.e. not FIXING)
|
||||
3. Is the destination node operational (both physically and at an O/S level), and is the service (protocol / port) associated with the IER (a) present on this node, and (b) in an operational state (i.e. not FIXING)
|
||||
4. Are there any Access Control List rules in place that prevent the application of this IER
|
||||
5. Are all switches in the (OSPF) path between source and destination operational (both physically and at an O/S level)
|
||||
For red agent IERs, the application of IERs between a source and destination follows a number of subtly different rules. Specifically:
|
||||
1. Does the current simulation time step fall between IER start and end step
|
||||
2. Is the source node operational, and is the service (protocol / port) associated with the IER (a) present on that node and (b) already in a compromised state
|
||||
3. Is the destination node operational, and is the service (protocol / port) associated with the IER present on that node
|
||||
4. Are there any Access Control List rules in place that prevent the application of this IER
|
||||
5. Are all switches in the (OSPF) path between source and destination operational (both physically and at an O/S level)
|
||||
Assuming the rules pass, the IER is applied to all relevant links (based on use of OSPF) between source and destination.
|
||||
Node Pattern-of-Life
|
||||
********************
|
||||
Every node can be impacted (i.e. have a status change applied to it) by either green agent pattern-of-life or red agent pattern-of-life. This is distinct from IERs, and allows for attacks (and defence) to be modelled purely within the confines of a node.
|
||||
The status changes that can be made to a node are as follows:
|
||||
* All Nodes:
|
||||
* Hardware State:
|
||||
* ON
|
||||
* OFF
|
||||
* RESETTING - when a status of resetting is entered, the node will automatically exit this state after a number of steps (as defined by the nodeResetDuration configuration item) after which it returns to an ON state
|
||||
* BOOTING
|
||||
* SHUTTING_DOWN
|
||||
* Active Nodes and Service Nodes:
|
||||
* Software State:
|
||||
* GOOD
|
||||
* FIXING - when a status of FIXING is entered, the node will automatically exit this state after a number of steps (as defined by the osFIXINGDuration configuration item) after which it returns to a GOOD state
|
||||
* COMPROMISED
|
||||
* File System State:
|
||||
* GOOD
|
||||
* CORRUPT (can be resolved by repair or restore)
|
||||
* DESTROYED (can be resolved by restore only)
|
||||
* REPAIRING - when a status of repairing is entered, the node will automatically exit this state after a number of steps (as defined by the fileSystemRepairingLimit configuration item) after which it returns to a GOOD state
|
||||
* RESTORING - when a status of repairing is entered, the node will automatically exit this state after a number of steps (as defined by the fileSystemRestoringLimit configuration item) after which it returns to a GOOD state
|
||||
* Service Nodes only:
|
||||
* Service State (for any associated service):
|
||||
* GOOD
|
||||
* FIXING - when a status of FIXING is entered, the service will automatically exit this state after a number of steps (as defined by the serviceFIXINGDuration configuration item) after which it returns to a GOOD state
|
||||
* COMPROMISED
|
||||
* OVERWHELMED
|
||||
Red agent pattern-of-life has an additional feature not found in the green pattern-of-life. This is the ability to influence the state of the attributes of a node via a number of different conditions:
|
||||
* DIRECT:
|
||||
The pattern-of-life described by the configuration file item will be applied regardless of any other conditions in the network. This is particularly useful for direct red agent entry into the network.
|
||||
* IER:
|
||||
The pattern-of-life described by the configuration file item will be applied to the service on the node, only if there is an IER of the same protocol / service type incoming at the specified timestep.
|
||||
* SERVICE:
|
||||
The pattern-of-life described by the configuration file item will be applied to the node based on the state of a service. The service can either be on the same node, or a different node within the network.
|
||||
Access Control List modelling
|
||||
*****************************
|
||||
An Access Control List (ACL) is modelled to provide the means to manage traffic flows in the system. This will allow defensive agents the means to turn on / off rules, or potentially create new rules, to counter an attack.
|
||||
The ACL follows a standard network firewall format. For example:
|
||||
.. list-table:: ACL example
|
||||
:widths: 25 25 25 25 25
|
||||
:header-rows: 1
|
||||
* - Permission
|
||||
- Source IP
|
||||
- Dest IP
|
||||
- Protocol
|
||||
- Port
|
||||
* - DENY
|
||||
- 192.168.1.2
|
||||
- 192.168.1.3
|
||||
- HTTPS
|
||||
- 443
|
||||
* - ALLOW
|
||||
- 192.168.1.4
|
||||
- ANY
|
||||
- SMTP
|
||||
- 25
|
||||
* - DENY
|
||||
- ANY
|
||||
- 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 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.
|
||||
PrimAITE builds on top of Gymnasium Spaces to create an observation space that is easily configurable for users. It's made up of components which are managed by the :py:class:`primaite.environment.observations.ObservationsHandler`. Each training scenario can define its own observation space, and the user can choose which information to inlude, and how it should be formatted.
|
||||
NodeLinkTable component
|
||||
-----------------------
|
||||
For example, the :py:class:`primaite.environment.observations.NodeLinkTable` component represents the status of nodes and links as a ``gym.spaces.Box`` with an example format shown below:
|
||||
An example observation space is provided below:
|
||||
.. list-table:: Observation Space example
|
||||
:widths: 25 25 25 25 25 25 25
|
||||
:header-rows: 1
|
||||
* -
|
||||
- ID
|
||||
- Hardware State
|
||||
- Software State
|
||||
- File System State
|
||||
- Service / Protocol A
|
||||
- Service / Protocol B
|
||||
* - Node A
|
||||
- 1
|
||||
- 1
|
||||
- 1
|
||||
- 1
|
||||
- 1
|
||||
- 1
|
||||
* - Node B
|
||||
- 2
|
||||
- 1
|
||||
- 3
|
||||
- 1
|
||||
- 1
|
||||
- 1
|
||||
* - Node C
|
||||
- 3
|
||||
- 2
|
||||
- 1
|
||||
- 1
|
||||
- 3
|
||||
- 2
|
||||
* - Link 1
|
||||
- 5
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 10000
|
||||
* - Link 2
|
||||
- 6
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 10000
|
||||
* - Link 3
|
||||
- 7
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 5000
|
||||
- 0
|
||||
For the nodes, the following values are represented:
|
||||
.. code-block::
|
||||
[
|
||||
ID
|
||||
Hardware State (1=ON, 2=OFF, 3=RESETTING, 4=SHUTTING_DOWN, 5=BOOTING)
|
||||
Operating System State (0=none, 1=GOOD, 2=PATCHING, 3=COMPROMISED)
|
||||
File System State (0=none, 1=GOOD, 2=CORRUPT, 3=DESTROYED, 4=REPAIRING, 5=RESTORING)
|
||||
Service1/Protocol1 state (0=none, 1=GOOD, 2=FIXING, 3=COMPROMISED)
|
||||
Service2/Protocol2 state (0=none, 1=GOOD, 2=FIXING, 3=COMPROMISED)
|
||||
]
|
||||
(Note that each service available in the network is provided as a column, although not all nodes may utilise all services)
|
||||
For the links, the following statuses are represented:
|
||||
.. code-block::
|
||||
[
|
||||
ID
|
||||
Hardware State (0=not applicable)
|
||||
Operating System State (0=not applicable)
|
||||
File System State (0=not applicable)
|
||||
Service1/Protocol1 state (Traffic load from this protocol on this link)
|
||||
Service2/Protocol2 state (Traffic load from this protocol on this link)
|
||||
]
|
||||
NodeStatus component
|
||||
----------------------
|
||||
This is a MultiDiscrete observation space that can be though of as a one-dimensional vector of discrete states.
|
||||
The example above would have the following structure:
|
||||
.. code-block::
|
||||
[
|
||||
node1_info
|
||||
node2_info
|
||||
node3_info
|
||||
]
|
||||
Each ``node_info`` contains the following:
|
||||
.. code-block::
|
||||
[
|
||||
hardware_state (0=none, 1=ON, 2=OFF, 3=RESETTING, 4=SHUTTING_DOWN, 5=BOOTING)
|
||||
software_state (0=none, 1=GOOD, 2=PATCHING, 3=COMPROMISED)
|
||||
file_system_state (0=none, 1=GOOD, 2=CORRUPT, 3=DESTROYED, 4=REPAIRING, 5=RESTORING)
|
||||
service1_state (0=none, 1=GOOD, 2=FIXING, 3=COMPROMISED)
|
||||
service2_state (0=none, 1=GOOD, 2=FIXING, 3=COMPROMISED)
|
||||
]
|
||||
In a network with three nodes and two services, the full observation space would have 15 elements. It can be written with ``gym`` notation to indicate the number of discrete options for each of the elements of the observation space. For example:
|
||||
.. code-block::
|
||||
gym.spaces.MultiDiscrete([4,5,6,4,4,4,5,6,4,4,4,5,6,4,4])
|
||||
.. note::
|
||||
NodeStatus observation component provides information only about nodes. Links are not considered.
|
||||
LinkTrafficLevels
|
||||
-----------------
|
||||
This component is a MultiDiscrete space showing the traffic flow levels on the links in the network, after applying a threshold to convert it from a continuous to a discrete value.
|
||||
There are two configurable parameters:
|
||||
* ``quantisation_levels`` determines how many discrete bins to use for converting the continuous traffic value to discrete (default is 5).
|
||||
* ``combine_service_traffic`` determines whether to separately output traffic use for each network protocol or whether to combine them into an overall value for the link. (default is ``True``)
|
||||
For example, with default parameters and a network with three links, the structure of this component would be:
|
||||
.. code-block::
|
||||
[
|
||||
link1_status
|
||||
link2_status
|
||||
link3_status
|
||||
]
|
||||
Each ``link_status`` is a number from 0-4 representing the network load in relation to bandwidth.
|
||||
.. code-block::
|
||||
0 = No traffic (0%)
|
||||
1 = low traffic (1%-33%)
|
||||
2 = medium traffic (33%-66%)
|
||||
3 = high traffic (66%-99%)
|
||||
4 = max traffic/ overwhelmed (100%)
|
||||
Using ``gym`` notation, the shape of the obs space is: ``gym.spaces.MultiDiscrete([5,5,5])``.
|
||||
Action Spaces
|
||||
**************
|
||||
The action space available to the blue agent comes in two types:
|
||||
1. Node-based
|
||||
2. Access Control List
|
||||
3. Any (Agent can take both node-based and ACL-based actions)
|
||||
The choice of action space used during a training session is determined in the config_[name].yaml file.
|
||||
**Node-Based**
|
||||
The agent is able to influence the status of nodes by switching them off, resetting, or FIXING operating systems and services. In this instance, the action space is a Gymnasium spaces.Discrete type, as follows:
|
||||
* Dictionary item {... ,1: [x1, x2, x3,x4] ...}
|
||||
The placeholders inside the list under the key '1' mean the following:
|
||||
* [0, num nodes] - Node ID (0 = nothing, node ID)
|
||||
* [0, 4] - What property it's acting on (0 = nothing, 1 = state, 2 = SoftwareState, 3 = service state, 4 = file system state)
|
||||
* [0, 3] - Action on property (0 = nothing, 1 = on / scan, 2 = off / repair, 3 = reset / patch / restore)
|
||||
* [0, num services] - Resolves to service ID (0 = nothing, resolves to service)
|
||||
**Access Control List**
|
||||
The blue agent is able to influence the configuration of the Access Control List rule set (which implements a system-wide firewall). In this instance, the action space is an Gymnasium spaces.Discrete type, as follows:
|
||||
* 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 = 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)
|
||||
* [0, num ports] - Port (0 = any, then 1 -> x resolving to port)
|
||||
**ANY**
|
||||
The agent is able to carry out both **Node-Based** and **Access Control List** operations.
|
||||
This means the dictionary will contain key-value pairs in the format of BOTH Node-Based and Access Control List as seen above.
|
||||
Rewards
|
||||
*******
|
||||
A reward value is presented back to the blue agent on the conclusion of every step. The reward value is calculated via two methods which combine to give the total value:
|
||||
1. Node and service status
|
||||
2. IER status
|
||||
**Node and service status**
|
||||
On every step, the status of each node is compared against both a reference environment (simulating the situation if the red and blue agents had not impacted the environment)
|
||||
and the before and after state of the environment. If the comparison against the reference environment shows no difference, then the score provided is "AllOK". If there is a
|
||||
difference with respect to the reference environment, the before and after states are compared, and a score determined. See :ref:`config` for details of reward values.
|
||||
**IER status**
|
||||
On every step, the full IER set is examined to determine whether green and red agent IERs are being permitted to run. Any red agent IERs running incur a penalty; any green agent
|
||||
IERs not permitted to run also incur a penalty. See :ref:`config` for details of reward values.
|
||||
Future Enhancements
|
||||
*******************
|
||||
The PrimAITE project has an ambition to include the following enhancements in future releases:
|
||||
* Integration with a suitable standardised framework to allow multi-agent integration
|
||||
* Integration with external threat emulation tools, either using off-line data, or integrating at runtime
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _action_masking:
|
||||
|
||||
Action Masking
|
||||
**************
|
||||
The PrimAITE simulation is able to provide action masks in the environment output. These action masks let the agents know
|
||||
about which actions are invalid based on the current environment state. For instance, it's not possible to install
|
||||
software on a node that is turned off. Therefore, if an agent has a NODE_SOFTWARE_INSTALL in it's action map for that node,
|
||||
software on a node that is turned off. Therefore, if an agent has a ``node-software-install`` in it's action map for that node,
|
||||
the action mask will show `0` in the corresponding entry.
|
||||
|
||||
*Note: just because an action is available in the action mask does not mean it will be successful when executed. It just means it's possible to try to execute the action at this time.*
|
||||
@@ -20,132 +22,127 @@ Masking Logic
|
||||
=============
|
||||
The following logic is applied:
|
||||
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| Action | Action Mask Logic |
|
||||
+==========================================+=====================================================================+
|
||||
| **do-nothing** | Always Possible. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-service-scan** | 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-pause** | Node is on. Service is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-service-resume** | Node is on. Service is paused. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-service-restart** | Node is on. Service is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-service-disable** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-service-enable** | Node is on. Service is disabled. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-service-fix** | Node is on. Service is running. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-application-execute** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-application-scan** | 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-install** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-application-remove** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-file-scan** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-file-create** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-file-checkhash** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-file-delete** | Node is on. File exists. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-file-repair** | Node is on. File exists. File not 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-access** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-folder-create** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-folder-scan** | 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-restore** | Node is on. Folder exists. Folder is deleted. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-os-scan** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **host-nic-enable** | NIC is disabled. Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **host-nic-disable** | NIC is enabled. Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-shutdown** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-startup** | Node is off. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-reset** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-nmap-ping-scan** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-nmap-port-scan** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-network-service-recon** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **network-port-enable** | Node is on. Router is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **network-port-disable** | Router is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **router-acl-add-rule** | Router is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **router-acl-remove-rule** | Router is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **firewall-acl-add-rule** | Firewall is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **firewall-acl-remove-rule** | Firewall is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **configure-database-client** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **configure-ransomware-script** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **c2-server-ransomware-configure** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **configure-dos-bot** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **configure-c2-beacon** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **c2-server-ransomware-launch** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **c2-server-terminal-command** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **c2-server-data-exfiltrate** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-account-change-password** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-session-remote-login** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-session-remote-logoff** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
| **node-send-remote-command** | Node is on. |
|
||||
+------------------------------------------+---------------------------------------------------------------------+
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| Action | Action Mask Logic |
|
||||
+==========================================+================================================+
|
||||
| **do-nothing** | Always Possible. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-service-scan** | 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-pause** | Node is on. Service is running. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-service-resume** | Node is on. Service is paused. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-service-restart** | Node is on. Service is running. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-service-disable** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-service-enable** | Node is on. Service is disabled. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-service-fix** | Node is on. Service is running. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-application-execute** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-application-scan** | 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-install** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-application-remove** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-file-scan** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-file-create** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-file-checkhash** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-file-delete** | Node is on. File exists. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-file-repair** | Node is on. File exists. File not 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-access** | Node is on. File exists. File not deleted. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-folder-create** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-folder-scan** | 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-restore** | Node is on. Folder exists. Folder is deleted. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-os-scan** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **host-nic-enable** | NIC is disabled. Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **host-nic-disable** | NIC is enabled. Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-shutdown** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-startup** | Node is off. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-reset** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-nmap-ping-scan** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-nmap-port-scan** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-network-service-recon** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **network-port-enable** | Node is on. Router is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **network-port-disable** | Router is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **router-acl-add-rule** | Router is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **router-acl-remove-rule** | Router is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **firewall-acl-add-rule** | Firewall is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **firewall-acl-remove-rule** | Firewall is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **configure-database-client** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **configure-ransomware-script** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **c2-server-ransomware-configure** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **configure-dos-bot** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **configure-c2-beacon** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **c2-server-ransomware-launch** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **c2-server-terminal-command** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **c2-server-data-exfiltrate** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-account-change-password** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-session-remote-login** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-session-remote-logoff** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
| **node-send-remote-command** | Node is on. |
|
||||
+------------------------------------------+------------------------------------------------+
|
||||
|
||||
|
||||
Mechanism
|
||||
=========
|
||||
The environment iterates over the RL agent's ``action_map`` and generates the corresponding simulator request string.
|
||||
It uses the ``RequestManager.check_valid()`` method to invoke the relevant ``RequestPermissionValidator`` without
|
||||
actually running the request on the simulation.
|
||||
The environment iterates over the RL agent's ``action_map`` and generates the corresponding simulator :ref:`request <request_system>` string. It uses the :py:meth:`RequestManager.check_valid()<primaite.simulator.core.RequestManager.check_valid>` method to invoke the relevant :py:class:`RequestPermissionValidator <primaite.simulator.core.RequestPermissionValidator>` without actually running the request on the simulation.
|
||||
|
||||
Current Limitations
|
||||
===================
|
||||
Currently, action masking only considers whether the action as a whole is possible, it doesn't verify that the exact
|
||||
parameter combination passed to the action make sense in the current context. For instance, if ACL rule 3 on router_1 is
|
||||
already populated, the action for adding another rule at position 3 will be available regardless, as long as that router
|
||||
is turned on. This will never block valid actions. It will just occasionally allow invalid actions.
|
||||
Currently, action masking only considers whether the action as a whole is possible, it doesn't verify that the exact parameter combination passed to the action make sense in the current context. or instance, if ACL rule 3 on router_1 is already populated, the action for adding another rule at position 3 will be available regardless, as long as that router is turned on. This will never block valid actions. It will just occasionally allow invalid actions.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _Configurable_Items:
|
||||
|
||||
PrimAITE |VERSION| Configuration
|
||||
********************************
|
||||
|
||||
|
||||
@@ -13,20 +13,19 @@ Agents can be scripted (deterministic and stochastic), or controlled by a reinfo
|
||||
.. code-block:: yaml
|
||||
|
||||
agents:
|
||||
- ref: red_agent_example
|
||||
...
|
||||
- ref: blue_agent_example
|
||||
...
|
||||
- ref: green_agent_example
|
||||
team: GREEN
|
||||
type: probabilistic-agent
|
||||
- ref: red_agent_example
|
||||
...
|
||||
- ref: blue_agent_example
|
||||
...
|
||||
- ref: green_agent_example
|
||||
team: GREEN
|
||||
type: probabilistic-agent
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
flatten_obs: False
|
||||
agent_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
flatten_obs: False
|
||||
|
||||
``ref``
|
||||
-------
|
||||
|
||||
@@ -42,14 +42,14 @@ The maximum number of episodes a Reinforcement Learning agent(s) can be trained
|
||||
|
||||
A list of ports that the Reinforcement Learning agent(s) are able to see in the observation space.
|
||||
|
||||
See :ref:`List of Ports <List of Ports>` for a list of ports.
|
||||
See :py:const:`primaite.utils.validation.port.PORT_LOOKUP` for a list of ports.
|
||||
|
||||
``protocols``
|
||||
-------------
|
||||
|
||||
A list of protocols that the Reinforcement Learning agent(s) are able to see in the observation space.
|
||||
|
||||
See :ref:`List of IPProtocols <List of IPProtocols>` for a list of protocols.
|
||||
See :py:const:`primaite.utils.validation.ip_protocol.PROTOCOL_LOOKUP` for a list of protocols.
|
||||
|
||||
``thresholds``
|
||||
--------------
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _io_settings:
|
||||
|
||||
``io_settings``
|
||||
===============
|
||||
|
||||
@@ -17,19 +17,18 @@ example computer
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: client_1
|
||||
hostname: client_1
|
||||
type: computer
|
||||
ip_address: 192.168.0.10
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.0.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
...
|
||||
services:
|
||||
...
|
||||
network:
|
||||
nodes:
|
||||
- hostname: client_1
|
||||
type: computer
|
||||
ip_address: 192.168.0.10c
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.0.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
...
|
||||
services:
|
||||
...
|
||||
|
||||
.. include:: common/common_node_attributes.rst
|
||||
|
||||
|
||||
@@ -19,38 +19,35 @@ example firewall
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: firewall
|
||||
hostname: firewall
|
||||
type: firewall
|
||||
start_up_duration: 0
|
||||
shut_down_duration: 0
|
||||
ports:
|
||||
external_port: # port 1
|
||||
ip_address: 192.168.20.1
|
||||
subnet_mask: 255.255.255.0
|
||||
internal_port: # port 2
|
||||
ip_address: 192.168.1.2
|
||||
subnet_mask: 255.255.255.0
|
||||
dmz_port: # port 3
|
||||
ip_address: 192.168.10.1
|
||||
subnet_mask: 255.255.255.0
|
||||
acl:
|
||||
internal_inbound_acl:
|
||||
...
|
||||
internal_outbound_acl:
|
||||
...
|
||||
dmz_inbound_acl:
|
||||
...
|
||||
dmz_outbound_acl:
|
||||
...
|
||||
external_inbound_acl:
|
||||
...
|
||||
external_outbound_acl:
|
||||
...
|
||||
routes:
|
||||
...
|
||||
network:
|
||||
nodes:
|
||||
- hostname: firewall
|
||||
type: firewall
|
||||
ports:
|
||||
external_port: # port 1
|
||||
ip_address: 192.168.20.1
|
||||
subnet_mask: 255.255.255.0
|
||||
internal_port: # port 2
|
||||
ip_address: 192.168.1.2
|
||||
subnet_mask: 255.255.255.0
|
||||
dmz_port: # port 3
|
||||
ip_address: 192.168.10.1
|
||||
subnet_mask: 255.255.255.0
|
||||
acl:
|
||||
internal_inbound_acl:
|
||||
...
|
||||
internal_outbound_acl:
|
||||
...
|
||||
dmz_inbound_acl:
|
||||
...
|
||||
dmz_outbound_acl:
|
||||
...
|
||||
external_inbound_acl:
|
||||
...
|
||||
external_outbound_acl:
|
||||
...
|
||||
routes:
|
||||
...
|
||||
|
||||
.. include:: common/common_node_attributes.rst
|
||||
|
||||
@@ -70,18 +67,18 @@ The ports should be defined with an ip address and subnet mask e.g.
|
||||
.. code-block:: yaml
|
||||
|
||||
nodes:
|
||||
- ref: firewall
|
||||
...
|
||||
- hostname: firewall
|
||||
...
|
||||
ports:
|
||||
external_port: # port 1
|
||||
ip_address: 192.168.20.1
|
||||
subnet_mask: 255.255.255.0
|
||||
internal_port: # port 2
|
||||
ip_address: 192.168.1.2
|
||||
subnet_mask: 255.255.255.0
|
||||
dmz_port: # port 3
|
||||
ip_address: 192.168.10.1
|
||||
subnet_mask: 255.255.255.0
|
||||
external_port: # port 1
|
||||
ip_address: 192.168.20.1
|
||||
subnet_mask: 255.255.255.0
|
||||
internal_port: # port 2
|
||||
ip_address: 192.168.1.2
|
||||
subnet_mask: 255.255.255.0
|
||||
dmz_port: # port 3
|
||||
ip_address: 192.168.10.1
|
||||
subnet_mask: 255.255.255.0
|
||||
|
||||
``ip_address``
|
||||
""""""""""""""
|
||||
@@ -129,21 +126,21 @@ example:
|
||||
.. code-block:: yaml
|
||||
|
||||
nodes:
|
||||
- ref: firewall
|
||||
- hostname: firewall
|
||||
...
|
||||
acl:
|
||||
internal_inbound_acl:
|
||||
21: # position 21 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port
|
||||
dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
internal_inbound_acl:
|
||||
21: # position 21 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port
|
||||
dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
|
||||
``internal_outbound_acl``
|
||||
"""""""""""""""""""""""""
|
||||
@@ -155,21 +152,21 @@ example:
|
||||
.. code-block:: yaml
|
||||
|
||||
nodes:
|
||||
- ref: firewall
|
||||
...
|
||||
- hostname: firewall
|
||||
...
|
||||
acl:
|
||||
internal_outbound_acl:
|
||||
21: # position 21 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port
|
||||
dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
internal_outbound_acl:
|
||||
21: # position 21 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port
|
||||
dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
|
||||
|
||||
``dmz_inbound_acl``
|
||||
@@ -216,29 +213,29 @@ example:
|
||||
.. code-block:: yaml
|
||||
|
||||
nodes:
|
||||
- ref: firewall
|
||||
...
|
||||
acl:
|
||||
dmz_outbound_acl:
|
||||
19: # position 19 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port
|
||||
dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port
|
||||
20: # position 20 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: HTTP # are emitted from the HTTP port
|
||||
dst_port: HTTP # are going towards an HTTP port
|
||||
21: # position 21 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: HTTPS # are emitted from the HTTPS port
|
||||
dst_port: HTTPS # are going towards an HTTPS port
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
- hostname: firewall
|
||||
...
|
||||
acl:
|
||||
dmz_outbound_acl:
|
||||
19: # position 19 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port
|
||||
dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port
|
||||
20: # position 20 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: HTTP # are emitted from the HTTP port
|
||||
dst_port: HTTP # are going towards an HTTP port
|
||||
21: # position 21 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: HTTPS # are emitted from the HTTPS port
|
||||
dst_port: HTTPS # are going towards an HTTPS port
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
|
||||
|
||||
|
||||
@@ -254,21 +251,21 @@ example:
|
||||
.. code-block:: yaml
|
||||
|
||||
nodes:
|
||||
- ref: firewall
|
||||
...
|
||||
acl:
|
||||
external_inbound_acl:
|
||||
21: # position 19 on ACL list
|
||||
action: DENY # deny packets that
|
||||
src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port
|
||||
dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
- hostname: firewall
|
||||
...
|
||||
acl:
|
||||
external_inbound_acl:
|
||||
21: # position 19 on ACL list
|
||||
action: DENY # deny packets that
|
||||
src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port
|
||||
dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
|
||||
``external_outbound_acl``
|
||||
"""""""""""""""""""""""""
|
||||
@@ -282,17 +279,17 @@ example:
|
||||
.. code-block:: yaml
|
||||
|
||||
nodes:
|
||||
- ref: firewall
|
||||
...
|
||||
- hotsname: firewall
|
||||
...
|
||||
acl:
|
||||
external_outbound_acl:
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
external_outbound_acl:
|
||||
22: # position 22 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
src_port: ARP # are emitted from the ARP port
|
||||
dst_port: ARP # are going towards an ARP port
|
||||
23: # position 23 on ACL list
|
||||
action: PERMIT # allow packets that
|
||||
protocol: ICMP # are ICMP
|
||||
|
||||
.. include:: common/common_network_node_attributes.rst
|
||||
|
||||
|
||||
@@ -389,7 +389,7 @@ connections, but the ACL that allows the nodes in the LAN to communicate with th
|
||||
pc_1 = network.get_node_by_hostname("pc_1")
|
||||
pc_1.ping(pc_1.default_gateway)
|
||||
|
||||
pc_1.sys_log.show()
|
||||
pc_1.sys_log.show()
|
||||
|
||||
If SysLog capture is toggled on and the simulation log level is set to INFO, the `pc_1` the result of the ping should be
|
||||
captured in the `pc_1` SysLog:
|
||||
@@ -443,7 +443,8 @@ SomeTech. This extended network includes detailed sub-networks with specialised
|
||||
complex routing capabilities, and robust security protocols implemented through Access Control Lists (ACLs). Designed
|
||||
to mimic the intricacies of actual network environments, this network provides a detailed look at how various network
|
||||
components interact and function together to support both internal corporate activities and external communications.
|
||||
|
||||
NB: the network described here is not the same as the UC7 network used by notebooks such as ``UC7-Training,ipynb`` or
|
||||
the network in ``Privilege-Escalation-and-Data-Loss-Example.ipynb``.
|
||||
|
||||
.. image:: images/primaite_example_multi_lan_with_internet_network_dark.png
|
||||
:align: center
|
||||
|
||||
@@ -17,16 +17,15 @@ example router
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: router_1
|
||||
hostname: router_1
|
||||
type: router
|
||||
num_ports: 5
|
||||
ports:
|
||||
...
|
||||
acl:
|
||||
...
|
||||
network:
|
||||
nodes:
|
||||
- hostname: router_1
|
||||
type: router
|
||||
num_ports: 5
|
||||
ports:
|
||||
...
|
||||
acl:
|
||||
...
|
||||
|
||||
.. include:: common/common_node_attributes.rst
|
||||
|
||||
@@ -49,15 +48,15 @@ Example of setting ports for a router with 2 ports:
|
||||
.. code-block:: yaml
|
||||
|
||||
nodes:
|
||||
- ref: router_1
|
||||
- hostname: router_1
|
||||
...
|
||||
ports:
|
||||
1:
|
||||
ip_address: 192.168.1.1
|
||||
subnet_mask: 255.255.255.0
|
||||
2:
|
||||
ip_address: 192.168.10.1
|
||||
subnet_mask: 255.255.255.0
|
||||
1:
|
||||
ip_address: 192.168.1.1
|
||||
subnet_mask: 255.255.255.0
|
||||
2:
|
||||
ip_address: 192.168.10.1
|
||||
subnet_mask: 255.255.255.0
|
||||
|
||||
``ip_address``
|
||||
""""""""""""""
|
||||
@@ -81,12 +80,12 @@ e.g.
|
||||
.. code-block:: yaml
|
||||
|
||||
nodes:
|
||||
- ref: router_1
|
||||
- hostname: router_1
|
||||
...
|
||||
acl:
|
||||
1:
|
||||
action: PERMIT
|
||||
protocol: ICMP
|
||||
1:
|
||||
action: PERMIT
|
||||
protocol: ICMP
|
||||
|
||||
See :py:mod:`primaite.simulator.network.hardware.nodes.network.router.AccessControlList`
|
||||
|
||||
|
||||
@@ -19,16 +19,15 @@ example server
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: server_1
|
||||
hostname: server_1
|
||||
type: server
|
||||
ip_address: 192.168.10.10
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
- hostname: server_1
|
||||
type: server
|
||||
ip_address: 192.168.10.10
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
...
|
||||
services:
|
||||
services:
|
||||
...
|
||||
|
||||
.. include:: common/common_node_attributes.rst
|
||||
|
||||
@@ -17,12 +17,11 @@ example switch
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: switch_1
|
||||
hostname: switch_1
|
||||
type: switch
|
||||
num_ports: 8
|
||||
network:
|
||||
nodes:
|
||||
hostname: switch_1
|
||||
type: switch
|
||||
num_ports: 8
|
||||
|
||||
.. include:: common/common_node_attributes.rst
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
.. only:: comment
|
||||
|
||||
© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
Customising Agents
|
||||
******************
|
||||
|
||||
For an example of how to customise red agent behaviour in the Data Manipulation scenario, please refer to the notebook ``Data-Manipulation-Customising-Red-Agent.ipynb``.
|
||||
@@ -42,7 +42,7 @@ An agent's reward function is managed by the ``RewardManager``. It calculates re
|
||||
Reward Components
|
||||
-----------------
|
||||
|
||||
Currently implemented are reward components tailored to the data manipulation scenario. View the full API and description of how they work here: :py:modules:`primaite.game.agent.rewards`.
|
||||
Currently implemented are reward components tailored to the data manipulation scenario. View the full API and description of how they work here: :py:mod:`primaite.game.agent.rewards`.
|
||||
|
||||
Reward Sharing
|
||||
--------------
|
||||
|
||||
@@ -113,7 +113,7 @@ For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/{todo:fill in URL}/PrimAITE
|
||||
git clone https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE
|
||||
cd primaite
|
||||
|
||||
2. Create and activate your Python virtual environment (venv)
|
||||
|
||||
@@ -9,10 +9,10 @@ Glossary
|
||||
:sorted:
|
||||
|
||||
Network
|
||||
The network in primaite is a logical representation of a computer network containing :term:`Nodes<Node>` and :term:`Links<Link>`.
|
||||
The network in primaite is a logical representation of a computer network containing :term:`Nodes<Node>` and :term:`Links<Link>`. See :ref:`network`.
|
||||
|
||||
Node
|
||||
A Node represents a network endpoint. For example a computer, server, switch, or an actuator.
|
||||
A Node represents a network endpoint. For example a computer, server, switch, or an actuator. See :ref:`node_description`
|
||||
|
||||
Link
|
||||
A Link represents the connection between two Nodes. For example, a physical wire between a computer and a switch or a wireless connection.
|
||||
@@ -21,7 +21,7 @@ Glossary
|
||||
Protocols are used by links to separate different types of network traffic. Common examples would be HTTP, TCP, and UDP.
|
||||
|
||||
Service
|
||||
A service represents a piece of software that is installed on a node, such as a web server or a database.
|
||||
A service represents a piece of software that is installed on a node, such as a web server or a database. See :ref:`software`
|
||||
|
||||
Access Control List
|
||||
PrimAITE blocks or allows certain traffic on the network by simulating firewall rules, which are defined in the Access Control List.
|
||||
@@ -42,7 +42,7 @@ Glossary
|
||||
PoLs allow agents to change the current hardware, OS, file system, or service statuses of nodes during the course of an episode. For example, a green agent may restart a server node to represent scheduled maintainance. A red agent's Pattern-of-Life can be used to attack nodes by changing their states to CORRUPTED or COMPROMISED.
|
||||
|
||||
Reward
|
||||
The reward is a single number used by the blue agent to understand whether it's performing well or poorly. RL agents change their behaviour in an attempt to increase the expected reward each episode. The reward is generated based on the current states of the environment and is impacted positively by things like green PoL running successfully and negatively by things like nodes being compromised.
|
||||
The reward is a single number used by the blue agent to understand whether it's performing well or poorly. RL agents change their behaviour in an attempt to increase the expected reward each episode. The reward is generated based on the current states of the environment and is impacted positively by things like green PoL running successfully and negatively by things like nodes being compromised. See :ref:`Rewards`
|
||||
|
||||
Observation
|
||||
An observation is a representation of the current state of the environment that is given to the learning agent so it can decide on which action to perform. If the environment is 'fully observable', the observation contains information about every possible aspect of the environment. More commonly, the environment is 'partially observable' which means the learning agent has to make decisions without knowing every detail of the current environment state.
|
||||
@@ -50,6 +50,9 @@ Glossary
|
||||
Action
|
||||
The learning agent decides on an action to take on every step in the simulation. The action has the chance to positively or negatively impact the environment state. Over time, the agent aims to learn which actions to take when to maximise the expected reward.
|
||||
|
||||
Action mask
|
||||
An input to RL algorithms that contains information about which of the actions in the action space are currently valid. See :ref:`action_masking`
|
||||
|
||||
Training
|
||||
During training, an RL agent is placed in the simulated network and it learns which actions to take in which scenarios to obtain maximum reward.
|
||||
|
||||
@@ -69,4 +72,13 @@ Glossary
|
||||
PrimAITE uses the Gymnasium reinforcement learning framework API to create a training environment and interface with RL agents. Gymnasium defines a common way of creating observations, actions, and rewards.
|
||||
|
||||
User app home
|
||||
PrimAITE supports upgrading software version while retaining user data. The user data directory is where configs, notebooks, and results are stored, this location is `~/primaite<version>/` on linux/darwin and `C:\\Users\\<username>\\primaite<version>` on Windows.
|
||||
PrimAITE supports upgrading software version while retaining user data. The user data directory is where configs, notebooks, and results are stored, this location is ``~/primaite/<version>/`` on linux/darwin and ``C:\\Users\\<username>\\primaite\\<version>`` on Windows.
|
||||
|
||||
Episode schedule
|
||||
The strategy for selecting different variants around the same scenario when advancing from one episode to another in the environment.
|
||||
|
||||
Discriminator
|
||||
A unique string given to extensible components in PrimAITE that allow them to be mapped from a YAML config definition to a simulation class.
|
||||
|
||||
Plugin
|
||||
A python package that extends base PrimAITE classes.
|
||||
|
||||
@@ -18,7 +18,7 @@ An example of a custom action is seen below, with key information about what is
|
||||
|
||||
.. code:: Python
|
||||
|
||||
class ExampleActionClass(AbstractAction, identifier="ExampleActions"):
|
||||
class ExampleActionClass(AbstractAction, discriminator="ExampleActions"):
|
||||
"""Example Action Class"""
|
||||
|
||||
config: ExampleAction.ConfigSchema(AbstractAction.ConfigSchema)
|
||||
|
||||
@@ -42,4 +42,4 @@ Should your custom environment need any additional PrimAITE plugins, each must b
|
||||
Configuration Items
|
||||
===================
|
||||
|
||||
For detailed information about the remaining configuration items found within the configuration file, see :ref:`Configurable Items`.
|
||||
For detailed information about the remaining configuration items found within the configuration file, see :ref:`Configurable_Items`.
|
||||
|
||||
@@ -9,7 +9,7 @@ Creating Custom Rewards in PrimAITE
|
||||
|
||||
Rewards within PrimAITE are contained within ``rewards.py``, which details the rewards available for all agents within training sessions, how they are calculated and any other specific information where necessary.
|
||||
|
||||
Rewards within PrimAITE have been updated to facilitate extensability and the creation of plugins with the release of PrimAITE version 4.0. Additional information about this is covered within :ref:`extensible_rewards`.
|
||||
Rewards within PrimAITE have been updated to facilitate extensibility and the creation of plugins with the release of PrimAITE version 4.0. Additional information about this is covered within :ref:`extensible_rewards`.
|
||||
|
||||
Custom Rewards within PrimAITE should inherit from the ``AbstractReward`` class, found in ``rewards.py``. It's important to include an identifier for any class created within PrimAITE.
|
||||
|
||||
|
||||
@@ -17,50 +17,51 @@ All agent types within PrimAITE must be subclassed from ``AbstractAgent`` in ord
|
||||
|
||||
The core features that should be implemented in any new agent are detailed below:
|
||||
|
||||
#. **ConfigSchema**:
|
||||
**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.
|
||||
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
|
||||
.. code-block:: python
|
||||
|
||||
class ExampleAgent(AbstractAgent, discriminator = "ExampleAgent"):
|
||||
"""An example agent for demonstration purposes."""
|
||||
class ExampleAgent(AbstractAgent, discriminator = "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"""
|
||||
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"""
|
||||
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."""
|
||||
type: str = "ExampleAgent
|
||||
"""Name of agent"""
|
||||
starting_host: int
|
||||
"""Host node that this agent should start from in the given environment."""
|
||||
|
||||
|
||||
.. code-block:: yaml
|
||||
.. code-block:: yaml
|
||||
|
||||
- ref: example_green_agent
|
||||
team: GREEN
|
||||
type: example-agent
|
||||
- ref: example_green_agent
|
||||
team: GREEN
|
||||
type: example-agent
|
||||
|
||||
action_space:
|
||||
action_map:
|
||||
0:
|
||||
action: do-nothing
|
||||
options: {}
|
||||
agent_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
starting_host: "Server_1"
|
||||
agent_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
starting_host: "Server_1"
|
||||
|
||||
action_space:
|
||||
action_map:
|
||||
0:
|
||||
action: do-nothing
|
||||
options: {}
|
||||
|
||||
|
||||
#. **discriminators**:
|
||||
**discriminators**:
|
||||
|
||||
All agent classes should have an ``discriminator`` 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.
|
||||
|
||||
|
||||
@@ -22,30 +22,30 @@ An example of how additional Node classes is below, taken from `router.py` withi
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
class Router(NetworkNode, identifier="router"):
|
||||
""" Represents a network router within the simulation, managing routing and forwarding of IP packets across network interfaces."""
|
||||
class Router(NetworkNode, identifier="router"):
|
||||
""" Represents a network router within the simulation, managing routing and forwarding of IP packets across network interfaces."""
|
||||
|
||||
SYSTEM_SOFTWARE: ClassVar[Dict] = {
|
||||
"user-session-manager": UserSessionManager,
|
||||
"user-manager": UserManager,
|
||||
"terminal": Terminal,
|
||||
}
|
||||
SYSTEM_SOFTWARE: ClassVar[Dict] = {
|
||||
"user-session-manager": UserSessionManager,
|
||||
"user-manager": UserManager,
|
||||
"terminal": Terminal,
|
||||
}
|
||||
|
||||
network_interfaces: Dict[str, RouterInterface] = {}
|
||||
"The Router Interfaces on the node."
|
||||
network_interface: Dict[int, RouterInterface] = {}
|
||||
"The Router Interfaces on the node by port id."
|
||||
network_interfaces: Dict[str, RouterInterface] = {}
|
||||
"The Router Interfaces on the node."
|
||||
network_interface: Dict[int, RouterInterface] = {}
|
||||
"The Router Interfaces on the node by port id."
|
||||
|
||||
sys_log: SysLog
|
||||
sys_log: SysLog
|
||||
|
||||
config: "Router.ConfigSchema" = Field(default_factory=lambda: Router.ConfigSchema())
|
||||
config: "Router.ConfigSchema" = Field(default_factory=lambda: Router.ConfigSchema())
|
||||
|
||||
class ConfigSchema(NetworkNode.ConfigSchema):
|
||||
"""Configuration Schema for Router Objects."""
|
||||
class ConfigSchema(NetworkNode.ConfigSchema):
|
||||
"""Configuration Schema for Router Objects."""
|
||||
|
||||
num_ports: int = 5
|
||||
num_ports: int = 5
|
||||
|
||||
hostname: str = "Router"
|
||||
hostname: str = "Router"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -28,30 +28,28 @@ To add a new reward class follow the example below. Note that the type attribute
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
class DatabaseFileIntegrity(AbstractReward, discriminator="database-file-integrity"):
|
||||
"""Reward function component which rewards the agent for maintaining the integrity of a database file."""
|
||||
class DatabaseFileIntegrity(AbstractReward, discriminator="database-file-integrity"):
|
||||
"""Reward function component which rewards the agent for maintaining the integrity of a database file."""
|
||||
|
||||
config: "DatabaseFileIntegrity.ConfigSchema"
|
||||
location_in_state: List[str] = [""]
|
||||
reward: float = 0.0
|
||||
config: "DatabaseFileIntegrity.ConfigSchema"
|
||||
location_in_state: List[str] = [""]
|
||||
reward: float = 0.0
|
||||
|
||||
class ConfigSchema(AbstractReward.ConfigSchema):
|
||||
"""ConfigSchema for DatabaseFileIntegrity."""
|
||||
class ConfigSchema(AbstractReward.ConfigSchema):
|
||||
"""ConfigSchema for DatabaseFileIntegrity."""
|
||||
|
||||
type: str = "database-file-integrity"
|
||||
node_hostname: str
|
||||
folder_name: str
|
||||
file_name: str
|
||||
type: str = "database-file-integrity"
|
||||
node_hostname: str
|
||||
folder_name: str
|
||||
file_name: str
|
||||
|
||||
def calculate(self, state: Dict, last_action_response: "AgentHistoryItem") -> float:
|
||||
"""Calculate the reward for the current state.
|
||||
pass
|
||||
def calculate(self, state: Dict, last_action_response: "AgentHistoryItem") -> float:
|
||||
"""Calculate the reward for the current state.
|
||||
pass
|
||||
|
||||
|
||||
|
||||
Changes to YAML file.
|
||||
=====================
|
||||
.. code:: YAML
|
||||
|
||||
There's no longer a need to provide a `dns_server` as an option in the simulation section
|
||||
of the config file.
|
||||
|
||||
411
docs/source/how_to_guides/primaite_yaml_migration_guide.rst
Normal file
411
docs/source/how_to_guides/primaite_yaml_migration_guide.rst
Normal file
@@ -0,0 +1,411 @@
|
||||
.. only:: comment
|
||||
|
||||
© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _migration_guide:
|
||||
|
||||
|
||||
PrimAITE 4.0.0 YAML Configuration Migration Guide
|
||||
*************************************************
|
||||
|
||||
Users upgrading from previous PrimAITE versions will be required to update their pre-existing YAML configs.
|
||||
|
||||
This migration guide details how to update any 3.0.0 yaml configs section by section to match the new 4.0.0 schema.
|
||||
|
||||
Any users accustomed to PrimAITE 2.0.0 are encouraged to make a fresh start to fully adapt to the changes since 2.0.0 release.
|
||||
|
||||
``io_settings``
|
||||
===============
|
||||
|
||||
No major schema alterations are required for ``io_settings``.
|
||||
|
||||
However, a few more options have been introduced:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
io_settings:
|
||||
save_agent_actions: false
|
||||
save_step_metadata: false
|
||||
save_pcap_logs: false
|
||||
save_sys_logs: false
|
||||
save_agent_logs: false
|
||||
write_sys_log_to_terminal: false
|
||||
sys_log_level: WARNING
|
||||
agent_log_level: INFO
|
||||
|
||||
More information can be found in the detailed in the configuration page: :ref:`io_settings`.
|
||||
|
||||
``game``
|
||||
========
|
||||
|
||||
No reformatting required for ``game`` section.
|
||||
|
||||
If users have installed plugins that introduce new ports or protocols then the game can be configured with use them.
|
||||
|
||||
This can be done by adding to the ``ports`` and ``protocols`` list as shown in the yaml snippet below:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
game:
|
||||
max_episode_length: 128
|
||||
ports:
|
||||
- HTTP
|
||||
- POSTGRES_SERVER
|
||||
- <EXAMPLE_PLUGIN_PORT>
|
||||
protocols:
|
||||
- ICMP
|
||||
- TCP
|
||||
- UDP
|
||||
- <EXAMPLE_PLUGIN_PROTOCOL>
|
||||
thresholds:
|
||||
nmne:
|
||||
high: 10
|
||||
medium: 5
|
||||
low: 0
|
||||
|
||||
|
||||
``agents``
|
||||
==========
|
||||
|
||||
PrimAITE 4.0.0 changes action parameters to use meaningful names instead of indexes.
|
||||
|
||||
To match the new schema, agent configs written for PrimAITE 3.X should make the following changes:
|
||||
|
||||
``action_space``
|
||||
----------------
|
||||
|
||||
- remove the ``options``, and ``action_list`` sections.
|
||||
- update the ``action_map`` to use the new naming schema for actions, they use kebab case instead of camel case. A conversion table is provided below.
|
||||
- update the ``action_map`` to follow the new parameter schemas. ID-based parameters were replaced with name-based parameters. Use your old config's ``action_space.options`` field to find the appropriate mapping for action parameters in your particular scenario.
|
||||
- ``node_id`` is now ``node_name``
|
||||
- ``application_id`` is now ``application_name``
|
||||
- ``service_id`` is now ``service_name``
|
||||
- ``folder_id`` is now ``folder_name``
|
||||
- ``nic_id`` is now ``nic_num`` (and is now 1-indexed instead of 0-indexed for consistency with the simulation)
|
||||
- ``port_id`` is now ``port_num`` (and is now 1-indexed instead of 0-indexed for consistency with the simulation)
|
||||
- ``source_ip_id`` is now ``src_ip``
|
||||
- ``source_wildcard_id`` is now ``src_wildcard``
|
||||
- ``source_port_id`` is now ``src_port``
|
||||
- ``dest_port_id`` is now ``dst_port``
|
||||
- ``dest_wildcard_id`` is now ``dst_wildcard``
|
||||
- ``dest_port_id`` is now ``dst_port``
|
||||
- ``protocol_id`` is now ``protocol``
|
||||
|
||||
**Example on how to map old paramater IDs to new paramter names**
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
game:
|
||||
max_episode_length: 128
|
||||
ports:
|
||||
- FTP
|
||||
- HTTP
|
||||
protocols:
|
||||
- TCP
|
||||
- UDP
|
||||
|
||||
# ...
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: PC-1
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
folders:
|
||||
- folder_name: downloads
|
||||
files:
|
||||
- file_name: chrome.exe
|
||||
- folder_name: other_folder
|
||||
files:
|
||||
- file_name: firefox.exe
|
||||
- node_name: PC-2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
folders:
|
||||
- folder_name: folder_1
|
||||
files:
|
||||
- file_name: file2.jpg
|
||||
- folder_name: folder_2
|
||||
files:
|
||||
- file_name: file3.jpg
|
||||
- node_name: PC-3
|
||||
services:
|
||||
- service_name: FTPClient
|
||||
- node_name: PC-4
|
||||
- node_name: PC-5
|
||||
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
# 0 reserved for padding to align with observations
|
||||
# 1 reserved for ALL ips
|
||||
- 192.168.1.11 # 2
|
||||
- 200.10.1.10 # 3
|
||||
|
||||
|
||||
wildcard_list:
|
||||
- 0.0.0.1 # 0
|
||||
- 0.0.0.255 # 1
|
||||
- 0.0.255.255 # 2
|
||||
|
||||
From the above old-style YAML ``action_space.options`` example, the following changes should be made to action map:
|
||||
|
||||
- Actions with ``node_id: 0`` should use ``node_name: PC-1``
|
||||
- Actions with ``node_id: 1`` should use ``node_name: PC-2``
|
||||
- Actions with ``node_id: 2`` should use ``node_name: PC-3``
|
||||
- Actions with ``node_id: 3`` should use ``node_name: PC-4``
|
||||
- Actions with ``node_id: 4`` should use ``node_name: PC-5``
|
||||
- Actions with ``node_id: 0`` and ``application_id: 0`` should use ``application_name: DatabaseClient`` (The application list is specific to each node)
|
||||
- Actions with ``node_id: 1`` and ``application_id: 0`` should use ``application_name: WebBrowser`` (The application list is specific to each node)
|
||||
- Actions with ``node_id: 0`` and ``folder_id: 0`` should use ``folder_name: downloads`` (The folder list is specific to each node)
|
||||
- Actions with ``node_id: 0`` and ``folder_id: 1`` should use ``folder_name: other_folder`` (The folder list is specific to each node)
|
||||
- Actions with ``node_id: 1`` and ``folder_id: 0`` should use ``folder_name: folder_1`` (The folder list is specific to each node)
|
||||
- Actions with ``node_id: 1`` and ``folder_id: 1`` should use ``folder_name: folder_2`` (The folder list is specific to each node)
|
||||
- Actions with ``node_id: 0`` and ``folder_id: 0`` and ``file_id: 0`` should use ``file_name: chrome.exe`` (The file list is specific to each node and folder)
|
||||
- Actions with ``node_id: 0`` and ``folder_id: 1`` and ``file_id: 0`` should use ``file_name: firefox.exe`` (The file list is specific to each node and folder)
|
||||
- Actions with ``node_id: 1`` and ``folder_id: 0`` and ``file_id: 0`` should use ``file_name: file2.jpg`` (The file list is specific to each node and folder)
|
||||
- Actions with ``node_id: 1`` and ``folder_id: 1`` and ``file_id: 0`` should use ``file_name: file3.jpg`` (The file list is specific to each node and folder)
|
||||
- Actions with ``nic_id: <N>`` should use ``nic_num: <N+1>``
|
||||
- Actions with ``port_id: <N>`` should use ``port_num: <N+1>``
|
||||
- Actions with ``source_ip_id: 0`` should not be present in your original config as this has no effect
|
||||
- Actions with ``source_ip_id: 1`` should use ``src_ip: ALL``
|
||||
- Actions with ``source_ip_id: 2`` should use ``src_ip: 192.168.1.11``
|
||||
- Actions with ``source_ip_id: 3`` should use ``src_ip: 200.10.1.10``
|
||||
- Actions with ``dest_ip_id: 0`` should not be present in your original config as this has no effect
|
||||
- Actions with ``dest_ip_id: 1`` should use ``dst_ip: ALL``
|
||||
- Actions with ``dest_ip_id: 2`` should use ``dst_ip: 192.168.1.11``
|
||||
- Actions with ``dest_ip_id: 3`` should use ``dst_ip: 200.10.1.10``
|
||||
- Actions with ``source_wildcard_id: 0`` should use ``src_wildcard: 0.0.0.1``
|
||||
- Actions with ``source_wildcard_id: 0`` should use ``src_wildcard: 0.0.0.255``
|
||||
- Actions with ``source_wildcard_id: 0`` should use ``src_wildcard: 0.0.255.255``
|
||||
- Actions with ``dest_wildcard_id: 0`` should use ``dst_wildcard: 0.0.0.1``
|
||||
- Actions with ``dest_wildcard_id: 0`` should use ``dst_wildcard: 0.0.0.255``
|
||||
- Actions with ``dest_wildcard_id: 0`` should use ``dst_wildcard: 0.0.255.255``
|
||||
- Actions with ``source_port_id: 0`` should not be present in your original config as this has no effect
|
||||
- Actions with ``source_port_id: 1`` should use ``src_port: ALL``
|
||||
- Actions with ``source_port_id: 2`` should use ``src_port: FTP``
|
||||
- Actions with ``source_port_id: 3`` should use ``src_port: HTTP``
|
||||
- Actions with ``dest_port_id: 0`` should not be present in your original config as this has no effect
|
||||
- Actions with ``dest_port_id: 1`` should use ``dst_port: ALL``
|
||||
- Actions with ``dest_port_id: 2`` should use ``dst_port: FTP``
|
||||
- Actions with ``dest_port_id: 3`` should use ``dst_port: HTTP``
|
||||
- Actions with ``protocol_id: 0`` should not be present in your original config as this has no effect
|
||||
- Actions with ``protocol_id: 1`` should use ``protocol: ALL``
|
||||
- Actions with ``protocol_id: 2`` should use ``protocol: TCP``
|
||||
- Actions with ``protocol_id: 3`` should use ``protocol: UDP``
|
||||
|
||||
``observation_space``
|
||||
---------------------
|
||||
|
||||
- the ``type`` parameter values now use lower kebab case. A conversion table is provided below.
|
||||
|
||||
``reward_function``
|
||||
-------------------
|
||||
- the ``type`` parameter values now use lower kebab case. A conversion table is provided below.
|
||||
|
||||
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| *3.0.0 action name* | *4.0.0 action name* |
|
||||
+=====================================+=====================================+
|
||||
| ``DONOTHING`` | ``do-nothing`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SERVICE_SCAN`` | ``node-service-scan`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SERVICE_STOP`` | ``node-service-stop`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SERVICE_START`` | ``node-service-start`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SERVICE_PAUSE`` | ``node-service-pause`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SERVICE_RESUME`` | ``node-service-resume`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SERVICE_RESTART`` | ``node-service-restart`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SERVICE_DISABLE`` | ``node-service-disable`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SERVICE_ENABLE`` | ``node-service-enable`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SERVICE_FIX`` | ``node-service-fix`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_APPLICATION_REMOVE`` | ``node-application-remove`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_APPLICATION_CLOSE`` | ``node-application-close`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_APPLICATION_SCAN`` | ``node-application-scan`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_APPLICATION_FIX`` | ``node-application-fix`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FILE_SCAN`` | ``node-file-scan`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FILE_CHECKHASH`` | ``node-file-checkhash`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FILE_DELETE`` | ``node-file-delete`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FILE_REPAIR`` | ``node-file-repair`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FILE_RESTORE`` | ``node-file-restore`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FOLDER_SCAN`` | ``node-folder-scan`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FOLDER_CHECKHASH`` | ``node-folder-checkhash`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FOLDER_REPAIR`` | ``node-folder-repair`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FOLDER_RESTORE`` | ``node-folder-restore`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_OS_SCAN`` | ``node-os-scan`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SHUTDOWN`` | ``node-shutdown`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_STARTUP`` | ``node-startup`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_RESET`` | ``node-reset`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``HOST_NIC_ENABLE`` | ``host-nic-enable`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``HOST_NIC_DISABLE`` | ``host-nic-disable`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NETWORK_PORT_ENABLE`` | ``network-port-enable`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NETWORK_PORT_DISABLE`` | ``network-port-disable`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``ROUTER_ACL_ADDRULE`` | ``router-acl-addrule`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``ROUTER_ACL_REMOVERULE`` | ``router-acl-removerule`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``FIREWALL_ACL_ADDRULE`` | ``firewall-acl-addrule`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``FIREWALL_ACL_REMOVERULE`` | ``firewall-acl-removerule`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_APPLICATION_EXECUTE`` | ``node-application-execute`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_APPLICATION_INSTALL`` | ``node-application-install`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FOLDER_CREATE`` | ``node-folder-create`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FILE_CREATE`` | ``node-file-create`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FILE_ACCESS`` | ``node-file-access`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_NMAP_PING_SCAN`` | ``node-nmap-ping-scan`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_NMAP_PORT_SCAN`` | ``node-nmap-port-scan`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_NMAP_NETWORK_SERVICE_RECON`` | ``node-nmap-network-service-recon`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``CONFIGURE_RANSOMWARE_SCRIPT`` | ``configure-ransomware-script`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``CONFIGURE_C2_BEACON`` | ``configure-c2-beacon`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``CONFIGURE_DATABASE_CLIENT`` | ``configure-database-client`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``CONFIGURE_DOS_BOT`` | ``configure-dos-bot`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``C2_SERVER_RANSOMWARE_LAUNCH`` | ``c2-server-ransomware-launch`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``C2_SERVER_RANSOMWARE_CONFIGURE`` | ``c2-server-ransomware-configure`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``C2_SERVER_TERMINAL_COMMAND`` | ``c2-server-terminal-command`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``C2_SERVER_DATA_EXFILTRATE`` | ``c2-server-data-exfiltrate`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``HOST_NIC_ENABLE`` | ``host-nic-enable`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``HOST_NIC_DISABLE`` | ``host-nic-disable`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_FILE_CORRUPT`` | ``node-file-corrupt`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SESSION_REMOTE_LOGIN`` | ``node-session-remote-login`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SESSION_REMOTE_LOGOFF`` | ``node-session-remote-logoff`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_ACCOUNT_CHANGE_PASSWORD`` | ``node-account-change-password`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
| ``NODE_SEND_REMOTE_COMMAND`` | ``node-send-remote-command`` |
|
||||
+-------------------------------------+-------------------------------------+
|
||||
|
||||
|
||||
- All reward component types must be converted to kebab-case. (``SHARED_REWARD`` - ``shared-reward``)
|
||||
|
||||
+----------------------------------------------+----------------------------------------------+
|
||||
| *3.0.0 reward type* | *4.0.0 reward name* |
|
||||
+==============================================+==============================================+
|
||||
| ``SHARED_REWARD`` | ``shared-reward`` |
|
||||
+----------------------------------------------+----------------------------------------------+
|
||||
| ``WEB_SERVER_404_PENALTY`` | ``web-server-404-penalty`` |
|
||||
+----------------------------------------------+----------------------------------------------+
|
||||
| ``WEBPAGE_UNAVAILABLE_PENALTY`` | ``webpage-unavailable-penalty`` |
|
||||
+----------------------------------------------+----------------------------------------------+
|
||||
| ``GREEN_ADMIN_DATABASE_UNREACHABLE_PENALTY`` | ``green-admin-database-unreachable-penalty`` |
|
||||
+----------------------------------------------+----------------------------------------------+
|
||||
| ``ACTION_PENALTY`` | ``action-penalty`` |
|
||||
+----------------------------------------------+----------------------------------------------+
|
||||
| ``DATABASE_FILE_INTEGRITY`` | ``database-file-integrity`` |
|
||||
+----------------------------------------------+----------------------------------------------+
|
||||
|
||||
|
||||
- All agent types must be converted to kebab-case. (``ProxyAgent`` - ``proxy-agent``)
|
||||
|
||||
+--------------------------------+-----------------------------------+
|
||||
| *3.0.0 action type* | *4.0.0 agent type* |
|
||||
+================================+===================================+
|
||||
| ``ProxyAgent`` | ``proxy-agent`` |
|
||||
+--------------------------------+-----------------------------------+
|
||||
| ``RedDatabaseCorruptingAgent`` | ``red-database-corrupting-agent`` |
|
||||
+--------------------------------+-----------------------------------+
|
||||
| ``ProbabilisticAgent`` | ``probabilistic-agent`` |
|
||||
+--------------------------------+-----------------------------------+
|
||||
| ``RandomAgent`` | ``random-agent`` |
|
||||
+--------------------------------+-----------------------------------+
|
||||
| ``PeriodicAgent`` | ``periodic-agent`` |
|
||||
+--------------------------------+-----------------------------------+
|
||||
|
||||
|
||||
``simulation``
|
||||
==============
|
||||
|
||||
The only simulation yaml changes are that all software has been renamed to use kebab-case:
|
||||
|
||||
+-----------------------+------------------------+
|
||||
|*3.0.0 software name* |*4.0.0 software name* |
|
||||
+=======================+========================+
|
||||
| ``WebBrowser`` | ``web-browser`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``DatabaseClient`` | ``database-client`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``DNSClient`` | ``dns-client`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``FTPServer`` | ``ftp-server`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``C2Beacon`` | ``c2-beacon`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``C2Server`` | ``c2-server`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``RansomwareScript`` | ``ransomware-script`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``WebServer`` | ``web-server`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``DOSBot`` | ``dos-bot`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``FTPClient`` | ``ftp-client`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``DNSServer`` | ``dns-server`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``Terminal`` | ``terminal`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``NTPClient`` | ``ntp-client`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``NTPServer`` | ``ntp-server`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``NMAP`` | ``nmap`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``HostARP`` | ``host-arp`` |
|
||||
+-----------------------+------------------------+
|
||||
| ``ICMP`` | ``icmp`` |
|
||||
+-----------------------+------------------------+
|
||||
|
||||
|
||||
A simple search and replace can be used with the lists above to update any configs.
|
||||
@@ -50,6 +50,7 @@ Via YAML Config
|
||||
---------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
|
||||
@@ -78,17 +78,26 @@ The ``RequestType`` object stores a reference to a method that executes the requ
|
||||
|
||||
The ``RequestManager`` object stores a mapping between strings and request types. It is responsible for processing the request and passing it down the ownership tree. Technically, the ``RequestManager`` is itself a callable that accepts `request, context` tuple, and so it can be chained with other request managers.
|
||||
|
||||
A simple example without chaining can be seen in the :py:class:`primaite.simulator.file_system.file_system.File` class.
|
||||
A simple example without chaining can be seen in the :py:class:`primaite.simulator.file_system.file_systemfile_system_item_abc.FileSystemItemABC` class.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class File(FileSystemItemABC):
|
||||
class FileSystemItemABC(SimComponent):
|
||||
...
|
||||
def _init_request_manager(self):
|
||||
...
|
||||
request_manager.add_request("scan", RequestType(func=lambda request, context: RequestResponse.from_bool(self.scan())))
|
||||
request_manager.add_request("repair", RequestType(func=lambda request, context: RequestResponse.from_bool(self.repair())))
|
||||
request_manager.add_request("restore", RequestType(func=lambda request, context: RequestResponse.from_bool(self.restore())))
|
||||
rm.add_request(
|
||||
name="scan", request_type=RequestType(func=lambda request, context: RequestResponse.from_bool(self.scan()))
|
||||
)
|
||||
rm.add_request(
|
||||
name="checkhash",
|
||||
request_type=RequestType(func=lambda request, context: RequestResponse.from_bool(self.check_hash())),
|
||||
)
|
||||
rm.add_request(
|
||||
name="repair",
|
||||
request_type=RequestType(func=lambda request, context: RequestResponse.from_bool(self.repair())),
|
||||
)
|
||||
...
|
||||
|
||||
*ellipses (``...``) used to omit code impertinent to this explanation*
|
||||
|
||||
@@ -103,27 +112,18 @@ An example of how this works is in the :py:class:`primaite.simulator.network.har
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Node(SimComponent):
|
||||
class Node(SimComponent, ABC):
|
||||
...
|
||||
def _init_request_manager(self):
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
...
|
||||
# a regular action which is processed by the Node itself
|
||||
request_manager.add_request("turn_on", RequestType(func=lambda request, context: self.turn_on()))
|
||||
|
||||
# if the Node receives a request where the first word is 'service', it will use a dummy manager
|
||||
# called self._service_request_manager to pass on the request to the relevant service. This dummy
|
||||
# manager is simply here to map the service name that that service's own action manager. This is
|
||||
# done because the next string after "service" is always the name of that service, so we need an
|
||||
# RequestManager to pop that string before sending it onto the relevant service's RequestManager.
|
||||
# since there are potentially many services, create an request manager that can map service name
|
||||
self._service_request_manager = RequestManager()
|
||||
request_manager.add_request("service", RequestType(func=self._service_request_manager))
|
||||
...
|
||||
rm.add_request("service", RequestType(func=self._service_request_manager, validator=_node_is_on))
|
||||
self._nic_request_manager = RequestManager()
|
||||
rm.add_request("network_interface", RequestType(func=self._nic_request_manager, validator=_node_is_on))
|
||||
|
||||
rm.add_request("file_system", RequestType(func=self.file_system._request_manager, validator=_node_is_on))
|
||||
|
||||
def install_service(self, service):
|
||||
self.services[service.name] = service
|
||||
...
|
||||
# Here, the service name is registered to allow passing actions between the node and the service.
|
||||
self._service_request_manager.add_request(service.name, RequestType(func=service._request_manager))
|
||||
|
||||
This process is repeated until the request word corresponds to a callable function rather than another ``RequestManager`` .
|
||||
|
||||
@@ -142,3 +142,8 @@ The :py:class:`primaite.interface.request.RequestResponse<RequestResponse>` carr
|
||||
For instance, the ``execute`` action on a :py:class:`primaite.simulator.system.applications.web_browser.WebBrowser<WebBrowser>` calls the ``get_webpage()`` method. ``get_webpage()`` returns a True if the webpage was successfully retrieved, and False if unsuccessful for any reason, such as being blocked by an ACL, or if the database server is unresponsive. The boolean returned from ``get_webpage()`` is used to create the request response with ``from_bool()``.
|
||||
|
||||
Just as the requests themselves were passed from owner to component, the request response is bubbled back up from component to owner until it arrives at the game layer.
|
||||
|
||||
Example notebooks
|
||||
-----------------
|
||||
Further examples of the request system and be found in ``Requests-and-Responses.ipynb``
|
||||
and ``Terminal-Processing.ipynb`` notebooks.
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
|
||||
© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _Rewards:
|
||||
|
||||
Rewards
|
||||
#######
|
||||
|
||||
Rewards in PrimAITE are based on a system of individual components that react to events in the simulation. An agent's reward function is calculated as the weighted sum of several reward components.
|
||||
|
||||
Some rewards, such as the ``GreenAdminDatabaseUnreachablePenalty``, can be marked as 'sticky' in their configuration. Setting this to ``True`` will mean that they continue to output the same value after an event until another event of that type.
|
||||
In the instance of the ``GreenAdminDatabaseUnreachablePenalty``, the database admin reward will stay negative until the next successful database request is made, even if the database admin agents do nothing and the database returns a good state.
|
||||
Some rewards, such as the ``green-admin-database-unreachable-penalty``, can be marked as 'sticky' in their configuration. Setting this to ``True`` will mean that they continue to output the same value after an event until another event of that type.
|
||||
In the instance of the ``green-admin-database-unreachable-penalty``, the database admin reward will stay negative until the next successful database request is made, even if the database admin agents do nothing and the database returns a good state.
|
||||
|
||||
Components
|
||||
**********
|
||||
@@ -23,8 +25,8 @@ The following API pages describe the use of each reward component and the possib
|
||||
# ...
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: dummy
|
||||
weight: 1.0
|
||||
- type: dummy
|
||||
weight: 1.0
|
||||
|
||||
|
||||
:py:class:`primaite.game.agent.rewards.DatabaseFileIntegrity`
|
||||
@@ -36,12 +38,12 @@ The following API pages describe the use of each reward component and the possib
|
||||
# ...
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: database-file-integrity
|
||||
weight: 1.0
|
||||
options:
|
||||
node_hostname: server_1
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
- type: database-file-integrity
|
||||
weight: 1.0
|
||||
options:
|
||||
node_hostname: server_1
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
|
||||
|
||||
:py:class:`primaite.game.agent.rewards.WebServer404Penalty`
|
||||
@@ -53,12 +55,12 @@ The following API pages describe the use of each reward component and the possib
|
||||
# ...
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: web-server-404-penalty
|
||||
node_hostname: web_server
|
||||
weight: 1.0
|
||||
options:
|
||||
service_name: WebService
|
||||
sticky: false
|
||||
- type: web-server-404-penalty
|
||||
node_hostname: web_server
|
||||
weight: 1.0
|
||||
options:
|
||||
service_name: WebService
|
||||
sticky: false
|
||||
|
||||
|
||||
:py:class:`primaite.game.agent.rewards.WebpageUnavailablePenalty`
|
||||
@@ -70,11 +72,11 @@ The following API pages describe the use of each reward component and the possib
|
||||
# ...
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: webpage-unavailable-penalty
|
||||
node_hostname: computer_1
|
||||
weight: 1.0
|
||||
options:
|
||||
sticky: false
|
||||
- type: webpage-unavailable-penalty
|
||||
node_hostname: computer_1
|
||||
weight: 1.0
|
||||
options:
|
||||
sticky: false
|
||||
|
||||
|
||||
:py:class:`primaite.game.agent.rewards.GreenAdminDatabaseUnreachablePenalty`
|
||||
@@ -86,11 +88,11 @@ The following API pages describe the use of each reward component and the possib
|
||||
# ...
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: green-admin-database-unreachable-penalty
|
||||
weight: 1.0
|
||||
options:
|
||||
node_hostname: admin_pc_1
|
||||
sticky: false
|
||||
- type: green-admin-database-unreachable-penalty
|
||||
weight: 1.0
|
||||
options:
|
||||
node_hostname: admin_pc_1
|
||||
sticky: false
|
||||
|
||||
|
||||
:py:class:`primaite.game.agent.rewards.SharedReward`
|
||||
@@ -104,10 +106,10 @@ The following API pages describe the use of each reward component and the possib
|
||||
# ...
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: shared-reward
|
||||
weight: 1.0
|
||||
options:
|
||||
agent_name: scripted_agent
|
||||
- type: shared-reward
|
||||
weight: 1.0
|
||||
options:
|
||||
agent_name: scripted_agent
|
||||
|
||||
|
||||
:py:class:`primaite.game.agent.rewards.ActionPenalty`
|
||||
@@ -119,8 +121,8 @@ The following API pages describe the use of each reward component and the possib
|
||||
# ...
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: action-penalty
|
||||
weight: 1.0
|
||||
options:
|
||||
action_penalty: -0.3
|
||||
do_nothing_penalty: 0.0
|
||||
- type: action-penalty
|
||||
weight: 1.0
|
||||
options:
|
||||
action_penalty: -0.3
|
||||
do_nothing_penalty: 0.0
|
||||
|
||||
@@ -21,6 +21,9 @@ The key elements defined in ``base.py`` are:
|
||||
|
||||
``Node``
|
||||
========
|
||||
|
||||
.. _node_description:
|
||||
|
||||
The Node class stands as a central component in ``base.py``, acting as the superclass for all network nodes within a
|
||||
PrimAITE simulation.
|
||||
|
||||
|
||||
@@ -156,8 +156,8 @@ To prevent all external traffic from accessing the internal network, with except
|
||||
# Exception rule to allow HTTP traffic from external to internal network
|
||||
firewall.internal_inbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
dst_port=Port["HTTP"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
dst_port=PORT_LOOKUP["HTTP"],
|
||||
dst_ip_address="192.168.1.0",
|
||||
dst_wildcard_mask="0.0.0.255",
|
||||
position=2
|
||||
@@ -172,16 +172,16 @@ To enable external traffic to access specific services hosted within the DMZ:
|
||||
# Allow HTTP and HTTPS traffic to the DMZ
|
||||
firewall.dmz_inbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
dst_port=Port["HTTP"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
dst_port=PORT_LOOKUP["HTTP"],
|
||||
dst_ip_address="172.16.0.0",
|
||||
dst_wildcard_mask="0.0.0.255",
|
||||
position=3
|
||||
)
|
||||
firewall.dmz_inbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
dst_port=Port["HTTPS"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
dst_port=PORT_LOOKUP["HTTPS"],
|
||||
dst_ip_address="172.16.0.0",
|
||||
dst_wildcard_mask="0.0.0.255",
|
||||
position=4
|
||||
@@ -196,9 +196,9 @@ To permit SSH access from a designated external IP to a specific server within t
|
||||
# Allow SSH from a specific external IP to an internal server
|
||||
firewall.internal_inbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
src_ip_address="10.0.0.2",
|
||||
dst_port=Port["SSH"],
|
||||
dst_port=PORT_LOOKUP["SSH"],
|
||||
dst_ip_address="192.168.1.10",
|
||||
position=5
|
||||
)
|
||||
@@ -212,9 +212,9 @@ To limit database server access to selected external IP addresses:
|
||||
# Allow PostgreSQL traffic from an authorized external IP to the internal DB server
|
||||
firewall.internal_inbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
src_ip_address="10.0.0.3",
|
||||
dst_port=Port["POSTGRES_SERVER"],
|
||||
dst_port=PORT_LOOKUP["POSTGRES_SERVER"],
|
||||
dst_ip_address="192.168.1.20",
|
||||
position=6
|
||||
)
|
||||
@@ -222,8 +222,8 @@ To limit database server access to selected external IP addresses:
|
||||
# Deny all other PostgreSQL traffic from external sources
|
||||
firewall.internal_inbound_acl.add_rule(
|
||||
action=ACLAction.DENY,
|
||||
protocol=IPProtocol["TCP"],
|
||||
dst_port=Port["POSTGRES_SERVER"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
dst_port=PORT_LOOKUP["POSTGRES_SERVER"],
|
||||
dst_ip_address="192.168.1.0",
|
||||
dst_wildcard_mask="0.0.0.255",
|
||||
position=7
|
||||
@@ -247,15 +247,15 @@ To authorize HTTP/HTTPS access to a DMZ-hosted web server, excluding known malic
|
||||
# Allow HTTP/HTTPS traffic to the DMZ web server
|
||||
firewall.dmz_inbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
dst_port=Port["HTTP"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
dst_port=PORT_LOOKUP["HTTP"],
|
||||
dst_ip_address="172.16.0.2",
|
||||
position=9
|
||||
)
|
||||
firewall.dmz_inbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
dst_port=Port["HTTPS"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
dst_port=PORT_LOOKUP["HTTPS"],
|
||||
dst_ip_address="172.16.0.2",
|
||||
position=10
|
||||
)
|
||||
@@ -269,9 +269,9 @@ To facilitate restricted access from the internal network to DMZ-hosted services
|
||||
# Permit specific internal application server HTTPS access to a DMZ-hosted API
|
||||
firewall.internal_outbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
src_ip_address="192.168.1.30", # Internal application server IP
|
||||
dst_port=Port["HTTPS"],
|
||||
dst_port=PORT_LOOKUP["HTTPS"],
|
||||
dst_ip_address="172.16.0.3", # DMZ API server IP
|
||||
position=11
|
||||
)
|
||||
@@ -289,9 +289,9 @@ To facilitate restricted access from the internal network to DMZ-hosted services
|
||||
# Corresponding rule in DMZ inbound ACL to allow the traffic from the specific internal server
|
||||
firewall.dmz_inbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
src_ip_address="192.168.1.30", # Ensuring this specific source is allowed
|
||||
dst_port=Port["HTTPS"],
|
||||
dst_port=PORT_LOOKUP["HTTPS"],
|
||||
dst_ip_address="172.16.0.3", # DMZ API server IP
|
||||
position=13
|
||||
)
|
||||
@@ -301,7 +301,7 @@ To facilitate restricted access from the internal network to DMZ-hosted services
|
||||
action=ACLAction.DENY,
|
||||
src_ip_address="192.168.1.0",
|
||||
src_wildcard_mask="0.0.0.255",
|
||||
dst_port=Port["HTTPS"],
|
||||
dst_port=PORT_LOOKUP["HTTPS"],
|
||||
dst_ip_address="172.16.0.3", # DMZ API server IP
|
||||
position=14
|
||||
)
|
||||
@@ -315,8 +315,8 @@ To block all SSH access attempts from the external network:
|
||||
# Deny all SSH traffic from any external source
|
||||
firewall.external_inbound_acl.add_rule(
|
||||
action=ACLAction.DENY,
|
||||
protocol=IPProtocol["TCP"],
|
||||
dst_port=Port["SSH"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
dst_port=PORT_LOOKUP["SSH"],
|
||||
position=1
|
||||
)
|
||||
|
||||
@@ -329,8 +329,8 @@ To allow the internal network to initiate HTTP connections to the external netwo
|
||||
# Permit outgoing HTTP traffic from the internal network to any external destination
|
||||
firewall.external_outbound_acl.add_rule(
|
||||
action=ACLAction.PERMIT,
|
||||
protocol=IPProtocol["TCP"],
|
||||
dst_port=Port["HTTP"],
|
||||
protocol=PROTOCOL_LOOKUP["TCP"],
|
||||
dst_port=PORT_LOOKUP["HTTP"],
|
||||
position=2
|
||||
)
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ other wireless devices within the same frequency band.
|
||||
Example Scenario
|
||||
----------------
|
||||
|
||||
This example sets up a network with two PCs (PC A and PC B), each connected to their own `WirelessRouter`
|
||||
This example sets up a network with two PCs (PC A and PC B), each connected to their own ``WirelessRouter``
|
||||
(Router 1 and Router 2). These routers are then wirelessly connected to each other, enabling communication between the
|
||||
PCs through the routers over the airspace. Access Control Lists (ACLs) are configured on the routers to permit ARP and
|
||||
ICMP traffic, ensuring basic network connectivity and ping functionality.
|
||||
@@ -160,7 +160,7 @@ network segments.
|
||||
Viewing Wireless Network Configuration
|
||||
--------------------------------------
|
||||
|
||||
The `AirSpace.show()` function is an invaluable tool for inspecting the current wireless network configuration within
|
||||
The :py:meth:`AirSpace.show() <primaite.simulator.network.airspace.AirSpace.show()>` function is an invaluable tool for inspecting the current wireless network configuration within
|
||||
the PrimAITE environment. It presents a table summarising all wireless interfaces, including routers and access points,
|
||||
that are active within the airspace. The table outlines each device's connected node name, MAC address, IP address,
|
||||
subnet mask, operating frequency, and status, providing a comprehensive view of the wireless network topology.
|
||||
@@ -168,7 +168,7 @@ subnet mask, operating frequency, and status, providing a comprehensive view of
|
||||
Example Output
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Below is an example output of the `AirSpace.show()` function, demonstrating the visibility it provides into the
|
||||
Below is an example output of the :py:meth:`AirSpace.show() <primaite.simulator.network.airspace.AirSpace.show()>` function, demonstrating the visibility it provides into the
|
||||
wireless network:
|
||||
|
||||
.. code-block:: none
|
||||
@@ -182,10 +182,10 @@ wireless network:
|
||||
|
||||
This table aids in verifying that wireless devices are correctly configured and operational. It also helps in
|
||||
diagnosing connectivity issues by ensuring that devices are on the correct frequency and have the appropriate network
|
||||
settings. The `Status` column, indicating whether a device is enabled or disabled, further assists in troubleshooting
|
||||
settings. The ``Status`` column, indicating whether a device is enabled or disabled, further assists in troubleshooting
|
||||
by quickly identifying any devices that are not actively participating in the network.
|
||||
|
||||
Utilising the `AirSpace.show()` function is particularly beneficial in complex network simulations where multiple
|
||||
Utilising the :py:meth:`AirSpace.show() <primaite.simulator.network.airspace.AirSpace.show()>` function is particularly beneficial in complex network simulations where multiple
|
||||
wireless devices are in use. It provides a snapshot of the wireless landscape, facilitating the understanding of how
|
||||
devices interact within the network and ensuring that configurations are aligned with the intended network architecture.
|
||||
|
||||
|
||||
@@ -14,9 +14,11 @@ Transport Layer (Layer 4)
|
||||
**UDPHeader:** Represents a UDP header for the transport layer of a Network Frame. It includes source and destination
|
||||
ports. UDP (User Datagram Protocol) is a connectionless and unreliable transport protocol used for data transmission.
|
||||
|
||||
**TCPFlags:** Enum representing TCP control flags used in a TCP connection, such as SYN, ACK, FIN, and RST. TCP
|
||||
(Transmission Control Protocol) is a connection-oriented and reliable transport protocol used for establishing and
|
||||
maintaining data streams.
|
||||
..
|
||||
**TCPFlags:** Enum representing TCP control flags used in a TCP connection, such as SYN, ACK, FIN, and RST. TCP
|
||||
(Transmission Control Protocol) is a connection-oriented and reliable transport protocol used for establishing and
|
||||
maintaining data streams.
|
||||
.. not currently used
|
||||
|
||||
**TCPHeader:** Represents a TCP header for the transport layer of a Network Frame. It includes source and destination
|
||||
ports and TCP flags. This header is used for establishing and managing TCP connections.
|
||||
@@ -104,7 +106,7 @@ address of 'aa:bb:cc:dd:ee:ff' to port 8080 on the host 10.0.0.10 which has a NI
|
||||
ip_packet = IPPacket(
|
||||
src_ip_address="192.168.0.100",
|
||||
dst_ip_address="10.0.0.10",
|
||||
protocol=IPProtocol["TCP"]
|
||||
protocol=PROTOCOL_LOOKUP["TCP"]
|
||||
)
|
||||
# Data Link Layer
|
||||
ethernet_header = EthernetHeader(
|
||||
|
||||
@@ -77,9 +77,9 @@ Adding to this, the following behaviour of the C2 beacon can be configured by us
|
||||
+---------------------+---------------------------------------------------------------------------+
|
||||
|keep_alive_frequency | How often should the C2 Beacon confirm it's connection in timesteps. |
|
||||
+---------------------+---------------------------------------------------------------------------+
|
||||
|masquerade_protocol | What protocol should the C2 traffic masquerade as? (HTTP, FTP or DNS) |
|
||||
|masquerade_protocol | What protocol should the C2 traffic masquerade as? (TCP opr UDP) |
|
||||
+---------------------+---------------------------------------------------------------------------+
|
||||
|masquerade_port | What port should the C2 traffic use? (TCP or UDP) |
|
||||
|masquerade_port | What port should the C2 traffic use? (HTTP, FTP, or DNS) |
|
||||
+---------------------+---------------------------------------------------------------------------+
|
||||
|
||||
|
||||
@@ -115,38 +115,30 @@ Python
|
||||
""""""
|
||||
.. code-block:: python
|
||||
|
||||
from primaite.simulator.network.container import Network
|
||||
from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.network.switch import Switch
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript
|
||||
from primaite.simulator.system.services.database.database_service import DatabaseService
|
||||
from primaite.simulator.system.applications.red_applications.c2.c2_server import C2Command, C2Server
|
||||
from primaite.simulator.system.applications.red_applications.c2.c2_beacon import C2Beacon
|
||||
|
||||
# Network Setup
|
||||
network = Network()
|
||||
|
||||
|
||||
switch = Switch(config={"hostname":"switch", "start_up_duration":0, "num_ports":4})
|
||||
switch = Switch(config=Switch.ConfigSchema(hostname="switch", start_up_duration=0, num_ports=4))
|
||||
switch.power_on()
|
||||
|
||||
node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0})
|
||||
node_a = Computer(config=Computer.ConfigSchema(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0))
|
||||
node_a.power_on()
|
||||
network.connect(node_a.network_interface[1], switch.network_interface[1])
|
||||
|
||||
node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0})
|
||||
node_b = Computer(config=Computer.ConfigSchema(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0))
|
||||
node_b.power_on()
|
||||
|
||||
network.connect(node_b.network_interface[1], switch.network_interface[2])
|
||||
|
||||
node_c = Computer(config={"hostname":"node_c", "ip_address":"192.168.0.12", "subnet_mask":"255.255.255.0", "start_up_duration":0})
|
||||
node_c = Computer(config=Computer.ConfigSchema(hostname="node_c", ip_address="192.168.0.12", subnet_mask="255.255.255.0", start_up_duration=0))
|
||||
node_c.power_on()
|
||||
network.connect(node_c.network_interface[1], switch.network_interface[3])
|
||||
|
||||
node_c.software_manager.install(software_class=DatabaseService)
|
||||
node_b.software_manager.install(software_class=DatabaseClient)
|
||||
node_b.software_manager.install(software_class=RansomwareScript)
|
||||
node_b.software_manager.install(software_class=C2Beacon)
|
||||
node_a.software_manager.install(software_class=C2Server)
|
||||
|
||||
# C2 Application objects
|
||||
@@ -154,8 +146,8 @@ Python
|
||||
c2_server_host: Computer = network.get_node_by_hostname("node_a")
|
||||
c2_beacon_host: Computer = network.get_node_by_hostname("node_b")
|
||||
|
||||
c2_server: C2Server = c2_server_host.software_manager.software["C2Server"]
|
||||
c2_beacon: C2Beacon = c2_beacon_host.software_manager.software["C2Beacon"]
|
||||
c2_server: C2Server = c2_server_host.software_manager.software["c2-server"]
|
||||
c2_beacon: C2Beacon = c2_beacon_host.software_manager.software["c2-beacon"]
|
||||
|
||||
# Configuring the C2 Beacon
|
||||
c2_beacon.configure(c2_server_ip_address="192.168.0.10", keep_alive_frequency=5)
|
||||
@@ -287,8 +279,6 @@ It's worth noting that this may be a useful option to bypass ACL rules.
|
||||
|
||||
This must be a string i.e *UDP*. Defaults to ``TCP``.
|
||||
|
||||
*Please refer to the ``IPProtocol`` class for further reference.*
|
||||
|
||||
``Masquerade Port``
|
||||
"""""""""""""""""""
|
||||
|
||||
@@ -300,8 +290,6 @@ It's worth noting that this may be a useful option to bypass ACL rules.
|
||||
|
||||
This must be a string i.e ``DNS``. Defaults to ``HTTP``.
|
||||
|
||||
*Please refer to the ``IPProtocol`` class for further reference.*
|
||||
|
||||
``Common Attributes``
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ The bot performs attacks in the following stages to simulate the real pattern of
|
||||
- Attacking - *The bot delivers the payload to the discovered database servers.*
|
||||
|
||||
Each of these stages has a random, configurable probability of succeeding (by default 10%). The bot can also be configured to repeat the attack once complete.
|
||||
NB: The Port Scan is achieved using game layer functionality based on a probablility of success calculation.
|
||||
|
||||
Usage
|
||||
=====
|
||||
@@ -99,16 +100,12 @@ If not using the data manipulation bot manually, it needs to be used with a data
|
||||
type: red-database-corrupting-agent
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 25
|
||||
frequency: 20
|
||||
variance: 5
|
||||
# ...
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: client_1
|
||||
- hostname: client_1
|
||||
type: computer
|
||||
# ... additional configuration here
|
||||
applications:
|
||||
|
||||
@@ -76,17 +76,15 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_computer
|
||||
hostname: example_computer
|
||||
type: computer
|
||||
...
|
||||
applications:
|
||||
- ref: database_client
|
||||
type: database-client
|
||||
options:
|
||||
db_server_ip: 192.168.0.1
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_computer
|
||||
type: computer
|
||||
...
|
||||
applications:
|
||||
- type: database-client
|
||||
options:
|
||||
db_server_ip: 192.168.0.1
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
@@ -79,22 +79,20 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_computer
|
||||
hostname: example_computer
|
||||
type: computer
|
||||
...
|
||||
applications:
|
||||
- ref: dos_bot
|
||||
type: dos-bot
|
||||
options:
|
||||
target_ip_address: 192.168.0.10
|
||||
payload: SPOOF DATA
|
||||
repeat: False
|
||||
port_scan_p_of_success: 0.8
|
||||
dos_intensity: 1.0
|
||||
max_sessions: 1000
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_computer
|
||||
type: computer
|
||||
...
|
||||
applications:
|
||||
- type: dos-bot
|
||||
options:
|
||||
target_ip_address: 192.168.0.10
|
||||
payload: SPOOF DATA
|
||||
repeat: False
|
||||
port_scan_p_of_success: 0.8
|
||||
dos_intensity: 1.0
|
||||
max_sessions: 1000
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
@@ -167,8 +167,8 @@ Perform a horizontal port scan on port 5432 across multiple IP addresses:
|
||||
|
||||
{
|
||||
IPv4Address('192.168.1.12'): {
|
||||
<IPProtocol["TCP"]: 'tcp'>: [
|
||||
<Port["POSTGRES_SERVER"]: 5432>
|
||||
<PROTOCOL_LOOKUP["TCP"]: 'tcp'>: [
|
||||
<PORT_LOOKUP["POSTGRES_SERVER"]: 5432>
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -202,9 +202,9 @@ Perform a vertical port scan on multiple ports on a single IP address:
|
||||
|
||||
{
|
||||
IPv4Address('192.168.1.12'): {
|
||||
<IPProtocol["TCP"]: 'tcp'>: [
|
||||
<Port["FTP"]: 21>,
|
||||
<Port["HTTP"]: 80>
|
||||
<PROTOCOL_LOOKUP["TCP"]: 'tcp'>: [
|
||||
<PORT_LOOKUP["FTP"]: 21>,
|
||||
<PORT_LOOKUP["HTTP"]: 80>
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -243,15 +243,15 @@ Perform a box scan on multiple ports across multiple IP addresses:
|
||||
|
||||
{
|
||||
IPv4Address('192.168.1.13'): {
|
||||
<IPProtocol["TCP"]: 'tcp'>: [
|
||||
<Port["FTP"]: 21>,
|
||||
<Port["HTTP"]: 80>
|
||||
<PROTOCOL_LOOKUP["TCP"]: 'tcp'>: [
|
||||
<PORT_LOOKUP["FTP"]: 21>,
|
||||
<PORT_LOOKUP["HTTP"]: 80>
|
||||
]
|
||||
},
|
||||
IPv4Address('192.168.1.12'): {
|
||||
<IPProtocol["TCP"]: 'tcp'>: [
|
||||
<Port["FTP"]: 21>,
|
||||
<Port["HTTP"]: 80>
|
||||
<PROTOCOL_LOOKUP["TCP"]: 'tcp'>: [
|
||||
<PORT_LOOKUP["FTP"]: 21>,
|
||||
<PORT_LOOKUP["HTTP"]: 80>
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -291,36 +291,36 @@ Perform a full box scan on all ports, over both TCP and UDP, on a whole subnet:
|
||||
|
||||
{
|
||||
IPv4Address('192.168.1.11'): {
|
||||
<IPProtocol["UDP"]: 'udp'>: [
|
||||
<Port["ARP"]: 219>
|
||||
<PROTOCOL_LOOKUP["UDP"]: 'udp'>: [
|
||||
<PORT_LOOKUP["ARP"]: 219>
|
||||
]
|
||||
},
|
||||
IPv4Address('192.168.1.1'): {
|
||||
<IPProtocol["UDP"]: 'udp'>: [
|
||||
<Port["ARP"]: 219>
|
||||
<PROTOCOL_LOOKUP["UDP"]: 'udp'>: [
|
||||
<PORT_LOOKUP["ARP"]: 219>
|
||||
]
|
||||
},
|
||||
IPv4Address('192.168.1.12'): {
|
||||
<IPProtocol["TCP"]: 'tcp'>: [
|
||||
<Port["HTTP"]: 80>,
|
||||
<Port["DNS"]: 53>,
|
||||
<Port["POSTGRES_SERVER"]: 5432>,
|
||||
<Port["FTP"]: 21>
|
||||
<PROTOCOL_LOOKUP["TCP"]: 'tcp'>: [
|
||||
<PORT_LOOKUP["HTTP"]: 80>,
|
||||
<PORT_LOOKUP["DNS"]: 53>,
|
||||
<PORT_LOOKUP["POSTGRES_SERVER"]: 5432>,
|
||||
<PORT_LOOKUP["FTP"]: 21>
|
||||
],
|
||||
<IPProtocol["UDP"]: 'udp'>: [
|
||||
<Port["NTP"]: 123>,
|
||||
<Port["ARP"]: 219>
|
||||
<PROTOCOL_LOOKUP["UDP"]: 'udp'>: [
|
||||
<PORT_LOOKUP["NTP"]: 123>,
|
||||
<PORT_LOOKUP["ARP"]: 219>
|
||||
]
|
||||
},
|
||||
IPv4Address('192.168.1.13'): {
|
||||
<IPProtocol["TCP"]: 'tcp'>: [
|
||||
<Port["HTTP"]: 80>,
|
||||
<Port["DNS"]: 53>,
|
||||
<Port["FTP"]: 21>
|
||||
<PROTOCOL_LOOKUP["TCP"]: 'tcp'>: [
|
||||
<PORT_LOOKUP["HTTP"]: 80>,
|
||||
<PORT_LOOKUP["DNS"]: 53>,
|
||||
<PORT_LOOKUP["FTP"]: 21>
|
||||
],
|
||||
<IPProtocol["UDP"]: 'udp'>: [
|
||||
<Port["NTP"]: 123>,
|
||||
<Port["ARP"]: 219>
|
||||
<PROTOCOL_LOOKUP["UDP"]: 'udp'>: [
|
||||
<PORT_LOOKUP["NTP"]: 123>,
|
||||
<PORT_LOOKUP["ARP"]: 219>
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ The :ref:`DNSClient` must be configured to use the :ref:`DNSServer`. The :ref:`D
|
||||
web_browser.run()
|
||||
|
||||
# configure the WebBrowser
|
||||
web_browser.target_url = "arcd.com"
|
||||
web_browser.target_url = "example.com"
|
||||
|
||||
# once DNS server is configured with the correct domain mapping
|
||||
# this should work
|
||||
@@ -78,17 +78,15 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_computer
|
||||
hostname: example_computer
|
||||
type: computer
|
||||
...
|
||||
applications:
|
||||
- ref: web_browser
|
||||
type: web-browser
|
||||
options:
|
||||
target_url: http://arcd.com/
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_computer
|
||||
type: computer
|
||||
...
|
||||
applications:
|
||||
- type: web-browser
|
||||
options:
|
||||
target_url: http://example.com/
|
||||
|
||||
Configuration
|
||||
=============
|
||||
@@ -101,11 +99,10 @@ The URL that the ``WebBrowser`` will request when ``get_webpage`` is called with
|
||||
|
||||
The URL can be in any format so long as the domain is within it e.g.
|
||||
|
||||
The domain ``arcd.com`` can be matched by
|
||||
The domain ``example.com`` can be matched by
|
||||
|
||||
- http://arcd.com/
|
||||
- http://arcd.com/users/
|
||||
- arcd.com
|
||||
- http://example.com/
|
||||
- example.com
|
||||
|
||||
|
||||
``Common Attributes``
|
||||
|
||||
@@ -80,17 +80,15 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_server
|
||||
hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- ref: database_service
|
||||
type: database-service
|
||||
options:
|
||||
backup_server_ip: 192.168.0.10
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- type: database-service
|
||||
options:
|
||||
backup_server_ip: 192.168.0.10
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
@@ -70,17 +70,15 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_server
|
||||
hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- ref: dns_client
|
||||
type: dns-client
|
||||
options:
|
||||
dns_server: 192.168.0.10
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- type: dns-client
|
||||
options:
|
||||
dns_server: 192.168.0.10
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
@@ -20,7 +20,7 @@ Key capabilities
|
||||
Usage
|
||||
=====
|
||||
- Install on a Node via the ``SoftwareManager`` to start the database service.
|
||||
- Service runs on TCP port 53 by default. (TODO: TCP for now, should be UDP in future)
|
||||
- Service runs on TCP port 53 by default.
|
||||
|
||||
Implementation
|
||||
==============
|
||||
@@ -58,7 +58,7 @@ Python
|
||||
dns_server.start()
|
||||
|
||||
# configure DatabaseService
|
||||
dns_server.dns_register("arcd.com", IPv4Address("192.168.10.10"))
|
||||
dns_server.dns_register("example.com", IPv4Address("192.168.10.10"))
|
||||
|
||||
|
||||
Via Configuration
|
||||
@@ -67,19 +67,17 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_server
|
||||
hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- ref: dns_server
|
||||
type: dns-server
|
||||
options:
|
||||
domain_mapping:
|
||||
arcd.com: 192.168.0.10
|
||||
another-example.com: 192.168.10.10
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- type: dns-server
|
||||
options:
|
||||
domain_mapping:
|
||||
example.com: 192.168.0.10
|
||||
another-example.com: 192.168.10.10
|
||||
|
||||
Configuration
|
||||
=============
|
||||
@@ -90,7 +88,7 @@ Configuration
|
||||
|
||||
Domain mapping takes the domain and IP Addresses as a key-value pairs i.e.
|
||||
|
||||
If the domain is "arcd.com" and the IP Address attributed to the domain is 192.168.0.10, then the value should be ``arcd.com: 192.168.0.10``
|
||||
If the domain is "example.com" and the IP Address attributed to the domain is 192.168.0.10, then the value should be ``example.com: 192.168.0.10``
|
||||
|
||||
The key must be a string and the IP Address must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ Key features
|
||||
- Connects to the :ref:`FTPServer` via the ``SoftwareManager``.
|
||||
- Simulates FTP requests and FTPPacket transfer across a network
|
||||
- Allows the emulation of FTP commands between an FTP client and server:
|
||||
- PORT: specifies the port that server should connect to on the client (currently only uses ``Port["FTP"]``)
|
||||
- PORT: specifies the port that server should connect to on the client (currently only uses ``PORT_LOOKUP["FTP"]``)
|
||||
- STOR: stores a file from client to server
|
||||
- RETR: retrieves a file from the FTP server
|
||||
- QUIT: disconnect from server
|
||||
@@ -71,15 +71,13 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_server
|
||||
hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- ref: ftp_client
|
||||
type: ftp-client
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- type: ftp-client
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
@@ -67,17 +67,15 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_server
|
||||
hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- ref: ftp_server
|
||||
type: ftp-server
|
||||
options:
|
||||
server_password: test
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- type: ftp-server
|
||||
options:
|
||||
server_password: test
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
@@ -66,17 +66,15 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_server
|
||||
hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- ref: ntp_client
|
||||
type: ntp-client
|
||||
options:
|
||||
ntp_server_ip: 192.168.0.10
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- type: ntp-client
|
||||
options:
|
||||
ntp_server_ip: 192.168.0.10
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
@@ -66,15 +66,13 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_server
|
||||
hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- ref: ntp_server
|
||||
type: ntp-server
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- type: ntp-server
|
||||
|
||||
|
||||
``Common Attributes``
|
||||
|
||||
@@ -89,7 +89,7 @@ Agents can execute local commands without needing to perform a separate remote l
|
||||
...
|
||||
action: node-send-local-command
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: node_a
|
||||
username: admin
|
||||
password: admin
|
||||
command: # Example command - Creates a file called 'cat.png' in the downloads folder.
|
||||
@@ -112,7 +112,7 @@ Agents are able to use the terminal to login into remote nodes via ``SSH`` which
|
||||
...
|
||||
action: node-session-remote-login
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: node_a
|
||||
username: admin
|
||||
password: admin
|
||||
remote_ip: 192.168.0.10 # Example Ip Address. (The remote host's IP that will be used by ssh)
|
||||
@@ -129,7 +129,7 @@ After remotely logging into another host, an agent can use the ``node-send-remot
|
||||
...
|
||||
action: node-send-remote-command
|
||||
options:
|
||||
node_id: 0
|
||||
node_name: node_a
|
||||
remote_ip: 192.168.0.10
|
||||
command:
|
||||
- "file_system"
|
||||
|
||||
@@ -21,7 +21,7 @@ Usage
|
||||
=====
|
||||
|
||||
- Install on a Node via the ``SoftwareManager`` to start the `WebServer`.
|
||||
- Service runs on HTTP port 80 by default. (TODO: HTTPS)
|
||||
- Service runs on HTTP port 80 by default.
|
||||
- A :ref:`DatabaseClient` must be installed and configured on the same node as the ``WebServer`` if it is intended to send a users request i.e.
|
||||
in the case that the :ref:`WebBrowser` sends a request with users in its request path, the ``WebServer`` will utilise the ``DatabaseClient`` to send a request to the ``DatabaseService``
|
||||
|
||||
@@ -66,15 +66,13 @@ Via Configuration
|
||||
.. code-block:: yaml
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- ref: example_server
|
||||
hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- ref: web_server
|
||||
type: web-server
|
||||
network:
|
||||
nodes:
|
||||
- hostname: example_server
|
||||
type: server
|
||||
...
|
||||
services:
|
||||
- type: web-server
|
||||
|
||||
|
||||
``Common Attributes``
|
||||
|
||||
@@ -7,8 +7,7 @@ Simulation Structure
|
||||
====================
|
||||
|
||||
The simulation is made up of many smaller components which are related to each other in a tree-like structure. At the
|
||||
top level, there is the :py:meth:`primaite.simulator.sim_container.Simulation`, which keeps track of the physical network
|
||||
and a domain controller for managing software and users.
|
||||
top level, there is the :py:meth:`primaite.simulator.sim_container.Simulation`, which keeps track of the physical network and a domain controller for managing software and users.
|
||||
|
||||
Each node of the simulation 'tree' has responsibility for creating, deleting, and updating its direct descendants. Also,
|
||||
when a component's ``describe_state()`` method is called, it will include the state of its descendants. The
|
||||
@@ -25,48 +24,54 @@ relationship between components.
|
||||
|
||||
Actions
|
||||
=======
|
||||
Agents can interact with the simulation by using actions. Actions are standardised with the
|
||||
:py:class:`primaite.simulation.core.RequestType` class, which just holds a reference to two special functions.
|
||||
Agents can interact with the simulation by using actions. Actions adhere to the Common Action and Observation Space (CAOS) specification, and are converted into Requests for use by the simulation. Requests are standardised via the :py:class:`primaite.simulation.core.RequestType` class, which just holds a reference to two special functions.
|
||||
|
||||
1. The request function itself, it must accept a `request` parameters which is a list of strings that describe what the
|
||||
action should do. It must also accept a `context` dict which can house additional information surrounding the action.
|
||||
For example, the context will typically include information about which entity intiated the action.
|
||||
2. A validator function. This function should return a boolean value that decides if the request is permitted or not.
|
||||
It uses the same paramters as the action function.
|
||||
1. The function that actions the request, it must accept a `request` parameters which is a list of strings that describe what the action should do. It must also accept a `context` dict which can house additional information surrounding the action.
|
||||
2. A validator function. This function should return a boolean value that decides if the request is permitted or not. It uses the same paramters as the action function.
|
||||
|
||||
Action Permissions
|
||||
Action Validation
|
||||
------------------
|
||||
When an agent tries to perform an action on a simulation component, that action will only be executed if the request is
|
||||
validated. For example, some actions can require that an agent is logged into an admin account. Each action defines its
|
||||
When an agent tries to perform an action on a simulation component, that action will only be executed if the request is validated. For example, some actions can require that the target network node is powered on. Each action defines its
|
||||
own permissions using an instance of :py:class:`primaite.simulation.core.ActionPermissionValidator`. The below code
|
||||
snippet demonstrates usage of the ``ActionPermissionValidator``.
|
||||
|
||||
.. code:: python
|
||||
|
||||
from primaite.simulator.core import Action, RequestManager, SimComponent
|
||||
from primaite.simulator.domain.controller import AccountGroup, GroupMembershipValidator
|
||||
from primaite.simulator.core import Action, RequestManager, SimComponent, ActionPermissionValidator
|
||||
from primaite.interface.request import RequestResponse
|
||||
|
||||
class Smartphone(SimComponent):
|
||||
name: str
|
||||
apps = []
|
||||
connected: bool
|
||||
apps: List = []
|
||||
|
||||
class _ConnectedToNetworkValidator(ActionPermissionValidator):
|
||||
|
||||
smartphone: Smarphone
|
||||
"""A reference to the smartphone object."""
|
||||
|
||||
def __call__(self, request: RequestFormat, context: Dict) -> bool:
|
||||
return self.smartphone.connected
|
||||
|
||||
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
am = super()._init_request_manager()
|
||||
am.add_request(
|
||||
"reset_factory_settings",
|
||||
Action(
|
||||
func = lambda request, context: self.reset_factory_settings(),
|
||||
validator = GroupMembershipValidator([AccountGroup.DOMAIN_ADMIN]),
|
||||
ReqeustType(
|
||||
func = lambda request, context: RequestResponse.from_bool(self.reset_factory_settings()),
|
||||
validator = Smartphone._ConnectedToNetworkValidator(smartphone=self),
|
||||
)
|
||||
)
|
||||
|
||||
def reset_factory_settings(self):
|
||||
self.apps = []
|
||||
return True
|
||||
|
||||
phone = Smartphone(name="phone1")
|
||||
phone = Smartphone(name="phone1", connected=False)
|
||||
phone.apply_request(request=["reset_factory_settings"])
|
||||
# >>> False
|
||||
|
||||
# try to wipe the phone as a domain user, this will have no effect
|
||||
phone.apply_action(["reset_factory_settings"], context={"request_source":{"groups":["DOMAIN_USER"]})
|
||||
|
||||
# try to wipe the phone as an admin user, this will wipe the phone
|
||||
phone.apply_action(["reset_factory_settings"], context={"request_source":{"groups":["DOMAIN_ADMIN"]})
|
||||
phone2 = Smartphone(name="phone2", connected=True)
|
||||
phone.apply_request(request=["reset_factory_settings"])
|
||||
# >>> True
|
||||
|
||||
@@ -13,19 +13,67 @@ This code snippet demonstrates how the state information is defined within the `
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Node(SimComponent):
|
||||
class Node(SimComponent, ABC):
|
||||
"""
|
||||
A basic Node class that represents a node on the network.
|
||||
|
||||
This class manages the state of the node, including the NICs (Network Interface Cards), accounts, applications,
|
||||
services, processes, file system, and various managers like ARP, ICMP, SessionManager, and SoftwareManager.
|
||||
|
||||
:param hostname: The node hostname on the network.
|
||||
:param operating_state: The node operating state, either ON or OFF.
|
||||
"""
|
||||
|
||||
operating_state: NodeOperatingState = NodeOperatingState.OFF
|
||||
"The hardware state of the node."
|
||||
network_interfaces: Dict[str, NetworkInterface] = {}
|
||||
"The Network Interfaces on the node."
|
||||
network_interface: Dict[int, NetworkInterface] = {}
|
||||
"The Network Interfaces on the node by port id."
|
||||
accounts: Dict[str, Account] = {}
|
||||
"All accounts on the node."
|
||||
applications: Dict[str, Application] = {}
|
||||
"All applications on the node."
|
||||
services: Dict[str, Service] = {}
|
||||
"All services on the node."
|
||||
processes: Dict[str, Process] = {}
|
||||
"All processes on the node."
|
||||
file_system: FileSystem
|
||||
"The nodes file system."
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
state = super().describe_state()
|
||||
state["operating_state"] = self.operating_state.value
|
||||
state["services"] = {uuid: svc.describe_state() for uuid, svc in self.services.items()}
|
||||
return state
|
||||
...
|
||||
class ConfigSchema(BaseModel, ABC):
|
||||
"""Configuration Schema for Node based classes."""
|
||||
|
||||
class Service(SimComponent):
|
||||
health_state: ServiceHealthState = ServiceHealthState.GOOD
|
||||
def describe_state(self) -> Dict:
|
||||
state = super().describe_state()
|
||||
state["health_state"] = self.health_state.value
|
||||
return state
|
||||
...
|
||||
revealed_to_red: bool = False
|
||||
"Informs whether the node has been revealed to a red agent."
|
||||
|
||||
...
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
Produce a dictionary describing the current state of this object.
|
||||
|
||||
Please see :py:meth:`primaite.simulator.core.SimComponent.describe_state` for a more detailed explanation.
|
||||
|
||||
:return: Current state of this object and child objects.
|
||||
:rtype: Dict
|
||||
"""
|
||||
state = super().describe_state()
|
||||
state.update(
|
||||
{
|
||||
"hostname": self.config.hostname,
|
||||
"operating_state": self.operating_state.value,
|
||||
"NICs": {
|
||||
eth_num: network_interface.describe_state()
|
||||
for eth_num, network_interface in self.network_interface.items()
|
||||
},
|
||||
"file_system": self.file_system.describe_state(),
|
||||
"applications": {app.name: app.describe_state() for app in self.applications.values()},
|
||||
"services": {svc.name: svc.describe_state() for svc in self.services.values()},
|
||||
"process": {proc.name: proc.describe_state() for proc in self.processes.values()},
|
||||
"revealed_to_red": self.config.revealed_to_red,
|
||||
}
|
||||
)
|
||||
return state
|
||||
...
|
||||
|
||||
@@ -92,7 +92,7 @@ order_by_type = "False"
|
||||
line-length = 120
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/{todo:fill in URL}/PrimAITE"
|
||||
Documentation = "https://{todo:fill in URL}.github.io/PrimAITE"
|
||||
Repository = "https://github.com/{todo:fill in URL}/PrimAITE"
|
||||
Changelog = "https://github.com/{todo:fill in URL}/PrimAITE/blob/main/CHANGELOG.md"
|
||||
Homepage = "https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE"
|
||||
Documentation = "https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE"
|
||||
Repository = "https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE"
|
||||
Changelog = "https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE/blob/main/CHANGELOG.md"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[metadata]
|
||||
url = https://github.com/{todo:fill in URL}/PrimAITE
|
||||
url = https://github.com/Autonomous-Resilient-Cyber-Defence/PrimAITE
|
||||
author = Defence Science and Technology Laboratory UK
|
||||
author_email = oss@dstl.gov.uk
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Configuration parameters for running experiments."""
|
||||
"""A collection of example configuration files."""
|
||||
|
||||
@@ -404,7 +404,7 @@ agents:
|
||||
action: "router-acl-add-rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 1
|
||||
position: 0
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: ALL # ALL
|
||||
@@ -417,7 +417,7 @@ agents:
|
||||
action: "router-acl-add-rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 2
|
||||
position: 1
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: ALL # ALL
|
||||
@@ -430,7 +430,7 @@ agents:
|
||||
action: "router-acl-add-rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 3
|
||||
position: 2
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
@@ -443,7 +443,7 @@ agents:
|
||||
action: "router-acl-add-rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 4
|
||||
position: 3
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.12 # web server
|
||||
@@ -456,7 +456,7 @@ agents:
|
||||
action: "router-acl-add-rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 5
|
||||
position: 4
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.21 # client 1
|
||||
dst_ip: 192.168.1.14 # database
|
||||
@@ -469,7 +469,7 @@ agents:
|
||||
action: "router-acl-add-rule"
|
||||
options:
|
||||
target_router: router_1
|
||||
position: 6
|
||||
position: 5
|
||||
permission: DENY
|
||||
src_ip: 192.168.10.22 # client 2
|
||||
dst_ip: 192.168.1.14 # database
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Convenience methods for finding filepaths to default PrimAITE configs."""
|
||||
from pathlib import Path
|
||||
from typing import Dict, Final, Union
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""PrimAITE-specific exceptions."""
|
||||
|
||||
|
||||
class PrimaiteError(Exception):
|
||||
"""The root PrimAITE Error."""
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Agents that act in the environment, including RL and scripted agents, their actions, observations, and rewards."""
|
||||
from primaite.game.agent.interface import ProxyAgent
|
||||
from primaite.game.agent.scripted_agents.data_manipulation_bot import DataManipulationAgent
|
||||
from primaite.game.agent.scripted_agents.probabilistic_agent import ProbabilisticAgent
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
"""Actions convert CAOS data into the request format for the PrimAITE simulation."""
|
||||
from primaite.game.agent.actions import (
|
||||
abstract,
|
||||
acl,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Action base class."""
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Actions for manipulating Access Control Lists (ACLs)."""
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Actions for interacting with applications on network hosts."""
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Actions for interacting with the files on network hosts."""
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Actions for interacting with folders on network hosts."""
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Actions for interacting with network interfact cards (NICs) on network hosts."""
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
# © 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:
|
||||
"""
|
||||
"""Validate and keep track of an agent's action set."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
"""Actions for interacting with network ports of routers, switches, and firewalls."""
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Actions for interacting with nodes on the network."""
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import ClassVar, List, Literal, Optional, Union
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Actions for interacting with services on network hosts."""
|
||||
from abc import ABC
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Actions for performing login and logout on local and remote hosts."""
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from primaite.game.agent.actions.manager import AbstractAction
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
"""Actions for configuring software on network hosts."""
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pydantic import ConfigDict, Field
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Optional logger for internal agent decisions and debugging."""
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
# flake8: noqa
|
||||
# Pre-import all the observations when we load up the observations module so that they can be resolved by the parser.
|
||||
"""Converts PrimAITE simulation data into numerical RL-ready observations."""
|
||||
from primaite.game.agent.observations.acl_observation import ACLObservation
|
||||
from primaite.game.agent.observations.file_system_observations import FileObservation, FolderObservation
|
||||
from primaite.game.agent.observations.firewall_observation import FirewallObservation
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Observations for access control lists (ACLs) on routers and firewalls."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
|
||||
"""Agents that automatically choose their behaviour according to scripted rules."""
|
||||
from primaite.game.agent import interface
|
||||
from primaite.game.agent.scripted_agents import (
|
||||
abstract_tap,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Utility functions used in the PrimAITE game layer."""
|
||||
from typing import Any, Dict, Hashable, Optional, Sequence
|
||||
|
||||
NOT_PRESENT_IN_STATE = object()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""Mathematical methods used in PrimAITE."""
|
||||
from random import random
|
||||
from typing import Any, Iterable, Mapping
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
|
||||
"""The interface between the simulation and game layers of PrimAITE."""
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"PrimAITE environments support action masking. The action mask shows which of the agent's actions are applicable with the current environment state. For example, a node can only be turned on if it is currently turned off."
|
||||
"PrimAITE environments support action masking. The action mask shows which of the agent's actions are applicable with the current environment state. For example, a node can only be turned on if it is currently turned off. Please refer to the action masking configuration user guide page for more information."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -151,7 +151,10 @@
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Action masking with MARL in Ray RLLib\n",
|
||||
"Each agent has their own action mask, this is useful if the agents have different action spaces."
|
||||
"\n",
|
||||
"Each agent has their own action mask which is useful for multi-agent environments where each agent are configured with different action spaces.\n",
|
||||
"\n",
|
||||
"The code snippets below demonstrate how users can use multiple agents with action masks using the [UC2 MARL example config](./Training-an-RLLIB-MARL-System.ipynb)."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"\n",
|
||||
"This notebook uses the same network setup as UC2. Please refer to the main [UC2-E2E-Demo notebook for further reference](./Data-Manipulation-E2E-Demonstration.ipynb).\n",
|
||||
"\n",
|
||||
"However, this notebook replaces the red agent used in UC2 with a custom proxy red agent built for this notebook."
|
||||
"However, this notebook replaces the red agent used in UC2 with a custom proxy red agent built for this notebook. This allows us to control the red agent manually via `env.step()` in the same way that other notebooks use the blue agent."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -159,9 +159,9 @@
|
||||
"## **Notebook Setup** | Network Prerequisites\n",
|
||||
"\n",
|
||||
"Before the Red Agent is able to perform any C2 specific actions, the C2 Server needs to be installed and run.\n",
|
||||
"This is because in higher fidelity environments (and the real-world) a C2 server would not be accessible by a private network blue agent and the C2 Server would already be in place before the an adversary (Red Agent) starts.\n",
|
||||
"This is because in higher fidelity environments (and the real-world) a C2 server would not be accessible by a private network blue agent and the C2 Server would already be in place before an adversary (red agent) began it's direct attack.\n",
|
||||
"\n",
|
||||
"The cells below install and run the C2 Server on client_1 directly via the simulation API."
|
||||
"The cells below install and run the C2 Server on **client_1** directly via the simulation API."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -192,26 +192,17 @@
|
||||
"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",
|
||||
"The below yaml snippet shows all the relevant agent options for this action:\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",
|
||||
"```yaml\n",
|
||||
" action_space:\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" - node_name: web_server\n",
|
||||
" applications: \n",
|
||||
" - application_name: c2-beacon\n",
|
||||
" ...\n",
|
||||
" ...\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",
|
||||
" node_name: web_server\n",
|
||||
" application_name: c2-beacon\n",
|
||||
"```"
|
||||
]
|
||||
@@ -231,11 +222,9 @@
|
||||
"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",
|
||||
"The yaml snippet below shows all the relevant agent options for this action:\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",
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
@@ -269,11 +258,9 @@
|
||||
"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",
|
||||
"\n",
|
||||
"The yaml snippet below shows all the relevant agent options for this action:\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",
|
||||
"```yaml\n",
|
||||
" action_space:\n",
|
||||
@@ -321,18 +308,16 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Server Actions | c2-server-terminal-command\n",
|
||||
"### **Command and Control** | C2 Server Actions | `c2-server-terminal-command`\n",
|
||||
"\n",
|
||||
"The C2 Server's terminal action: ``c2-server-terminal-command`` is indexed at ``4`` in it's action map. \n",
|
||||
"\n",
|
||||
"This action leverages the terminal service that is installed by default on all nodes to grant red agents a lot more configurability. If you're unfamiliar with terminals then it's recommended that you refer to the ``Terminal Processing`` notebook.\n",
|
||||
"This action leverages the terminal service that is installed by default on all nodes to grant red agents a lot more configurability. If you're unfamiliar with terminals then it's recommended that you refer to the [Terminal-Processing notebook](./Terminal-Processing.ipynb) for more info.\n",
|
||||
"\n",
|
||||
"It's worth noting that an additional benefit a red agent has when using the terminal service via the C2 Server is that you can execute multiple commands in one action. \n",
|
||||
"\n",
|
||||
"In this notebook, the ``c2-server-terminal-command`` is used to install a RansomwareScript application on the ``web_server`` node.\n",
|
||||
"\n",
|
||||
"The yaml snippet below shows all the relevant agent options for this action:\n",
|
||||
"\n",
|
||||
"``` yaml\n",
|
||||
" action_space:\n",
|
||||
" action_map:\n",
|
||||
@@ -376,11 +361,9 @@
|
||||
"source": [
|
||||
"### **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",
|
||||
"Another action offered by the C2 server grants a red agent the ability to configure the `RansomwareScript` via the C2 Server rather than the node directly.\n",
|
||||
"\n",
|
||||
"This action is indexed as action ``5``.\n",
|
||||
"\n",
|
||||
"The yaml snippet below shows all the relevant agent options for this action:\n",
|
||||
"This action is indexed as action ``5``\n",
|
||||
"\n",
|
||||
"``` yaml\n",
|
||||
" action_space:\n",
|
||||
@@ -418,27 +401,25 @@
|
||||
"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",
|
||||
"\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",
|
||||
"The below yaml snippet shows all the relevant agent options for this action:\n",
|
||||
"\n",
|
||||
"``` yaml\n",
|
||||
" action_space:\n",
|
||||
" action_map:\n",
|
||||
" 6:\n",
|
||||
" 6:\n",
|
||||
" action: c2-server-data-exfiltrate\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" node_name: client_1\n",
|
||||
" target_file_name: \"database.db\"\n",
|
||||
" target_folder_name: \"database\"\n",
|
||||
" exfiltration_folder_name: \"spoils\"\n",
|
||||
" target_ip_address: \"192.168.1.14\"\n",
|
||||
" username: \"admin\"\n",
|
||||
" password: \"admin\"\n",
|
||||
" target_ip_address: 192.168.1.14\n",
|
||||
" username: admin\n",
|
||||
" password: admin\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
@@ -476,21 +457,17 @@
|
||||
"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",
|
||||
"\n",
|
||||
"This action is indexed as action ``7``.\n",
|
||||
"\n",
|
||||
"\"The yaml snippet below shows all the relevant agent options for this action:\n",
|
||||
"Finally, the last available action is for the c2-server-ransomware-launch to start the ransomware script installed previously:\n",
|
||||
"\n",
|
||||
"``` yaml\n",
|
||||
" action_space:\n",
|
||||
" action_map:\n",
|
||||
" 7:\n",
|
||||
" 7:\n",
|
||||
" action: c2-server-ransomware-launch\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" node_name: client_1\n",
|
||||
"```\n"
|
||||
]
|
||||
},
|
||||
@@ -770,11 +747,11 @@
|
||||
"source": [
|
||||
"#### **Command and Control** | OBS Impact | C2 Server | Terminal Command\n",
|
||||
"\n",
|
||||
"Using the C2 Server's ``TERMINAL`` command it is possible to install a ``RansomwareScript`` application onto the C2 Beacon's host.\n",
|
||||
"As shown, we can use the C2 Server to install the ``RansomwareScript`` application onto the C2 Beacon's host.\n",
|
||||
"\n",
|
||||
"The below code cells perform this as well as capturing the OBS impacts.\n",
|
||||
"\n",
|
||||
"It's important to note that the ``TERMINAL`` command is not limited to just installing software."
|
||||
"It's important to note that the ``c2-server-terminal-command`` action is not limited to just installing software as shown in the [Terminal-Processing](./Terminal-Processing.ipynb) notebook."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -783,7 +760,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Installing RansomwareScript via C2 Terminal Commands\n",
|
||||
"# Installing RansomwareScript via C2 Terminal Commands (This is via the PrimAITE simulation rather than the c2-server-terminal-command action)\n",
|
||||
"ransomware_install_command = {\"commands\":[[\"software_manager\", \"application\", \"install\", \"ransomware-script\"]],\n",
|
||||
" \"username\": \"admin\",\n",
|
||||
" \"password\": \"admin\"}\n",
|
||||
@@ -826,7 +803,7 @@
|
||||
"source": [
|
||||
"#### **Command and Control** | OBS Impact | C2 Server | Data Exfiltration\n",
|
||||
"\n",
|
||||
"Before encrypting the database.db file, the ``DATA_EXFILTRATION`` command can be used to copy the database.db file onto both the C2 Server and the C2 Beacon's file systems:"
|
||||
"Before encrypting the database.db file, we can use the exfiltration command to copy the database.db file onto both the C2 Server and the C2 Beacon's file systems:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -988,7 +965,17 @@
|
||||
"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:\n",
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
" action_space:\n",
|
||||
" action_map:\n",
|
||||
" 1:\n",
|
||||
" action: node-application-remove\n",
|
||||
" options:\n",
|
||||
" node_name: web_server\n",
|
||||
" application_name: c2-beacon\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1005,7 +992,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Which we can see after the effects of after stepping another timestep and looking at the web_servers software manager and the OBS differences."
|
||||
"Which we can see after the effects of after stepping another timestep and looking at the **web_server**'s software manager and the OBS differences."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1083,7 +1070,16 @@
|
||||
"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.\n",
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
" action_space:\n",
|
||||
" action_map:\n",
|
||||
" 2:\n",
|
||||
" action: node-shutdown\n",
|
||||
" options:\n",
|
||||
" node_name: web_server\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1173,7 +1169,27 @@
|
||||
"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_add_rule 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.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
" action_space:\n",
|
||||
" action_map:\n",
|
||||
" 3:\n",
|
||||
" action: router-acl-add-rule\n",
|
||||
" options:\n",
|
||||
" target_router: router_1\n",
|
||||
" position: 1\n",
|
||||
" permission: DENY\n",
|
||||
" src_ip: 192.168.10.21\n",
|
||||
" dst_ip: 192.168.1.12\n",
|
||||
" src_port: HTTP\n",
|
||||
" dst_port: HTTP\n",
|
||||
" protocol_name: ALL\n",
|
||||
" src_wildcard: 0.0.0.1\n",
|
||||
" dst_wildcard: 0.0.0.1\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1236,7 +1252,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Because of the ACL rule the C2 beacon never received the ransomware installation and execute commands from the C2 server:"
|
||||
"Because of the ACL rule the C2 beacon never receives the ransomware installation and execute commands from the C2 server:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1254,7 +1270,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"database_server: Server = blue_env.game.simulation.network.get_node_by_hostname(\"database-server\")\n",
|
||||
"database_server: Server = blue_env.game.simulation.network.get_node_by_hostname(\"database_server\")\n",
|
||||
"database_server.software_manager.file_system.show(full=True)"
|
||||
]
|
||||
},
|
||||
@@ -1317,11 +1333,11 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | Configurability | C2 Server IP Address\n",
|
||||
"### **Command and Control** | Configurability | `c2_server_ip_address`\n",
|
||||
"\n",
|
||||
"As with a majority of client and server based application configurations in primaite, the remote IP of a server must be supplied.\n",
|
||||
"\n",
|
||||
"In the case of the C2 Beacon, the C2 Server's IP address must be supplied before the C2 beacon will be able to perform any other actions (including ``APPLICATION EXECUTE``).\n",
|
||||
"In the case of the C2 Beacon, the C2 Server's IP address must be supplied before the C2 beacon will be able to perform any other actions.\n",
|
||||
"\n",
|
||||
"If the network contains multiple C2 Servers then it's also possible to switch to a different C2 server mid-episode which is demonstrated in the below code cells."
|
||||
]
|
||||
@@ -1374,7 +1390,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Configuring the C2 Beacon to establish connection to the C2 Server on client_1 (192.168.10.21)"
|
||||
"Configuring the C2 Beacon to establish connection to the C2 Server on **client_1** (*192.168.10.21)*"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1393,7 +1409,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now reconfiguring the C2 Beacon to establish connection to the C2 Server on client_2 (192.168.10.22)"
|
||||
"Now reconfiguring the C2 Beacon to establish connection to the C2 Server on **client_2** (*192.168.10.22*)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1413,7 +1429,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"After six timesteps the client_1 server will recognise the C2 beacon's previous connection as dead and clear its connections. (This is dependent on the ``Keep Alive Frequency`` setting.)"
|
||||
"After six timesteps the client_1 server will recognise the C2 beacon's previous connection as dead and clear its connections. (This is dependent on the ``keep_alive_frequency`` setting.)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1432,9 +1448,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | Configurability | Keep Alive Frequency\n",
|
||||
"### **Command and Control** | Configurability | `keep_alive_frequency`\n",
|
||||
"\n",
|
||||
"In order to confirm it's connection the C2 Beacon will send out a ``Keep Alive`` to the C2 Server and receive a keep alive back. \n",
|
||||
"In order to confirm it's connection the C2 Beacon will send out a keep alive packet to the C2 Server and expects a keep alive sent back. \n",
|
||||
"\n",
|
||||
"By default, this occurs every 5 timesteps. However, this setting can be configured to be much more infrequent or as frequent as every timestep. \n",
|
||||
"\n",
|
||||
@@ -1480,7 +1496,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The next code cells capture the obs impact of the default Keep Alive Frequency which is 5 timesteps:"
|
||||
"The next code cells capture the obs impact of the default `keep_alive_frequency` which is 5 timesteps:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1536,7 +1552,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Demonstrating that the observation impacts of the Keep Alive can be seen on every timestep:"
|
||||
"Now the keep alive's observation impacts can be seen on every timestep:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1555,7 +1571,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Lastly, the keep_alive_frequency can also be used to configure the C2 Beacon to confirm connection less frequently. \n",
|
||||
"Lastly, the `keep_alive_frequency` can also be used to configure the C2 Beacon to confirm connection less frequently. \n",
|
||||
"\n",
|
||||
"The code cells below demonstrate the impacts of changing the frequency rate to ``7`` timesteps."
|
||||
]
|
||||
@@ -1578,7 +1594,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | Configurability | Masquerade Port & Masquerade Protocol\n",
|
||||
"### **Command and Control** | Configurability | `masquerade_port` & `masquerade_protocol`\n",
|
||||
"\n",
|
||||
"The final configurable options are ``Masquerade Port`` & ``Masquerade Protocol``. These options can be used to control the networking IP Protocol and Port the C2 traffic is currently using.\n",
|
||||
"\n",
|
||||
@@ -1586,7 +1602,7 @@
|
||||
"\n",
|
||||
"In primAITE, red agents can begin to simulate stealth behaviour by configuring C2 traffic to use different protocols mid episode or between episodes.\n",
|
||||
"\n",
|
||||
"Currently, red agent actions support the following port and protocol options:\n",
|
||||
"Currently, the C2 Suite support the following port and protocol options:\n",
|
||||
"\n",
|
||||
"| Supported Ports | Supported Protocols |\n",
|
||||
"|------------------|---------------------|\n",
|
||||
@@ -1640,7 +1656,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"However, C2 Beacon can be configured to use UDP (``Masquerade Protocol``) and we can also configure the C2 Beacon to use a different Port (``Masquerade Port``) for example ``DNS``. "
|
||||
"But we can use the aforementioned options to configure the C2 Beacon to use different protocol and port such as a `UDP` and `DNS`. "
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1677,7 +1693,6 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"env.game.agents[\"CustomC2Agent\"].show_history()"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"This notebook will go over some examples of how red agent behaviour can be varied by changing its configuration parameters.\n",
|
||||
"This notebook will go over some examples of how UC2 red agent behaviour can be varied by changing its configuration parameters.\n",
|
||||
"\n",
|
||||
"First, let's load the standard Data Manipulation config file, and see what the red agent does.\n",
|
||||
"\n",
|
||||
"*(For a full explanation of the Data Manipulation scenario, check out the data manipulation scenario notebook)*"
|
||||
"*For a full explanation of the Data Manipulation scenario (also known as UC2), check out the [data manipulation scenario notebook](./Data-Manipulation-E2E-Demonstration.ipynb)*"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -175,22 +175,20 @@
|
||||
" network:\n",
|
||||
" nodes:\n",
|
||||
" - hostname: client_1\n",
|
||||
" type: computer\n",
|
||||
" ip_address: 192.168.10.21\n",
|
||||
" subnet_mask: 255.255.255.0\n",
|
||||
" default_gateway: 192.168.10.1\n",
|
||||
" \n",
|
||||
" # \n",
|
||||
" applications:\n",
|
||||
" - type: data-manipulation-bot\n",
|
||||
" options:\n",
|
||||
" port_scan_p_of_success: 0.8 # Probability that port scan is successful\n",
|
||||
" data_manipulation_p_of_success: 0.8 # Probability that SQL attack is successful\n",
|
||||
" payload: \"DELETE\" # The SQL query which causes the attack (this has to be DELETE)\n",
|
||||
" server_ip: 192.168.1.14 # IP address of server hosting the database\n",
|
||||
" - type: database-client # Database client must be installed in order for DataManipulationBot to function\n",
|
||||
" options:\n",
|
||||
" db_server_ip: 192.168.1.14 # IP address of server hosting the database\n",
|
||||
" type: computer\n",
|
||||
" ip_address: 192.168.10.21\n",
|
||||
" subnet_mask: 255.255.255.0\n",
|
||||
" default_gateway: 192.168.10.1\n",
|
||||
" applications:\n",
|
||||
" - type: data-manipulation-bot\n",
|
||||
" options:\n",
|
||||
" port_scan_p_of_success: 0.8 # Probability that port scan is successful\n",
|
||||
" data_manipulation_p_of_success: 0.8 # Probability that SQL attack is successful\n",
|
||||
" payload: \"DELETE\" # The SQL query which causes the attack (this has to be DELETE)\n",
|
||||
" server_ip: 192.168.1.14 # IP address of server hosting the database\n",
|
||||
" - type: database-client # Database client must be installed in order for DataManipulationBot to function\n",
|
||||
" options:\n",
|
||||
" db_server_ip: 192.168.1.14 # IP address of server hosting the database\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -90,21 +90,21 @@
|
||||
"source": [
|
||||
"## Scripted agents:\n",
|
||||
"### Red\n",
|
||||
"The red agent sits on a client and uses an application called DataManipulationBot whose sole purpose is to send a DELETE query to the database.\n",
|
||||
"The red agent sits on a client and uses an application called **DataManipulationBot** whose sole purpose is to send a DELETE query to the database.\n",
|
||||
"The red agent can choose one of two action each timestep:\n",
|
||||
"1. do nothing\n",
|
||||
"2. execute the data manipulation application\n",
|
||||
"The schedule for selecting when to execute the application is controlled by three parameters:\n",
|
||||
"- start time\n",
|
||||
"- frequency\n",
|
||||
"- variance\n",
|
||||
" - start time\n",
|
||||
" - frequency\n",
|
||||
" - variance\n",
|
||||
"\n",
|
||||
"Attacks start at a random timestep between (start_time - variance) and (start_time + variance). After each attack, another is attempted after a random delay between (frequency - variance) and (frequency + variance) timesteps.\n",
|
||||
"\n",
|
||||
"The data manipulation app itself has an element of randomness because the attack has a probability of success. The default is 0.8 to succeed with the port scan step and 0.8 to succeed with the attack itself.\n",
|
||||
"Upon a successful attack, the database file becomes corrupted which incurs a negative reward for the RL defender.\n",
|
||||
"\n",
|
||||
"The red agent does not use information about the state of the network to decide its action.\n",
|
||||
"*The red agent does not use information about the state of the network to decide its action. For a more complex red agent please refer to the [UC7 scenario](./UC7-E2E-Demo.ipynb)*\n",
|
||||
"\n",
|
||||
"### Green\n",
|
||||
"The green agents use the web browser application to send requests to the web server. The schedule of each green agent is currently random, it will do nothing 30% of the time, send a web request 60% of the time, and send a db status check 10% of the time.\n",
|
||||
@@ -121,42 +121,50 @@
|
||||
"## Observation Space\n",
|
||||
"\n",
|
||||
"The blue agent's observation space is structured as nested dictionary with the following information:\n",
|
||||
"```\n",
|
||||
"``` yaml\n",
|
||||
"\n",
|
||||
"- ICS\n",
|
||||
"- LINKS\n",
|
||||
" - <link_id>\n",
|
||||
" - PROTOCOLS\n",
|
||||
" - <protocol>\n",
|
||||
" - load\n",
|
||||
"- NODES\n",
|
||||
" - <node_id 1-7>\n",
|
||||
" - <node_id>\n",
|
||||
" - SERVICES\n",
|
||||
" - <service_id 1-1>\n",
|
||||
" - <service_id>\n",
|
||||
" - operating_status\n",
|
||||
" - health_status\n",
|
||||
" - FOLDERS\n",
|
||||
" - <folder_id 1-1>\n",
|
||||
" - <folder_id>\n",
|
||||
" - health_status\n",
|
||||
" - FILES\n",
|
||||
" - <file_id 1-1>\n",
|
||||
" - <file_id>\n",
|
||||
" - health_status\n",
|
||||
" - NETWORK_INTERFACES\n",
|
||||
" - <nic_id 1-2>\n",
|
||||
" - <nic_id>\n",
|
||||
" - nic_status\n",
|
||||
" - nmne\n",
|
||||
" - inbound\n",
|
||||
" - outbound\n",
|
||||
" - operating_status\n",
|
||||
"- LINKS\n",
|
||||
" - <link_id 1-10>\n",
|
||||
" - PROTOCOLS\n",
|
||||
" - ALL\n",
|
||||
" - load\n",
|
||||
"- ACL\n",
|
||||
" - <rule_number 1-10>\n",
|
||||
" - position\n",
|
||||
" - permission\n",
|
||||
" - source_node_id\n",
|
||||
" - source_port\n",
|
||||
" - dest_node_id\n",
|
||||
" - dest_port\n",
|
||||
" - protocol\n",
|
||||
"- ICS\n",
|
||||
" - users \n",
|
||||
" - local_login\n",
|
||||
" - remote_sessions\n",
|
||||
" - <router_id>\n",
|
||||
" - ACL\n",
|
||||
" - <rule_number 1-10>\n",
|
||||
" - position\n",
|
||||
" - permission\n",
|
||||
" - source_node_id\n",
|
||||
" - source_port\n",
|
||||
" - dest_node_id\n",
|
||||
" - dest_port\n",
|
||||
" - protocol\n",
|
||||
" - users \n",
|
||||
" - local_login\n",
|
||||
" - remote_session\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### Mappings\n",
|
||||
@@ -447,13 +455,20 @@
|
||||
" red_info : AgentHistoryItem = info['agent_actions']['data_manipulation_attacker']\n",
|
||||
" red_action = red_info.action\n",
|
||||
" if red_action == 'do-nothing':\n",
|
||||
" red_str = 'DO NOTHING'\n",
|
||||
" red_str = \"do-nothing\"\n",
|
||||
" elif red_action == 'node-application-execute':\n",
|
||||
" client = \"client 1\" if red_info.parameters['node_name'] == 0 else \"client 2\"\n",
|
||||
" client = \"client 1\" if red_info.parameters['node_name'] == \"client_1\" else \"client_2\"\n",
|
||||
" red_str = f\"ATTACK from {client}\"\n",
|
||||
" return red_str"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Also, the NMNE outbound of either client 1 (node 5) or client 2 (node 6) has increased from 0 to 1. This tells us which client is being used by the red agent."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -462,7 +477,25 @@
|
||||
"source": [
|
||||
"for step in range(35):\n",
|
||||
" obs, reward, terminated, truncated, info = env.step(0)\n",
|
||||
" print(f\"step: {env.game.step_counter}, Red action: {friendly_output_red_action(info)}, Blue reward:{reward:.2f}\" )"
|
||||
" red_info : AgentHistoryItem = info['agent_actions']['data_manipulation_attacker']\n",
|
||||
" red_action = red_info.action\n",
|
||||
" if red_action == 'do-nothing':\n",
|
||||
" pass\n",
|
||||
" else:\n",
|
||||
" # Immediate drop in reward from the red agent attack.\n",
|
||||
" print(f\"step: {env.game.step_counter}, Red action: {friendly_output_red_action(info)}, Blue reward: {reward:.2f}\" )\n",
|
||||
" print(f\"step: {env.game.step_counter}, client 1 NMNE: {obs['NODES']['HOST5']['NICS'][1]['NMNE']}\")\n",
|
||||
" print(f\"step: {env.game.step_counter}, client 2 NMNE: {obs['NODES']['HOST6']['NICS'][1]['NMNE']}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Reward drops even further as green agents are unable to access the web-server after the red agent attack\n",
|
||||
"print(f\"step: {env.game.step_counter}, Current (Post Attack) Blue reward: {reward:.2f}\" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -472,20 +505,11 @@
|
||||
"Now the reward is -0.8, let's have a look at blue agent's observation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pprint(obs['NODES'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The true statuses of the database file and webapp are not updated. The blue agent needs to perform a scan to see that they have degraded."
|
||||
"The true statuses of the database file and web-server are not updated. The blue agent needs to perform a scan to see that they have degraded."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -495,26 +519,19 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"obs, reward, terminated, truncated, info = env.step(9) # scan database file\n",
|
||||
"obs, reward, terminated, truncated, info = env.step(1) # scan webapp service\n",
|
||||
"\n",
|
||||
"pprint(obs['NODES'])\n"
|
||||
"print(f\"step: {env.game.step_counter}, database file obs: {obs['NODES']['HOST2']['FOLDERS'][1]['FILES']}\")\n",
|
||||
"obs, reward, terminated, truncated, info = env.step(1) # scan web-server service\n",
|
||||
"print(f\"step: {env.game.step_counter}, webserver status {obs['NODES']['HOST1']['SERVICES'][1]}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now service 1 on HOST1 has `health_status = 3`, indicating that the webapp is compromised.\n",
|
||||
"Now service 1 on HOST1 has `health_status = 3`, indicating that the web-server is compromised.\n",
|
||||
"File 1 in folder 1 on HOST2 has `health_status = 2`, indicating that the database file is compromised."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Also, the NMNE outbound of either client 1 (node 6) or client 2 (node 7) has increased from 0 to 1. This tells us which client is being used by the red agent."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -533,7 +550,7 @@
|
||||
"print(f\"Red action: {info['agent_actions']['data_manipulation_attacker'].action}\" )\n",
|
||||
"print(f\"Green action: {info['agent_actions']['client_1_green_user'].action}\" )\n",
|
||||
"print(f\"Green action: {info['agent_actions']['client_2_green_user'].action}\" )\n",
|
||||
"print(f\"Blue reward:{reward}\" )"
|
||||
"print(f\"Blue reward: {reward}\" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -556,9 +573,9 @@
|
||||
"obs, reward, terminated, truncated, info = env.step(0) # do nothing\n",
|
||||
"print(f\"step: {env.game.step_counter}\")\n",
|
||||
"print(f\"Red action: {info['agent_actions']['data_manipulation_attacker'].action}\" )\n",
|
||||
"print(f\"Green action: {info['agent_actions']['client_2_green_user']}\" )\n",
|
||||
"print(f\"Green action: {info['agent_actions']['client_1_green_user']}\" )\n",
|
||||
"print(f\"Blue reward:{reward:.2f}\" )"
|
||||
"print(f\"Green action: {info['agent_actions']['client_2_green_user'].action}\" )\n",
|
||||
"print(f\"Green action: {info['agent_actions']['client_1_green_user'].action}\" )\n",
|
||||
"print(f\"Blue reward: {reward:.2f}\" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -603,7 +620,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's also have a look at the ACL observation to verify our new ACL rule at positions 5 and 6."
|
||||
"Let's also have a look at the ACL observation to verify our new ACL rule at positions 4 and 5."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -612,7 +629,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"obs['NODES']['ROUTER0']"
|
||||
"pprint(obs['NODES']['ROUTER0']['ACL'][4])\n",
|
||||
"pprint(obs['NODES']['ROUTER0']['ACL'][5])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -685,36 +703,15 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Reset the environment, you can rerun the other cells to verify that the attack works the same every episode. (except the red agent will move between `client_1` and `client_2`.)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.reset()"
|
||||
"You can rerun the notebook to verify that the attack works the same every episode. (except the red agent will move between `client_1` and `client_2`.)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
"# Imports\n",
|
||||
"import yaml\n",
|
||||
"from primaite import PRIMAITE_CONFIG\n",
|
||||
"\n",
|
||||
"from primaite.config.load import data_manipulation_config_path\n",
|
||||
"from primaite.session.environment import PrimaiteGymEnv\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.computer import Computer\n",
|
||||
@@ -39,7 +38,14 @@
|
||||
"with open(data_manipulation_config_path(), 'r') as f:\n",
|
||||
" cfg = yaml.safe_load(f)\n",
|
||||
"\n",
|
||||
"env = PrimaiteGymEnv(env_config=cfg)\n"
|
||||
"env = PrimaiteGymEnv(env_config=cfg)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook opts to use the [data manipulation scenario](./Data-Manipulation-E2E-Demonstration.ipynb) (also known as UC2) network configuration but all of the methods demonstrated are config agnostic and can be used in any PrimAITE scenario."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -53,7 +59,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The network can be visualised by running the code below."
|
||||
"Some of the simpler networks can be visualised by using the `.draw()` method as show in the code snippet below. \n",
|
||||
"\n",
|
||||
"Larger networks will still render but users may prefer to create their own network diagrams via other tooling as shown in the [UC7 notebooks](./UC7-E2E-Demo.ipynb)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -75,7 +83,7 @@
|
||||
"\n",
|
||||
"Any object created using the ``SimComponent`` class has a ``describe_state`` method which can show the state of the object.\n",
|
||||
"\n",
|
||||
"An example of such an object is ``Computer`` which inherits from ``SimComponent``. In the default network configuration, ``client_1`` is a Computer object."
|
||||
"An example of such an object is ``Computer`` which inherits from ``SimComponent``. As this notebook utilises the [UC2 network configuration]((./Data-Manipulation-E2E-Demonstration.ipynb)) we can initialise the **client_1** node and confirm that it's a ``Computer`` object."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -94,9 +102,9 @@
|
||||
"source": [
|
||||
"### More specific describe_state\n",
|
||||
"\n",
|
||||
"As you can see, the output from the ``describe_state`` method for the ``Computer`` object includes the describe state for all its components. This can cause a large describe state output.\n",
|
||||
"As you can see, the output from the ``describe_state`` method for the ``Computer`` object includes the describe state for all its component which causes a rather large output.\n",
|
||||
"\n",
|
||||
"As stated, the ``describe_state`` can be called on any object that inherits ``SimComponent``. This can allow you retrieve the state of a specific item."
|
||||
"As stated, the ``describe_state`` can be called on any object that inherits ``SimComponent``. Meaning, we can narrow down our output by retrieving the state of a specific item. The code snippet below calls the `describe_state` method on **client_1**'s filesystem."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -112,11 +120,29 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## System Logs\n",
|
||||
"It's worth reiterating that the `describe_state()` method can be used on literally any object that inherits from ``SimComponent``. For example, even the system default **'admin'** user inherits ``.describe_state()``:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"client_1.user_manager.admins.get(\"admin\").describe_state()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## System Logs \n",
|
||||
"\n",
|
||||
"Objects that inherit from the ``Node`` class will inherit the ``sys_log`` attribute.\n",
|
||||
"\n",
|
||||
"This is to simulate the idea that items such as Computer, Routers, Servers, etc. have a logging system used to diagnose problems."
|
||||
"This is to simulate the idea that items such as Computer, Routers, Servers, etc. have a logging system used to diagnose problems.\n",
|
||||
"\n",
|
||||
"Enabling this functionality will slow down training time due to the amount of sheer amount of logs created therefore it's recommended to disable these logs when training/evaluating agents."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -134,9 +160,6 @@
|
||||
"PRIMAITE_CONFIG[\"developer_mode\"][\"enabled\"] = True\n",
|
||||
"PRIMAITE_CONFIG[\"developer_mode\"][\"output_sys_logs\"] = True\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Remake the environment\n",
|
||||
"env = PrimaiteGymEnv(env_config=cfg)\n",
|
||||
"\n",
|
||||
@@ -146,9 +169,6 @@
|
||||
"# show sys logs on terminal\n",
|
||||
"client_1.sys_log.show()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# restore config\n",
|
||||
"PRIMAITE_CONFIG[\"developer_mode\"][\"enabled\"] = was_enabled\n",
|
||||
"PRIMAITE_CONFIG[\"developer_mode\"][\"output_sys_logs\"] = was_syslogs_enabled"
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
"source": [
|
||||
"# PrimAITE Developer mode\n",
|
||||
"\n",
|
||||
"PrimAITE has built in developer tools.\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"The dev-mode is designed to help make the development of PrimAITE easier.\n",
|
||||
"`NOTE: For the purposes of the notebook, the commands are preceded by \"!\". When running the commands, remove the \"!\".`\n",
|
||||
"\n",
|
||||
"`NOTE: For the purposes of the notebook, the commands are preceeded by \"!\". When running the commands, run it without the \"!\".`\n",
|
||||
"PrimAITE has built in developer tools which are designed to aid in PrimAITE development.\n",
|
||||
"\n",
|
||||
"To display the available dev-mode options, run the command below:"
|
||||
]
|
||||
@@ -41,14 +41,14 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Dev mode options"
|
||||
"## PrimAITE developer mode CLI options"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### enable\n",
|
||||
"### ``enable``\n",
|
||||
"\n",
|
||||
"Enables the dev mode for PrimAITE.\n",
|
||||
"\n",
|
||||
@@ -70,7 +70,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### disable\n",
|
||||
"### ``disable``\n",
|
||||
"\n",
|
||||
"Disables the dev mode for PrimAITE.\n",
|
||||
"\n",
|
||||
@@ -90,7 +90,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### show\n",
|
||||
"### ``show``\n",
|
||||
"\n",
|
||||
"Shows if PrimAITE is running in dev mode or production mode.\n",
|
||||
"\n",
|
||||
@@ -110,7 +110,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### config\n",
|
||||
"### ``config``\n",
|
||||
"\n",
|
||||
"Configure the PrimAITE developer mode"
|
||||
]
|
||||
@@ -128,7 +128,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### path\n",
|
||||
"#### ``path``\n",
|
||||
"\n",
|
||||
"Set the path where generated session files will be output.\n",
|
||||
"\n",
|
||||
@@ -154,7 +154,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### --sys-log-level or -slevel\n",
|
||||
"#### ``--sys-log-level`` or ``-slevel``\n",
|
||||
"\n",
|
||||
"Set the system log level.\n",
|
||||
"\n",
|
||||
@@ -189,7 +189,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### --agent-log-level or -alevel\n",
|
||||
"#### ``--agent-log-level`` or ``-alevel``\n",
|
||||
"\n",
|
||||
"Set the agent log level.\n",
|
||||
"\n",
|
||||
@@ -224,7 +224,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### --output-sys-logs or -sys\n",
|
||||
"#### ``--output-sys-logs`` or ``-sys``\n",
|
||||
"\n",
|
||||
"If enabled, developer mode will output system logs.\n",
|
||||
"\n",
|
||||
@@ -268,7 +268,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### --output-agent-logs or -agent\n",
|
||||
"#### ``--output-agent-logs`` or ``-agent``\n",
|
||||
"\n",
|
||||
"If enabled, developer mode will output agent action logs.\n",
|
||||
"\n",
|
||||
@@ -312,7 +312,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### --output-pcap-logs or -pcap\n",
|
||||
"#### ``--output-pcap-logs`` or ``-pcap``\n",
|
||||
"\n",
|
||||
"If enabled, developer mode will output PCAP logs.\n",
|
||||
"\n",
|
||||
@@ -356,7 +356,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### --output-to-terminal or -t\n",
|
||||
"#### ``--output-to-terminal`` or ``-t``\n",
|
||||
"\n",
|
||||
"If enabled, developer mode will output logs to the terminal.\n",
|
||||
"\n",
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"_This notebook uses alternative version of [UC7](./UC7-E2E-Demo.ipynb) which has a larger focus on PrimAITE's simulation capabilities._\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This Jupyter notebook demonstrates a cyber scenario focusing on internal privilege escalation and data loss through the manipulation of SSH access and Access Control Lists (ACLs). The scenario is designed to model and visualise how a disgruntled junior engineer might exploit internal network vulnerabilities and social engineering of account credentials to escalate privileges and cause significant data loss and disruption to services.\n",
|
||||
@@ -21,11 +23,11 @@
|
||||
"</a>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"- **SomeTech Developer PC (`some_tech_jnr_dev_pc`)**: The workstation used by the junior engineer.\n",
|
||||
"- **SomeTech Core Router (`some_tech_rt`)**: A critical network device that controls access between nodes.\n",
|
||||
"- **SomeTech PostgreSQL Database Server (`some_tech_db_srv`)**: Hosts the company’s critical database.\n",
|
||||
"- **SomeTech Storage Server (`some_tech_storage_srv`)**: Stores important files and database backups.\n",
|
||||
"- **SomeTech Web Server (`some_tech_web_srv`)**: Serves the company’s website.\n",
|
||||
"- **SomeTech Developer PC** (`some_tech_jnr_dev_pc`): The workstation used by the junior engineer.\n",
|
||||
"- **SomeTech Core Router** (`some_tech_rt`): A critical network device that controls access between nodes.\n",
|
||||
"- **SomeTech PostgreSQL Database Server** (`some_tech_db_srv`): Hosts the company’s critical database.\n",
|
||||
"- **SomeTech Storage Server** (`some_tech_storage_srv`): Stores important files and database backups.\n",
|
||||
"- **SomeTech Web Server** (`some_tech_web_srv`): Serves the company’s website.\n",
|
||||
"\n",
|
||||
"By default, the junior developer PC is restricted from connecting to the storage server via FTP or SSH due to ACL rules that permit only senior members of the engineering team to access these services.\n",
|
||||
"\n",
|
||||
@@ -35,12 +37,12 @@
|
||||
"\n",
|
||||
"1. **Privilege Escalation**: The junior engineer uses social engineering to obtain login credentials for the core router, SSHs into the router, and modifies the ACL rules to allow SSH access from their PC to the storage server.\n",
|
||||
"2. **Remote Access**: The junior engineer then uses the newly gained SSH access to connect to the storage server from their PC. This step is crucial for executing further actions, such as deleting files.\n",
|
||||
"3. **File Deletion**: With SSH access to the storage server, the engineer deletes the backup file from the storage server and subsequently removes critical data from the PostgreSQL database, bringing down the sometech.ai website.\n",
|
||||
"4. **Website Impact Verification:** After the deletion of the database backup, the scenario checks the sometech.ai website's status to confirm it has been brought down due to the data loss.\n",
|
||||
"3. **File Deletion**: With SSH access to the storage server, the engineer deletes the backup file from the storage server and subsequently removes critical data from the PostgreSQL database, bringing down the *sometech.ai* website.\n",
|
||||
"4. **Website Impact Verification:** After the deletion of the database backup, the scenario checks the *sometech.ai* website's status to confirm it has been brought down due to the data loss.\n",
|
||||
"5. **Database Restore Failure:** An attempt is made to restore the deleted backup, demonstrating that the restoration fails and highlighting the severity of the data loss.\n",
|
||||
"\n",
|
||||
"### Notes:\n",
|
||||
"- The demo will utilise CAOS (Common Action and Observation Space) actions wherever they are available. For actions where a CAOS action does not yet exist, the action will be performed manually on the node/service.\n",
|
||||
"- The demo will utilise **CAOS** (Common Action and Observation Space) actions wherever they are available. For actions where a CAOS action does not yet exist, the action will be performed manually on the node/service via the PrimAITE simulation API.\n",
|
||||
"- This notebook will be updated to incorporate new CAOS actions as they become supported."
|
||||
]
|
||||
},
|
||||
@@ -72,6 +74,8 @@
|
||||
"\n",
|
||||
"from primaite import PRIMAITE_PATHS\n",
|
||||
"from primaite.game.game import PrimaiteGame\n",
|
||||
"from primaite.simulator.file_system.folder import Folder\n",
|
||||
"from primaite.utils.validation.port import PORT_LOOKUP\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.computer import Computer\n",
|
||||
"from primaite.simulator.network.hardware.nodes.network.router import Router\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.server import Server\n",
|
||||
@@ -186,8 +190,8 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"db_backup_folder = [folder.name for folder in some_tech_storage_srv.file_system.folders.values() if folder.name != \"root\"][0]\n",
|
||||
"db_backup_folder"
|
||||
"db_backup_folder_list = [folder.name for folder in some_tech_storage_srv.file_system.folders.values() if folder.name != \"root\"]\n",
|
||||
"db_backup_folder = db_backup_folder_list[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -209,11 +213,11 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"caos_action = [\n",
|
||||
"simulation_request = [\n",
|
||||
" \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n",
|
||||
" \"service\", \"terminal\", \"node-session-remote-login\", \"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)"
|
||||
"game.simulation.apply_request(simulation_request)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -233,8 +237,8 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"caos_action = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n",
|
||||
"game.simulation.apply_request(caos_action)"
|
||||
"simulation_request = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n",
|
||||
"game.simulation.apply_request(simulation_request)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -267,11 +271,11 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"caos_action = [\n",
|
||||
"simulation_request = [\n",
|
||||
" \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n",
|
||||
" \"service\", \"terminal\", \"node-session-remote-login\", \"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)"
|
||||
"game.simulation.apply_request(simulation_request)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -313,20 +317,20 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"caos_action = [\n",
|
||||
"simulation_request = [\n",
|
||||
" \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n",
|
||||
" \"service\", \"terminal\", \"send_remote_command\", str(some_tech_rt.network_interface[4].ip_address),\n",
|
||||
" {\n",
|
||||
" \"command\": [\n",
|
||||
" \"acl\", \"add_rule\", \"PERMIT\", \"TCP\",\n",
|
||||
" str(some_tech_jnr_dev_pc.network_interface[1].ip_address), \"0.0.0.0\", \"SSH\",\n",
|
||||
" str(some_tech_storage_srv.network_interface[1].ip_address), \"0.0.0.0\", \"SSH\",\n",
|
||||
" str(some_tech_jnr_dev_pc.network_interface[1].ip_address), \"0.0.0.0\", PORT_LOOKUP[\"SSH\"],\n",
|
||||
" str(some_tech_storage_srv.network_interface[1].ip_address), \"0.0.0.0\", PORT_LOOKUP[\"SSH\"],\n",
|
||||
" 1\n",
|
||||
" ]\n",
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"game.simulation.apply_request(caos_action)"
|
||||
"game.simulation.apply_request(simulation_request)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -366,11 +370,11 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"caos_action = [\n",
|
||||
"simulation_request = [\n",
|
||||
" \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n",
|
||||
" \"service\", \"terminal\", \"remote_logoff\", str(some_tech_rt.network_interface[4].ip_address)\n",
|
||||
"]\n",
|
||||
"game.simulation.apply_request(caos_action)"
|
||||
"game.simulation.apply_request(simulation_request)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -404,11 +408,11 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"caos_action = [\n",
|
||||
"simulation_request = [\n",
|
||||
" \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n",
|
||||
" \"service\", \"terminal\", \"node-session-remote-login\", \"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)"
|
||||
"game.simulation.apply_request(simulation_request)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -419,7 +423,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"caos_action = [\n",
|
||||
"simulation_request = [\n",
|
||||
" \"network\", \"node\", \"some_tech_jnr_dev_pc\", \n",
|
||||
" \"service\", \"terminal\", \"send_remote_command\", str(some_tech_storage_srv.network_interface[1].ip_address),\n",
|
||||
" {\n",
|
||||
@@ -429,7 +433,7 @@
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"game.simulation.apply_request(caos_action)"
|
||||
"game.simulation.apply_request(simulation_request)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -450,6 +454,16 @@
|
||||
"some_tech_storage_srv.file_system.show(full=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Should return 'None' as the database.db file has been deleted (as shown in the above table)\n",
|
||||
"print(some_tech_storage_srv.file_system.get_file(folder_name=db_backup_folder, file_name=\"database.db\", include_deleted=False))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -476,8 +490,8 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"caos_action = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n",
|
||||
"game.simulation.apply_request(caos_action)"
|
||||
"simulation_request = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n",
|
||||
"game.simulation.apply_request(simulation_request)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -535,8 +549,8 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"caos_action = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n",
|
||||
"game.simulation.apply_request(caos_action)"
|
||||
"simulation_request = [\"network\", \"node\", \"some_tech_jnr_dev_pc\", \"application\", \"web-browser\", \"execute\"]\n",
|
||||
"game.simulation.apply_request(simulation_request)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -595,7 +609,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@@ -609,7 +623,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.11"
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -8,21 +8,7 @@
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"Agents interact with the PrimAITE simulation via the Request system.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Sending a request"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's set up a minimal network simulation and send some requests to see how it works."
|
||||
"This notebook demonstrates how agents interact with the PrimAITE simulation via the Request system.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -45,6 +31,20 @@
|
||||
"from primaite.simulator.sim_container import Simulation\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Sending a request"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Before we can send some requests we need to set up a minimal network simulation. The code snippet below creates a PrimAITE simulation with a singular generic host called `client`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -71,9 +71,16 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"A request is structured in a similar way to a command line interface - a list of strings with positional args. It's also possible to supply an optional `context` dictionary. We will craft a request that stops the pre-installed DNSClient service on the client node.\n",
|
||||
"Now we can simulation component to interact with, we can start sending some requests."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"A request is structured in a similar way to a command line interface - a list of strings with positional args. It's also possible to supply an optional `context` dictionary. We will craft a request that stops the pre-installed `dns-client` service on the client node.\n",
|
||||
"\n",
|
||||
"First let's verify that the DNS Client is running on the client.\n"
|
||||
"First let's verify that the `dns-client` is running on the client."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -82,14 +89,15 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"client.software_manager.show()"
|
||||
"client.software_manager.show()\n",
|
||||
"client.software_manager.software['dns-client'].operating_state.name"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Send a request to the simulator to stop the DNSClient."
|
||||
"Send a request to the simulator to stop the `dns-client`."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -110,7 +118,7 @@
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"The request returns a `RequestResponse` object which tells us that the request was successfully executed. Let's verify that the DNS client is in a stopped state now."
|
||||
"The request returns a `RequestResponse` object which tells us that the request was successfully executed. Let's verify that the `dns-client` is in a stopped state now."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -196,7 +204,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now, if we try to start the DNSClient back up, we get a failure because we cannot start software on a node that is turned off."
|
||||
"Now, if we try to start the `dns-client` back up, we get a failure because we cannot start software on a node that is turned off."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,23 +13,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Simulation Layer Implementation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Simulation Layer Implementation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook serves as a guide on the functionality and use of the new Terminal simulation component.\n",
|
||||
"\n",
|
||||
"The Terminal service comes pre-installed on most Nodes (The exception being Switches, as these are currently dumb). "
|
||||
"This notebook serves as a guide on the functionality and use of the `terminal` service from both the simulation and game layers."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -51,8 +35,47 @@
|
||||
"from primaite.simulator.network.container import Network\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.computer import Computer\n",
|
||||
"from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript\n",
|
||||
"from primaite.simulator.system.services.terminal.terminal import RemoteTerminalConnection\n",
|
||||
"from primaite.simulator.system.services.terminal.terminal import RemoteTerminalConnection\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Simulation Layer Implementation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The `terminal` service comes pre-installed on most node types. \n",
|
||||
"\n",
|
||||
"_The only exception to this being `switches` network nodes, this is because PrimAITE currently only implements 'dumb' switches. `routers` and `firewalls` however all support the `terminal`._"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!primaite setup"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In this notebook, the terminal is demoed on a basic network consisting of two computers, connected together via a link to form a basic LAN network which can be seen by the `basic_network()` method defined below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def basic_network() -> Network:\n",
|
||||
" \"\"\"Utility function for creating a default network to demonstrate Terminal functionality\"\"\"\n",
|
||||
" network = Network()\n",
|
||||
@@ -65,7 +88,6 @@
|
||||
" # \"startup_duration\": 0,\n",
|
||||
" }\n",
|
||||
" )\n",
|
||||
" print(f\"{node_a=}\")\n",
|
||||
" node_a.power_on()\n",
|
||||
" node_b = Computer.from_config(\n",
|
||||
" config = {\n",
|
||||
@@ -85,9 +107,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The terminal can be accessed from a `Node` via the `software_manager` as demonstrated below. \n",
|
||||
"\n",
|
||||
"In the example, we have a basic network consisting of two computers, connected to form a basic network."
|
||||
"After setting up the network, the terminal can be accessed from a `Node` via the `software_manager`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -107,10 +127,11 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To be able to send commands from `node_a` to `node_b`, you will need to `login` to `node_b` first, using valid user credentials. In the example below, we are remotely logging in to the 'admin' account on `node_b`, from `node_a`. \n",
|
||||
"If you are not logged in, any commands sent will be rejected by the remote.\n",
|
||||
"However, before we're able to send commands from `node_a` to `node_b`, you will need to `login` to `node_b` first, using valid user credentials. \n",
|
||||
"\n",
|
||||
"Remote Logins return a RemoteTerminalConnection object, which can be used for sending commands to the remote node. "
|
||||
"After providing successful credentials, the login method will return type of `TerminalClientConnection` object which can then be used for sending commands to the node. \n",
|
||||
"\n",
|
||||
"In the example below, we are remotely logging in to the default ***'admin'*** account on `node_b`, from `node_a` (If you are not logged in, any commands sent will be rejected by the remote).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -143,7 +164,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The new connection object allows us to forward commands to be executed on the target node. The example below demonstrates how you can remotely install an application on the target node."
|
||||
"As we logged into a remote node, the login method return a `RemoteTerminalConnection` which allows us to forward commands to be executed on the target node. \n",
|
||||
"\n",
|
||||
"The example below demonstrates how you can remotely install an application on the target node."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -168,7 +191,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The code block below demonstrates how the Terminal class allows the user of `terminal_a`, on `computer_a`, to send a command to `computer_b` to create a downloads folder. \n"
|
||||
"As the terminal allows us to leverage the [request system](./Requests-and-Responses.ipynb) we have full access to the request manager on any simulation component. For example, the code snippet below demonstrates how we the `terminal` allows the user of `terminal_a`, on `computer_a`, to send a command (in the form of a request) to `computer_b` to create a downloads folder. \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -263,14 +286,16 @@
|
||||
"\n",
|
||||
"This notebook section will detail the implementation of how the game layer utilises the terminal to support different agent actions.\n",
|
||||
"\n",
|
||||
"The ``Terminal`` is used in a variety of different ways in the game layer. Specifically, the terminal is leveraged to implement the following actions:\n",
|
||||
"The ``terminal`` is directly leveraged to implement the following agent actions.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"| Game Layer Action | Simulation Layer |\n",
|
||||
"|-----------------------------------|--------------------------|\n",
|
||||
"| ``node-send-local-command`` | Uses the given user credentials, creates a ``LocalTerminalSession`` and executes the given command and returns the ``RequestResponse``.\n",
|
||||
"| ``node-session-remote-login`` | Uses the given user credentials and remote IP to create a ``RemoteTerminalSession``.\n",
|
||||
"| ``node-send-remote-command`` | Uses the given remote IP to locate the correct ``RemoteTerminalSession``, executes the given command and returns the ``RequestsResponse``."
|
||||
"| ``node-send-remote-command`` | Uses the given remote IP to locate the correct ``RemoteTerminalSession``, executes the given command and returns the ``RequestsResponse``.\n",
|
||||
"\n",
|
||||
"Additionally, the `terminal` is utilised extensively by the [c2 suite](./Command-and-Control-E2E-Demonstration.ipynb) and it's related actions. "
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -302,7 +327,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"custom_terminal_agent = \"\"\"\n",
|
||||
" - ref: CustomC2Agent\n",
|
||||
" - ref: CustomTerminalAgent\n",
|
||||
" team: RED\n",
|
||||
" type: proxy-agent\n",
|
||||
" action_space:\n",
|
||||
@@ -373,22 +398,11 @@
|
||||
"The yaml snippet below shows all the relevant agent options for this action:\n",
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: node-send-local-command\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" - node_name: client_1\n",
|
||||
" ...\n",
|
||||
" ...\n",
|
||||
" action_map:\n",
|
||||
" 1:\n",
|
||||
" action: node-send-local-command\n",
|
||||
" options:\n",
|
||||
" node_id: 0 # Index 0 at the node list.\n",
|
||||
" node_name: client_1\n",
|
||||
" username: admin\n",
|
||||
" password: admin\n",
|
||||
" command:\n",
|
||||
@@ -420,22 +434,11 @@
|
||||
"The yaml snippet below shows all the relevant agent options for this action:\n",
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: node-session-remote-login\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" - node_name: client_1\n",
|
||||
" ...\n",
|
||||
" ...\n",
|
||||
" action_map:\n",
|
||||
" 2:\n",
|
||||
" action: node-session-remote-login\n",
|
||||
" options:\n",
|
||||
" node_id: 0 # Index 0 at the node list.\n",
|
||||
" node_name: client_1\n",
|
||||
" username: admin\n",
|
||||
" password: admin\n",
|
||||
" remote_ip: 192.168.10.22 # client_2's ip address.\n",
|
||||
@@ -461,24 +464,13 @@
|
||||
"The yaml snippet below shows all the relevant agent options for this action:\n",
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" ...\n",
|
||||
" - type: node-send-remote-command\n",
|
||||
" ...\n",
|
||||
" options:\n",
|
||||
" nodes: # Node List\n",
|
||||
" - node_name: client_1\n",
|
||||
" ...\n",
|
||||
" ...\n",
|
||||
" action_map:\n",
|
||||
" 1:\n",
|
||||
" 3:\n",
|
||||
" action: node-send-remote-command\n",
|
||||
" options:\n",
|
||||
" node_id: 0 # Index 0 at the node list.\n",
|
||||
" remote_ip: 192.168.10.22\n",
|
||||
" commands:\n",
|
||||
" node_name: client_1\n",
|
||||
" remote_ip: 192.168.10.22 # client_2's ip address.\n",
|
||||
" command:\n",
|
||||
" - file_system\n",
|
||||
" - create\n",
|
||||
" - file\n",
|
||||
@@ -501,7 +493,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"This notebook will demonstrate how to use the `PrimaiteRayMARLEnv` to train a very basic system with two PPO agents."
|
||||
"This notebook will demonstrate how to use the `PrimaiteRayMARLEnv` to train a very basic system with two PPO agents on the [UC2 scenario](./Data-Manipulation-E2E-Demonstration.ipynb)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -34,17 +34,20 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import yaml\n",
|
||||
"\n",
|
||||
"from primaite import PRIMAITE_PATHS\n",
|
||||
"\n",
|
||||
"import ray\n",
|
||||
"from primaite import PRIMAITE_PATHS\n",
|
||||
"from ray.rllib.algorithms.ppo import PPOConfig\n",
|
||||
"from primaite.session.ray_envs import PrimaiteRayMARLEnv\n",
|
||||
"from primaite.game.agent.scripted_agents import probabilistic_agent\n",
|
||||
"\n",
|
||||
"from primaite.session.ray_envs import PrimaiteRayMARLEnv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with open(PRIMAITE_PATHS.user_config_path / 'example_config/data_manipulation_marl.yaml', 'r') as f:\n",
|
||||
" cfg = yaml.safe_load(f)\n",
|
||||
"\n",
|
||||
"ray.init(local_mode=True)"
|
||||
]
|
||||
},
|
||||
@@ -114,6 +117,18 @@
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"This notebook will demonstrate how to use PrimaiteRayEnv to train a basic PPO agent."
|
||||
"This notebook demonstrates how to use the ``PrimaiteRayEnv`` to train a basic PPO agent on the [UC2 scenario](./Data-Manipulation-E2E-Demonstration.ipynb)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -27,13 +27,10 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import yaml\n",
|
||||
"from primaite.config.load import data_manipulation_config_path\n",
|
||||
"\n",
|
||||
"from primaite.session.ray_envs import PrimaiteRayEnv\n",
|
||||
"import ray\n",
|
||||
"from primaite.config.load import data_manipulation_config_path\n",
|
||||
"from primaite.session.ray_envs import PrimaiteRayEnv\n",
|
||||
"from ray.rllib.algorithms.ppo import PPOConfig\n",
|
||||
"from primaite.game.agent.scripted_agents import probabilistic_agent\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# If you get an error saying this config file doesn't exist, you may need to run `primaite setup` in your command line\n",
|
||||
"# to copy the files to your user data path.\n",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"This notebook will demonstrate how to use primaite to create and train a PPO agent, using a pre-defined configuration file."
|
||||
"This notebook will demonstrate how to use primaite to create and train a PPO agent, using a pre-defined configuration file using the [UC2 scenario](./Data-Manipulation-E2E-Demonstration.ipynb)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -33,21 +33,11 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from primaite.game.game import PrimaiteGame\n",
|
||||
"from primaite.session.environment import PrimaiteGymEnv\n",
|
||||
"from primaite.game.agent.scripted_agents import probabilistic_agent\n",
|
||||
"from primaite.config.load import data_manipulation_config_path\n",
|
||||
"import yaml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from primaite.config.load import data_manipulation_config_path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
|
||||
@@ -4,16 +4,18 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# UC7 Demonstration\n",
|
||||
"# Use Case 7 Scenario Demonstration\n",
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"UC7 is a cybersecurity scenario set in a generic medium sized organisation, where multiple LAN networks which interconnect via the 'internet' to represent a corporate WAN. Comprising of four major networks; `Home Office (HOME)`, `INTERNET (ISP)`, `REMOTE SITE (REMOTE)` and the larger main site `SOME_TECH`. Each network is comprised of routers, switches, computers and servers which green agents use to represent a more real-world accurate pattern of life.\n",
|
||||
"Use Case 7 (UC7) is a cybersecurity scenario set in a generic enterprise organisation, where multiple LAN networks are connected via the 'internet' to represent a corporate WAN. Each network is comprised of routers, switches, computers and servers which green agents use to represent a more real-world accurate network architecture and pattern of life.\n",
|
||||
"\n",
|
||||
"Intended to be a step-up from the [smaller network of UC2](./Data-Manipulation-E2E-Demonstration.ipynb), UC7 introduces two new potential attacks (TAPS) that the blue agent must defend against. \n",
|
||||
"Comprising of four major networks; `Home Office (HOME)`, `INTERNET (ISP)`, `REMOTE SITE (REMOTE)` and the larger main site `SOME_TECH`, UC7 is a significant step-up in fidelity from the [smaller network of UC2](./Data-Manipulation-E2E-Demonstration.ipynb). Additionally, two new red agents known as Threat Actor Profiles (TAPs) have been introduced which the blue agent can be trained to defend against. \n",
|
||||
"\n",
|
||||
"_This notebook acts as the starting point for any users unfamiliar with UC7 and will also sign post to any other UC7 relevant notebooks for further information._"
|
||||
"Lastly, UC7 is intended to be a generic 'out-of-the-box' configuration that demonstrates the flexibility of PrimAITE rather than a predefined 'challenge' that can solved. Users are encouraged to modify, remove and introduce as much as they wish to create their own unique scenarios. \n",
|
||||
"\n",
|
||||
"_This notebook acts as the starting point for any users unfamiliar with UC7 and will sign post other UC7 relevant notebooks which provide further information._"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -31,6 +33,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import yaml\n",
|
||||
"from primaite.session.environment import PrimaiteGymEnv\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.computer import Computer\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.server import Server\n",
|
||||
@@ -38,17 +41,10 @@
|
||||
"from primaite.simulator.system.services.dns.dns_server import DNSServer\n",
|
||||
"from primaite.simulator.system.software import SoftwareHealthState\n",
|
||||
"from primaite.simulator.file_system.file_system_item_abc import FileSystemItemHealthStatus\n",
|
||||
"from primaite.simulator.network.hardware.nodes.network.switch import Switch\n",
|
||||
"from primaite.simulator.system.applications.web_browser import WebBrowser\n",
|
||||
"from primaite.simulator.network.container import Network\n",
|
||||
"from primaite.simulator.system.services.service import ServiceOperatingState\n",
|
||||
"from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState\n",
|
||||
"from primaite.simulator.system.services.database.database_service import DatabaseService\n",
|
||||
"from primaite.simulator.system.applications.database_client import DatabaseClient\n",
|
||||
"from primaite.simulator.network.hardware.nodes.network.firewall import Firewall\n",
|
||||
"from primaite.game.game import PrimaiteGame\n",
|
||||
"from primaite.simulator.sim_container import Simulation\n",
|
||||
"import yaml\n",
|
||||
"from pprint import pprint\n",
|
||||
"from primaite.config.load import load, _EXAMPLE_CFG"
|
||||
]
|
||||
@@ -339,7 +335,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH HEAD OFFICE (ST_HO)\n",
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH HEAD OFFICE (`ST_HO`)\n",
|
||||
"\n",
|
||||
"The some tech head office (`ST_HO`) is a simple LAN containing three computers with the default PC configuration."
|
||||
]
|
||||
@@ -358,7 +354,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH HUMAN RESOURCES (ST_HR)\n",
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH HUMAN RESOURCES (`ST_HR`)\n",
|
||||
"\n",
|
||||
"Similarly, the some tech head human resources office (`ST_HR`) consisting of three default PC configurations computers."
|
||||
]
|
||||
@@ -377,9 +373,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH DATA (ST_DATA)\n",
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH DATA (`ST_DATA`)\n",
|
||||
"\n",
|
||||
"The `ST_DATA` networks contains two servers pivotal to the daily operation of SOME_TECH.\n",
|
||||
"The `ST_DATA` networks contains two servers pivotal to the daily operation of ``SOME_TECH``.\n",
|
||||
"\n",
|
||||
"| Server | Purpose |\n",
|
||||
"|--------|---------|\n",
|
||||
@@ -414,7 +410,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH PROJECT A (ST_PROJ_A)\n",
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH PROJECT A (`ST_PROJ_A`)\n",
|
||||
"\n",
|
||||
"All of the `ST_PROJ_A`/`B`/`C` project networks contain three computers and a switch which connects to the `ST_INTRA-PRV-RT-DR-1` router (as described previously)."
|
||||
]
|
||||
@@ -433,7 +429,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH PROJECT B (ST_PROJ_B)"
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH PROJECT B (`ST_PROJ_B`)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -450,7 +446,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH PROJECT C (ST_PROJ_C)"
|
||||
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH PROJECT C (`ST_PROJ_C`)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -467,7 +463,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Use Case 7 Agent Description / Demonstration"
|
||||
"## Agent Description / Demonstration"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -505,38 +501,38 @@
|
||||
"\n",
|
||||
" **ID** | **PoL Type** | **Description of Activity** | **Agent Name** | **Source Node** | **Source App / Service** | **Destination Node** | **Destination App / Service** | **Transport Protocol** | **Application Protocol** | **Behaviour Type** | **Probabilities** | **Start Step** | **Start Variance** | **Max Executions** | **Frequency** | **Variance** | **Reward Impact** \n",
|
||||
":------:|:------------:|:---------------------------------------------------:|:-------------------:|:------------------:|:------------------------:|:-----------------------:|:-----------------------------:|:----------------------:|:------------------------:|:------------------:|:-----------------:|:--------------:|:------------------:|:------------------:|:-------------:|:------------:|:-----------------:\n",
|
||||
" 1 | AGENT | Home Worker accessing Some Tech database | HOME_WORKER-1 | HOME-PUB-PC-1 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 4 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 2 | AGENT | Home Worker accessing Some Tech web pages | HOME_WORKER-1 | HOME-PUB-PC-1 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 3 | AGENT | Home Worker accessing Some Tech database | HOME_WORKER-2 | HOME-PUB-PC-2 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 8 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 4 | AGENT | Home Worker accessing Some Tech web pages | HOME_WORKER-2 | HOME-PUB-PC-2 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 5 | AGENT | Remote Worker accessing Some Tech database | REMOTE_WORKER-1 | REM-PUB-PC-1 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 12 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 6 | AGENT | Remote Worker accessing Some Tech web pages | REMOTE_WORKER-1 | REM-PUB-PC-1 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 7 | AGENT | Remote Worker accessing Some Tech database | REMOTE_WORKER-2 | REM-PUB-PC-2 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 16 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 8 | AGENT | Remote Worker accessing Some Tech web pages | REMOTE_WORKER-2 | REM-PUB-PC-2 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 9 | AGENT | Senior Developer accessing Some Tech database | PROJ_A-SENIOR_DEV | ST_PROJ_A-PRV-PC-1 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | HIGH \n",
|
||||
" 10 | AGENT | Senior Developer accessing Some Tech web pages | PROJ_A-SENIOR_DEV | ST_PROJ_A-PRV-PC-1 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 40% chance | | | | | | LOW \n",
|
||||
" 11 | AGENT | Junior Developer accessing Some Tech database | PROJ_A-JUNIOR_DEV-1 | ST_PROJ_A-PRV-PC-2 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 12 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_A-JUNIOR_DEV-1 | ST_PROJ_A-PRV-PC-2 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 13 | AGENT | Junior Developer accessing Some Tech database | PROJ_A-JUNIOR_DEV-2 | ST_PROJ_A-PRV-PC-3 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 14 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_A-JUNIOR_DEV-2 | ST_PROJ_A-PRV-PC-3 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 15 | AGENT | Senior Developer accessing Some Tech database | PROJ_B-SENIOR_DEV | ST_PROJ_B-PRV-PC-1 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | HIGH \n",
|
||||
" 16 | AGENT | Senior Developer accessing Some Tech web pages | PROJ_B-SENIOR_DEV | ST_PROJ_B-PRV-PC-1 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 40% chance | | | | | | LOW \n",
|
||||
" 17 | AGENT | Junior Developer accessing Some Tech database | PROJ_B-JUNIOR_DEV-1 | ST_PROJ_B-PRV-PC-2 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 18 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_B-JUNIOR_DEV-1 | ST_PROJ_B-PRV-PC-2 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 19 | AGENT | Junior Developer accessing Some Tech database | PROJ_B-JUNIOR_DEV-2 | ST_PROJ_B-PRV-PC-3 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 20 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_B-JUNIOR_DEV-2 | ST_PROJ_B-PRV-PC-3 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 21 | AGENT | Senior Developer accessing Some Tech database | PROJ_C-SENIOR_DEV | ST_PROJ_C-PRV-PC-1 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | HIGH \n",
|
||||
" 22 | AGENT | Senior Developer accessing Some Tech web pages | PROJ_C-SENIOR_DEV | ST_PROJ_C-PRV-PC-1 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 40% chance | | | | | | LOW \n",
|
||||
" 23 | AGENT | Junior Developer accessing Some Tech database | PROJ_C-JUNIOR_DEV-1 | ST_PROJ_C-PRV-PC-2 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 24 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_C-JUNIOR_DEV-1 | ST_PROJ_C-PRV-PC-2 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 25 | AGENT | Junior Developer accessing Some Tech database | PROJ_C-JUNIOR_DEV-2 | ST_PROJ_C-PRV-PC-3 | Database Client | ST_DATA-PRV-SRV-DB | Database Service | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 26 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_C-JUNIOR_DEV-2 | ST_PROJ_C-PRV-PC-3 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 27 | AGENT | CEO accessing Some Tech web pages | CEO | ST_HO-PRV-PC-1 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | HIGH \n",
|
||||
" 28 | AGENT | CTO accessing Some Tech web pages | CTO | ST_HO-PRV-PC-2 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | MEDIUM \n",
|
||||
" 29 | AGENT | CFO accessing Some Tech web pages | CFO | ST_HO-PRV-PC-3 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | MEDIUM \n",
|
||||
" 30 | AGENT | Senior HR accessing Some Tech web pages | SENIOR_HR | ST_HR-PRV-PC-1 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | MEDIUM \n",
|
||||
" 31 | AGENT | Junior HR accessing Some Tech web pages | JUNIOR_HR-1 | ST_HR-PRV-PC-2 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | LOW \n",
|
||||
" 32 | AGENT | Junior HR accessing Some Tech web pages | JUNIOR_HR-2 | ST_HR-PRV-PC-3 | Web Browser | ST_DMZ-PUB-SRV-WEB | Web Server | TCP | \n",
|
||||
" 1 | AGENT | Home Worker accessing Some Tech database | HOME_WORKER-1 | HOME-PUB-PC-1 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 4 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 2 | AGENT | Home Worker accessing Some Tech web pages | HOME_WORKER-1 | HOME-PUB-PC-1 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 3 | AGENT | Home Worker accessing Some Tech database | HOME_WORKER-2 | HOME-PUB-PC-2 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 8 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 4 | AGENT | Home Worker accessing Some Tech web pages | HOME_WORKER-2 | HOME-PUB-PC-2 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 5 | AGENT | Remote Worker accessing Some Tech database | REMOTE_WORKER-1 | REM-PUB-PC-1 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 12 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 6 | AGENT | Remote Worker accessing Some Tech web pages | REMOTE_WORKER-1 | REM-PUB-PC-1 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 7 | AGENT | Remote Worker accessing Some Tech database | REMOTE_WORKER-2 | REM-PUB-PC-2 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 16 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 8 | AGENT | Remote Worker accessing Some Tech web pages | REMOTE_WORKER-2 | REM-PUB-PC-2 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 9 | AGENT | Senior Developer accessing Some Tech database | PROJ_A-SENIOR_DEV | ST_PROJ_A-PRV-PC-1 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | HIGH \n",
|
||||
" 10 | AGENT | Senior Developer accessing Some Tech web pages | PROJ_A-SENIOR_DEV | ST_PROJ_A-PRV-PC-1 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 40% chance | | | | | | LOW \n",
|
||||
" 11 | AGENT | Junior Developer accessing Some Tech database | PROJ_A-JUNIOR_DEV-1 | ST_PROJ_A-PRV-PC-2 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 12 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_A-JUNIOR_DEV-1 | ST_PROJ_A-PRV-PC-2 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 13 | AGENT | Junior Developer accessing Some Tech database | PROJ_A-JUNIOR_DEV-2 | ST_PROJ_A-PRV-PC-3 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 14 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_A-JUNIOR_DEV-2 | ST_PROJ_A-PRV-PC-3 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 15 | AGENT | Senior Developer accessing Some Tech database | PROJ_B-SENIOR_DEV | ST_PROJ_B-PRV-PC-1 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | HIGH \n",
|
||||
" 16 | AGENT | Senior Developer accessing Some Tech web pages | PROJ_B-SENIOR_DEV | ST_PROJ_B-PRV-PC-1 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 40% chance | | | | | | LOW \n",
|
||||
" 17 | AGENT | Junior Developer accessing Some Tech database | PROJ_B-JUNIOR_DEV-1 | ST_PROJ_B-PRV-PC-2 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 18 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_B-JUNIOR_DEV-1 | ST_PROJ_B-PRV-PC-2 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 19 | AGENT | Junior Developer accessing Some Tech database | PROJ_B-JUNIOR_DEV-2 | ST_PROJ_B-PRV-PC-3 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 20 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_B-JUNIOR_DEV-2 | ST_PROJ_B-PRV-PC-3 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 21 | AGENT | Senior Developer accessing Some Tech database | PROJ_C-SENIOR_DEV | ST_PROJ_C-PRV-PC-1 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | HIGH \n",
|
||||
" 22 | AGENT | Senior Developer accessing Some Tech web pages | PROJ_C-SENIOR_DEV | ST_PROJ_C-PRV-PC-1 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 40% chance | | | | | | LOW \n",
|
||||
" 23 | AGENT | Junior Developer accessing Some Tech database | PROJ_C-JUNIOR_DEV-1 | ST_PROJ_C-PRV-PC-2 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 24 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_C-JUNIOR_DEV-1 | ST_PROJ_C-PRV-PC-2 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 25 | AGENT | Junior Developer accessing Some Tech database | PROJ_C-JUNIOR_DEV-2 | ST_PROJ_C-PRV-PC-3 | `database-client` | ST_DATA-PRV-SRV-DB | `database-service` | TCP | PostgreSQL | PERIODIC | | 1 | 1 | 1000 | 4 | 1 | MEDIUM \n",
|
||||
" 26 | AGENT | Junior Developer accessing Some Tech web pages | PROJ_C-JUNIOR_DEV-2 | ST_PROJ_C-PRV-PC-3 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 20% chance | | | | | | LOW \n",
|
||||
" 27 | AGENT | CEO accessing Some Tech web pages | CEO | ST_HO-PRV-PC-1 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | HIGH \n",
|
||||
" 28 | AGENT | CTO accessing Some Tech web pages | CTO | ST_HO-PRV-PC-2 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | MEDIUM \n",
|
||||
" 29 | AGENT | CFO accessing Some Tech web pages | CFO | ST_HO-PRV-PC-3 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | MEDIUM \n",
|
||||
" 30 | AGENT | Senior HR accessing Some Tech web pages | SENIOR_HR | ST_HR-PRV-PC-1 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | MEDIUM \n",
|
||||
" 31 | AGENT | Junior HR accessing Some Tech web pages | JUNIOR_HR-1 | ST_HR-PRV-PC-2 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | HTTPS | PROBABILISTIC | 60% chance | | | | | | LOW \n",
|
||||
" 32 | AGENT | Junior HR accessing Some Tech web pages | JUNIOR_HR-2 | ST_HR-PRV-PC-3 | `web-browser` | ST_DMZ-PUB-SRV-WEB | `web-server` | TCP | \n",
|
||||
"</details>"
|
||||
]
|
||||
},
|
||||
@@ -548,7 +544,7 @@
|
||||
"\n",
|
||||
"The `database-client` green agents will attempt to use their host's `database-client` application to make a simple connection to the `database-service` on the `ST_DATA-PRV-SRV-DB` host (these connections have no direct impact to the `database-service` or the `database.db` file itself).\n",
|
||||
"\n",
|
||||
"Additionally, `database-client` green agents are *Periodic* meaning they will attempt to use the database based on game time-steps. Specifically, these agents will begin on the time-step given in their `start step` setting and will then will reattempt on each subsequence timestep based on the `Frequency` setting. These settings are then randomised using the remaining `Start Variance` and `Variance` options (also given in timesteps). These values are used to *±* their respective base settings to ensure the green agents achieve a moderate amount of domain randomisation in each PrimAITE episode.\n",
|
||||
"Additionally, `database-client` green agents are *Periodic* meaning they will attempt to use the database based on game time-steps. Specifically, these agents will begin on the time-step given in their `start_step` setting and will then will reattempt on each subsequence timestep based on the `Frequency` setting. These settings are then randomised using the remaining `start_variance` and `variance` options (also given in timesteps). These values are used to *±* their respective base settings to ensure the green agents achieve a moderate amount of domain randomisation in each PrimAITE episode.\n",
|
||||
"\n",
|
||||
"For example, take a *Periodic* green agent set with a `start_step` of 4 and a `frequency` of **4** with a `start_variance` and a `variance` of **4** will cause a green agent to make it's first action on timestep $4 \\pm 1$ and then any subsequent actions every $4 \\pm 1$ timesteps afterwards.\n"
|
||||
]
|
||||
@@ -581,9 +577,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### AGENTS | Green *PoL* | web-browser Agents Demo\n",
|
||||
"#### AGENTS | Green PoL | `web-browser` Agents Demo\n",
|
||||
"\n",
|
||||
"Unlike the `database-client` green agents, the `web-browser` green agents are *probabilistic*. These agents are quite simple; on every timestep a probability roll is made to determine whenever the agent acts. On a successful outcome the agent will attempt to execute the `web-browser` application which will then attempt to connect to the `ST-DMZ-PUB-SRV-WEB` host (Some Tech's web-server). On a unsuccessful outcome then the green agent will simply perform not action on this timestep.\n",
|
||||
"Unlike the `database-client` green agents, the `web-browser` green agents are *probabilistic*. These agents are quite simple; on every timestep a probability roll is made to determine whenever the agent acts. On a successful outcome the agent will attempt to execute the `web-browser` application which will then attempt to connect to the `ST-DMZ-PUB-SRV-WEB` host. On a unsuccessful outcome then the green agent will simply perform not action on this timestep.\n",
|
||||
"\n",
|
||||
"For example, a `web-browser` green agent with a `20%` chance has a $\\frac{1}{5}$ chance of actioning it's host's `web-browser` to access the `ST-DMZ-PUB-SRV-WEB` web-server. "
|
||||
]
|
||||
@@ -618,9 +614,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### AGENTS | Red Agent\n",
|
||||
"### AGENTS | Red Agents\n",
|
||||
"\n",
|
||||
"For UC7, two new red agents have been developed which introduce a much more complex and realistic attacks in comparison to UC2's [data manipulation red agent](./Data-Manipulation-Customising-Red-Agent.ipynb) for the blue agent to defend against. These new red agents, or more commonly referred to `Threat Actor Profiles` (_TAPS_), utilise a series of different green, blue and red actions to simulate the different steps of a real-world attack.\n",
|
||||
"For UC7, two new red agents have been developed which introduce a much more complex and realistic attacks in comparison to UC2's [data manipulation red agent](./Data-Manipulation-Customising-Red-Agent.ipynb) for the blue agent to defend against. These new red agents, or more commonly referred to `Threat Actor Profiles` (*TAPS*), utilise a series of different green, blue and red actions to simulate the different steps of a real-world attack.\n",
|
||||
"\n",
|
||||
"This notebook does not cover the red agents in much detail, hence it is highly recommended that readers should check out the respective TAP notebooks for a much more in-depth look at each TAP and their impacts.\n"
|
||||
]
|
||||
@@ -629,11 +625,11 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### AGENTS | RED AGENT | Threat Actor Profile 001 (TAP001)\n",
|
||||
"### AGENTS | RED AGENT | Threat Actor Profile 001 (`TAP001`)\n",
|
||||
"\n",
|
||||
"This TAP aims to exfiltrate and then encrypt the `database.db` file on `ST_DATA-PRV-SRV-DB` host, whilst leaving the functionality of the database intact. Configured by default to start on the `ST_PROJ-A-PRV-PC-1` host, `TAP001` must first embed itself on the host, locate the target (`ST_DATA-PRV-SRV-DB`) through a series of NMAP scans, establish a connection to it's `C2Server` (`ISP-PUB-SRV-DNS` by default) and then finally attempt to exfiltrate and encrypt. \n",
|
||||
"This TAP aims to exfiltrate and then encrypt the `database.db` file on `ST_DATA-PRV-SRV-DB` host, whilst leaving the functionality of the database intact. Configured by default to start on the `ST_PROJ-A-PRV-PC-1` host, `TAP001` must first embed itself on the host, locate the target (`ST_DATA-PRV-SRV-DB`) through a series of [`nmap`](/PrimAITE/docs/source/simulation_components/system/applications/nmap.rst) scans, establish a connection to it's [`c2-server`](./Command-and-Control-E2E-Demonstration.ipynb)(`ISP-PUB-SRV-DNS` by default) and then finally attempt to exfiltrate and encrypt. \n",
|
||||
"\n",
|
||||
"If successful, the blue agent is configured to receive a serve negative reward and thus must prevent `TAP001` from ever reaching the target database. This could be through blocking it's connection to the target or it's `C2Server` via a carefully crafted ACL or perhaps through more a forceful approach such as shutting down the starting host.\n",
|
||||
"If successful, the blue agent is configured to receive a serve negative reward and thus must prevent `TAP001` from ever reaching the target database. This could be through blocking it's connection to the target or it's `c2-server` via a carefully crafted ACL or perhaps through more a forceful approach such as shutting down the starting host.\n",
|
||||
"\n",
|
||||
"For more information on `TAP001` and it's impacts, [please refer to the TAP001 E2E notebook](./UC7-TAP001-Kill-Chain-E2E.ipynb) or for more blue agent involved demonstration refer to the [UC7 attack variants notebook](./UC7-attack-variants.ipynb) "
|
||||
]
|
||||
@@ -690,9 +686,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### AGENTS | RED AGENT | Threat Actor Profile 003 (TAP003)\n",
|
||||
"### AGENTS | RED AGENT | Threat Actor Profile 003 (`TAP003`)\n",
|
||||
"\n",
|
||||
"Unlike `TAP001` more traditional representation of a threat actor, `TAP003` represents a malicious insider which leverages it's pre-existing knowledge to covertly add malicious access control lists (ACLs) to three different routers each of which affecting green agent traffic in a different way causing the blue agent to receive negative rewards. Thus, the blue agent must learn to leverage it's ability to remove rules and change credentials throughout the network to rectify the impacts of `TA003` and re-establish green POL and prevent TAP003 from accessing additional routers.\n",
|
||||
"Unlike `TAP001`'s more traditional representation of a threat actor, `TAP003` represents a malicious insider which leverages it's pre-existing knowledge to covertly add malicious access control lists (ACLs) to three different routers each of which affecting green agent traffic in a different way causing the blue agent to receive negative rewards. Thus, the blue agent must learn to leverage it's ability to remove rules and change credentials throughout the network to rectify the impacts of `TA003` and re-establish green POL and prevent `TAP003` from accessing additional routers.\n",
|
||||
"\n",
|
||||
"The table below is a brief summary of the malicious acls added by `TAP003`\n",
|
||||
"\n",
|
||||
@@ -776,7 +772,7 @@
|
||||
"\n",
|
||||
"- `observation_space`\n",
|
||||
"\n",
|
||||
"The observation_space (or more commonly `OBS`) refers to the what simulation components the blue agent observes each `time_step`. A blue agent `OBS` can be configured to be as large the entire network or just an individual node. \n",
|
||||
"The observation space (or more commonly `OBS`) refers to the what simulation components the blue agent observes each `time_step`. A blue agent `OBS` can be configured to be as large the entire network or just an individual node. \n",
|
||||
"\n",
|
||||
"- `action_space`\n",
|
||||
"\n",
|
||||
@@ -918,14 +914,14 @@
|
||||
"source": [
|
||||
"#### HOSTS\n",
|
||||
"\n",
|
||||
"By default the blue agent is monitoring `3` different computers and `1` server:\n",
|
||||
"By default the blue agent is monitoring **3** different computers and **4** server:\n",
|
||||
"\n",
|
||||
"|Host label|hostname| services | applications | folders | files |\n",
|
||||
"|:--:|:--:|:--:|:--:|:--:|:--:|\n",
|
||||
"|HOST1|ST_PROJ-A-PRV-PC-1 | ftp-client | ransomware_script, database-client | downloads, exfiltration_folder | malware_dropper.ps1, database.db |\n",
|
||||
"|HOST2|ST_PROJ-B-PRV-PC-2| ftp-client | ransomware-script, database-client | downloads, exfiltration_folder | malware_dropper.ps1, database.db |\n",
|
||||
"|HOST3|ST_PROJ-C-PRV-PC-3| ftp-client | ransomware-script, database-client | downloads, exfiltration_folder | malware_dropper.ps1, database.db |\n",
|
||||
"|HOST4|ST_DATA-PRV-SRV-DB||| database | database.db|\n",
|
||||
"|HOST0|**ST_PROJ-A-PRV-PC-1** | `ftp-client` | `ransomware_script`, `database-client` | `downloads`, `exfiltration_folder `|` malware_dropper.ps1`, `database.db` |\n",
|
||||
"|HOST1|**ST_PROJ-B-PRV-PC-2**| `ftp-client` | `ransomware-script`, `database-client` | `downloads`, `exfiltration_folder` | `malware_dropper.ps1`, `database.db` |\n",
|
||||
"|HOST2|**ST_PROJ-C-PRV-PC-3**| `ftp-client` | `ransomware-script`, `database-client `|` downloads`, `exfiltration_folder` | `malware_dropper.ps1`, `database.db` |\n",
|
||||
"|HOST3|**ST_DATA-PRV-SRV-DB**||| `database` | `database.db`|\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Each `time_step` these hosts report the following to the blue agent:\n",
|
||||
@@ -1102,9 +1098,9 @@
|
||||
"\n",
|
||||
"In addition, the agent can observe the list of Access Control List rules present on routers and firewalls.\n",
|
||||
"\n",
|
||||
"Routers have one ACL and a list of network interfaces (ports)\n",
|
||||
"`Routers` have one ACL which apply to each network interface (which in the context of networking devices are referenced as ports).\n",
|
||||
"\n",
|
||||
"Firewalls have six ACLs and three ports (ports are Internal/External/DMZ, with an Inbound and Outbound ACL for each)\n",
|
||||
"`Firewalls` have six ACLs and three ports. These port are predefined as the `Internal`, `External` and `DMZ` port. Each port comes with two ACL lists - inbound and outbound which apply to traffic ingress and egress on a specific port.\n",
|
||||
"\n",
|
||||
"by default, the UC7 agent is configured to observe `3` different routers:\n",
|
||||
"\n",
|
||||
@@ -1228,7 +1224,7 @@
|
||||
"source": [
|
||||
"obs, reward, _,_,info = env.step(0)\n",
|
||||
"for node_id, node_obs in obs['NODES'].items():\n",
|
||||
" if not \"HOST\" in node_id: # filter out hosts OBS and focus on ROUTER\n",
|
||||
" if not \"HOST\" in node_id: # filter out hosts OBS and focus on ROUTERs\n",
|
||||
" print(node_id)\n",
|
||||
" pprint(node_obs)\n"
|
||||
]
|
||||
@@ -1248,7 +1244,7 @@
|
||||
"\n",
|
||||
"#### `action_map`\n",
|
||||
"\n",
|
||||
"Numerically ordered, the `action_map` combines the options set out previously to define the actual details of what actions and the amount of actions that a blue agent can perform.\n",
|
||||
"Numerically ordered, the `action_map` define the actual details of what actions and the amount of actions that a blue agent can perform.\n",
|
||||
"\n",
|
||||
"For example, the snippet below details the first four actions the the default UC7 blue agent is setup with:\n",
|
||||
"\n",
|
||||
@@ -1284,19 +1280,19 @@
|
||||
"\n",
|
||||
"|Action Num | Action Type | Options|\n",
|
||||
"|:---------:|:-----------:|:------:|\n",
|
||||
"|0|**DONOTHING**|*n/a*|\n",
|
||||
"|1|**NODE_OS_SCAN**|*node_name: ST_PROJ-A-PRV-PC-1*|\n",
|
||||
"|2|**NODE_SHUTDOWN**|*node_name: ST_PROJ-A-PRV-PC-1*|\n",
|
||||
"|3|**NODE_STARTUP**|*node_name: ST_PROJ-A-PRV-PC-1*|\n"
|
||||
"|0|**donothing**|*n/a*|\n",
|
||||
"|1|**node-os-scan**|*node_name: ST_PROJ-A-PRV-PC-1*|\n",
|
||||
"|2|**node-shutdown**|*node_name: ST_PROJ-A-PRV-PC-1*|\n",
|
||||
"|3|**node-startup**|*node_name: ST_PROJ-A-PRV-PC-1*|\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"`0: DONOTHING`:\n",
|
||||
"`0: do-nothing`:\n",
|
||||
"\n",
|
||||
"The first action, `DONOTHING` is a default standard that all agents are setup to use by default in primAITE. Quite simply this action makes no impact to the simulation - literally does nothing. Although this obviously does not seem all that useful, in practice an agent with a small yet impactful actions (such as adding or removing ACL's rules) may find that performing no action may be better than risking a potentially detrimental one.\n",
|
||||
"The first action, `do-nothing` is the default standard that all agents are setup to use by default in primAITE. Quite simply this action makes no impact to the simulation - literally does nothing. Although this obviously does not seem all that useful, in practice an agent with a small yet impactful actions (such as adding or removing ACL's rules) may find that performing no action may be better than using a potentially detrimental one .\n",
|
||||
"\n",
|
||||
"Additionally, you may spotted the code snippet below dotted around this notebook and many others.\n",
|
||||
"\n",
|
||||
@@ -1316,20 +1312,20 @@
|
||||
"env.reset()\n",
|
||||
"env.step(0)\n",
|
||||
"defender = env.game.rl_agents.get(\"defender\")\n",
|
||||
"print(defender.history[0])"
|
||||
"defender.show_history(ignored_actions=['']) # By default `show_history()` will ignore 'do-nothing'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"`1: NODE_OS_SCAN`:\n",
|
||||
"`1: node-os-scan`:\n",
|
||||
"\n",
|
||||
"The first actual action that the blue agent can perform is scanning action. A variety of different scanning type actions (such as `NODE_APPLICATION_SCAN` or `NODE_FILE/FOLDER_SCAN`) which can be used to by the blue agent to gain a deeper understanding of the simulation state. Specifically, these actions will cause the blue agent's observations to update to the \"true\" `HEALTH_STATUS` of a simulation component. The `NODE_OS_SCAN` acts a combined version of all these scan type actions.\n",
|
||||
"The first actual action that the blue agent can perform is scanning action. The blue agent is capable of a variety of different scanning type actions (such as `node-application-scan` or `node-file/folder-scan`) which can be used to gain a deeper understanding of the simulation state. Specifically, these actions will cause the blue agent's observations to update to the **\"true\"** `health_status` of a simulation component. The `node-os-scan` acts a combined version of all these scan type actions.\n",
|
||||
"\n",
|
||||
"For example, if a red agent corrupts and alters the health status of a file, the blue agent's observation space will not reflect this until the agent performs a `NODE_FILE_SCAN` on the newly corrupted file. It's worth noting that blue agents can be configured to see the true `HEALTH_STATUS` of software and files without needing to scan in the yaml. Although this may make it easier for an train and create an effective blue agent it could be seen as reducing the fidelity of the simulation.\n",
|
||||
"For example, if a red agent corrupts and alters the health status of a file, the blue agent's observation space will not reflect this until the agent performs a `node-file-scan` on the newly corrupted file. It's worth noting that blue agents can be configured to see the true `health_status` of software and files without needing to scan in the yaml. Although this may make it easier for an train and create an effective blue agent it could be seen as reducing the fidelity of the simulation.\n",
|
||||
"\n",
|
||||
"The code snippet below demonstrates an example where the blue agent uses the `NODE_OS_SCAN` action to reveal the true health status `ST_PROJ-A-PRV-PC-1`."
|
||||
"The code snippet below demonstrates an example where the blue agent uses the `node-os-scan` action to reveal the true health status `ST_PROJ-A-PRV-PC-1`."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1339,7 +1335,6 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"obs, reward, term, trunc, info = env.step(0)\n",
|
||||
"print(defender.history[1])\n",
|
||||
"print(f\"ftp-client (Prior Scan) OBS: {defender.observation_manager.current_observation['NODES']['HOST0']['SERVICES'][1]}\")\n",
|
||||
"print(f\"database-client (Prior Scan) OBS: {defender.observation_manager.current_observation['NODES']['HOST0']['APPLICATIONS'][2]}\")"
|
||||
]
|
||||
@@ -1371,7 +1366,7 @@
|
||||
"source": [
|
||||
"print(f'Node OS Scan time step duration: {cfg[\"simulation\"][\"defaults\"][\"node_scan_duration\"]}')\n",
|
||||
"env.step(1)\n",
|
||||
"print(defender.history[2])\n",
|
||||
"print(defender.show_history())\n",
|
||||
"for _ in range(9):\n",
|
||||
" obs, reward, term, trunc, info = env.step(0)\n",
|
||||
"\n",
|
||||
@@ -1384,9 +1379,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"`2: NODE_SHUTDOWN`:\n",
|
||||
"`2: node-shutdown`:\n",
|
||||
"\n",
|
||||
"The next action available is the `NODE_SHUTDOWN` action. This action quite is quite simple in comparison and literally attempts to shut down the target host given in the `options` settings which is set to `ST_PROJ-A-PRV-PC-1`. Shutting a PC down affects the `operating_status` of the host machine which the following snippets demonstrate."
|
||||
"The next action available is `node-shutdown`. This action quite simply attempts to shut down the given `node_name` which in this case is set to `ST_PROJ-A-PRV-PC-1`. Shutting a PC down affects the `operating_status` of the host machine which the following snippets demonstrate."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1397,7 +1392,14 @@
|
||||
"source": [
|
||||
"# `1` is equal to 'ON' in this case.\n",
|
||||
"obs, reward, term, trunc, info = env.step(0)\n",
|
||||
"print(f\"ST_PROJ-A-PRV-PC-1's (prior shutdown) operating state: {defender.observation_manager.current_observation['NODES']['HOST0']['operating_status']}\")"
|
||||
"print(f\"ST_PROJ-A-PRV-PC-1's (prior `node-shutdown`) operating state: {defender.observation_manager.current_observation['NODES']['HOST0']['operating_status']}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"As mentioned previously, some actions require a number of timesteps to elapse before their impact is resolved within the simulation. `node-shutdown` by default takes three timesteps to take effect."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1407,8 +1409,9 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"obs, reward, term, trunc, info = env.step(2)\n",
|
||||
"# Skipping three timesteps by forcing the blue agent into performing a `do-nothing` action.\n",
|
||||
"for _ in range(3):\n",
|
||||
" env.step(0) # 3 second shut down time.\n"
|
||||
" env.step(0) "
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1418,16 +1421,16 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"obs, reward, term, trunc, info = env.step(0)\n",
|
||||
"print(f\"ST_PROJ-A-PRV-PC-1's (post shutdown) operating state: {defender.observation_manager.current_observation['NODES']['HOST0']['operating_status']}\")"
|
||||
"print(f\"ST_PROJ-A-PRV-PC-1's (post `node-shutdown`) operating state: {defender.observation_manager.current_observation['NODES']['HOST0']['operating_status']}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"`3: NODE_STARTUP`:\n",
|
||||
"`3: node-startup`:\n",
|
||||
"\n",
|
||||
"Luckily, the blue agent can use it's third action `NODE_STARTUP` has been configured to bring the `ST_PROJ-A-PRV-PC-1` back up and running. Although, with the a three timestep reboot time.\n"
|
||||
"Lastly, the blue agent third action `node-startup` can be used to bring the `ST_PROJ-A-PRV-PC-1` back up and running. Similar to the previous action, `node-startup` takes three timesteps.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1442,7 +1445,16 @@
|
||||
" env.step(0) # 3 second reboot time.\n",
|
||||
" \n",
|
||||
"obs, reward, term, trunc, info = env.step(0)\n",
|
||||
"print(f\"ST_PROJ-A-PRV-PC-1's (prior shutdown) operating state: {defender.observation_manager.current_observation['NODES']['HOST0']['operating_status']}\")"
|
||||
"print(f\"ST_PROJ-A-PRV-PC-1's (post `node-startup`) operating state: {defender.observation_manager.current_observation['NODES']['HOST0']['operating_status']}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(defender.show_history())"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1458,7 +1470,7 @@
|
||||
"```yaml\n",
|
||||
" reward_function:\n",
|
||||
" reward_components:\n",
|
||||
" - type: DATABASE_FILE_INTEGRITY\n",
|
||||
" - type: database-file-integrity\n",
|
||||
" weight: *HIGH_WEIGHT_IMPACT\n",
|
||||
" options: \n",
|
||||
" node_hostname: ST_DATA-PRV-SRV-DB \n",
|
||||
@@ -1466,7 +1478,7 @@
|
||||
" file_name: database.db\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The blue agent's remaining reward function is comprised of **32** different ``SHARED_REWARD`` components. These rewards will grant the blue agent a positive or negative reward based on the current reward of the **32** green agents. The next code snippets The code snippets below demonstrate how the blue agent's reward is affected by simulation state."
|
||||
"The blue agent's remaining reward function is comprised of **32** different ``shared-reward`` components. These rewards will grant the blue agent a positive or negative reward based on the current reward of the **32** green agents. The next code snippets The code snippets below demonstrate how the blue agent's reward is affected by simulation state."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1584,7 +1596,7 @@
|
||||
"st_dmz_pub_srv_web: Server = env.game.simulation.network.get_node_by_hostname(\"ST_DMZ-PUB-SRV-WEB\")\n",
|
||||
"st_dmz_pub_srv_web.software_manager.software[\"web-server\"].operating_state = ServiceOperatingState.DISABLED\n",
|
||||
"\n",
|
||||
"# Shutting down the DNSServer\n",
|
||||
"# Shutting down the dns-server\n",
|
||||
"\n",
|
||||
"isp_pub_srv_dns_server: Server = env.game.simulation.network.get_node_by_hostname(\"ISP-PUB-SRV-DNS\")\n",
|
||||
"isp_pub_srv_dns_server.software_manager.software[\"dns-server\"].operating_state = ServiceOperatingState.DISABLED\n",
|
||||
@@ -1597,7 +1609,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
|
||||
@@ -4,20 +4,19 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Mobile Malware Kill Chain - Ransomware Script Variant\n",
|
||||
"# TAP001 - Mobile Malware Kill Chain\n",
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"**Threat Actor Profile (TAP):** 001 <br/>\n",
|
||||
"**Kill Chain**: Mobile Malware - Ransomware Script Variant\n",
|
||||
"\n",
|
||||
"This notebook demonstrates TAP001 on the UC7 network infrastructure. In this scenario, a some_tech employee within the development project network plugs in his personal device. Whilst browsing, they encounter a ransomware virus which moves onto the host machine thus triggering the malware! \n",
|
||||
"<br/>\n",
|
||||
"This notebook demonstrates the new threat actor profile (TAP) on the UC7 network infrastructure. In this scenario, a `some_tech` employee within the development project network plugs in his personal device. Whilst browsing, they encounter a ransomware virus which moves onto the host machine thus triggering the malware! \n",
|
||||
"\n",
|
||||
"This ransomware variant targets the database service's file directly, rather than the disrupting the database service, hence why in this scenario the data service still functions after becoming corrupted.\n",
|
||||
"<br/>\n",
|
||||
"\n",
|
||||
"The red attack intends to introduce realistic impacts to the observation space, such as files created/removed and applications installing mid-episode whilst still providing usable data for agent training."
|
||||
"This malware variant targets the database service's file directly, rather than the disrupting the service, hence why in this scenario the `data-service` is still functional after becoming corrupted.\n",
|
||||
"\n",
|
||||
"This new red agent intends to introduce more realistic impacts to the observation space, such as files created/removed and applications installing mid-episode whilst still providing the configurability needed for effective blue agent training."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -173,9 +172,10 @@
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Notebook Setup** | Instantiating Relevant Simulation Objects\n",
|
||||
"Simulation objects can be instantiated and called independently of agents via the environment.game.simulation (PrimAITE API).\n",
|
||||
"\n",
|
||||
"[Please refer to the main UC7 notebook for further details regarding agent implementations and the general UC7 scenario.](./example layout-E2E-Demo.ipynb)"
|
||||
"Simulation objects can be instantiated and called independently of agents via the environment.game.simulation (PrimAITE API) which is useful for demonstrating the simulation state at different points within an episode.\n",
|
||||
"\n",
|
||||
"Any readers unfamiliar with the UC7 scenario should refer to the [main UC7 notebook for further details](./UC7-E2E-Demo.ipynb)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -205,7 +205,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The first section of this notebook displays the relevant default Observation Space (OBS)."
|
||||
"The first section of this notebook displays the relevant initial `observation_space` (OBS) of effected nodes before the attack takes place."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -316,7 +316,7 @@
|
||||
" </a> \n",
|
||||
"</p>\n",
|
||||
"\n",
|
||||
"In this stage, TAP001 uses the **NODE_FOLDER_CREATE** and **NODE_FILE_CREATE** to create a file called ```\"malware_dropper.ps1\"``` within a ```\"Downloads\"``` folder. <br>\n",
|
||||
"In this stage, TAP001 uses the **node-folder-create** and **node-file-create** to create a file called ```\"malware_dropper.ps1\"``` within a ```\"Downloads\"``` folder. <br>\n",
|
||||
"These actions are intended to simulate the malicious payload creating a ```ps1``` (A windows powershell script) malware dropper on the `SOME_TECH` employee's phone. \n",
|
||||
"\n",
|
||||
"Currently, PrimAITE cannot simulate hosts joining the simulation mid-episode thus we must treat `ST_PROJ-A-PRV-PC-1`'s as also including the employee's phone. <br>\n",
|
||||
@@ -350,7 +350,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"tap001.logger.show()"
|
||||
"tap001.logger.show()\n",
|
||||
"tap001.show_history()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -369,7 +370,7 @@
|
||||
" \n",
|
||||
"</p>\n",
|
||||
"\n",
|
||||
"In this stage, TAP001 uses the **NODE_FILE_ACCESS** to increase the number of accesses of the ```\"malware_dropper.ps1\"```. <br>\n",
|
||||
"In this stage, TAP001 uses the **node-file-access** to increase the number of accesses of the ```\"malware_dropper.ps1\"```. <br>\n",
|
||||
"\n",
|
||||
"These actions represent the employee executing malware dropper created in the previous stage. "
|
||||
]
|
||||
@@ -399,7 +400,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"tap001.logger.show()"
|
||||
"tap001.logger.show()\n",
|
||||
"tap001.show_history()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -419,12 +421,10 @@
|
||||
" \n",
|
||||
"</p>\n",
|
||||
"\n",
|
||||
"In this stage, TAP001 uses the **NODE_APPLICATION_INSTALL** to install the ransomware application onto the starting host. <br>\n",
|
||||
"In this stage, TAP001 uses the **node-application-install** to install the ransomware application onto the starting host. <br>\n",
|
||||
"\n",
|
||||
"These actions represent the malware dropper successfully installing ransomware on the host machine. Similarly to the malware dropper, the ransomware currently implemented is intended to be a generic and OS agnostic ransomware which is not intended to represent any specific real world implementation. \n",
|
||||
"\n",
|
||||
"Please see the [Ransomware Notebook](./Ransomware-Kill-Chain-E2E.ipynb) for further information about the current implementation of the ransomware application.\n",
|
||||
"\n",
|
||||
"Future versions of PrimAITE intend to expand the capability of the ransomware application to more faithfully represent a real-world example; for example, a Trickbot variation such as Ryuk or Conti."
|
||||
]
|
||||
},
|
||||
@@ -463,7 +463,7 @@
|
||||
"|-----|------------|----------|---------|\n",
|
||||
"|4|Propagate|HOST:NICS:NIC:TRAFFIC:PROTOCOL:PORT:*|The malware attempts to spread to other systems or networks, looking for vulnerable services.|\n",
|
||||
"\n",
|
||||
"In this stage, TAP001 uses **NODE_NMAP_PORT_SCAN**, **NODE_NMAP_PING_SCAN** and **NODE_NMAP_NETWORK_SERVICE_RECON** to scan the simulation in order to search for a valid database target.\n",
|
||||
"In this stage, TAP001 uses **node-nmap-port-scan**, **node-nmap-ping-scan** and **node-nmap-network-service-recon** to scan the simulation in order to search for a valid database target.\n",
|
||||
"\n",
|
||||
"Unlike previous stages, the behaviour of this stage is dependant on the simulation and thus will perform differently dependant on the location of the target as well as the topology of the network. Specifically, the ```PROPAGATE``` stage uses three network enumeration actions and their action responses to populate its knowledge of the network.<br>\n",
|
||||
"These actions represent the now infected `ST_PROJ-A-PRV-PC-1` searching the UC7 network for valid targets ransomware. \n",
|
||||
@@ -481,7 +481,7 @@
|
||||
"source": [
|
||||
"#### **Kill Chain** | PROPAGATE | Scan walkthrough\n",
|
||||
"\n",
|
||||
"The next juypter cells of this notebook will go through each individual CAOS action that the TAP001 leverages to reach the target host as well as the OBS each action impacts.\n",
|
||||
"The next juypter cells of this notebook will go through each individual nmap action that the TAP001 leverages to reach the target host as well as the OBS each action impacts.\n",
|
||||
"\n",
|
||||
"This section uses the following ```PROPAGATE``` relevant TAP001 settings:\n",
|
||||
"```yaml\n",
|
||||
@@ -788,7 +788,7 @@
|
||||
"</p>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"For further details please refer to the ``Command-and-Control-E2E-Demonstration`` notebook.\n",
|
||||
"For further details please refer to the [Command-and-Control-E2E-Demonstration notebook](./Command-and-Control-E2E-Demonstration.ipynb).\n",
|
||||
"\n",
|
||||
"_Note: The referenced notebook above uses the UC2 scenario for demonstration purposes, however all the OBS impacts and C2 suite functionality is equally applicable to UC7._\n",
|
||||
"\n"
|
||||
@@ -921,7 +921,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We can also see that the database.db file was successfully exfiltrated."
|
||||
"We can also see that the `database.db` file was successfully exfiltrated."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -948,16 +948,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## **Post Attack Impacts**\n",
|
||||
"\n",
|
||||
"Please refer to the [Ransomware E2E Notebook](./Ransomware-Kill-Chain-E2E.ipynb) for an in-depth look on the knock-on affects of the ransomware application."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Attack Configurations** | Threat Actor Profile Settings"
|
||||
"### **Attack Configurations** "
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1294,7 +1285,7 @@
|
||||
"\n",
|
||||
"<sup>[1]</sup> _PrimAITE does not actually enforce agent type (Red/Green/Blue) specific actions_\n",
|
||||
"\n",
|
||||
"_However, some actions such as ``APPLICATION_EXECUTE`` and ``NETWORK_RECON_SCAN`` require an understanding of the simulation that is beyond the blue agent's current observation and thus are not suitable for use by reinforcement algorithms._\n",
|
||||
"_However, some actions such as `node-application-execute` and `node-nmap-network-service-recon` require an understanding of the simulation that is beyond the blue agent's current observation and thus are not suitable for use by reinforcement algorithms._\n",
|
||||
"\n",
|
||||
"_These actions are usually only leveraged by Green or Red agents; hence why they are commonly referenced as such._\n",
|
||||
"\n",
|
||||
@@ -1307,7 +1298,7 @@
|
||||
"source": [
|
||||
"#### **Attack Configurations** | Mobile Malware Kill Chain | Command and Control Stage\n",
|
||||
"\n",
|
||||
"TAP001's Command and Control stage leverages the C2 beacon which has it's own set of configuration options. In the case of TAP001 some of these settings are already pre-defined based on other settings such as ``target_node``. The table below details the currently available options.\n",
|
||||
"TAP001's Command and Control stage leverages the `c2-beacon` which has it's own set of configuration options. In the case of TAP001 some of these settings are already pre-defined based on other settings such as ``target_node``. The table below details the currently available options.\n",
|
||||
"\n",
|
||||
"<details> <summary> Command and Control Configuration Settings </summary>\n",
|
||||
"\n",
|
||||
@@ -1318,9 +1309,10 @@
|
||||
"|keep_alive_frequency | How often should the C2 Beacon confirm its connection in timesteps. Defaults to 5 |Int | _Optional_ |\n",
|
||||
"|masquerade_port | What port should the C2 traffic use? Defaults to TCP. |Str | _Optional_ |\n",
|
||||
"|masquerade_protocol | What protocol should the C2 traffic masquerade as? Defaults to HTTP. |Str | _Optional_ |\n",
|
||||
"\n",
|
||||
"</details> \n",
|
||||
"\n",
|
||||
"For further information around the configuration of the C2 beacon please refer to the ``Command-&-Control-E2E-Demonstration`` last section on configurability."
|
||||
"For further information around the configuration of the `c2-beacon` please refer to the [Command-&-Control-E2E-Demonstration notebook](./Command-and-Control-E2E-Demonstration.ipynb)'s last section on configurability."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1347,7 +1339,7 @@
|
||||
" cfg['agents'][32]['agent_settings']['kill_chain']['COMMAND_AND_CONTROL'][\"masquerade_protocol\"] = \"TCP\"\n",
|
||||
"env = PrimaiteGymEnv(env_config = cfg)\n",
|
||||
"env.reset()\n",
|
||||
"# TAP001 runs for exactly 110 timesteps using default TAP settings.\n",
|
||||
"# TAP001 requires around 110 timesteps using default TAP settings.\n",
|
||||
"for _ in range(110):\n",
|
||||
" env.step(0)"
|
||||
]
|
||||
@@ -1356,7 +1348,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The code cells below use .show() methods to show that the configuration options have successfully altered the C2's suite configuration. For example the C2 beacon's remote connection is now ``REM-PUB-PC-1``'s ip address which is ``192.168.20.2``."
|
||||
"The code cells below use .show() methods to show that the configuration options have successfully altered the C2's suite configuration. For example the `c2-beacon`'s remote connection is now ``REM-PUB-PC-1``'s ip address which is ``192.168.20.2``."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1448,7 +1440,7 @@
|
||||
"|exfiltrate | Should TAP001 exfiltrate the target database.db file? |Boolean | _Required_ |\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Similar to ``corrupt``, this option is a boolean value which indicates if TAP001 should attempt to exfiltrate the database.db file.\n",
|
||||
"Similar to ``corrupt``, this option is a boolean value which indicates if TAP001 should attempt to exfiltrate the `database.db` file.\n",
|
||||
"\n",
|
||||
"By default this is enabled but if users wish to disable the exfiltration for training purposes then this value can be set to ``False`` which will prevent the TAP001 agent from attempting to exfiltrate the database.db file."
|
||||
]
|
||||
@@ -1457,14 +1449,14 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"_If both ``exfiltrate`` and ``corrupt`` options are enabled then the TAP001 agent will exfiltrate the database.db and then launch the ``RansomwareScript`` against the target._"
|
||||
"_If both ``exfiltrate`` and ``corrupt`` options are enabled then the TAP001 agent will exfiltrate the database.db and then launch the ``ransomware-script`` against the target._"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Yaml Example:\n",
|
||||
"_yaml config example_\n",
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
" kill_chain:\n",
|
||||
@@ -1822,7 +1814,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
|
||||
@@ -4,26 +4,25 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Backdoor & Vulnerability Creation Kill Chain\n",
|
||||
"# TAP003 - Malicious Insider Kill Chain\n",
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"**Threat Actor Profile (TAP):** 003 <br/>\n",
|
||||
"**Kill Chain**: Backdoor & Vulnerability Creation"
|
||||
"**Kill Chain**: Insider"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook demonstrates a new UC7 Kill Chain which aims to represent a different style of attack in comparison to the mobile malware kill chain (TAP001).\n",
|
||||
"Kill chains aim to represent a potential real world cyber attack. In this scenario an malicious `SOME_TECH` admin (TAP003) leverages his legitimate credentials and permissions to create purposeful backdoors, establish footholds and use other legitimate features in malicious ways.\n",
|
||||
"This notebook demonstrates the new TAP003 red agent which simulates a malicious insider which performs an internal cyber attack. In this scenario an malicious `some_tech` admin leverages their legitimate credentials and permissions to create purposeful backdoors, establish footholds and use other legitimate features in malicious ways.\n",
|
||||
"<br/>\n",
|
||||
"\n",
|
||||
"In this version - this scenario is limited in scope. TAP003 opts to alter user accounts and implement malicious ACL rule by using the ``terminal`` service to SSH into target routers. These ACLs block green traffic which trigger a negative reward.\n",
|
||||
"In this version of PrimAITE, TAP003 opts to alter user accounts and implement malicious ACL rule by using the ``terminal`` service to SSH into target routers. These ACLs block green traffic which trigger a negative reward.\n",
|
||||
"<br/>\n",
|
||||
"\n",
|
||||
"This kill chain intends to introduce a new UC7 attack which is both realistic but also dissimilar to other kill chains."
|
||||
"This TAP was designed to be both realistic but also dissimilar to the more traditional red agents such as [TAP001](./UC7-TAP001-Kill-Chain-E2E.ipynb) or use case 2's [data_manipulation_bot](./Data-Manipulation-Customising-Red-Agent.ipynb)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -101,10 +100,10 @@
|
||||
" node = item.parameters.get('node_name')\n",
|
||||
"\n",
|
||||
" else:\n",
|
||||
" if (node_id := item.parameters.get('node_id')) is not None:\n",
|
||||
" node = env.game.agents[agent_name].action_manager.node_names[node_id]\n",
|
||||
" if (application_id := item.parameters.get('application_id')) is not None:\n",
|
||||
" application = env.game.agents[agent_name].action_manager.application_names[node_id][application_id]\n",
|
||||
" if (item.parameters.get('node_name')) is not None:\n",
|
||||
" node = item.parameters.get('node_name')\n",
|
||||
" if (item.parameters.get('application_name')) is not None:\n",
|
||||
" application = item.parameters.get('application_name')\n",
|
||||
" if (application_name := item.parameters.get('application_name')) is not None:\n",
|
||||
" application = application_name\n",
|
||||
"\n",
|
||||
@@ -157,39 +156,38 @@
|
||||
"source": [
|
||||
"### **Notebook Intro** | **Backdoor & Vulnerability Creation Kill Chain Intro** \n",
|
||||
"\n",
|
||||
"TAP003's kill chain is comprised of a variety of blue actions which are leveraged in unusual ways. This includes introducing malicious ACL's which block green traffic and installing and execute green applications in order to simulate unusual green pattern of life. The rest of this notebook will go through each step in more detail whilst demonstrating the impacts that each step has on both observation and simulation behaviour.\n",
|
||||
"TAP003's kill chain is comprised of a variety of blue actions which are leveraged in unusual ways. This includes introducing malicious ACL's which block green traffic. The rest of this notebook will go through each step in more detail whilst demonstrating the impacts that each step has on both observation and simulation behaviour.\n",
|
||||
"\n",
|
||||
"_Reconnaissance - DONOTHING CAOS Action_\n",
|
||||
"_Reconnaissance_\n",
|
||||
"\n",
|
||||
"|Index | Action Stage| OBS Impact | Narrative |\n",
|
||||
"|-----|-------------|-------------|-----------|\n",
|
||||
"|1|Reconnaissance|*No Direct Impact*|TAP003 is passively investigating sensitive systems, data and access control mechanisms.|\n",
|
||||
"|Index | Action Stage| OBS Impact | Narrative |action(s)|\n",
|
||||
"|-----|-------------|-------------|-----------|---|\n",
|
||||
"|1|Reconnaissance|*No Direct Impact*|TAP003 is passively investigating sensitive systems, data and access control mechanisms.|`do-nothing`|\n",
|
||||
"\n",
|
||||
"_Planning - DONOTHING CAOS Action_\n",
|
||||
"_Planning_\n",
|
||||
"\n",
|
||||
"|Index| Action Stage| OBS Impact | Narrative |\n",
|
||||
"|-----|-------------|------------|-----------|\n",
|
||||
"|2|Planning| **No current impact**|TAP003 is devising a plan to exploit their elevated privileges.|\n",
|
||||
"|Index| Action Stage| OBS Impact | Narrative |action(s)|\n",
|
||||
"|-----|-------------|------------|-----------|---|\n",
|
||||
"|2|Planning| **No current impact**|TAP003 is devising a plan to exploit their elevated privileges.|`do-nothing`|\n",
|
||||
"\n",
|
||||
" _Access - DONOTHING CAOS Action__\n",
|
||||
" _Access_\n",
|
||||
"\n",
|
||||
"|Index| Action Stage| OBS Impact | Narrative |\n",
|
||||
"|-----|-------------|------------|-----------|\n",
|
||||
"|3|Access|**No current impact** |TAP003 uses their legitimate credentials to access the access control settings.|\n",
|
||||
"|Index| Action Stage| OBS Impact | Narrative |action(s)|\n",
|
||||
"|-----|-------------|------------|-----------|---|\n",
|
||||
"|3|Access|**No current impact** |TAP003 uses their legitimate credentials to access the access control settings.|`do-nothing`|\n",
|
||||
"\n",
|
||||
" _Manipulation - HOST:SESSIONS_SEND_REMOTE_COMMAND -> HOST:ACCOUNTS:CHANGE:PASSWORD CAOS ACTION_\n",
|
||||
" _Manipulation_\n",
|
||||
" \n",
|
||||
"|Index| Action Stage| OBS Impact | Narrative |\n",
|
||||
"|-----|-------------|------------|-----------|\n",
|
||||
"|4|Manipulation| **Target Host(s)** HOST::SESSIONS:REMOTE |TAP003 exploits their insider knowledge/privilege to implement changes for sabotage.|\n",
|
||||
"|Index| Action Stage| OBS Impact | Narrative |action(s)|\n",
|
||||
"|-----|-------------|------------|-----------|---|\n",
|
||||
"|4|Manipulation| **Target Host(s)** HOST::SESSIONS:REMOTE |TAP003 exploits their insider knowledge/privilege to implement changes for sabotage.| - `node-session-remote-login` & `sessions-send-remote-command` (`node-account-change-password`)|\n",
|
||||
"\n",
|
||||
" _Exploit - FIREWALL:ACL:add_rule CAOS ACTION_\n",
|
||||
"_Exploit_\n",
|
||||
"\n",
|
||||
"|Index| Action Stage| OBS Impact | Narrative |\n",
|
||||
"|-----|-------------|------------|-----------|\n",
|
||||
"|5|Exploit| **Target Host(s)** FIREWALL:ACL:INTERNAL/EXTERNAL:*|TAP003 exploits their insider knowledge/privilege to implement changes for sabotage.|\n",
|
||||
"\n",
|
||||
"_Only the initial five steps are represented in the this version of this kill-chain._ <br/>\n"
|
||||
"|Index| Action Stage| OBS Impact | Narrative |action(s)|\n",
|
||||
"|-----|-------------|------------|-----------|---|\n",
|
||||
"|5|Exploit| **Target Host(s)** ROUTER:ACL:INTERNAL/EXTERNAL:*|TAP003 exploits their insider knowledge/privilege to implement changes for sabotage.| `node-session-remote-login` & `node-session-send-remote-command` (`router-acl-addrule`) |\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -198,9 +196,7 @@
|
||||
"source": [
|
||||
"## **Notebook Setup** | **Network Configuration:**\n",
|
||||
"\n",
|
||||
"This notebook uses the same network setup as UC7. \n",
|
||||
"\n",
|
||||
"Please refer to the main [UC7-E2E-Demo notebook for further reference](./UC7-E2E-Demo.ipynb)."
|
||||
"Any readers unfamiliar with UC7 can refer to the main [UC7-E2E-Demo notebook for further reference](./UC7-E2E-Demo.ipynb)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -255,7 +251,7 @@
|
||||
"source": [
|
||||
"env.reset() # resetting the environment\n",
|
||||
"# The TAP003 Agent\n",
|
||||
"tap003 = env.game.agents['attacker']\n",
|
||||
"tap003: TAP003 = env.game.agents['attacker']\n",
|
||||
"tap003.logger.logger.setLevel(\"INFO\")"
|
||||
]
|
||||
},
|
||||
@@ -483,7 +479,7 @@
|
||||
"|-----|-------------|------------|-----------|\n",
|
||||
"|1|RECONNAISSANCE|*No Direct Impact*|TAP003 is identifying Sensitive systems, data and access control mechanisms in legitimate ways.|\n",
|
||||
"\n",
|
||||
"Currently, this stage in the kill chain is implemented via the 'DONOTHING' CAOS action."
|
||||
"Currently, this stage in the kill chain is implemented via the 'do-nothing' CAOS action."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -566,7 +562,7 @@
|
||||
"\n",
|
||||
"|Index| Action Stage| OBS Impact | Narrative |\n",
|
||||
"|-----|-------------|------------|-----------|\n",
|
||||
"|3|Access|_DONOTHING CAOS Action_|TAP003 uses their legitimate credentials to access the access control settings.|\n",
|
||||
"|3|Access|_do-nothing CAOS Action_|TAP003 uses their legitimate credentials to access the access control settings.|\n",
|
||||
"\n",
|
||||
"Currently, at this point of the kill chain stage the TAP003 does not perform any simulations actions. Future versions of TAP003 aim to leverage more of the simulation to create and remove accounts at this stage."
|
||||
]
|
||||
@@ -1692,7 +1688,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"# Training an SB3 Agent\n",
|
||||
"# Training an Agent on UC7\n",
|
||||
"\n",
|
||||
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
|
||||
"\n",
|
||||
"This notebook will demonstrate how to use primaite to create and train a PPO agent, using a pre-defined configuration file."
|
||||
"This notebook is identical in content to the [training an SB3 agent](./Training-an-SB3-Agent.ipynb) except this notebook trains an agent on the [use case 7 scenario](./UC7-E2E-Demo.ipynb) rather than [use case 2](./Data-Manipulation-E2E-Demonstration.ipynb). By default, the `uc7_config.yaml` blue agent (`defender`) is setup to defend against Threat Actor Profile (TAP) 001 which can be explored in more detail [here](./UC7-TAP001-Kill-Chain-E2E.ipynb).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -42,10 +42,6 @@
|
||||
"from primaite import PRIMAITE_PATHS\n",
|
||||
"from prettytable import PrettyTable\n",
|
||||
"from deepdiff.diff import DeepDiff\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.server import Server\n",
|
||||
"from primaite.simulator.network.hardware.nodes.network.router import Router\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.computer import Computer\n",
|
||||
"\n",
|
||||
"scenario_path = PRIMAITE_PATHS.user_config_path / \"example_config/uc7_config.yaml\""
|
||||
]
|
||||
},
|
||||
@@ -125,21 +121,9 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"This notebook demonstrates the PrimAITE environment with the UC7 network laydown and multiple attack personas. The first attack persona is TAP001 which performs a ransomware attack against the database. The other one is TAP003 which is able to maliciously add ACL rules that block green pattern of life.\n",
|
||||
"This notebook demonstrates the PrimAITE environment with the UC7 network laydown and multiple attack personas. The first threat actor persona is **TAP001** which performs a ransomware attack against the database. The other one is **TAP003** which is able to maliciously add ACL rules that block green pattern of life.\n",
|
||||
"\n",
|
||||
"The environment switches between these two attacks on a pre-defined schedule which is defined in the schedule.yaml file of the scenario folder."
|
||||
"Any users unfamiliar with these red agents should take a look into the [TAP001 notebook](./UC7-TAP001-Kill-Chain-E2E.ipynb) and the [TAP003 notebook](./UC7-TAP003-Kill-Chain-E2E.ipynb) for further details.\n",
|
||||
"\n",
|
||||
"The environment switches between these two attacks on a pre-defined schedule which is defined in the `schedule.yaml` file of the scenario folder."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -44,32 +46,15 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import yaml\n",
|
||||
"from primaite.session.environment import PrimaiteGymEnv\n",
|
||||
"from primaite import PRIMAITE_PATHS\n",
|
||||
"from prettytable import PrettyTable\n",
|
||||
"from deepdiff.diff import DeepDiff\n",
|
||||
"from primaite.session.environment import PrimaiteGymEnv\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.computer import Computer\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.server import Server\n",
|
||||
"from primaite.simulator.network.hardware.nodes.network.router import Router\n",
|
||||
"from primaite.simulator.system.services.dns.dns_server import DNSServer\n",
|
||||
"from primaite.simulator.system.software import SoftwareHealthState\n",
|
||||
"from primaite.simulator.file_system.file_system_item_abc import FileSystemItemHealthStatus\n",
|
||||
"from primaite.simulator.network.hardware.nodes.network.switch import Switch\n",
|
||||
"from primaite.simulator.system.applications.web_browser import WebBrowser\n",
|
||||
"from primaite.simulator.network.container import Network\n",
|
||||
"from primaite.simulator.system.services.service import ServiceOperatingState\n",
|
||||
"from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState\n",
|
||||
"from primaite.simulator.system.services.database.database_service import DatabaseService\n",
|
||||
"from primaite.simulator.system.applications.database_client import DatabaseClient\n",
|
||||
"from primaite.simulator.network.hardware.nodes.network.firewall import Firewall\n",
|
||||
"from primaite.game.game import PrimaiteGame\n",
|
||||
"from primaite.simulator.sim_container import Simulation\n",
|
||||
"from primaite.config.load import load, _EXAMPLE_CFG\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.server import Server\n",
|
||||
"from primaite.simulator.network.hardware.nodes.network.router import Router\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.computer import Computer\n",
|
||||
"\n",
|
||||
"scenario_path = PRIMAITE_PATHS.user_config_path / \"example_config/uc7_multiple_attack_variants\""
|
||||
]
|
||||
@@ -220,7 +205,7 @@
|
||||
"source": [
|
||||
"The blue agent should be able to prevent the ransomware attack by blocking the red agent's access to the database. Let's run the environment until the observation space shows symptoms of the attack starting.\n",
|
||||
"\n",
|
||||
"Because we are in episode index 1, the red agent will use `ST-PROJ-A-PRV-PC-1` to start the attack. On step 25, the red agent installs `RansomwareScript`."
|
||||
"Because we are in episode index 1, the red agent will use `ST_PROJ-A-PRV-PC-1` to start the attack. On step 25, the red agent installs `ransomware-script`."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -246,9 +231,33 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We can see that on HOST0, application index 1 has gone from `operating_status` 0 to 3, meaning there wasn't an application before, but now there is an application in the `INSTALLING` state. The blue agent should be able to detect this and block the red agent's access to the database. Action 43 will block `ST-PROJ-A-PRV-PC-1` from sending POSTGRES traffic to the DB server.\n",
|
||||
"We can see that on HOST0, application index 1 has gone from `operating_status` 0 to 3, meaning there wasn't an application before, but now there is an application in the `INSTALLING` state. The blue agent should be able to detect this and block the red agent's access to the database. Action 43 will block `ST_PROJ-A-PRV-PC-1` from sending POSTGRES traffic to the DB server.\n",
|
||||
"\n",
|
||||
"If this were a different episode, it could have been `ST-PROJ-B-PRV-PC-2` or `ST-PROJ-C-PRV-PC-3` that are affected, and a different defensive action would be required."
|
||||
"If this were a different episode, it could have been `ST_PROJ-B-PRV-PC-2` or `ST_PROJ-C-PRV-PC-3` that are affected, and a different defensive action would be required."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# ST_INTRA-PRV-RT-CR | router-acl-add-rule | P2: ST_PROJ-A-PRV-PC-1 !==> ST_DATA-PRV-SRV-DB (TCP:POSTGRES_SERVER)\n",
|
||||
"43:\n",
|
||||
" action: router-acl-add-rule\n",
|
||||
" options:\n",
|
||||
" target_router: ST_INTRA-PRV-RT-CR\n",
|
||||
" position: 1\n",
|
||||
" permission: DENY\n",
|
||||
" src_ip: 192.168.230.2 # (ST_PROJ-A-PRV-PC-1)\n",
|
||||
" src_wildcard: 0.0.255.255\n",
|
||||
" src_port: POSTGRES_SERVER\n",
|
||||
" dst_ip: 192.168.220.3 # (ST_DATA-PRV-SRV-DB)\n",
|
||||
" dst_wildcard: 0.0.255.255\n",
|
||||
" dst_port: POSTGRES_SERVER\n",
|
||||
" protocol_name: TCP\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -257,9 +266,73 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(43)\n",
|
||||
"env.step(45)\n",
|
||||
"env.step(47)"
|
||||
"env.step(43);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# ST_INTRA-PRV-RT-CR | router-acl-add-rule | P3: ST_PROJ-B-PRV-PC-2 !==> ST_DATA-PRV-SRV-DB (TCP:POSTGRES_SERVER)\n",
|
||||
"45:\n",
|
||||
" action: router-acl-add-rule\n",
|
||||
" options:\n",
|
||||
" target_router: ST_INTRA-PRV-RT-CR\n",
|
||||
" position: 2\n",
|
||||
" permission: DENY\n",
|
||||
" src_ip: 192.168.240.3 # (ST_PROJ-B-PRV-PC-2)\n",
|
||||
" src_wildcard: 0.0.255.255\n",
|
||||
" src_port: POSTGRES_SERVER\n",
|
||||
" dst_ip: 192.168.220.3 # (ST_DATA-PRV-SRV-DB)\n",
|
||||
" dst_wildcard: 0.0.255.255\n",
|
||||
" dst_port: POSTGRES_SERVER\n",
|
||||
" protocol_name: TCP\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(45);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# ST_INTRA-PRV-RT-CR | router-acl-add-rule | P4: ST_PROJ-C-PRV-PC-3 !==> ST_DATA-PRV-SRV-DB (TCP:POSTGRES_SERVER)\n",
|
||||
"47:\n",
|
||||
" action: router-acl-add-rule\n",
|
||||
" options:\n",
|
||||
" target_router: ST_INTRA-PRV-RT-CR\n",
|
||||
" position: 3\n",
|
||||
" permission: DENY\n",
|
||||
" src_ip: 192.168.250.4 # (ST_PROJ-C-PRV-PC-3)\n",
|
||||
" src_wildcard: 0.0.255.255\n",
|
||||
" src_port: POSTGRES_SERVER\n",
|
||||
" dst_ip: 192.168.220.3 # (ST_DATA-PRV-SRV-DB)\n",
|
||||
" dst_wildcard: 0.0.255.255\n",
|
||||
" dst_port: POSTGRES_SERVER\n",
|
||||
" protocol_name: TCP\n",
|
||||
" \n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(47);"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -319,7 +392,7 @@
|
||||
"|Target Router | Impact |\n",
|
||||
"|----------------------|--------|\n",
|
||||
"|`ST_INTRA-PRV-RT-DR-1`| Blocks all `POSTGRES_SERVER` that arrives at the `ST_INTRA-PRV-RT-DR-1` router. This rule will prevent all ST_PROJ_* hosts from accessing the database (`ST_DATA-PRV-SRV-DB`).|\n",
|
||||
"|`ST_INTRA-PRV-RT-CR`| Blocks all `HTTP` traffic that arrives at the`ST_INTRA-PRV-RT-CR` router. This rule will prevent all SOME_TECH hosts from accessing the webserver (`ST-DMZ-PUB-SRV-WEB`)|\n",
|
||||
"|`ST_INTRA-PRV-RT-CR`| Blocks all `HTTP` traffic that arrives at the`ST_INTRA-PRV-RT-CR` router. This rule will prevent all SOME_TECH hosts from accessing the webserver (`ST_DMZ-PUB-SRV-WEB`)|\n",
|
||||
"|`REM-PUB-RT-DR`| Blocks all `DNS` traffic that arrives at the `REM-PUB-RT-DR` router. This rule prevents any remote site works from accessing the DNS Server (`ISP-PUB-SRV-DNS`).|"
|
||||
]
|
||||
},
|
||||
@@ -418,26 +491,7 @@
|
||||
"source": [
|
||||
"## Preventing TAP003 attack\n",
|
||||
"\n",
|
||||
"The blue agent can prevent the red agent from adding ACL rules. TAP003 relies on connecting to the router via SSH, and sending remote ACL_ADDRULE requests. The blue agent can prevent this by pre-emptively changing the admin password on the affected routers or by blocking SSH traffic between the red agent's starting node and the target routers."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.reset()\n",
|
||||
"obs, reward, term, trunc, info = env.step(0)\n",
|
||||
"old = obs\n",
|
||||
"for i in range(128): \n",
|
||||
" obs, reward, term, trunc, info = env.step(0)\n",
|
||||
" new = obs\n",
|
||||
"\n",
|
||||
"diff = DeepDiff(old,new)\n",
|
||||
"print(f\"Step {env.game.step_counter}\") # it's the next step now because the step counter is incremented after the step\n",
|
||||
"for d,v in diff.get('values_changed', {}).items():\n",
|
||||
" print(f\"{d}: {v['old_value']} -> {v['new_value']}\")"
|
||||
"TAP003 relies on connecting to the routers via SSH, and sending `add_rule` terminal commands. The blue agent can prevent this by pre-emptively changing the admin password on the affected routers or by blocking SSH traffic between the red agent's starting node and the target routers."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -453,8 +507,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.reset()\n",
|
||||
"finish_episode_and_print_reward()\n",
|
||||
"\n",
|
||||
"for ag in env.game.agents.values():\n",
|
||||
" print(ag.config.ref, ag.reward_function.total_reward)"
|
||||
]
|
||||
@@ -473,7 +527,39 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.reset()\n",
|
||||
"env.step(51) # SSH Blocking ACL on ST-INRA-PRV-RT-R1\n",
|
||||
"env.step(51) # SSH Blocking ACL on ST_INRA-PRV-RT-R1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# ST_INTRA-PRV-RT-DR-1 | router-acl-add-rule | P1: ST_INTRA-PRV-RT-DR-1 !==> ANY (TCP:SSH)\n",
|
||||
"51:\n",
|
||||
" action: router-acl-add-rule\n",
|
||||
" options:\n",
|
||||
" target_router: ST_INTRA-PRV-RT-DR-1\n",
|
||||
" position: 1\n",
|
||||
" permission: DENY\n",
|
||||
" src_ip: 192.168.230.2 # (ST_PROJ-A-PRV-PC-1)\n",
|
||||
" src_wildcard: 0.0.255.255\n",
|
||||
" src_port: SSH\n",
|
||||
" dst_ip: ALL\n",
|
||||
" dst_wildcard: 0.0.255.255\n",
|
||||
" dst_port: SSH\n",
|
||||
" protocol_name: TCP\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"finish_episode_and_print_reward()\n",
|
||||
"\n",
|
||||
"for ag in env.game.agents.values():\n",
|
||||
@@ -484,7 +570,97 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Additionally, another option the blue agent can take is to change the passwords of the different target routers that TAP003 will attack through the `NODE_ACCOUNTS_CHANGE_PASSWORD` action."
|
||||
"Additionally, another option the blue agent can take is to change the passwords of the different target routers that TAP003 will attack through the `node-account-change-password` action."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.reset()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# ST_DATA-PRV-SRV-DB | node-account-change-password | Changes the password of a user account\n",
|
||||
"50:\n",
|
||||
" action: node-account-change-password\n",
|
||||
" options:\n",
|
||||
" node_name: ST_DATA-PRV-SRV-DB\n",
|
||||
" username: admin # default account\n",
|
||||
" current_password: admin # default password\n",
|
||||
" new_password: thr33_alert_wolv3z # A more 'secure' password\n",
|
||||
" \n",
|
||||
"```\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(50); "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# ST_INTRA-PRV-RT-DR-1 | node-account-change-password\n",
|
||||
"52:\n",
|
||||
" action: node-account-change-password\n",
|
||||
" options:\n",
|
||||
" node_name: ST_INTRA-PRV-RT-DR-1\n",
|
||||
" username: admin\n",
|
||||
" current_password: admin\n",
|
||||
" new_password: secure_password\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(52);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# REM-PUB-RT-DR | node-account-change-password\n",
|
||||
"54:\n",
|
||||
" action: node-account-change-password\n",
|
||||
" options:\n",
|
||||
" node_name: REM-PUB-RT-DR\n",
|
||||
" username: admin\n",
|
||||
" current_password: admin\n",
|
||||
" new_password: secure_password\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(54); "
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -493,10 +669,6 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.reset()\n",
|
||||
"env.step(50) # NODE_ACCOUNTS_CHANGE_PASSWORD | ST_INTRA-prv-rt-cr\n",
|
||||
"env.step(52) # NODE_ACCOUNTS_CHANGE_PASSWORD | ST_INTRA-prv-rt-dr-1\n",
|
||||
"env.step(54) # NODE_ACCOUNTS_CHANGE_PASSWORD | rem-pub-rt-dr\n",
|
||||
"finish_episode_and_print_reward()\n",
|
||||
"\n",
|
||||
"for ag in env.game.agents.values():\n",
|
||||
@@ -527,15 +699,88 @@
|
||||
"env.game.simulation.network.get_node_by_hostname(\"REM-PUB-RT-DR\").acl.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(44) # ROUTER_ACL_REMOVERULE | ST_INTRA-prv-rt-cr\n",
|
||||
"env.step(53) # ROUTER_ACL_REMOVERULE | ST_INTRA-prv-rt-dr-1\n",
|
||||
"env.step(55) # ROUTER_ACL_REMOVERULE | rem-pub-rt-dr"
|
||||
"env.step(44);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# ST_INTRA-PRV-RT-CR | REMOVE_ACL_ADDRULE | Removes a given ACL at position 1\n",
|
||||
"44:\n",
|
||||
" action: router-acl-remove-rule\n",
|
||||
" options:\n",
|
||||
" target_router: ST_INTRA-PRV-RT-CR\n",
|
||||
" position: 1\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(53);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# ST_INTRA-PRV-RT-DR-1 | router-acl-remove-rule | Removes the given ACL at position 1\n",
|
||||
"53:\n",
|
||||
" action: router-acl-remove-rule\n",
|
||||
" options:\n",
|
||||
" target_router: ST_INTRA-PRV-RT-DR-1\n",
|
||||
" position: 1\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(55);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"```yaml\n",
|
||||
"\n",
|
||||
"# REM-PUB-RT-DR | router-acl-remove-rule | Removes the given ACL at position 1\n",
|
||||
"55:\n",
|
||||
" action: router-acl-remove-rule\n",
|
||||
" options:\n",
|
||||
" target_router: REM-PUB-RT-DR\n",
|
||||
" position: 1\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -546,7 +791,7 @@
|
||||
"source": [
|
||||
"env.game.simulation.network.get_node_by_hostname(\"ST_INTRA-PRV-RT-CR\").acl.show()\n",
|
||||
"env.game.simulation.network.get_node_by_hostname(\"ST_INTRA-PRV-RT-DR-1\").acl.show()\n",
|
||||
"env.game.simulation.network.get_node_by_hostname(\"REM-PUB-RT-DR\").acl.show()\n"
|
||||
"env.game.simulation.network.get_node_by_hostname(\"REM-PUB-RT-DR\").acl.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -564,7 +809,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user