Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
324 changes: 30 additions & 294 deletions README.md

Large diffs are not rendered by default.

62 changes: 1 addition & 61 deletions README_pypi.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,67 +43,7 @@ python3 -m netsecgame.game.worlds.NetSecGame \
--game_port=9000
```
### Configuration
To start the game, a task configuration file must be provided. Task configuration specifies the starting points and goals for agents, the episode length, rewards, and other game properties. Here is an example of the configuration:
```YAML
# Example of the task configuration for NetSecGame
# The objective of the Attacker in this task is to locate specific data
# and exfiltrate it to a remote C&C server.
# The scenario starts AFTER the initial breach of the local network
# (the attacker controls 1 local device + the remote C&C server).

coordinator:
agents:
Attacker: # Configuration of 'Attacker' agents
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."
known_networks: []
known_hosts: []
controlled_hosts: []
known_services: {}
known_data: {213.47.23.195: [[User1,DataFromServer1]]} # winning condition
known_blocks: {}
start_position: # Definition of the starting state (keywords "random" and "all" can be used)
known_networks: []
known_hosts: []
controlled_hosts: [213.47.23.195, random] # keyword 'random' will be replaced by randomly selected IP during initialization
known_services: {}
known_data: {}
known_blocks: {}

Defender:
goal:
description: "Block all attackers."
known_networks: []
known_hosts: []
controlled_hosts: []
known_services: {}
known_data: {}
known_blocks: {213.47.23.195: 'all_attackers'}

