diff --git a/docs/source/simulation_components/system/services/terminal.rst b/docs/source/simulation_components/system/services/terminal.rst index 37872b5b..0e362326 100644 --- a/docs/source/simulation_components/system/services/terminal.rst +++ b/docs/source/simulation_components/system/services/terminal.rst @@ -39,6 +39,12 @@ Implementation - Extends Service class. - A detailed guide on the implementation and functionality of the Terminal class can be found in the "Terminal-Processing" jupyter notebook. + +Usage +===== + +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. + Python """""" @@ -59,3 +65,109 @@ Python ) terminal: Terminal = client.software_manager.software.get("Terminal") + +Obtaining Remote Connection +""""""""""""""""""""""""""" + + +.. 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() + node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) + node_a.power_on() + node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) + node_b.power_on() + network.connect(node_a.network_interface[1], node_b.network_interface[1]) + + terminal_a: Terminal = node_a.software_manager.software.get("Terminal") + + + 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 +""""""""""""""""""""""""""""""""" + +.. 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() + node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) + node_a.power_on() + node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) + node_b.power_on() + network.connect(node_a.network_interface[1], node_b.network_interface[1]) + + terminal_a: Terminal = node_a.software_manager.software.get("Terminal") + + + 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(["software_manager", "application", "install", "RansomwareScript"]) + + + +Creating a file on a remote node +"""""""""""""""""""""""""""""""" + +.. 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() + node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) + node_a.power_on() + node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) + node_b.power_on() + network.connect(node_a.network_interface[1], node_b.network_interface[1]) + + terminal_a: Terminal = node_a.software_manager.software.get("Terminal") + + + 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 + +.. 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() + node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) + node_a.power_on() + node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) + node_b.power_on() + network.connect(node_a.network_interface[1], node_b.network_interface[1]) + + terminal_a: Terminal = node_a.software_manager.software.get("Terminal") + + + 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() diff --git a/src/primaite/simulator/network/protocols/ssh.py b/src/primaite/simulator/network/protocols/ssh.py index 7ba629f8..ca9663d8 100644 --- a/src/primaite/simulator/network/protocols/ssh.py +++ b/src/primaite/simulator/network/protocols/ssh.py @@ -76,10 +76,14 @@ class SSHPacket(DataPacket): user_account: Optional[SSHUserCredentials] = None """User Account Credentials if passed""" - connection_request_uuid: Optional[str] = None # Connection Request uuid. + connection_request_uuid: Optional[str] = None + """Connection Request UUID used when establishing a remote connection""" - connection_uuid: Optional[str] = None # The connection uuid used to validate the session + connection_uuid: Optional[str] = None + """Connection UUID used when validating a remote connection""" - ssh_output: Optional[RequestResponse] = None # The Request Manager's returned RequestResponse + ssh_output: Optional[RequestResponse] = None + """RequestResponse from Request Manager""" - ssh_command: Optional[str] = None # This is the request string + ssh_command: Optional[str] = None + """Request String""" diff --git a/tests/unit_tests/_primaite/_simulator/_system/_services/test_terminal.py b/tests/unit_tests/_primaite/_simulator/_system/_services/test_terminal.py index c86d6466..7e98e501 100644 --- a/tests/unit_tests/_primaite/_simulator/_system/_services/test_terminal.py +++ b/tests/unit_tests/_primaite/_simulator/_system/_services/test_terminal.py @@ -336,3 +336,19 @@ def test_SSH_across_network(wireless_wan_network): terminal_b_on_terminal_a = terminal_b.login(username="username", password="password", ip_address="192.168.0.2") assert len(terminal_a._connections) == 1 + + +def test_multiple_remote_terminals_same_node(basic_network): + """Test to check that multiple remote terminals can be spawned by one node.""" + network: Network = basic_network + computer_a: Computer = network.get_node_by_hostname("node_a") + terminal_a: Terminal = computer_a.software_manager.software.get("Terminal") + computer_b: Computer = network.get_node_by_hostname("node_b") + + assert len(terminal_a._connections) == 0 + + # Spam login requests to terminal. + for attempt in range(10): + remote_connection = terminal_a.login(username="username", password="password", ip_address="192.168.0.11") + + assert len(terminal_a._connections) == 10