Files
PrimAITE/src/primaite/notebooks/UC7-E2E-Demo.ipynb
2025-03-14 14:06:03 +00:00

1740 lines
81 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Use Case 7 Scenario Demonstration\n",
"\n",
"© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK\n",
"\n",
"\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",
"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",
"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._"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!primaite setup"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import yaml\n",
"from prettytable import PrettyTable\n",
"from primaite.session.environment import PrimaiteGymEnv\n",
"from primaite.game.agent.scripted_agents.random_agent import PeriodicAgent\n",
"from primaite.game.agent.interface import ProxyAgent\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.system.applications.web_browser import WebBrowser\n",
"from primaite.simulator.system.services.service import ServiceOperatingState\n",
"from primaite.simulator.system.services.database.database_service import DatabaseService\n",
"from primaite.simulator.network.hardware.nodes.network.firewall import Firewall\n",
"from pprint import pprint\n",
"from primaite.config.load import load, _EXAMPLE_CFG"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"use_case_7_config = load(_EXAMPLE_CFG/\"uc7_config.yaml\")\n",
"with open(file=_EXAMPLE_CFG/\"uc7_config.yaml\", mode=\"r\") as uc7_config:\n",
" cfg = yaml.safe_load(uc7_config)\n",
" cfg['io_settings']['save_sys_logs'] = True # Saving syslogs\n",
" cfg['io_settings']['save_agent_logs'] = True # Save agent logs\n",
"env = PrimaiteGymEnv(env_config=use_case_7_config)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Table of Contents\n",
"\n",
"- [Network Description](#network-description)\n",
" - [Home Office](#network--home-office)\n",
" - [Internet](#network--internet)\n",
" - [Remote Site](#network--remote-site)\n",
" - [ST DMZ](#network--some_tech-dmz)\n",
" - [ST Main Site](#network--some_tech-main-site)\n",
" - [ST Head Office](#network--some_tech-main-site--some_tech-head-office-st_ho)\n",
" - [ST Human Resources](#network--some_tech-main-site--some_tech-human-resources-st_hr)\n",
" - [ST Data](#network--some_tech-main-site--some_tech-data-st_data)\n",
" - [ST Project A](#network--some_tech-main-site--some_tech-project-a-st_proj_a)\n",
" - [ST Project B](#network--some_tech-main-site--some_tech-project-b-st_proj_b)\n",
" - [ST Project C](#network--some_tech-main-site--some_tech-project-c-st_proj_c)\n",
"- [Agents](#agent-description)\n",
" - [Green POL](#agents--green-pattern-of-life-pol)\n",
" - [DatabaseService](#agents--green-pattern-of-life-pol--database-service)\n",
" - [web-server](#agents--green-pattern-of-life-pol--web-server)\n",
" - [Red Agent](#agents--red-agent)\n",
" - [TAP001](#agents--red-agent--threat-actor-profile-001-tap001)\n",
" - [TAP003](#agents--red-agent--threat-actor-profile-003-tap003)\n",
" - [Blue Agent](#agents--blue-agent)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## NETWORK DESCRIPTION\n",
"\n",
"<p align=\"center\">\n",
" <a href=\"./_package_data/uc7/uc7_network_detailed_svg.svg\" target=\"_blank\">\n",
" <img src=\"./_package_data/uc7/uc7_network_detailed_svg.svg\" alt=\"Image\">\n",
" </a> \n",
" \n",
"</p>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"uc7_network = env.game.simulation.network\n",
"uc7_network.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"| Default Computer Software |\n",
"|------------------|\n",
"| DNS Client (Service) | \n",
"| NTP Client (Service) | \n",
"| web-browser (Application) |\n",
"| database-client (Application) | "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"| Default Server Software |\n",
"|------------------|\n",
"| DNS Client (Service) | \n",
"| NTP Client (Service) | "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### NETWORK | HOME OFFICE \n",
"\n",
"The HOME OFFICE (HOME) network simulates a generic home office that consist of the following:\n",
"\n",
"- A main LAN with two computers (`HOME-PUB-PC-1`/`2`) and a server (`HOME-PUB-SRV`) using default configurations.\n",
"- A switch (`HOME-PUB-SW-AS`) which connects the above hosts.\n",
"- Lastly, a router (`HOME-PUB-RT-DR`) which connects the home office to the wider networks. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Home Office PC 1 (HOME-PUB-PC-1)\n",
"home_pub_pc_1: Computer = env.game.simulation.network.get_node_by_hostname(\"HOME-PUB-PC-1\")\n",
"home_pub_pc_1.show()\n",
"home_pub_pc_1.software_manager.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Home Office Router (HOME-PUB-RT-DR)\n",
"home_pub_rt_dr: Router = env.game.simulation.network.get_node_by_hostname(\"HOME-PUB-RT-DR\")\n",
"home_pub_rt_dr.show_nic()\n",
"home_pub_rt_dr.show_open_ports()\n",
"home_pub_rt_dr.acl.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### NETWORK | INTERNET (ISP)\n",
"\n",
"The internet (ISP) network intends to represent the internet. Currently, it's not feasible or possible for PrimAITE to simulate an internet service provider as well as the internet as a whole to a high degree of fidelity. Thus, in UC7, the \"internet\" refers to the following:\n",
"\n",
"- A router (`ISP-PUB-RT-BR`) which connects the all other UC7 LANS together. \n",
"- A server (`ISP-PUB-SRV-DNS`) which acts as the public DNS server that all PC's use. (Default IP of this host is *8.8.8.8*) "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"isp_pub_rt_br: Router = env.game.simulation.network.get_node_by_hostname(\"ISP-PUB-RT-BR\")\n",
"isp_pub_rt_br.show_nic()\n",
"isp_pub_rt_br.show_open_ports()\n",
"isp_pub_rt_br.acl.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"isp_pub_srv_dns: Server = env.game.simulation.network.get_node_by_hostname(\"ISP-PUB-SRV-DNS\")\n",
"isp_pub_srv_dns.show_nic()\n",
"isp_pub_srv_dns_server: DNSServer = isp_pub_srv_dns.software_manager.software[\"dns-server\"]\n",
"isp_pub_srv_dns_server.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### NETWORK | REMOTE SITE \n",
"\n",
"The remote site (`REMOTE`) network is similar to the previously introduced `HOME` network but includes a firewall between the `ISP` and the `REMOTE` network:\n",
"\n",
"- A main LAN with two computers (`REM-PUB-PC-1`/`2`) and a server (`REM-PUB-SRV`) using default configurations.\n",
"- A switch (`REM-PUB-SW-AS`) which connects the above hosts.\n",
"- A router (`HOME-PUB-RT-DR`) which connects the home office to a firewall (`REM-PUB-FW`) which then connects back to the `INTERNET` network.\n",
"\n",
"By default the `REM-PUB-FW` will not block any traffic."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"rem_pub_fw: Firewall = uc7_network.get_node_by_hostname(hostname=\"REM-PUB-FW\")\n",
"rem_pub_fw.show_nic()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# By default all of the `REM_PUB_FW` acls are configured to permit all traffic\n",
"rem_pub_fw.acl.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### NETWORK | SOME_TECH DMZ (ST DMZ)\n",
"\n",
"The `ST_DMZ` network is a small but important segment which sits between the `INTERNET` network (and thus the `REMOTE` and `HOME` networks as well) and the wider `SOME_TECH` main site networks. Additionally, accessible through the `ST_DMZ` firewall (`ST-PUB-FW`)'s DMZ port is a server which hosts a `web-server` that is accessible to all hosts in the UC7 network."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ST DMZ Public Firewall (Permits all traffic by default)\n",
"st_pub_fw: Firewall = uc7_network.get_node_by_hostname(hostname=\"ST_PUB-FW\")\n",
"st_pub_fw.show_nic()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ST DMZ Public web-server\n",
"st_dmz_pub_srv_web: Server = uc7_network.get_node_by_hostname(hostname=\"ST_DMZ-PUB-SRV-WEB\")\n",
"st_dmz_pub_srv_web.software_manager.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### NETWORK | SOME_TECH MAIN SITE\n",
"\n",
"SOME TECH's main site is comprised of 6 different networks:\n",
"\n",
"| ST Network | Purpose |\n",
"|------------|---------|\n",
"| `ST_HO` | Some Tech's Head Office. |\n",
"| `ST_HR` | Some Tech's Human Resourcing department |\n",
"| `ST_DATA` | Contains the ST database and backup server (FTP) |\n",
"| `ST_PROJ_A` | Development Network |\n",
"| `ST_PROJ_B` | Development Network |\n",
"| `ST_PROJ_C` | Development Network |\n",
"\n",
"In order for hosts to communicate between each network and the wider internet, the main site utilises three routers' `ST_INTRA-PRV-RT-DR-1`, `ST_INTRA-PRV-RT-DR-2` and `ST_INTRA-PRV-RT-CR`.\n",
"\n",
"The `ST_INTRA-PRV-RT-DR-1` router is responsible for routing all traffic from the `ST_PROJ_A`/`B`/`C` networks whereas the `ST_INTRA-PRV-RT-DR-2` router routes all traffic from the `ST_HO`/`HR` networks. Both of which then forward all traffic to the main `ST_INTRA-PRV-RT-CR` router. \n",
"\n",
"This central router connects to the `ST_DMZ` firewall (`ST-PUB-FW`) as well as any traffic that is headed to the `ST_DATA` (the ST database and database storage) network.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_intra_prv_rt_cr: Router = uc7_network.get_node_by_hostname(hostname=\"ST_INTRA-PRV-RT-CR\")\n",
"st_intra_prv_rt_cr.route_table.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_intra_prv_rt_dr_1: Router = uc7_network.get_node_by_hostname(hostname=\"ST_INTRA-PRV-RT-DR-1\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_intra_prv_rt_dr_2: Router = uc7_network.get_node_by_hostname(hostname=\"ST_INTRA-PRV-RT-DR-2\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 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."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_head_office_private_pc_1: Computer = uc7_network.get_node_by_hostname(\"ST_HO-PRV-PC-1\")\n",
"st_head_office_private_pc_1.software_manager.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 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."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_human_resources_private_pc_2: Computer = uc7_network.get_node_by_hostname(\"ST_HR-PRV-PC-2\")\n",
"st_human_resources_private_pc_2.software_manager.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 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",
"\n",
"| Server | Purpose |\n",
"|--------|---------|\n",
"| `ST_DATA-PRV-SRV-DB` | Hosts the `database-service` that all `database-client` are configured to use. | \n",
"| `ST_DATA-PRV-SRV-STORAGE`| Acts as a storage server for the `ST_DATA-PRV-SRV-DB`. |"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_data_private_server_database: Server = uc7_network.get_node_by_hostname(\"ST_DATA-PRV-SRV-DB\")\n",
"st_data_private_server_database_service: DatabaseService = st_data_private_server_database.software_manager.software[\"database-service\"]\n",
"st_data_private_server_database.software_manager.show()\n",
"st_data_private_server_database.software_manager.file_system.show(full=True)\n",
"st_data_private_server_database_service.backup_server_ip"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_data_private_server_storage: Server = uc7_network.get_node_by_hostname(\"ST_DATA-PRV-SRV-STORAGE\")\n",
"st_data_private_server_storage.software_manager.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 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)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_project_a_private_pc_1: Computer = uc7_network.get_node_by_hostname(\"ST_PROJ-A-PRV-PC-1\")\n",
"st_project_a_private_pc_1.software_manager.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH PROJECT B (`ST_PROJ_B`)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_project_b_private_pc_2: Computer = uc7_network.get_node_by_hostname(\"ST_PROJ-B-PRV-PC-2\")\n",
"st_project_b_private_pc_2.software_manager.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### NETWORK | SOME_TECH MAIN SITE | SOME_TECH PROJECT C (`ST_PROJ_C`)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_project_c_private_pc_3: Computer = uc7_network.get_node_by_hostname(\"ST_PROJ-C-PRV-PC-3\")\n",
"st_project_c_private_pc_3.software_manager.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Agent Description / Demonstration"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### AGENTS | Green Pattern of Life (*PoL*)\n",
"\n",
"The UC7 green pattern of life refers to the traffic and behaviour generated by the default `32` different green agents. For each host on the UC7 network, two green agents will attempt to execute the `web-browser` and `database-client` applications and receive a positive or negative reward dependant on whenever they are successful or not.\n",
"\n",
"The table below gives a summary of the different green agent behaviour split between the different UC7 networks.\n",
"\n",
"| **Network** |**Agent Host** | **Application** | **Behaviour Type** | **Probabilities** | **Start Step** | **Start Variance** | **Frequency** | **Variance** | **Reward Impact** |\n",
"|:-----------:|:-------:|:---------------:|:------------------:|:-----------------:|:--------------:|:------------------:|:-------------:|:------------:|:------------------:|\n",
"| `HOME SITE` |`HOME-PUB-PC-1`| `database-client`| *Periodic* | |**4** |**1** |**4** |**1** |**MEDIUM** |\n",
"| `HOME SITE` |`HOME-PUB-PC-2`| `database-client`| *Periodic* | |**8** |**1** |**4** |**1** |**MEDIUM** |\n",
"| `HOME SITE` |`HOME-PUB-PC-1`/`2`| `web-browser` | *Probabilistic* |**20%** | | | | |**LOW** |\n",
"| `REMOTE SITE` |`REM-PUB-PC-1`| `database-client`| *Periodic* | |**12** |**1** |**4** |**1** |**MEDIUM** |\n",
"| `REMOTE SITE` |`REM-PUB-PC-2`| `database-client`| *Periodic* | |**16** |**1** |**4** |**1** |**MEDIUM** |\n",
"| `REMOTE SITE` |`REM-PUB-PC-1`/`2`| `web-browser` | *Probabilistic* |**20%** | | | | |**LOW** |\n",
"| `ST PROJECT A`/`B`/`C` |`ST_PROJ-*-PRV-PC-1`| `database-client`| *Periodic* | |**1** |**1** |**4** |**1** |**HIGH** |\n",
"| `ST PROJECT A`/`B`/`C` |`ST_PROJ-*-PRV-PC-1`| `web-browser` | *Probabilistic* |**40%** | | | | |**LOW** |\n",
"| `ST PROJECT A`/`B`/`C` |`ST_PROJ-*-PRV-PC-2`/`3`| `database-client`| *Periodic* | |**1** |**1** |**4** |**1** |**MEDIUM** |\n",
"| `ST PROJECT A`/`B`/`C` |`ST_PROJ-*-PRV-PC-2`/`3`| `web-browser` | *Probabilistic* |**20%** | | | | |**LOW** |\n",
"| `ST HEAD OFFICE` |`ST-HO-PRV-PC-1`| `web-browser` | *Probabilistic* |**60%** | | | | |**HIGH** |\n",
"| `ST HEAD OFFICE` |`ST-HO-PRV-PC-2`/`3`| `web-browser` | *Probabilistic* |**60%** | | | | |**MEDIUM** |\n",
"| `ST HUMAN RESOURCES` |`ST_HR-PRV-PC-1`| `web-browser` | *Probabilistic* |**60%** | | | | |**MEDIUM** |\n",
"| `ST HUMAN RESOURCES` |`ST_HR-PRV-PC-2`/`3`| `web-browser` | *Probabilistic* |**60%** | | | | |**LOW** |\n",
"\n",
"\n",
"For the full details on each green agent then please click on the drop-down menu below:\n",
"\n",
"<details>\n",
" <summary>UC7 Green Agent Full Details</summary>\n",
"\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",
"</details>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### AGENTS | Green *PoL* | database-client Agents Demo\n",
"\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",
"\n",
"For example, take a *Periodic* green agent set with a `start_step` of **4** and a `frequency` of **4** with a `start_variance` of **1** and a `variance` of **1** 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"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.reset() # Resetting the simulation\n",
"home_pub_pc_1_database_green_agent = env.game.agents.get(\"HOME_WORKER-1-DB\")\n",
"for time_step in range(10):\n",
" env.step(0)\n",
" if not home_pub_pc_1_database_green_agent.history[time_step].action == 'DONOTHING':\n",
" print(home_pub_pc_1_database_green_agent.history[time_step])\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"home_pub_pc_1.software_manager.software[\"database-client\"].sys_log.show(last_n=10)\n",
"st_data_private_server_database.software_manager.software[\"database-service\"].sys_log.show(last_n=5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 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. 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. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.reset() # Resetting the simulation\n",
"home_pub_pc_1_web_browser_green_agent = env.game.agents.get(\"HOME_WORKER-1-WEB\")\n",
"for time_step in range(10):\n",
" env.step(0)\n",
" if not home_pub_pc_1_web_browser_green_agent.history[time_step].action == 'DONOTHING':\n",
" print(home_pub_pc_1_web_browser_green_agent.history[time_step])\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"home_pub_pc_1: Computer = env.game.simulation.network.get_node_by_hostname(\"HOME-PUB-PC-1\")\n",
"home_pub_pc_1_web_browser_green_agent.logger.show()\n",
"home_pub_pc_1_web_browser: WebBrowser = home_pub_pc_1.software_manager.software[\"web-browser\"]\n",
"home_pub_pc_1_web_browser.sys_log.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### AGENTS | Red Agents\n",
"\n",
"For UC7, two new red agents have been developed which introduce 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 its 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"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 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`](/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 `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) "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# By default the `uc7_config.yaml` is setup to use TAP001\n",
"env.reset()\n",
"for _ in range(80):\n",
" env.step(action=0)\n",
"\n",
"uc7_tap001 = env.game.agents.get(\"attacker\")\n",
"uc7_tap001.logger.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# TAP001 starting host\n",
"st_project_a_private_pc_1: Computer = env.game.simulation.network.get_node_by_hostname(\"ST_PROJ-A-PRV-PC-1\")\n",
"st_project_a_private_pc_1.software_manager.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_project_a_private_pc_1.file_system.show(full=True)\n",
"isp_pub_srv_dns: Server = env.game.simulation.network.get_node_by_hostname(hostname=\"ISP-PUB-SRV-DNS\")\n",
"isp_pub_srv_dns.file_system.show(full=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Database Impact \n",
"st_data_private_server_database: Server = env.game.simulation.network.get_node_by_hostname(hostname=\"ST_DATA-PRV-SRV-DB\")\n",
"st_data_private_server_database.file_system.show(full=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### AGENTS | RED AGENT | Threat Actor Profile 003 (`TAP003`)\n",
"\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",
"|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 web-server (`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`).|\n",
"\n",
"Lastly, it's highly recommended that users refer to the [TAP003 E2E notebook](./UC7-TAP003-Kill-Chain-E2E.ipynb) for further information or for the [UC7 attack variants notebook](./UC7-attack-variants.ipynb) demonstration of TAP003 defence."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Loading up the TAP003 UC7 config variant\n",
"with open(_EXAMPLE_CFG/\"uc7_config_tap003.yaml\", mode=\"r\") as uc7_config:\n",
" cfg = yaml.safe_load(uc7_config)\n",
" cfg[\"agents\"][33][\"agent_settings\"][\"flatten_obs\"] = False\n",
" cfg['io_settings']['save_sys_logs'] = True # Saving syslogs\n",
" cfg['io_settings']['save_agent_logs'] = True # Saving agent logs\n",
"\n",
"env = PrimaiteGymEnv(env_config=cfg)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# By default the `uc7_config.yaml` is setup to use TAP001\n",
"env.reset()\n",
"for _ in range(128):\n",
" env.step(action=0)\n",
"\n",
"uc7_tap003 = env.game.agents.get(\"attacker\")\n",
"uc7_tap003.logger.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.game.simulation.network.get_node_by_hostname(\"ST_INTRA-PRV-RT-DR-1\").acl.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.game.simulation.network.get_node_by_hostname(\"ST_INTRA-PRV-RT-CR\").acl.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.game.simulation.network.get_node_by_hostname(\"REM-PUB-RT-DR\").acl.show() "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## AGENTS | Blue Agent\n",
"\n",
"\n",
"\n",
"\n",
"In PrimAITE blue agent configuration is split into three separate sections, each responsible for a different part of the blue agent functionality.\n",
"\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",
"\n",
"- `action_space`\n",
"\n",
"The action space configuration is used to set the actions available to the blue agent. The larger range of actions could be optimal for responding to a large set of different scenarios but could lead to longer training times. Crafting the perfect `action_space` is pivotal for creating an effective blue agent.\n",
"\n",
"- `reward_function`\n",
"\n",
"The `reward_function` section configures what type of reward (or penalisation) the blue agent will receive based on the current status of the simulation. A balanced and well crafted reward function is the path of success for any blue agent to learn what the best approach to scenario may be.\n",
"\n",
"\n",
"\n",
"_The remaining section of this notebook will cover the UC7 blue agent and the default aforementioned settings._"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.reset() # Resetting the env\n",
"defender = env.game.agents.get(\"defender\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## AGENTS | Blue Agent | Observation Space (OBS)\n",
"\n",
"## NETWORK DESCRIPTION\n",
"\n",
"<p align=\"center\">\n",
" <a href=\"./_package_data/uc7/blue_agent_action_and_obs.png\" target=\"_blank\">\n",
" <img src=\"./_package_data/uc7/blue_agent_action_and_obs.png\" alt=\"Image\">\n",
" </a> \n",
" \n",
"</p>\n",
"\n",
"_(Click to enlarge)_\n",
"\n",
"Represented as a hierarchy (i.e the same way as a dictionary) the blue agent OBS is separate into multiple sections.\n",
"\n",
"### Links\n",
"\n",
"The first section is Links, which is used to report the current network traffic load on every link in the network. Since the observation space is composed of categorical variables, the traffic values are converted from MBit/s to a category based on a percentage of the link's capacity.\n",
"\n",
"<details> <summary> Link Values Mapping</summary>\n",
"\n",
"|load observation|percent utilisation|\n",
"|--|--|\n",
"|0|exactly 0%|\n",
"|1|0-11%|\n",
"|2|11-22%|\n",
"|3|22-33%|\n",
"|4|33-44%|\n",
"|5|44-55%|\n",
"|6|55-66%|\n",
"|7|66-77%|\n",
"|8|77-88%|\n",
"|9|88-99%|\n",
"|10|exactly 100%|\n",
"\n",
"\n",
"</details>\n",
"\n",
"<details>\n",
" <summary>Link List</summary>\n",
" \n",
"|Link number|Endpoint A|Endpoint B|\n",
"|---|---|---|\n",
"|1|HOME-PUB-SW-AS:eth-1|HOME-PUB-RT-DR:eth-1 |\n",
"|2|HOME-PUB-SW-AS:eth-1|HOME-PUB-PC-1:eth-1 |\n",
"|3|HOME-PUB-SW-AS:eth-1|HOME-PUB-PC-2:eth-1 |\n",
"|4|HOME-PUB-SW-AS:eth-1|HOME-PUB-SRV:eth-1 | \n",
"|5|ISP-PUB-RT-BR:eth-1|HOME-PUB-RT-DR:eth-2 |\n",
"|6|ISP-PUB-RT-BR:eth-2|ISP-PUB-SRV-DNS:eth-1 |\n",
"|7|ISP-PUB-RT-BR:eth-3|REM-PUB-FW:eth-1 |\n",
"|8|REM-PUB-FW:eth-2|REM-PUB-RT-DR:eth-1 |\n",
"|9|REM-PUB-RT-DR:eth-2|REM-PUB-SW-AS:eth-1 |\n",
"|10|REM-PUB-SW-AS:eth-2|REM-PUB-PC-1:eth-1 |\n",
"|11|REM-PUB-SW-AS:eth-3|REM-PUB-PC-2:eth-1 | \n",
"|12|REM-PUB-SW-AS:eth-4|REM-PUB-SRV:eth-1 |\n",
"|13|ISP-PUB-RT-BR:eth-4|ST_PUB-FW:eth-1 |\n",
"|14|ST_PUB-FW:eth-3|ST_DMZ-PUB-SRV-WEB:eth-1 |\n",
"|15|ST_INTRA-PRV-RT-CR:eth-1|ST_PUB-FW:eth-2 |\n",
"|16|ST_INTRA-PRV-RT-CR:eth-2|ST_INTRA-PRV-RT-DR-1:eth-1 |\n",
"|17|ST_INTRA-PRV-RT-CR:eth-3|ST_INTRA-PRV-RT-DR-2:eth-1 | \n",
"|18|ST_INTRA-PRV-RT-CR:eth-4|ST_DATA-PRV-SW-AS:eth-1 |\n",
"|19|ST_HO-PRV-SW-AS:eth-1|ST_INTRA-PRV-RT-DR-2:eth-2 |\n",
"|20|ST_HO-PRV-SW-AS:eth-2|ST_HO-PRV-PC-1:eth-1 |\n",
"|21|ST_HO-PRV-SW-AS:eth-3|ST_HO-PRV-PC-2:eth-1 |\n",
"|22|ST_HO-PRV-SW-AS:eth-4|ST_HO-PRV-PC-3:eth-1 |\n",
"|23|ST_HR-PRV-SW-AS:eth-1|ST_INTRA-PRV-RT-DR-2:eth-3 |\n",
"|24|ST_HR-PRV-SW-AS:eth-2|ST_HR-PRV-PC-1:eth-1 |\n",
"|25|ST_HR-PRV-SW-AS:eth-3|ST_HR-PRV-PC-2:eth-1 |\n",
"|26|ST_HR-PRV-SW-AS:eth-4|ST_HR-PRV-PC-3:eth-1 |\n",
"|27|ST_DATA-PRV-SW-AS:eth-2|ST_DATA-PRV-SRV-STORAGE:eth-1 |\n",
"|28|ST_DATA-PRV-SW-AS:eth-3|ST_DATA-PRV-SRV-DB:eth-1 | \n",
"|29|ST_INTRA-PRV-RT-DR-1:eth-2|ST_PROJ-A-PRV-SW-AS:eth-1 |\n",
"|30|ST_PROJ-A-PRV-SW-AS:eth2|ST_PROJ-A-PRV-PC-1:eth-1|\n",
"|31|ST_PROJ-A-PRV-SW-AS:eth3|ST_PROJ-A-PRV-PC-2:eth-1 |\n",
"|32|ST_PROJ-A-PRV-SW-AS:eth4|ST_PROJ-A-PRV-PC-3:eth-1 | \n",
"|33|ST_INTRA-PRV-RT-DR-1:eth-3|ST_PROJ-B-PRV-SW-AS:eth-1 |\n",
"|34|ST_PROJ-B-PRV-SW-AS:eth2|ST_PROJ-B-PRV-PC-1:eth-1 |\n",
"|35|ST_PROJ-B-PRV-SW-AS:eth3|ST_PROJ-B-PRV-PC-2:eth-1 |\n",
"|36|ST_PROJ-B-PRV-SW-AS:eth4|ST_PROJ-B-PRV-PC-3:eth-1 | \n",
"|37|ST_INTRA-PRV-RT-DR-1:eth-4|ST_PROJ-C-PRV-SW-AS:eth-1 |\n",
"|38|ST_PROJ-A-PRV-SW-AS:eth2|ST_PROJ-C-PRV-PC-1:eth-1 |\n",
"|39|ST_PROJ-A-PRV-SW-AS:eth3|ST_PROJ-C-PRV-PC-2:eth-1 |\n",
"|40|ST_PROJ-A-PRV-SW-AS:eth4|ST_PROJ-C-PRV-PC-3:eth-1 |\n",
"\n",
"</details>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The code cell below prints out how the above link list table appears in the blue agent observation space"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.reset()\n",
"\n",
"obs, reward, _,_,info = env.step(0)\n",
"for i,x in obs['LINKS'].items():\n",
" print(i, x)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### HOSTS\n",
"\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",
"|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",
"\n",
"- operating status \n",
"- number of file creations\n",
"- number of file deletions\n",
"- up to 4 installed services (operating status and health status)\n",
"- up to 2 installed applications (operating status, health status, and number of executions)\n",
"- up to 1 folder (health status)\n",
"- up to 1 file on the folders (health status and number of accesses)\n",
"- 1 network interface, including: \n",
" - operating status\n",
" - number of malicious network events detected\n",
" - amount of incoming and outgoing traffic on each protocol and port\n",
"\n",
"\n",
"\n",
"It's worth noting that for larger observation spaces, not every host will have the maximum number of files, folders, services, and applications configured for the observation space, so padding is used to ensure that the shape of each host observation is the same. The hosts appear in the order that they are defined in the config file."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.reset()\n",
"\n",
"obs, reward, _,_,info = env.step(0)\n",
"for node_id, node_obs in obs['NODES'].items():\n",
" if not \"ROUTER\" in node_id: # filter out router OBS for now\n",
" print(node_id)\n",
" pprint(node_obs)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For any readers unfamiliar with the different enumeration values in any of the obs output (i.e what the `0`,`1`,`2`,`3` values represent) then please refer to the following tables for reference:\n",
"\n",
"<details> <summary> Host operating state category table</summary>\n",
"\n",
"|value|meaning|\n",
"|-|-|\n",
"|0|UNUSED|\n",
"|1|ON|\n",
"|2|OFF|\n",
"|3|BOOTING|\n",
"|4|SHUTTING DOWN|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> No. file creations/deletions category table</summary>\n",
"\n",
"|value|meaning|\n",
"|-|-|\n",
"|0|0|\n",
"|1|1-5|\n",
"|2|6-10|\n",
"|3|>10|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> Service operating state category table</summary>\n",
"\n",
"|operating_state|label|\n",
"|--|--|\n",
"|0|UNUSED|\n",
"|1|RUNNING|\n",
"|2|STOPPED|\n",
"|3|PAUSED|\n",
"|4|DISABLED|\n",
"|5|INSTALLING|\n",
"|6|RESTARTING|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> Application operating state category table</summary>\n",
"\n",
"|operating_state|label|\n",
"|--|--|\n",
"|0|UNUSED|\n",
"|1|RUNNING|\n",
"|2|CLOSED|\n",
"|3|INSTALLING|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> Service/Application health state category table</summary>\n",
"\n",
"|health_state|label|\n",
"|--|--|\n",
"|0|UNUSED|\n",
"|1|GOOD|\n",
"|2|FIXING|\n",
"|3|COMPROMISED|\n",
"|4|OVERWHELMED|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> Application number of executions category table</summary>\n",
"\n",
"|num_executions label|meaning|\n",
"|-|-|\n",
"|0|0|\n",
"|1|1-5|\n",
"|2|6-10|\n",
"|3|>10|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> Folder/file health status table</summary>\n",
"\n",
"|health_status label|meaning|\n",
"|-|-|\n",
"|0|UNUSED|\n",
"|1|GOOD|\n",
"|2|COMPROMISED|\n",
"|3|CORRUPT|\n",
"|4|RESTORING|\n",
"|5|REPAIRING|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> File number of access category table</summary>\n",
"\n",
"|num_access label|meaning|\n",
"|-|-|\n",
"|0|0|\n",
"|1|1-5|\n",
"|2|6-10|\n",
"|3|>10|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> NICs' operating_status category table</summary>\n",
"\n",
"|operating_status|label|\n",
"|--|--|\n",
"|0|UNUSED|\n",
"|1|ENABLED|\n",
"|2|DISABLED|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> NIC monitored traffic utilisation category table </summary>\n",
"\n",
"|load observation|percent utilisation|\n",
"|--|--|\n",
"|0|exactly 0%|\n",
"|1|0-11%|\n",
"|2|11-22%|\n",
"|3|22-33%|\n",
"|4|33-44%|\n",
"|5|44-55%|\n",
"|6|55-66%|\n",
"|7|66-77%|\n",
"|8|77-88%|\n",
"|9|88-99%|\n",
"|10|exactly 100%|\n",
"\n",
"\n",
"</details>\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Routers and Firewalls\n",
"\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 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. 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",
"- `ST_INTRA-PRV-RT-CR`\n",
"- `ST_INTRA-PRV-RT-DR-1`\n",
"- `REM-PUB-RT-DR`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<details> <summary> Port operating status category table</summary>\n",
"\n",
"|operating_status|label|\n",
"|--|--|\n",
"|0|UNUSED|\n",
"|1|ENABLED|\n",
"|2|DISABLED|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> ACL Permission category table</summary>\n",
"\n",
"|permission|label|\n",
"|--|--|\n",
"|0|UNUSED|\n",
"|1|ALLOW|\n",
"|2|DENY|\n",
"\n",
"</details>\n",
"\n",
"\n",
"<details> <summary> ACL source/destination IP ID category table</summary>\n",
"\n",
"|IP ID|IP address| Associated node|\n",
"|--|--|--|\n",
"|0|UNUSED|\n",
"|1|ALL IPs|\n",
"|2|192.168.1.2 | HOME-PUB-PC-1 |\n",
"|3|192.168.1.3 | HOME-PUB-PC-2 |\n",
"|4|192.168.1.4 | HOME-PUB-PC-SRV |\n",
"|5|192.168.20.2 | REM-PUB-PC-1 |\n",
"|6|192.168.20.3 | REM-PUB-PC-2 |\n",
"|7|192.168.20.4 | REM-PUB-SRV |\n",
"|8|192.168.100.2| ST_PUB_SRV_WEB_IP |\n",
"|9|192.168.200.2 | ST_HO-PRV-PC-1 |\n",
"|10|192.168.200.3 | ST_HO-PRV-PC-2 |\n",
"|11|192.168.200.4 | ST_HO-PRV-PC-3 |\n",
"|12|192.168.210.2 | ST_HR-PRV-PC-1 |\n",
"|13|192.168.210.3 | ST_HR-PRV-PC-2 |\n",
"|14|192.168.210.4 | ST_HR-PRV-PC-3 |\n",
"|15|192.168.220.2 | ST_DATA-PRV-SRV-STORAGE | \n",
"|16|192.168.220.3 | ST_DATA-PRV-SRV-DB |\n",
"|17|192.168.230.2 | PROJ-A-PRV-PC-1 |\n",
"|18|192.168.230.3 | PROJ-A-PRV-PC-2 |\n",
"|19|192.168.230.4 | PROJ-A-PRV-PC-3 |\n",
"|20|192.168.240.2 | PROJ-B-PRV-PC-1 |\n",
"|21|192.168.240.3 | PROJ-B-PRV-PC-2 |\n",
"|22|192.168.240.4 | PROJ-B-PRV-PC-3 |\n",
"|23|192.168.250.2 | PROJ-C-PRV-PC-1 |\n",
"|24|192.168.250.3 | PROJ-C-PRV-PC-2 |\n",
"|25|192.168.250.4 | PROJ-C-PRV-PC-3 |\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> ACL Rule IP Address Wildcard category table</summary>\n",
"\n",
"|wildcard|label|\n",
"|--|--|\n",
"|0|UNUSED|\n",
"|1|None|\n",
"|2|0.0.0.1|\n",
"|3|0.0.0.255|\n",
"|4|0.0.255.255|\n",
"</details>\n",
"\n",
"<details> <summary> ACL Rule Port category table</summary>\n",
"\n",
"|permission|label|used for|\n",
"|--|--|--|\n",
"|0|UNUSED|padding|\n",
"|1|ANY||\n",
"|2|21|FTP|\n",
"|3|53|DNS|\n",
"|4|80|HTTP|\n",
"|5|123|NTP|\n",
"|6|5432|POSTGRES SERVER|\n",
"|7|22|SSH|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> ACL Rule Protocol category table</summary>\n",
"\n",
"|permission|label|\n",
"|--|--|\n",
"|0|UNUSED|\n",
"|1|ANY|\n",
"|2|ICMP|\n",
"|3|TCP|\n",
"|4|UDP|\n",
"\n",
"</details>\n",
"\n",
"<details> <summary> Firewall ports </summary>\n",
"\n",
"|index|label|\n",
"|--|--|\n",
"|1|external|\n",
"|2|internal|\n",
"|3|DMZ|\n",
"\n",
"</details>\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"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 ROUTERs\n",
" print(node_id)\n",
" pprint(node_obs)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## AGENTS | Blue Agent | Action Space"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"***\n",
"\n",
"#### `action_map`\n",
"\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",
"```yaml\n",
" action_space:\n",
" action_map:\n",
" 0:\n",
" action: do-nothing\n",
" options: {}\n",
"\n",
" # |======================================|\n",
" # | ST_PROJ-A-PRV-PC-1 |\n",
" # |======================================|\n",
"\n",
" # ST_PROJ-A-PRV-PC-1 | node-os-scan\n",
" 1:\n",
" action: node-os-scan\n",
" options:\n",
" node_name: ST_PROJ-A-PRV-PC-1\n",
" # ST_PROJ-A-PRV-PC-1 | node-shutdown\n",
" 2:\n",
" action: node-shutdown\n",
" options:\n",
" node_name: ST_PROJ-A-PRV-PC-1\n",
" # ST_PROJ-A-PRV-PC-1 | node-startup\n",
" 3:\n",
" action: node-startup\n",
" options:\n",
" node_name: ST_PROJ-A-PRV-PC-1\n",
"```\n",
"\n",
"Converting the yaml snippet below we end up with the following:\n",
"\n",
"|Action Num | Action Type | Options|\n",
"|:---------:|:-----------:|:------:|\n",
"|0|**do-nothing**|*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: do-nothing`:\n",
"\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",
"```py\n",
" env.step(0)\n",
"```\n",
"\n",
"This code snippet is used to step forward in an PrimAITE episode and force the blue agent into performing no action which is very useful for demonstrating default simulation behaviour as well as the different impacts that the green and red agents have upon the environment."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.reset()\n",
"env.step(0)\n",
"defender = env.game.rl_agents.get(\"defender\")\n",
"defender.show_history(ignored_actions=['']) # By default `show_history()` will ignore 'do-nothing'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`1: node-os-scan`:\n",
"\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",
"\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`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"obs, reward, term, trunc, info = env.step(0)\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]}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"st_project_a_private_pc_1: Computer = env.game.simulation.network.get_node_by_hostname(\"ST_PROJ-A-PRV-PC-1\")\n",
"st_project_a_private_pc_1.software_manager.software[\"ftp-client\"].set_health_state(SoftwareHealthState.COMPROMISED)\n",
"st_project_a_private_pc_1.software_manager.software[\"database-client\"].set_health_state(SoftwareHealthState.COMPROMISED)\n",
"st_project_a_private_pc_1.software_manager.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Set by the `node_scan_duration` option in the simulation `defaults` section, the results of `node-os-scan` take **8** timesteps before it impacts the blue agent's observation space."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(f'Node OS Scan time step duration: {cfg[\"simulation\"][\"defaults\"][\"node_scan_duration\"]}')\n",
"env.step(1)\n",
"print(defender.show_history())\n",
"for _ in range(9):\n",
" obs, reward, term, trunc, info = env.step(0)\n",
"\n",
"print(f\"Current Simulation Time Step: {env.game.step_counter}\")\n",
"print(f\"ftp-client (Post Scan) OBS: {defender.observation_manager.current_observation['NODES']['HOST0']['SERVICES'][1]}\")\n",
"print(f\"database-client (Post Scan) OBS: {defender.observation_manager.current_observation['NODES']['HOST0']['APPLICATIONS'][2]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`2: node-shutdown`:\n",
"\n",
"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."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"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 `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."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"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) "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"obs, reward, term, trunc, info = env.step(0)\n",
"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",
"\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"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"obs, reward, term, trunc, info = env.step(3)\n",
"\n",
"for _ in range(3):\n",
" 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 (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())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## AGENTS | Blue Agent | Reward Components\n",
"\n",
"In order to add context to the observation, the blue agent can be configured with different reward components. For any readers unfamiliar with PrimAITE rewards then user guide contains a good introduction as this notebook section will only cover the UC7 blue agent setup.\n",
"\n",
"For `UC7`, the blue agent is setup to receive a negative reward when the `database.db` file integrity is affected (i.e enters into a `COMPROMISED` state):\n",
"\n",
"```yaml\n",
" reward_function:\n",
" reward_components:\n",
" - type: database-file-integrity\n",
" weight: *HIGH_WEIGHT_IMPACT # Equal to 0.95 (Reward Anchors defined at lines 960 - 980 in the uc7_config.yaml)\n",
" options: \n",
" node_hostname: ST_DATA-PRV-SRV-DB \n",
" folder_name: database\n",
" 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. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"table = PrettyTable()\n",
"table.field_names = [\"Reward Type\", \"Reward Option\", \"Reward Weight\"]\n",
"for i in range(len(defender.reward_function.reward_components)):\n",
" reward_type = defender.reward_function.reward_components[i][0].config.type\n",
" try:\n",
" reward_option = defender.reward_function.reward_components[i][0].config.file_name\n",
" except:\n",
" reward_option = defender.reward_function.reward_components[i][0].config.agent_name\n",
" reward_weight = defender.reward_function.reward_components[i][1]\n",
" table.add_row(row=[reward_type, reward_option, reward_weight])\n",
"print(table)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By default, each of the `shared-reward` component is configured with a equal reward `weight` of `0.03125` which totals a blue agent reward weight of `1`. \n",
"\n",
"It's worth noting that `shared-reward` components are **not** required to have a equal weight or total a weight value under `1`. \n",
"\n",
"Users are recommended to alter the `weights` of these rewards when creating their own scenarios.\n",
"\n",
"```yaml\n",
"\n",
"# UC7 Shared Reward Component Green Agents (32 Green Agents each contributing 0.03125 of blue reward)\n",
"\n",
"# Blue Shared Reward | HOME_WORKER-1-DB\n",
"- type: shared-reward\n",
" weight: 0.03125\n",
" options:\n",
" agent_name: HOME_WORKER-1-DB\n",
"\n",
"# Green Agent HOME_WORKER-1-DB's reward function:\n",
" reward_function:\n",
" reward_components:\n",
" - type: green-admin-database-unreachable-penalty\n",
" weight: *MEDIUM_WEIGHT_IMPACT # Equal to 0.5 (Reward Anchors defined at lines 960 - 980 in the uc7_config.yaml)\n",
" options:\n",
" node_hostname: HOME-PUB-PC-1\n",
"\n",
"```\n",
"\n",
"The `weight` option in a `shared-reward` reward acts a multiplier to the reward of agent given in `agent_name`:\n",
"\n",
"$\\text{shared\\_reward} = \\text{agent\\_reward} \\times \\text{shared\\_reward\\_weight}$\n",
"\n",
"\n",
"This can a little difficult to understand intuitively so the following code snippets demonstrates how one of these rewards are calculated during a live episode."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Readers running this notebook natively can use edit this to test out different reward weight combinations\n",
"BLUE_AGENT_SHARED_REWARD_WEIGHT = 5"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For example, if a user wished to configure the blue agent to place more value on the head office green agents such as the `CEO` then the blue agent's `shared-reward` components could be altered to reflect this by increasing the `weight` of the `shared-reward` configured to the `CEO` green agent."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Reloads the UC7 config and removes all of other reward-components. \n",
"BLUE_AGENT_INDEX = 33\n",
"with open(_EXAMPLE_CFG/\"uc7_config.yaml\", mode=\"r\") as uc7_config:\n",
" cfg = yaml.safe_load(uc7_config)\n",
"\n",
" # Removing all the other blue agent rewards and adding a custom blue reward\n",
" blue_shared_reward_ceo = {'type': 'shared-reward', 'weight': BLUE_AGENT_SHARED_REWARD_WEIGHT, 'options': {'agent_name': 'CEO'}}\n",
"\n",
" # Add the new custom blue agent shared rewards\n",
" blue_shared_reward_home_worker = cfg['agents'][BLUE_AGENT_INDEX]['reward_function']['reward_components'].pop(1)\n",
" cfg['agents'][BLUE_AGENT_INDEX]['reward_function']['reward_components'].clear() # Remove all blue agent rewards\n",
" cfg['agents'][BLUE_AGENT_INDEX]['reward_function']['reward_components'].append(blue_shared_reward_ceo) \n",
" cfg['agents'][BLUE_AGENT_INDEX]['reward_function']['reward_components'].append(blue_shared_reward_home_worker) \n",
"\n",
"\n",
"env = PrimaiteGymEnv(env_config=cfg)\n",
"env.reset()\n",
"\n",
"# Run the episode 10 times and record the results\n",
"table = PrettyTable()\n",
"table.field_names = [\"Time Step\", \"Home Worker Reward\", \"CEO Reward\", \"Blue Agent Total Reward\"]\n",
"for _ in range(10):\n",
" env.step(0)\n",
" home_worker = env.game.agents.get('HOME_WORKER-1-DB')\n",
" ceo = env.game.agents.get('CEO')\n",
" defender = env.game.agents.get(\"defender\")\n",
" table.add_row([env.game.step_counter,home_worker.reward_function.current_reward, ceo.reward_function.current_reward, defender.reward_function.current_reward])\n",
"print(table)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As you can see from the table above, because we increased the `shared-reward` weightings the blue agent's reward is nearly all comprised of the CEO's reward - `4.75`:\n",
"\n",
"$\\text{ceo\\_reward\\_contribution} = 0.95 \\times 5$ \n",
"\n",
"We can see that the remote worker agent only contributes `0.015625` to the blue agent's total reward:\n",
"\n",
"$\\text{remote\\_worker\\_reward\\_contribution} = 0.5 \\times 0.03125$\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lastly, the final few code snippets demonstrate how the default UC7 blue agent's reward is affected by simulation state within an episode."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In a perfect episode, with no red agent interference, the blue agent can expect the following reward:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"with open(_EXAMPLE_CFG/\"uc7_config.yaml\", mode=\"r\") as uc7_config:\n",
" cfg = yaml.safe_load(uc7_config)\n",
" cfg[\"agents\"].pop(32) # removing red agent\n",
"env = PrimaiteGymEnv(env_config=cfg)\n",
"env.reset()\n",
"defender = env.game.rl_agents.get(\"defender\")\n",
"for _ in range(128):\n",
" env.step(0)\n",
"defender.reward_function.total_reward"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The below code snippet shows what you'd expect the defender's total reward to be after TAP001 is left unchallenged:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"with open(_EXAMPLE_CFG/\"uc7_config.yaml\", mode=\"r\") as uc7_config:\n",
" cfg = yaml.safe_load(uc7_config)\n",
"env = PrimaiteGymEnv(env_config=cfg)\n",
"env.reset()\n",
"defender = env.game.rl_agents.get(\"defender\")\n",
"for _ in range(128):\n",
" env.step(0)\n",
"print(f\"Successful TAP001 & Blue Agent Reward: {defender.reward_function.total_reward}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next is what you'd expect the defender's total reward to be after TAP003 is left unchallenged:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"with open(_EXAMPLE_CFG/\"uc7_config_tap003.yaml\", mode=\"r\") as uc7_config:\n",
" cfg = yaml.safe_load(uc7_config)\n",
" cfg[\"agents\"][33][\"agent_settings\"][\"flatten_obs\"] = False\n",
" cfg['io_settings']['save_sys_logs'] = True # Saving syslogs\n",
" cfg['io_settings']['save_agent_actions'] = True # Saving syslogs\n",
" cfg['io_settings']['save_agent_logs'] = True # Saving agent logs\n",
"env = PrimaiteGymEnv(env_config=cfg)\n",
"env.reset()\n",
"defender = env.game.rl_agents.get(\"defender\")\n",
"for _ in range(128):\n",
" env.step(0)\n",
"print(f\"Successful TAP003 & Blue Agent Reward: {defender.reward_function.total_reward}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lastly, if we completely block any green traffic and set the database.db to `COMPROMISED` we can simulate the potential worst case situation for the blue agent (based off the default `reward_components`)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env = PrimaiteGymEnv(env_config=cfg)\n",
"env.reset()\n",
"defender = env.game.rl_agents.get(\"defender\")\n",
"\n",
"# Corrupting and Disabling the database-service\n",
"st_data_private_server_database: Server = env.game.simulation.network.get_node_by_hostname(\"ST_DATA-PRV-SRV-DB\")\n",
"st_data_private_server_database_file = st_data_private_server_database.file_system.get_file(folder_name=\"database\", file_name=\"database.db\")\n",
"st_data_private_server_database_file.health_status = FileSystemItemHealthStatus.COMPROMISED\n",
"st_data_private_server_database.software_manager.software[\"database-service\"].operating_state = ServiceOperatingState.DISABLED\n",
"\n",
"# Shutting down the web-server\n",
"\n",
"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 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",
"\n",
"for _ in range(128):\n",
" env.step(0)\n",
"print(f\"Worst Case Episode Blue Agent Reward: {defender.reward_function.total_reward}\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}