start_position:
known_networks: []
known_hosts: []
controlled_hosts: []
known_services: {}
known_data: {}
blocked_ips: {}
known_blocks: {}

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
use_firewall: True # Use firewall
save_trajectories: False # Do not store trajectories
required_players: 1 # Minimal amount of agents required to start the game
rewards: # Configurable reward function
success: 100
step: -1
fail: -10
false_positive: -5
```
For detailed configuration instructions, please refer to the [Configuration Documentation](https://stratosphereips.github.io/NetSecGame/configuration/).
A YAML task configuration file is required to start the game. It defines starting positions, goals, rewards, network topology, and other game properties. An example configuration is included in the [GitHub repository](https://github.com/stratosphereips/NetSecGame/tree/main/examples). For a full reference of all options, see the [Configuration Documentation](https://stratosphereips.github.io/NetSecGame/configuration/).

## Creating Agents

Expand Down
50 changes: 47 additions & 3 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,61 @@ In the following table, we describe the effects of selected actions and their pr
|ExfiltrateData| `source_host`,`target_host`, `data` |`source_host`, `target_host` ∈ `controlled_hosts` AND `data` ∈ `known_data`| extends `known_data[target_host]` with `data`|
|BlockIP | `source_host`, `target_host`, `blocked_host`|`source_host` ∈ `controlled_hosts`| extends `known_blocks[target_host]` with `blocked_host`|

#### Assumption and Conditions for Actions
#### Assumptions 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 `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)
5. Playing `FindServices` 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`)
7. The `BlockIP` action requires its `source_host` and `target_host` parameters to be in the controlled list of the Agent.

### Observations
After submitting Action `a` to the environment, agents receive an `Observation` in return. Each observation consists of 4 parts:
- `state`:`Gamestate` - with the current view of the environment [state](#gamestate)
- `reward`: `int` - with the immediate reward agent gets for playing Action `a`
- `end`:`bool` - indicating if the interaction can continue after playing Action `a`
- `info`: `dict` - placeholder for any information given to the agent (e.g., the reason why `end is True` )
- `info`: `dict` - placeholder for any information given to the agent (e.g., the reason why `end is True` )

## Project Structure

```
├── netsecgame/
│ ├── agents/
│ │ ├── base_agent.py # Base agent class — API for agent-server communication
│ ├── game/
│ │ ├── scenarios/
│ │ │ ├── one_net.py # Single network scenario
│ │ │ ├── two_nets_tiny.py # Tiny two-network scenario
│ │ │ ├── two_nets_small.py # Small two-network scenario
│ │ │ ├── two_nets.py # Two-network scenario
│ │ │ ├── three_net_scenario.py # Three-network scenario
│ │ ├── worlds/
│ │ │ ├── NetSecGame.py # Base simulation coordinator
│ │ │ ├── RealWorldNetSecGame.py # Real-network coordinator
│ │ │ ├── CYSTCoordinator.py # CYST engine coordinator
│ │ │ ├── WhiteBoxNetSecGame.py # Whitebox coordinator (full action list)
│ │ ├── agent_server.py # Agent TCP server implementation
│ │ ├── config_parser.py # Task configuration parser
│ │ ├── configuration_manager.py # Configuration query helper
│ │ ├── coordinator.py # Core game coordinator (extend via worlds/)
│ │ ├── global_defender.py # Stochastic SIEM defender
│ ├── game_components.py # Core building blocks (IP, Network, Action, GameState, etc.)
│ ├── utils/
│ │ ├── utils.py # General-purpose utilities
│ │ ├── trajectory_recorder.py # Episode trajectory recording
│ │ ├── trajectory_analysis.py # Trajectory analysis tools
│ │ ├── log_parser.py # Game log parsing
│ │ ├── gameplay_graphs.py # Gameplay visualization
│ │ ├── actions_parser.py # Action parsing and analysis
│ │ ├── aidojo_log_colorizer.py # Log colorization
```

### Key Components

- **[`coordinator.py`](game_coordinator.md)** — Base coordinator class handling agent communication and coordination. Does not implement world dynamics — must be extended (see `worlds/`).
- **[`game_components.py`](game_components.md)** — Library of core objects used throughout the environment.
- **[`global_defender.py`](global_defender.md)** — Stochastic omnipresent defender simulating a SIEM system.
- **[`base_agent.py`](base_agent.md)** — Base class for all agents. Implements the TCP communication protocol.

The [scenarios](#) define the **topology** of a network (hosts, connections, networks, services, data, firewall rules) while the [task configuration](configuration.md) defines the exact task for agents within a given topology.
6 changes: 6 additions & 0 deletions docs/base_agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Base Agent
The `BaseAgent` class provides the foundational interface for all agents interacting with the NetSecGame environment. It handles TCP socket communication with the game server, agent registration, game reset requests, and the core action-observation loop.

All custom agents should extend this class and implement their decision-making logic by overriding a method like `choose_action` (see [Getting Started](getting_started.md#creating-your-first-agent) for an example).

::: netsecgame.agents.base_agent.BaseAgent
220 changes: 220 additions & 0 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
# Getting Started

This guide covers installation, configuration, and running your first NetSecGame session.

## Installation

### Docker (recommended)

The easiest way to run the NetSecGame server is via the official Docker image:

```bash
docker pull stratosphereips/netsecgame
```

#### Building the image locally

```bash
docker build -t netsecgame:local .
```

To build the experimental **Whitebox** variant (agents receive the full action list upon registration):

```bash
docker build --build-arg GAME_MODULE="netsecgame.game.worlds.WhiteBoxNetSecGame" -t netsecgame:local-whitebox .
```

!!! warning
The Whitebox variant is currently experimental.

### pip install (agent development)

To install the package for developing agents:

```bash
pip install netsecgame
```

To include dependencies for running the game server locally:

```bash
pip install netsecgame[server]
```

### Installing from source

For modifying the environment itself, install in a virtual environment:

=== "Python venv"
```bash
python -m venv <venv-name>
source <venv-name>/bin/activate
pip install -e .
```

=== "Conda"
```bash
conda create --name aidojo python==3.12
conda activate aidojo
pip install -e .
```

## Task Configuration

A YAML configuration file defines the task for the NetSecGame. It specifies starting positions, goals, rewards, and environment properties.

### Example Configuration

```yaml
# The objective of the Attacker in this task is to locate specific data
# and exfiltrate it to a remote C&C server.
# The scenario starts AFTER the initial breach of the local network
# (the attacker controls 1 local device + the remote C&C server).

