Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
84f99fd
add missing configurations
ondrej-lukas Mar 16, 2026
172ae76
Add missing scenarios
ondrej-lukas Mar 16, 2026
43dd4ad
add missing line separators
ondrej-lukas Mar 16, 2026
8be08ed
Fix block IP action assumntions
ondrej-lukas Mar 16, 2026
d8449fc
Add missing line separator
ondrej-lukas Mar 16, 2026
d793e49
Remove deprecated option
ondrej-lukas Mar 16, 2026
d4d4935
Fix typo
ondrej-lukas Mar 16, 2026
c0ac888
Fix typo
ondrej-lukas Mar 16, 2026
d6d62b9
Remove outdated option
ondrej-lukas Mar 16, 2026
aa31421
fix path
ondrej-lukas Mar 16, 2026
2b7b77e
Fix typos
ondrej-lukas Mar 16, 2026
9e7ef48
Improve structure
ondrej-lukas Mar 16, 2026
6137bcc
Move worlds in a separate file
ondrej-lukas Mar 16, 2026
71e1c5f
show private methods
ondrej-lukas Mar 16, 2026
83f2391
Remove duplicate header
ondrej-lukas Mar 16, 2026
6d29ea5
split docs to separate file
ondrej-lukas Mar 16, 2026
f233795
Add typing
ondrej-lukas Mar 16, 2026
07cea54
Remove duplicate
ondrej-lukas Mar 16, 2026
f361700
Add config parser to links
ondrej-lukas Mar 16, 2026
3034557
Add signatures
ondrej-lukas Mar 16, 2026
0d0b2e3
Comply with google notation
ondrej-lukas Mar 16, 2026
37f9653
Coply with google notation in docstrings
ondrej-lukas Mar 16, 2026
45f9b1c
Fixed dosctrings and typing
ondrej-lukas Mar 16, 2026
fa6602f
Fix docstrings and typing
ondrej-lukas Mar 16, 2026
52c97a4
Fix docstring
ondrej-lukas Mar 16, 2026
5817f47
Fix imports and docstrings
ondrej-lukas Mar 16, 2026
f6fe19b
Fix args and docstrings
ondrej-lukas Mar 16, 2026
4e41bf1
Fix docstrings
ondrej-lukas Mar 16, 2026
f953fac
split worlds in separate files
ondrej-lukas Mar 17, 2026
44b4755
Fix docstring
ondrej-lukas Mar 17, 2026
f817740
Add module descriptions
ondrej-lukas Mar 17, 2026
a1c9320
Fix typos
ondrej-lukas Mar 17, 2026
8a5336c
Fix typos
ondrej-lukas Mar 17, 2026
9d1fc8b
add arg name
ondrej-lukas Mar 17, 2026
eabda59
Unify parameter name to "use_dynamic_addresses"
ondrej-lukas Mar 17, 2026
e4f2671
Add missing typing import
ondrej-lukas Mar 17, 2026
3e8158f
Fix missing imports
ondrej-lukas Mar 17, 2026
d378433
Fix imports
ondrej-lukas Mar 17, 2026
2458758
remove unused import (List)
ondrej-lukas Mar 17, 2026
551d626
Remove unused typing imports
ondrej-lukas Mar 17, 2026
022234e
Remove unused typing imports
ondrej-lukas Mar 17, 2026
62d4b5d
Remove unused imports
ondrej-lukas Mar 17, 2026
9b73bfe
Fix discrepency with the code. Ties are broken for the attacker, not …
ondrej-lukas Mar 17, 2026
3eea49c
add back self._data (removed previously by misake)
ondrej-lukas Mar 17, 2026
ed25aa7
add missing seed parameter
ondrej-lukas Mar 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ exclude netsecgame/game/worlds/CYSTCoordinator.py
exclude netsecgame/game/worlds/RealWorldNetSecGame.py
exclude netsecgame/utils/trajectory_analysis.py
exclude netsecgame/utils/actions_parser.py
exclude netsecgame/utils/gamaplay_graphs.py
exclude netsecgame/utils/gameplay_graphs.py
exclude netsecgame/utils/log_parser.py
31 changes: 20 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ coordinator:
max_steps: 25 # timout set for the role `Attacker`
goal: # Definition of the goal state
description: "Exfiltrate data from Samba server to remote C&C server."
is_any_part_of_goal_random: True
known_networks: []
known_hosts: []
controlled_hosts: []
Expand All @@ -87,7 +86,6 @@ coordinator:
Defender:
goal:
description: "Block all attackers"
is_any_part_of_goal_random: False
known_networks: []
known_hosts: []
controlled_hosts: []
Expand Down Expand Up @@ -127,7 +125,7 @@ With the configuration ready the environment can be started in selected port
docker run -d --rm --name nsg-server\
-v $(pwd)/examples/example_task_configuration.yaml:/netsecgame/netsecenv_conf.yaml \
-v $(pwd)/logs:/netsecgame/logs \
-p 9000:9000 stratosphereips/netsecgame
-p 9000:9000 stratosphereips/netsecgame \
--debug_level="INFO"
```
`--name nsg-server`: specifies the name of the container
Expand All @@ -146,7 +144,7 @@ docker run -d --rm --name netsecgame-server ^
-p 9000:9000 ^
-v "%cd%\examples\example_task_configuration.yaml:/netsecgame/netsecenv_conf.yaml" ^
-v "%cd%\logs:/netsecgame/logs" ^
stratosphereips/netsecgame:latest
stratosphereips/netsecgame:latest ^
--debug_level="INFO"
```

