2024-07-02 15:02:59 +01:00
.. only :: comment
2025-01-02 15:05:06 +00:00
© Crown-owned copyright 2025, Defence Science and Technology Laboratory UK
2024-07-02 15:02:59 +01:00
.. _Terminal:
Terminal
2024-08-16 15:47:41 +01:00
########
2024-07-02 15:02:59 +01:00
2024-07-23 15:18:20 +01:00
The `` Terminal.py `` class provides a generic terminal simulation, by extending the base Service class within PrimAITE. The aim of this is to act as the primary entrypoint for Nodes within the environment.
Overview
2024-08-16 15:47:41 +01:00
========
2024-07-23 15:18:20 +01:00
The Terminal service uses Secure Socket (SSH) as the communication method between terminals. They operate on port 22, and are part of the services automatically
installed on Nodes when they are instantiated.
2024-07-02 15:02:59 +01:00
Key capabilities
2024-08-16 15:47:41 +01:00
""""""""""""""""
2024-07-02 15:02:59 +01:00
- Ensures packets are matched to an existing session
2024-07-24 08:31:24 +01:00
- Simulates common Terminal processes/commands.
2024-07-02 15:02:59 +01:00
- Leverages the Service base class for install/uninstall, status tracking etc.
2025-02-10 14:39:28 +00:00
Usage
"""""
- Pre-Installs on any `Node` component (with the exception of `Switches` ).
- Terminal Clients connect, execute commands and disconnect from remote nodes.
- Ensures that users are logged in to the component before executing any commands.
- Service runs on SSH port 22 by default.
- Enables Agents to send commands both remotely and locally.
2024-07-08 07:58:10 +01:00
Implementation
2024-08-16 15:47:41 +01:00
""""""""""""""
2024-07-08 07:58:10 +01:00
2024-08-05 15:44:52 +01:00
- Manages remote connections in a dictionary by session ID.
- Processes commands, forwarding to the `` RequestManager `` or `` SessionManager `` where appropriate.
- Extends Service class.
2024-07-08 07:58:10 +01:00
2025-02-10 14:39:28 +00:00
A detailed guide on the implementation and functionality of the Terminal class can be found in the "Terminal-Processing" jupyter notebook.
2024-08-06 09:30:27 +01:00
2025-02-10 14:39:28 +00:00
Command Format
^^^^^^^^^^^^^^
2024-09-04 12:07:32 +01:00
2025-02-10 14:39:28 +00:00
Terminals implement their commands through leveraging the pre-existing :ref: `request_system` .
Due to this Terminals will only accept commands passed within the `` RequestFormat `` .
:py:class: `primaite.game.interface.RequestFormat`
For example, `` terminal `` command actions when used in `` yaml `` format are formatted as follows:
.. code-block :: yaml
command:
- "file_system"
- "create"
- "file"
- "downloads"
- "cat.png"
- "False
This is then loaded from yaml into a dictionary containing the terminal command:
.. code-block :: python
{"command":["file_system", "create", "file", "downloads", "cat.png", "False"]}
Which is then passed to the `` Terminals `` Request Manager to be executed.
Game Layer Usage (Agents)
========================
The below code examples demonstrate how to use terminal related actions in yaml files.
yaml
""""
`` node-send-local-command ``
"""""""""""""""""""""""""""
Agents can execute local commands without needing to perform a separate remote login action (`` node-session-remote-login `` ).
.. code-block :: yaml
...
...
action: node-send-local-command
options:
2025-03-12 14:53:34 +00:00
node_name: node_a
2025-02-10 14:39:28 +00:00
username: admin
password: admin
command: # Example command - Creates a file called 'cat.png' in the downloads folder.
- "file_system"
- "create"
- "file"
- "downloads"
- "cat.png"
- "False"
`` node-session-remote-login ``
"""""""""""""""""
Agents are able to use the terminal to login into remote nodes via `` SSH `` which allows for agents to execute commands on remote hosts.
.. code-block :: yaml
...
...
action: node-session-remote-login
options:
2025-03-12 14:53:34 +00:00
node_name: node_a
2025-02-10 14:39:28 +00:00
username: admin
password: admin
remote_ip: 192.168.0.10 # Example Ip Address. (The remote host's IP that will be used by ssh)
`` node-send-remote-command ``
""""""""""""""""""""""""""""
After remotely logging into another host, an agent can use the `` node-send-remote-command `` to execute commands across the network remotely.
.. code-block :: yaml
...
...
action: node-send-remote-command
options:
2025-03-12 14:53:34 +00:00
node_name: node_a
2025-02-10 14:39:28 +00:00
remote_ip: 192.168.0.10
command:
- "file_system"
- "create"
- "file"
- "downloads"
- "cat.png"
- "False"
Simulation Layer Usage
======================
2024-09-04 12:07:32 +01:00
2024-08-06 09:30:27 +01:00
The below code examples demonstrate how to create a terminal, a remote terminal, and how to send a basic application install command to a remote node.
2024-07-08 07:58:10 +01:00
Python
""""""
.. code-block :: python
from ipaddress import IPv4Address
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.system.services.terminal.terminal import Terminal
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
2025-02-27 18:16:45 +00:00
client = Computer(config= {
"hostname":"client",
"ip_address":"192.168.10.21",
"subnet_mask":"255.255.255.0",
"default_gateway":"192.168.10.1",
"operating_state":NodeOperatingState.ON,
}
2024-07-08 07:58:10 +01:00
)
2025-02-10 14:39:28 +00:00
terminal: Terminal = client.software_manager.software.get("terminal")
2024-08-06 09:30:27 +01:00
2024-08-06 09:33:41 +01:00
Creating Remote Terminal Connection
2024-08-16 15:47:41 +01:00
"""""""""""""""""""""""""""""""""""
2024-08-06 09:30:27 +01:00
.. code-block :: python
from primaite.simulator.system.services.terminal.terminal import Terminal
from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.system.services.terminal.terminal import RemoteTerminalConnection
network = Network()
2025-02-27 18:16:45 +00:00
node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0})
2024-08-06 09:30:27 +01:00
node_a.power_on()
2025-02-27 18:16:45 +00:00
node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0})
2024-08-06 09:30:27 +01:00
node_b.power_on()
network.connect(node_a.network_interface[1], node_b.network_interface[1])
2025-02-10 14:39:28 +00:00
terminal_a: Terminal = node_a.software_manager.software.get("terminal")
2024-08-06 09:30:27 +01:00
term_a_term_b_remote_connection: RemoteTerminalConnection = terminal_a.login(username="admin", password="Admin123!", ip_address="192.168.0.11")
Executing a basic application install command
2024-08-16 15:47:41 +01:00
"""""""""""""""""""""""""""""""""""""""""""""
2024-08-06 09:30:27 +01:00
.. code-block :: python
from primaite.simulator.system.services.terminal.terminal import Terminal
from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.system.services.terminal.terminal import RemoteTerminalConnection
from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript
network = Network()
2025-02-27 18:16:45 +00:00
node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0})
2024-08-06 09:30:27 +01:00
node_a.power_on()
2025-02-27 18:16:45 +00:00
node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0})
2024-08-06 09:30:27 +01:00
node_b.power_on()
network.connect(node_a.network_interface[1], node_b.network_interface[1])
2025-02-10 14:39:28 +00:00
terminal_a: Terminal = node_a.software_manager.software.get("terminal")
2024-08-06 09:30:27 +01:00
term_a_term_b_remote_connection: RemoteTerminalConnection = terminal_a.login(username="admin", password="Admin123!", ip_address="192.168.0.11")
2025-02-10 14:39:28 +00:00
term_a_term_b_remote_connection.execute(["software_manager", "application", "install", "ransomware-script"])
2024-08-06 09:30:27 +01:00
2024-08-06 09:33:41 +01:00
Creating a folder on a remote node
2024-08-16 15:47:41 +01:00
""""""""""""""""""""""""""""""""""
2024-08-06 09:30:27 +01:00
.. code-block :: python
from primaite.simulator.system.services.terminal.terminal import Terminal
from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.system.services.terminal.terminal import RemoteTerminalConnection
from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript
network = Network()
2025-02-27 18:16:45 +00:00
node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0})
2024-08-06 09:30:27 +01:00
node_a.power_on()
2025-02-27 18:16:45 +00:00
node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0})
2024-08-06 09:30:27 +01:00
node_b.power_on()
network.connect(node_a.network_interface[1], node_b.network_interface[1])
2025-02-10 14:39:28 +00:00
terminal_a: Terminal = node_a.software_manager.software.get("terminal")
2024-08-06 09:30:27 +01:00
term_a_term_b_remote_connection: RemoteTerminalConnection = terminal_a.login(username="admin", password="Admin123!", ip_address="192.168.0.11")
term_a_term_b_remote_connection.execute(["file_system", "create", "folder", "downloads"])
Disconnect from Remote Node
2024-08-16 15:47:41 +01:00
"""""""""""""""""""""""""""
2024-08-06 09:30:27 +01:00
.. code-block :: python
from primaite.simulator.system.services.terminal.terminal import Terminal
from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.system.services.terminal.terminal import RemoteTerminalConnection
from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript
network = Network()
2025-02-27 18:16:45 +00:00
node_a = Computer(config={"hostname":"node_a", "ip_address":"192.168.0.10", "subnet_mask":"255.255.255.0", "start_up_duration":0})
2024-08-06 09:30:27 +01:00
node_a.power_on()
2025-02-27 18:16:45 +00:00
node_b = Computer(config={"hostname":"node_b", "ip_address":"192.168.0.11", "subnet_mask":"255.255.255.0", "start_up_duration":0})
2024-08-06 09:30:27 +01:00
node_b.power_on()
network.connect(node_a.network_interface[1], node_b.network_interface[1])
2025-02-10 14:39:28 +00:00
terminal_a: Terminal = node_a.software_manager.software.get("terminal")
2024-08-06 09:30:27 +01:00
term_a_term_b_remote_connection: RemoteTerminalConnection = terminal_a.login(username="admin", password="Admin123!", ip_address="192.168.0.11")
term_a_term_b_remote_connection.disconnect()
2024-09-05 08:41:04 +01:00
`` Common Attributes ``
2024-09-05 11:23:52 +01:00
^^^^^^^^^^^^^^^^^^^^^
2024-09-05 08:41:04 +01:00
See :ref: `Common Configuration`