coordinator:
agents:
Attacker: # Configuration of 'Attacker' agents
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."
known_networks: []
known_hosts: []
controlled_hosts: []
known_services: {}
known_data: {213.47.23.195: [[User1,DataFromServer1]]} # winning condition
known_blocks: {}
start_position: # Definition of the starting state
known_networks: []
known_hosts: []
controlled_hosts: [213.47.23.195, random] # 'random' is replaced during init
known_services: {}
known_data: {}
known_blocks: {}

Defender:
goal:
description: "Block all attackers"
known_networks: []
known_hosts: []
controlled_hosts: []
known_services: {}
known_data: {}
known_blocks: {213.47.23.195: 'all_attackers'}

start_position:
known_networks: []
known_hosts: []
controlled_hosts: []
known_services: {}
known_data: {}
blocked_ips: {}
known_blocks: {}

env: # Environment configuration
scenario: 'two_networks_tiny' # use the smallest topology
use_global_defender: False
use_dynamic_addresses: False
use_firewall: True
save_trajectories: False
required_players: 1
rewards:
success: 100
step: -1
fail: -10
false_positive: -5
```

For a full reference of all configuration options, see the [Configuration Documentation](configuration.md).

## Running the Game Server

### In Docker

```bash
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 \
--debug_level="INFO"
```

| Flag | Description |
|------|-------------|
| `--name nsg-server` | Name of the container |
| `-v <config>:/netsecgame/netsecenv_conf.yaml` | Mount your configuration file |
| `-v $(pwd)/logs:/netsecgame/logs` | Mount logs directory |
| `-p <port>:9000` | Expose the game server port |
| `--debug_level` | Logging level: `DEBUG`, `INFO`, `WARNING`, `CRITICAL` (default: `INFO`) |

#### Running on Windows (Docker Desktop)

```cmd
docker run -d --rm --name nsg-server ^
-p 9000:9000 ^
-v "%cd%\examples\example_task_configuration.yaml:/netsecgame/netsecenv_conf.yaml" ^
-v "%cd%\logs:/netsecgame/logs" ^
stratosphereips/netsecgame:latest ^
--debug_level="INFO"
```

### Locally

```bash
python3 -m netsecgame.game.worlds.NetSecGame \
--task_config=./examples/example_task_configuration.yaml \
--game_port=9000 \
--debug_level="INFO"
```

The game server will start on `localhost:9000`.

## Creating Your First Agent

Agents connect to the game server and interact using the standard RL loop: submit an [Action](game_components.md), receive an [Observation](architecture.md#observations).

All agents should extend the [`BaseAgent`](base_agent.md) class:

```python
from netsecgame import BaseAgent, Action, GameState, Observation, AgentRole

class MyAgent(BaseAgent):
def __init__(self, host, port, role: str):
super().__init__(host, port, role)

def choose_action(self, observation: Observation) -> Action:
# Define your logic here based on observation.state
pass

def main():
agent = MyAgent(host="localhost", port=9000, role=AgentRole.Attacker)
observation = agent.register()

while not observation.end:
action = agent.choose_action(observation)
observation = agent.make_step(action)

agent.terminate_connection()
```

For full agent implementations, see the [NetSecGameAgents](https://github.com/stratosphereips/NetSecGameAgents) repository.

## Interaction Flow

```mermaid
sequenceDiagram
participant Agent
participant Server as NetSecGame Server

Agent->>Server: JoinGame (register)
Server-->>Agent: Initial Observation (state, reward, end, info)

loop Until end == True
Agent->>Server: Action (e.g., ScanNetwork, ExploitService)
Server-->>Agent: Observation (next_state, reward, end, info)
end

Agent->>Server: ResetGame (optional)
Server-->>Agent: Initial Observation (new episode)

Agent->>Server: QuitGame
```
Loading
Loading