Expand All @@ -155,7 +153,7 @@ The environment can be started locally with from the root folder of the reposito
```bash
python3 -m netsecgame.game.worlds.NetSecGame \
--task_config=./examples/example_task_configuration.yaml \
--game_port=9000
--game_port=9000 \
--debug_level="INFO"
```
Upon which the game server is created on `localhost:9000` to which the agents can connect to interact in the NetSecGame.
Expand All @@ -164,7 +162,7 @@ Upon which the game server is created on `localhost:9000` to which the agents ca
You can find user documentation at [https://stratosphereips.github.io/NetSecGame/](https://stratosphereips.github.io/NetSecGame/)

### Components of the NetSecGame Environment
The architecture of the environment can be seen [here](docs/Architecture.md).
The architecture of the environment can be seen [here](docs/architecture.md).
The NetSecGame environment has several components in the following files:
```
├── netsecgame/
Expand All @@ -176,6 +174,10 @@ The NetSecGame environment has several components in the following files:
| ├── smaller_scenario_configuration.py
| ├── scenario_configuration.py
| ├── three_net_scenario.py
| ├── two_nets.py
| ├── two_nets_tiny.py
| | ├── two_nets_small.py
| | ├── one_net.py
| ├── worlds/
| ├── NetSecGame.py # (NSG) basic simulation
| ├── RealWorldNetSecGame.py # Extension of `NSG` - runs actions in the *network of the host computer*
Expand All @@ -190,8 +192,9 @@ The NetSecGame environment has several components in the following files:
| ├── utils/
| ├── utils.py
| ├── log_parser.py
| ├── gamaplay_graphs.py
| ├── gameplay_graphs.py
| ├── actions_parser.py
| ├── trajectory_recorder.py

```
#### Directory Details
Expand All @@ -204,29 +207,35 @@ Modules for different world configurations:
- `NetSecGame.py`: Coordinator for the Network Security Game.
- `RealWorldNetSecGame.py`: Real-world NSG coordinator (actions are executed in the *real network*).
- `CYSTCoordinator.py`: Coordinator for CYST-based simulations (requires CYST running).
- `WhiteBoxNetSecGame.py`: Coordinator for Whitebox NSG (full action list provided to agents).

##### **`scenarios/`**
Predefined scenario configurations:
- `tiny_scenario_configuration.py`: A minimal example scenario.
- `smaller_scenario_configuration.py`: A compact scenario configuration used for development and rapid testing.
- `scenario_configuration.py`: The main scenario configuration.
- `three_net_scenario.py`: Configuration for a three-network scenario. Used for the evaluation of the model overfitting.
- `one_net.py`: A single network scenario.
- `two_nets.py`: A two-network scenario.
- `two_nets_tiny.py`: A tiny two-network scenario.
- `two_nets_small.py`: A small two-network scenario.

Implements the network game's configuration of hosts, data, services, and connections. It is taken from [CYST](https://pypi.org/project/cyst/).

##### **`utils/`**
Helper modules:
- `utils.py`: General-purpose utilities.
- `log_parser.py`: Tools for parsing game logs.
- `gamaplay_graphs.py`: Tools for visualizing gameplay data.
- `gameplay_graphs.py`: Tools for visualizing gameplay data.
- `actions_parser.py`: Parsing and analyzing game actions.
- `trajectory_recorder.py`: Tools for recording game trajectories.

The [scenarios](#definition-of-the-network-topology) define the **topology** of a network (number of hosts, connections, networks, services, data, users, firewall rules, etc.) while the [task-configuration](#task-configuration) is to be used for definition of the exact task for the agent in one of the scenarios (with fix topology).
- Agents compatible with the NetSecGame are located in a separate repository [NetSecGameAgents](https://github.com/stratosphereips/NetSecGameAgents/tree/main)

### Assumptions of the NetSecGame
1. NetSecGame works with the closed-world assumption. Only the defined entities exist in the simulation.
2. If the attacker does a successful action in the same step that the defender successfully detects the action, the priority goes to the defender. The reward is a penalty, and the game ends.
2. If the attacker does a successful action in the same step that the defender successfully detects the action, the priority goes to the attacker.
(From commit d6d4ac9, July 18th, 2024, the new action BlockIP removes controlled hosts from the state of others. So the state can get smaller)

- The action FindServices finds the new services in a host. If in a subsequent call to FindServices there are fewer services, they completely replace the list of previous services found. That is, each list of services is the final one, and no memory of previous open services is retained.
Expand All @@ -238,7 +247,7 @@ The [scenarios](#definition-of-the-network-topology) define the **topology** of
4. Playing `ExfiltrateData` requires controlling **BOTH** source and target hosts
5. Playing `Find Services` can be used to discover hosts (if those have any active services)
6. Parameters of `ScanNetwork` and `FindServices` can be chosen arbitrarily (they don't have to be listed in `known_newtworks`/`known_hosts`)
7. The `BlockIP` action needs its three parameters (Source host, Target host, and Blocked host) to be in the controlled list of the Agent.
7. The `BlockIP` action needs its `source_host` and `target_host` parameters to be in the controlled list of the Agent.

> [!NOTE]
> The global defender, available in the previous environment versions, will not be supported in the future. To enable backward compatibility, the global defender functionality can be enabled by adding `use_global_defender: True` to the configuration YAML file in the `env` section. This option is disabled by default.
Expand Down Expand Up @@ -319,7 +328,7 @@ This approach ensures that only repeated or excessive behavior is flagged, reduc


### Interaction with the Environment
When the game server is created, [agents](https://github.com/stratosphereips/NetSecGameAgents/tree/main) connect to it and interact with the environment. In every step of the interaction, agents submits an [Action](./AIDojoCoordinator/docs/Components.md#actions) and receive [Observation](./AIDojoCoordinator/docs/Components.md#observations) with `next_state`, `reward`, `is_terminal`, `end`, and `info` values. Once the terminal state or timeout is reached, no more interaction is possible until the agent asks for a game reset. Each agent should extend the `BaseAgent` class in [agents](https://github.com/stratosphereips/NetSecGameAgents/tree/main).
When the game server is created, [agents](https://github.com/stratosphereips/NetSecGameAgents/tree/main) connect to it and interact with the environment. In every step of the interaction, agents submits an [Action](./docs/game_components.md#netsecgame.game_components.Action) and receive [Observation](./docs/game_components.md#netsecgame.game_components.Observation) with `next_state`, `reward`, `is_terminal`, `end`, and `info` values. Once the terminal state or timeout is reached, no more interaction is possible until the agent asks for a game reset. Each agent should extend the `BaseAgent` class in [agents](https://github.com/stratosphereips/NetSecGameAgents/tree/main).

## Testing the environment

Expand Down
4 changes: 1 addition & 3 deletions README_pypi.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ coordinator:
max_steps: 25 # timeout set for the role `Attacker`
goal: # Definition of the goal state
description: "Exfiltrate data from Samba server to remote C&C server."
is_any_part_of_goal_random: True
known_networks: []
known_hosts: []
controlled_hosts: []
Expand All @@ -75,7 +74,6 @@ coordinator:
Defender:
goal:
description: "Block all attackers."
is_any_part_of_goal_random: False
known_networks: []
known_hosts: []
controlled_hosts: []
Expand All @@ -92,7 +90,7 @@ coordinator:
blocked_ips: {}
known_blocks: {}

env: # Environment configuraion
env: # Environment configuration
scenario: 'two_networks_tiny' # use the smallest topology for this example
use_global_defender: False # Do not use global SIEM Defender
use_dynamic_addresses: False # Do not randomize IP addresses
Expand Down
4 changes: 4 additions & 0 deletions docs/NetSecGame.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# NetSecGame
NetSecGame is an extension of the [`GameCoordinator`](game_coordinator.md) that implements the specific dynamics of the simulation while retaining the full functionality of the core game coordinator.

::: netsecgame.game.worlds.NetSecGame.NetSecGame
4 changes: 4 additions & 0 deletions docs/WhiteBoxNetSecGame.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# WhiteBoxNetSecGame
Whitebox version of NSG is an extension of the [`NetSecGame`](NetSecGame.md) which provides full action space for the agents upon registration in the game. This version is used for training of agents that require fixed size action space.

::: netsecgame.game.worlds.WhiteBoxNetSecGame.WhiteBoxNetSecGame
3 changes: 3 additions & 0 deletions docs/agent_server.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# Agent Server
The Agent Server is responsible for managing the low-level communication between the agents and the game coordinator. It handles incoming TCP connections, manages agent registration, and facilitates the asynchronous message passing required for real-time interaction in the game.

::: netsecgame.game.agent_server.AgentServer
12 changes: 6 additions & 6 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Each data instance has two parameters:
Examples:
```python
d1 = Data("User1", "DatabaseData")
d2 = Data("User1", "DatabaseData", size=42, type="txt", "SecretUserDatabase")
d2 = Data("User1", "DatabaseData", size=42, type="txt", description="SecretUserDatabase")
```

### GameState
Expand Down Expand Up @@ -74,13 +74,13 @@ The Action consists of two parts
#### List of ActionTypes
- **JoinGame**, params={`agent_info`:AgentInfo(`<name>`, `<role>`)}: Used to register agent in a game with a given `<role>`.
- **QuitGame**, params={}: Used for termination of agent's interaction.
- **ResetGame**, params={`request_trajectory`:`bool` (default=`False`), `randomize_topology`=`bool` (default=`True`)}: Used for requesting reset of the game to it's initial position. If `request_trajectory = True`, the coordinator will send back the complete trajectory of the previous run in the next message. If `randomize_topology`=`True`, the agent request topology to be changed in the next episode. NOTE: the topology is changed only if (i) the `use_dynamic_ips` is set to `True` in the task configuration AND all active agents ask for the change.
- **ResetGame**, params={`request_trajectory`:`bool` (default=`False`), `randomize_topology`=`bool` (default=`True`)}: Used for requesting reset of the game to its initial position. If `request_trajectory = True`, the coordinator will send back the complete trajectory of the previous run in the next message. If `randomize_topology`=`True`, the agent request topology to be changed in the next episode. NOTE: the topology is changed only if (i) the `use_dynamic_addresses` is set to `True` in the task configuration AND all active agents ask for the change.
---
- **ScanNetwork**, params{`source_host`:`<IP>`, `target_network`:`<Network>`}: Scans the given `<Network>` from a specified source host. Discovers ALL hosts in a network that are accessible from `<IP>`. If successful, returns set of discovered `<IP>` objects.
- **FindServices**, params={`source_host`:`<IP>`, `target_host`:`<IP>`}: Used to discover ALL services running in the `target_host` if the host is accessible from `source_host`. If successful, returns a set of all discovered `<Service>` objects.
- **FindData**, params={`source_host`:`<IP>`, `target_host`:`<IP>`}: Searches `target_host` for data. If `source_host` differs from `target_host`, success depends on accessability from the `source_host`. If successful, returns a set of all discovered `<Data>` objects.
- **FindData**, params={`source_host`:`<IP>`, `target_host`:`<IP>`}: Searches `target_host` for data. If `source_host` differs from `target_host`, success depends on accessibility from the `source_host`. If successful, returns a set of all discovered `<Data>` objects.
- **ExploitService**, params={`source_host`:`<IP>`, `target_host`:`<IP>`, `target_service`:`<Service>`}: Exploits `target_service` in a specified `target_host`. If successful, the attacker gains control of the `target_host`.
- **ExfiltrateData**, params{`source_host`:`<IP>`, `target_host`:`<IP>`, `data`:`<IP>`}: Copies `data` from the `source_host` to `target_host` IF both are controlled and `target_host` is accessible from `source_host`.
- **ExfiltrateData**, params{`source_host`:`<IP>`, `target_host`:`<IP>`, `data`:`<Data>`}: Copies `data` from the `source_host` to `target_host` IF both are controlled and `target_host` is accessible from `source_host`.
- **BlockIP**, params{`source_host`:`<IP>`, `target_host`:`<IP>`, `blocked_host`:`<IP>`}: Blocks communication from/to `blocked_host` on `target_host`. Requires control of `target_host`.

### Action preconditions and effects
Expand All @@ -97,8 +97,8 @@ In the following table, we describe the effects of selected actions and their pr

#### Assumption and Conditions for Actions
1. When playing the `ExploitService` action, it is expected that the agent has discovered this service before (by playing `FindServices` in the `target_host` before this action)
2. The `Find Data` action finds all the available data in the host if successful.
3. The `Find Data` action requires ownership of the target host.
2. The `FindData` action finds all the available data in the host if successful.
3. The `FindData` action requires ownership of the target host.
4. Playing `ExfiltrateData` requires controlling **BOTH** source and target hosts
5. Playing `Find Services` can be used to discover hosts (if those have any active services)
6. Parameters of `ScanNetwork` and `FindServices` can be chosen arbitrarily (they don't have to be listed in `known_networks`/`known_hosts`)
Expand Down
3 changes: 3 additions & 0 deletions docs/config_parser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ConfigParser is a class that is responsible for parsing the YAML configuration file and providing it to the game coordinator.

::: netsecgame.game.config_parser.ConfigParser
15 changes: 7 additions & 8 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The environment part defines the properties of the environment for the task (see
- `two_networks_small` - single client and 5 servers in separate local networks + remote C&C server
- `two_networks` - 5 clients and 5 servers in separate local networks + remote C&C server
- `three_net_scenario` - 5 clients in a local network, 5 servers split in 2 additional local networks + remote C&C server
- `save_tajectories` - if `True`, interaction of the agents is serialized and stored in a file
- `save_trajectories` - if `True`, interaction of the agents is serialized and stored in a file
- `use_dynamic_addresses` - if `True`, the network and IP addresses defined in `scenario` are randomly changed at the beginning of an episode (the network topology is kept as defined in the `scenario`. Relations between networks are kept, IPs inside networks are chosen at random based on the network IP and mask). The change also depend on the input from the agents:

### Available topologies
Expand Down Expand Up @@ -55,10 +55,10 @@ There are 5 topologies available in NSG:

|Task configuration| Agent reset request | Result|
|----------------------|----------------------|----------------------|
|`use_dynamic_ips = True` | `randomize_topology = True`| Changed topology |
|`use_dynamic_ips = True` | `randomize_topology = False`| SAME topology |
|`use_dynamic_ips = False` | `randomize_topology = True`| SAME topology |
|`use_dynamic_ips = False` | `randomize_topology = False`| SAME topology |
|`use_dynamic_addresses = True` | `randomize_topology = True`| Changed topology |
|`use_dynamic_addresses = True` | `randomize_topology = False`| SAME topology |
|`use_dynamic_addresses = False` | `randomize_topology = True`| SAME topology |
|`use_dynamic_addresses = False` | `randomize_topology = False`| SAME topology |

In summary, the topology change (IP randomization) can't change without allowing it in the task configuration. If allowed in the task config YAML, it can still be rejected by the agents.

Expand All @@ -67,7 +67,7 @@ In summary, the topology change (IP randomization) can't change without allowing
- `required_players` - Minimum required players for the game to start (default 1)
- `rewards`:
- `success` - sets reward which agent gets when it reaches the goal (default 100)
- `fail` - sets the reward that which agent does not reach it's objective (default -10)
- `fail` - sets the reward which agent gets when it does not reach its objective (default -10)
- `step` - sets reward which agent gets for every step taken (default -1)
- `false_positive` - sets reward for a false positive action (default -5)
- `actions` - defines the probability of success for every ActionType
Expand Down Expand Up @@ -159,7 +159,6 @@ coordinator:
max_steps: 20
goal:
description: "Exfiltrate data from Samba server to remote C&C server."
is_any_part_of_goal_random: True
known_networks: []
known_hosts: []
controlled_hosts: []
Expand Down Expand Up @@ -205,7 +204,7 @@ Example of defender configuration:
blocked_ips: {}
known_blocks: {}
```
As in other agents, the description is only a text for the agent, so it can know what is supposed to do to win. In the curent implementation, the *Defender* wins, if **NO ATTACKER** reaches their goal.
As in other agents, the description is only a text for the agent, so it can know what is supposed to do to win. In the current implementation, the *Defender* wins, if **NO ATTACKER** reaches their goal.

### Trajectory storing and analysis

Expand Down
10 changes: 1 addition & 9 deletions docs/configuration_manager.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
## Configuration Manager

Configuration manager is a component of the game coordinator that handles the configuration of the game. It is responsible for loading the configuration from the YAML file and providing it to the game coordinator.

::: netsecgame.game.configuration_manager.ConfigurationManager

## ConfigParser

ConfigParser is a class that is responsible for parsing the YAML configuration file and providing it to the game coordinator.

::: netsecgame.game.config_parser.ConfigParser
::: netsecgame.game.configuration_manager.ConfigurationManager
3 changes: 3 additions & 0 deletions docs/game_components.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# Game Components
This module contains the core building blocks and data structures used throughout the NetSecGame environment. These include fundamental types such as IP addresses, networks, services, data objects, and actions. These components are used to define both the environment's state and the interactions between agents and the world.

::: netsecgame.game_components
Loading
Loading