Merge dev into feature branch
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
io_settings:
|
||||
save_step_metadata: false
|
||||
save_pcap_logs: true
|
||||
save_sys_logs: true
|
||||
sys_log_level: WARNING
|
||||
agent_log_level: INFO
|
||||
save_agent_logs: true
|
||||
write_agent_log_to_terminal: True
|
||||
|
||||
|
||||
game:
|
||||
max_episode_length: 256
|
||||
ports:
|
||||
- ARP
|
||||
protocols:
|
||||
- ICMP
|
||||
- UDP
|
||||
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- hostname: client
|
||||
type: computer
|
||||
ip_address: 192.168.10.11
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
services:
|
||||
- type: DatabaseService
|
||||
options:
|
||||
backup_server_ip: 10.10.1.12
|
||||
listen_on_ports:
|
||||
- 631
|
||||
applications:
|
||||
- type: WebBrowser
|
||||
options:
|
||||
target_url: http://sometech.ai
|
||||
listen_on_ports:
|
||||
- SMB
|
||||
@@ -0,0 +1,84 @@
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
from typing import Any, Dict, List, Set
|
||||
|
||||
import yaml
|
||||
from pydantic import Field
|
||||
|
||||
from primaite.game.game import PrimaiteGame
|
||||
from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.services.database.database_service import DatabaseService
|
||||
from primaite.simulator.system.services.service import Service
|
||||
from tests import TEST_ASSETS_ROOT
|
||||
|
||||
|
||||
class _DatabaseListener(Service):
|
||||
name: str = "DatabaseListener"
|
||||
protocol: IPProtocol = IPProtocol.TCP
|
||||
port: Port = Port.NONE
|
||||
listen_on_ports: Set[Port] = {Port.POSTGRES_SERVER}
|
||||
payloads_received: List[Any] = Field(default_factory=list)
|
||||
|
||||
def receive(self, payload: Any, session_id: str, **kwargs) -> bool:
|
||||
self.payloads_received.append(payload)
|
||||
self.sys_log.info(f"{self.name}: received payload {payload}")
|
||||
return True
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
return super().describe_state()
|
||||
|
||||
|
||||
def test_http_listener(client_server):
|
||||
computer, server = client_server
|
||||
|
||||
server.software_manager.install(DatabaseService)
|
||||
server_db = server.software_manager.software["DatabaseService"]
|
||||
server_db.start()
|
||||
|
||||
server.software_manager.install(_DatabaseListener)
|
||||
server_db_listener: _DatabaseListener = server.software_manager.software["DatabaseListener"]
|
||||
server_db_listener.start()
|
||||
|
||||
computer.software_manager.install(DatabaseClient)
|
||||
computer_db_client: DatabaseClient = computer.software_manager.software["DatabaseClient"]
|
||||
|
||||
computer_db_client.run()
|
||||
computer_db_client.server_ip_address = server.network_interface[1].ip_address
|
||||
|
||||
assert len(server_db_listener.payloads_received) == 0
|
||||
computer.session_manager.receive_payload_from_software_manager(
|
||||
payload="masquerade as Database traffic",
|
||||
dst_ip_address=server.network_interface[1].ip_address,
|
||||
dst_port=Port.POSTGRES_SERVER,
|
||||
ip_protocol=IPProtocol.TCP,
|
||||
)
|
||||
|
||||
assert len(server_db_listener.payloads_received) == 1
|
||||
|
||||
db_connection = computer_db_client.get_new_connection()
|
||||
|
||||
assert db_connection
|
||||
|
||||
assert len(server_db_listener.payloads_received) == 2
|
||||
|
||||
assert db_connection.query("SELECT")
|
||||
|
||||
assert len(server_db_listener.payloads_received) == 3
|
||||
|
||||
|
||||
def test_set_listen_on_ports_from_config():
|
||||
config_path = TEST_ASSETS_ROOT / "configs" / "basic_node_with_software_listening_ports.yaml"
|
||||
|
||||
with open(config_path, "r") as f:
|
||||
config_dict = yaml.safe_load(f)
|
||||
network = PrimaiteGame.from_config(cfg=config_dict).simulation.network
|
||||
|
||||
client: Computer = network.get_node_by_hostname("client")
|
||||
assert Port.SMB in client.software_manager.get_open_ports()
|
||||
assert Port.IPP in client.software_manager.get_open_ports()
|
||||
|
||||
web_browser = client.software_manager.software["WebBrowser"]
|
||||
|
||||
assert not web_browser.listen_on_ports.difference({Port.SMB, Port.IPP})
|
||||
@@ -185,7 +185,7 @@ def test_terminal_receive(basic_network):
|
||||
)
|
||||
|
||||
term_a_on_node_b: RemoteTerminalConnection = terminal_a.login(
|
||||
username="username", password="password", ip_address="192.168.0.11"
|
||||
username="admin", password="admin", ip_address="192.168.0.11"
|
||||
)
|
||||
|
||||
term_a_on_node_b.execute(["file_system", "create", "folder", folder_name])
|
||||
@@ -208,7 +208,7 @@ def test_terminal_install(basic_network):
|
||||
)
|
||||
|
||||
term_a_on_node_b: RemoteTerminalConnection = terminal_a.login(
|
||||
username="username", password="password", ip_address="192.168.0.11"
|
||||
username="admin", password="admin", ip_address="192.168.0.11"
|
||||
)
|
||||
|
||||
term_a_on_node_b.execute(["software_manager", "application", "install", "RansomwareScript"])
|
||||
@@ -225,9 +225,7 @@ def test_terminal_fail_when_closed(basic_network):
|
||||
|
||||
terminal.operating_state = ServiceOperatingState.STOPPED
|
||||
|
||||
assert not terminal.login(
|
||||
username="admin", password="Admin123!", ip_address=computer_b.network_interface[1].ip_address
|
||||
)
|
||||
assert not terminal.login(username="admin", password="admin", ip_address=computer_b.network_interface[1].ip_address)
|
||||
|
||||
|
||||
def test_terminal_disconnect(basic_network):
|
||||
@@ -241,7 +239,7 @@ def test_terminal_disconnect(basic_network):
|
||||
assert len(terminal_b._connections) == 0
|
||||
|
||||
term_a_on_term_b = terminal_a.login(
|
||||
username="admin", password="Admin123!", ip_address=computer_b.network_interface[1].ip_address
|
||||
username="admin", password="admin", ip_address=computer_b.network_interface[1].ip_address
|
||||
)
|
||||
|
||||
assert len(terminal_b._connections) == 1
|
||||
@@ -250,6 +248,8 @@ def test_terminal_disconnect(basic_network):
|
||||
|
||||
assert len(terminal_b._connections) == 0
|
||||
|
||||
assert term_a_on_term_b.is_active is False
|
||||
|
||||
|
||||
def test_terminal_ignores_when_off(basic_network):
|
||||
"""Terminal should ignore commands when not running"""
|
||||
@@ -260,7 +260,7 @@ def test_terminal_ignores_when_off(basic_network):
|
||||
computer_b: Computer = network.get_node_by_hostname("node_b")
|
||||
|
||||
term_a_on_term_b: RemoteTerminalConnection = terminal_a.login(
|
||||
username="admin", password="Admin123!", ip_address="192.168.0.11"
|
||||
username="admin", password="admin", ip_address="192.168.0.11"
|
||||
) # login to computer_b
|
||||
|
||||
terminal_a.operating_state = ServiceOperatingState.STOPPED
|
||||
@@ -276,7 +276,7 @@ def test_computer_remote_login_to_router(wireless_wan_network):
|
||||
|
||||
assert len(pc_a_terminal._connections) == 0
|
||||
|
||||
pc_a_on_router_1 = pc_a_terminal.login(username="username", password="password", ip_address="192.168.1.1")
|
||||
pc_a_on_router_1 = pc_a_terminal.login(username="admin", password="admin", ip_address="192.168.1.1")
|
||||
|
||||
assert len(pc_a_terminal._connections) == 1
|
||||
|
||||
@@ -295,7 +295,7 @@ def test_router_remote_login_to_computer(wireless_wan_network):
|
||||
|
||||
assert len(router_1_terminal._connections) == 0
|
||||
|
||||
router_1_on_pc_a = router_1_terminal.login(username="username", password="password", ip_address="192.168.0.2")
|
||||
router_1_on_pc_a = router_1_terminal.login(username="admin", password="admin", ip_address="192.168.0.2")
|
||||
|
||||
assert len(router_1_terminal._connections) == 1
|
||||
|
||||
@@ -317,7 +317,7 @@ def test_router_blocks_SSH_traffic(wireless_wan_network):
|
||||
|
||||
assert len(pc_a_terminal._connections) == 0
|
||||
|
||||
pc_a_terminal.login(username="username", password="password", ip_address="192.168.0.2")
|
||||
pc_a_terminal.login(username="admin", password="admin", ip_address="192.168.0.2")
|
||||
|
||||
assert len(pc_a_terminal._connections) == 0
|
||||
|
||||
@@ -333,7 +333,7 @@ def test_SSH_across_network(wireless_wan_network):
|
||||
|
||||
assert len(terminal_a._connections) == 0
|
||||
|
||||
terminal_b_on_terminal_a = terminal_b.login(username="username", password="password", ip_address="192.168.0.2")
|
||||
terminal_b_on_terminal_a = terminal_b.login(username="admin", password="admin", ip_address="192.168.0.2")
|
||||
|
||||
assert len(terminal_a._connections) == 1
|
||||
|
||||
@@ -347,11 +347,13 @@ def test_multiple_remote_terminals_same_node(basic_network):
|
||||
|
||||
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")
|
||||
# Spam login requests to node.
|
||||
for attempt in range(3):
|
||||
remote_connection = terminal_a.login(username="admin", password="admin", ip_address="192.168.0.11")
|
||||
|
||||
assert len(terminal_a._connections) == 10
|
||||
terminal_a.show()
|
||||
|
||||
assert len(terminal_a._connections) == 3
|
||||
|
||||
|
||||
def test_terminal_rejects_commands_if_disconnect(basic_network):
|
||||
@@ -363,7 +365,7 @@ def test_terminal_rejects_commands_if_disconnect(basic_network):
|
||||
|
||||
terminal_b: Terminal = computer_b.software_manager.software.get("Terminal")
|
||||
|
||||
remote_connection = terminal_a.login(username="username", password="password", ip_address="192.168.0.11")
|
||||
remote_connection = terminal_a.login(username="admin", password="admin", ip_address="192.168.0.11")
|
||||
|
||||
assert len(terminal_a._connections) == 1
|
||||
assert len(terminal_b._connections) == 1
|
||||
@@ -378,3 +380,27 @@ def test_terminal_rejects_commands_if_disconnect(basic_network):
|
||||
assert not computer_b.software_manager.software.get("RansomwareScript")
|
||||
|
||||
assert remote_connection.is_active is False
|
||||
|
||||
|
||||
def test_terminal_connection_timeout(basic_network):
|
||||
"""Test that terminal_connections are affected by UserSession timeout."""
|
||||
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")
|
||||
terminal_b: Terminal = computer_b.software_manager.software.get("Terminal")
|
||||
|
||||
remote_connection = terminal_a.login(username="admin", password="admin", ip_address="192.168.0.11")
|
||||
|
||||
assert len(terminal_a._connections) == 1
|
||||
assert len(terminal_b._connections) == 1
|
||||
assert len(computer_b.user_session_manager.remote_sessions) == 1
|
||||
|
||||
remote_session = computer_b.user_session_manager.remote_sessions[remote_connection.connection_uuid]
|
||||
computer_b.user_session_manager._timeout_session(remote_session)
|
||||
|
||||
assert len(terminal_a._connections) == 0
|
||||
assert len(terminal_b._connections) == 0
|
||||
assert len(computer_b.user_session_manager.remote_sessions) == 0
|
||||
|
||||
assert not remote_connection.is_active
|
||||
|
||||
Reference in New Issue
Block a user