Files
PrimAITE/src/primaite/game/agent/scripted_agents/data_manipulation_bot.py

66 lines
2.9 KiB
Python
Raw Normal View History

2025-01-03 14:40:00 +00:00
# © Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
import random
2024-03-04 10:43:38 +00:00
from typing import Dict, Tuple
from gymnasium.core import ObsType
from primaite.game.agent.interface import AbstractScriptedAgent
class DataManipulationAgent(AbstractScriptedAgent):
"""Agent that uses a DataManipulationBot to perform an SQL injection attack."""
next_execution_timestep: int = 0
2024-02-08 09:19:18 +00:00
starting_node_idx: int = 0
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
2024-03-11 20:10:08 +00:00
self.setup_agent()
def _set_next_execution_timestep(self, timestep: int) -> None:
"""Set the next execution timestep with a configured random variance.
:param timestep: The timestep to add variance to.
"""
random_timestep_increment = random.randint(
-self.agent_settings.start_settings.variance, self.agent_settings.start_settings.variance
)
self.next_execution_timestep = timestep + random_timestep_increment
2024-03-04 10:43:38 +00:00
def get_action(self, obs: ObsType, timestep: int) -> Tuple[str, Dict]:
"""Waits until a specific timestep, then attempts to execute its data manipulation application.
2024-03-04 10:43:38 +00:00
:param obs: Current observation for this agent, not used in DataManipulationAgent
:type obs: ObsType
2024-03-04 10:43:38 +00:00
:param timestep: The current simulation timestep, used for scheduling actions
:type timestep: int
:return: Action formatted in CAOS format
:rtype: Tuple[str, Dict]
"""
2024-02-27 13:30:16 +00:00
if timestep < self.next_execution_timestep:
2024-12-13 09:49:21 +00:00
self.logger.debug(msg="Performing do nothing")
return "do_nothing", {}
2024-02-27 13:30:16 +00:00
self._set_next_execution_timestep(timestep + self.agent_settings.start_settings.frequency)
self.logger.info(msg="Performing a data manipulation attack!")
2024-12-13 09:49:21 +00:00
self.logger.info(msg=f"Chosen to attack {self.starting_node}")
# TODO: Why is the application_id hardcoded to target application 0?
return "node_application_execute", {
"type": "node_application_execute",
"node_name": self.starting_node,
"application_name": "test",
}
2024-01-09 14:53:15 +00:00
2024-03-11 20:10:08 +00:00
def setup_agent(self) -> None:
2024-01-09 14:53:15 +00:00
"""Set the next execution timestep when the episode resets."""
2024-02-08 09:19:18 +00:00
self._select_start_node()
2024-01-09 14:53:15 +00:00
self._set_next_execution_timestep(self.agent_settings.start_settings.start_step)
2024-02-08 09:19:18 +00:00
def _select_start_node(self) -> None:
"""Set the starting starting node of the agent to be a random node from this agent's action manager."""
# we are assuming that every node in the node manager has a data manipulation application at idx 0
num_nodes = len(self.action_manager.node_names)
self.starting_node_idx = random.randint(0, num_nodes - 1)
2024-12-13 09:49:21 +00:00
self.starting_node = self.action_manager.node_names[self.starting_node_idx]
self.logger.debug(msg=f"Select Start Node ID: {self.starting_node_idx}")