Merge branch 'dev' into bugfix/2676_NMNE_var_access
This commit is contained in:
792
tests/assets/configs/action_penalty.yaml
Normal file
792
tests/assets/configs/action_penalty.yaml
Normal file
@@ -0,0 +1,792 @@
|
||||
io_settings:
|
||||
save_agent_actions: false
|
||||
save_step_metadata: false
|
||||
save_pcap_logs: false
|
||||
save_sys_logs: false
|
||||
|
||||
|
||||
game:
|
||||
max_episode_length: 256
|
||||
ports:
|
||||
- HTTP
|
||||
- POSTGRES_SERVER
|
||||
protocols:
|
||||
- ICMP
|
||||
- TCP
|
||||
- UDP
|
||||
thresholds:
|
||||
nmne:
|
||||
high: 10
|
||||
medium: 5
|
||||
low: 0
|
||||
|
||||
agents:
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
type: ProxyAgent
|
||||
|
||||
observation_space:
|
||||
type: CUSTOM
|
||||
options:
|
||||
components:
|
||||
- type: NODES
|
||||
label: NODES
|
||||
options:
|
||||
hosts:
|
||||
- hostname: domain_controller
|
||||
- hostname: web_server
|
||||
services:
|
||||
- service_name: WebServer
|
||||
- hostname: database_server
|
||||
folders:
|
||||
- folder_name: database
|
||||
files:
|
||||
- file_name: database.db
|
||||
- hostname: backup_server
|
||||
- hostname: security_suite
|
||||
- hostname: client_1
|
||||
- hostname: client_2
|
||||
num_services: 1
|
||||
num_applications: 0
|
||||
num_folders: 1
|
||||
num_files: 1
|
||||
num_nics: 2
|
||||
include_num_access: false
|
||||
include_nmne: true
|
||||
routers:
|
||||
- hostname: router_1
|
||||
num_ports: 0
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
wildcard_list:
|
||||
- 0.0.0.1
|
||||
port_list:
|
||||
- 80
|
||||
- 5432
|
||||
protocol_list:
|
||||
- ICMP
|
||||
- TCP
|
||||
- UDP
|
||||
num_rules: 10
|
||||
|
||||
- type: LINKS
|
||||
label: LINKS
|
||||
options:
|
||||
link_references:
|
||||
- router_1:eth-1<->switch_1:eth-8
|
||||
- router_1:eth-2<->switch_2:eth-8
|
||||
- switch_1:eth-1<->domain_controller:eth-1
|
||||
- switch_1:eth-2<->web_server:eth-1
|
||||
- switch_1:eth-3<->database_server:eth-1
|
||||
- switch_1:eth-4<->backup_server:eth-1
|
||||
- switch_1:eth-7<->security_suite:eth-1
|
||||
- switch_2:eth-1<->client_1:eth-1
|
||||
- switch_2:eth-2<->client_2:eth-1
|
||||
- switch_2:eth-7<->security_suite:eth-2
|
||||
- type: "NONE"
|
||||
label: ICS
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_SERVICE_SCAN
|
||||
- type: NODE_SERVICE_STOP
|
||||
- type: NODE_SERVICE_START
|
||||
- type: NODE_SERVICE_PAUSE
|
||||
- type: NODE_SERVICE_RESUME
|
||||
- type: NODE_SERVICE_RESTART
|
||||
- type: NODE_SERVICE_DISABLE
|
||||
- type: NODE_SERVICE_ENABLE
|
||||
- type: NODE_SERVICE_FIX
|
||||
- type: NODE_FILE_SCAN
|
||||
- type: NODE_FILE_CHECKHASH
|
||||
- type: NODE_FILE_DELETE
|
||||
- type: NODE_FILE_REPAIR
|
||||
- type: NODE_FILE_RESTORE
|
||||
- type: NODE_FOLDER_SCAN
|
||||
- type: NODE_FOLDER_CHECKHASH
|
||||
- type: NODE_FOLDER_REPAIR
|
||||
- type: NODE_FOLDER_RESTORE
|
||||
- type: NODE_OS_SCAN
|
||||
- type: NODE_SHUTDOWN
|
||||
- type: NODE_STARTUP
|
||||
- type: NODE_RESET
|
||||
- type: ROUTER_ACL_ADDRULE
|
||||
- type: ROUTER_ACL_REMOVERULE
|
||||
- type: HOST_NIC_ENABLE
|
||||
- type: HOST_NIC_DISABLE
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
options: {}
|
||||
# scan webapp service
|
||||
1:
|
||||
action: NODE_SERVICE_SCAN
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
# stop webapp service
|
||||
2:
|
||||
action: NODE_SERVICE_STOP
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
# start webapp service
|
||||
3:
|
||||
action: "NODE_SERVICE_START"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
4:
|
||||
action: "NODE_SERVICE_PAUSE"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
5:
|
||||
action: "NODE_SERVICE_RESUME"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
6:
|
||||
action: "NODE_SERVICE_RESTART"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
7:
|
||||
action: "NODE_SERVICE_DISABLE"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
8:
|
||||
action: "NODE_SERVICE_ENABLE"
|
||||
options:
|
||||
node_id: 1
|
||||
service_id: 0
|
||||
9: # check database.db file
|
||||
action: "NODE_FILE_SCAN"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
10:
|
||||
action: "NODE_FILE_CHECKHASH"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
11:
|
||||
action: "NODE_FILE_DELETE"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
12:
|
||||
action: "NODE_FILE_REPAIR"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
file_id: 0
|
||||
13:
|
||||
action: "NODE_SERVICE_FIX"
|
||||
options:
|
||||
node_id: 2
|
||||
service_id: 0
|
||||
14:
|
||||
action: "NODE_FOLDER_SCAN"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
15:
|
||||
action: "NODE_FOLDER_CHECKHASH"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
16:
|
||||
action: "NODE_FOLDER_REPAIR"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
17:
|
||||
action: "NODE_FOLDER_RESTORE"
|
||||
options:
|
||||
node_id: 2
|
||||
folder_id: 0
|
||||
18:
|
||||
action: "NODE_OS_SCAN"
|
||||
options:
|
||||
node_id: 0
|
||||
19:
|
||||
action: "NODE_SHUTDOWN"
|
||||
options:
|
||||
node_id: 0
|
||||
20:
|
||||
action: NODE_STARTUP
|
||||
options:
|
||||
node_id: 0
|
||||
21:
|
||||
action: NODE_RESET
|
||||
options:
|
||||
node_id: 0
|
||||
22:
|
||||
action: "NODE_OS_SCAN"
|
||||
options:
|
||||
node_id: 1
|
||||
23:
|
||||
action: "NODE_SHUTDOWN"
|
||||
options:
|
||||
node_id: 1
|
||||
24:
|
||||
action: NODE_STARTUP
|
||||
options:
|
||||
node_id: 1
|
||||
25:
|
||||
action: NODE_RESET
|
||||
options:
|
||||
node_id: 1
|
||||
26: # old action num: 18
|
||||
action: "NODE_OS_SCAN"
|
||||
options:
|
||||
node_id: 2
|
||||
27:
|
||||
action: "NODE_SHUTDOWN"
|
||||
options:
|
||||
node_id: 2
|
||||
28:
|
||||
action: NODE_STARTUP
|
||||
options:
|
||||
node_id: 2
|
||||
29:
|
||||
action: NODE_RESET
|
||||
options:
|
||||
node_id: 2
|
||||
30:
|
||||
action: "NODE_OS_SCAN"
|
||||
options:
|
||||
node_id: 3
|
||||
31:
|
||||
action: "NODE_SHUTDOWN"
|
||||
options:
|
||||
node_id: 3
|
||||
32:
|
||||
action: NODE_STARTUP
|
||||
options:
|
||||
node_id: 3
|
||||
33:
|
||||
action: NODE_RESET
|
||||
options:
|
||||
node_id: 3
|
||||
34:
|
||||
action: "NODE_OS_SCAN"
|
||||
options:
|
||||
node_id: 4
|
||||
35:
|
||||
action: "NODE_SHUTDOWN"
|
||||
options:
|
||||
node_id: 4
|
||||
36:
|
||||
action: NODE_STARTUP
|
||||
options:
|
||||
node_id: 4
|
||||
37:
|
||||
action: NODE_RESET
|
||||
options:
|
||||
node_id: 4
|
||||
38:
|
||||
action: "NODE_OS_SCAN"
|
||||
options:
|
||||
node_id: 5
|
||||
39: # old action num: 19 # shutdown client 1
|
||||
action: "NODE_SHUTDOWN"
|
||||
options:
|
||||
node_id: 5
|
||||
40: # old action num: 20
|
||||
action: NODE_STARTUP
|
||||
options:
|
||||
node_id: 5
|
||||
41: # old action num: 21
|
||||
action: NODE_RESET
|
||||
options:
|
||||
node_id: 5
|
||||
42:
|
||||
action: "NODE_OS_SCAN"
|
||||
options:
|
||||
node_id: 6
|
||||
43:
|
||||
action: "NODE_SHUTDOWN"
|
||||
options:
|
||||
node_id: 6
|
||||
44:
|
||||
action: NODE_STARTUP
|
||||
options:
|
||||
node_id: 6
|
||||
45:
|
||||
action: NODE_RESET
|
||||
options:
|
||||
node_id: 6
|
||||
|
||||
46: # old action num: 22 # "ACL: ADDRULE - Block outgoing traffic from client 1"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 1
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
47: # old action num: 23 # "ACL: ADDRULE - Block outgoing traffic from client 2"
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 2
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 1 # ALL
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 1
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
48: # old action num: 24 # block tcp traffic from client 1 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 3
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
49: # old action num: 25 # block tcp traffic from client 2 to web app
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 4
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 3 # web server
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
50: # old action num: 26
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 5
|
||||
permission: 2
|
||||
source_ip_id: 7 # client 1
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
51: # old action num: 27
|
||||
action: "ROUTER_ACL_ADDRULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 6
|
||||
permission: 2
|
||||
source_ip_id: 8 # client 2
|
||||
dest_ip_id: 4 # database
|
||||
source_port_id: 1
|
||||
dest_port_id: 1
|
||||
protocol_id: 3
|
||||
source_wildcard_id: 0
|
||||
dest_wildcard_id: 0
|
||||
52: # old action num: 28
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 0
|
||||
53: # old action num: 29
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 1
|
||||
54: # old action num: 30
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 2
|
||||
55: # old action num: 31
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 3
|
||||
56: # old action num: 32
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 4
|
||||
57: # old action num: 33
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 5
|
||||
58: # old action num: 34
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 6
|
||||
59: # old action num: 35
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 7
|
||||
60: # old action num: 36
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 8
|
||||
61: # old action num: 37
|
||||
action: "ROUTER_ACL_REMOVERULE"
|
||||
options:
|
||||
target_router_nodename: router_1
|
||||
position: 9
|
||||
62: # old action num: 38
|
||||
action: "HOST_NIC_DISABLE"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
63: # old action num: 39
|
||||
action: "HOST_NIC_ENABLE"
|
||||
options:
|
||||
node_id: 0
|
||||
nic_id: 0
|
||||
64: # old action num: 40
|
||||
action: "HOST_NIC_DISABLE"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
65: # old action num: 41
|
||||
action: "HOST_NIC_ENABLE"
|
||||
options:
|
||||
node_id: 1
|
||||
nic_id: 0
|
||||
66: # old action num: 42
|
||||
action: "HOST_NIC_DISABLE"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
67: # old action num: 43
|
||||
action: "HOST_NIC_ENABLE"
|
||||
options:
|
||||
node_id: 2
|
||||
nic_id: 0
|
||||
68: # old action num: 44
|
||||
action: "HOST_NIC_DISABLE"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
69: # old action num: 45
|
||||
action: "HOST_NIC_ENABLE"
|
||||
options:
|
||||
node_id: 3
|
||||
nic_id: 0
|
||||
70: # old action num: 46
|
||||
action: "HOST_NIC_DISABLE"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
71: # old action num: 47
|
||||
action: "HOST_NIC_ENABLE"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 0
|
||||
72: # old action num: 48
|
||||
action: "HOST_NIC_DISABLE"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
73: # old action num: 49
|
||||
action: "HOST_NIC_ENABLE"
|
||||
options:
|
||||
node_id: 4
|
||||
nic_id: 1
|
||||
74: # old action num: 50
|
||||
action: "HOST_NIC_DISABLE"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
75: # old action num: 51
|
||||
action: "HOST_NIC_ENABLE"
|
||||
options:
|
||||
node_id: 5
|
||||
nic_id: 0
|
||||
76: # old action num: 52
|
||||
action: "HOST_NIC_DISABLE"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
77: # old action num: 53
|
||||
action: "HOST_NIC_ENABLE"
|
||||
options:
|
||||
node_id: 6
|
||||
nic_id: 0
|
||||
|
||||
|
||||
|
||||
options:
|
||||
nodes:
|
||||
- node_name: domain_controller
|
||||
- node_name: web_server
|
||||
applications:
|
||||
- application_name: DatabaseClient
|
||||
services:
|
||||
- service_name: WebServer
|
||||
- node_name: database_server
|
||||
folders:
|
||||
- folder_name: database
|
||||
files:
|
||||
- file_name: database.db
|
||||
services:
|
||||
- service_name: DatabaseService
|
||||
- node_name: backup_server
|
||||
- node_name: security_suite
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.1.10
|
||||
- 192.168.1.12
|
||||
- 192.168.1.14
|
||||
- 192.168.1.16
|
||||
- 192.168.1.110
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.110
|
||||
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: ACTION_PENALTY
|
||||
weight: 1.0
|
||||
options:
|
||||
action_penalty: -0.75
|
||||
do_nothing_penalty: 0.125
|
||||
|
||||
|
||||
agent_settings:
|
||||
flatten_obs: true
|
||||
|
||||
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nmne_config:
|
||||
capture_nmne: true
|
||||
nmne_capture_keywords:
|
||||
- DELETE
|
||||
nodes:
|
||||
|
||||
- hostname: router_1
|
||||
type: router
|
||||
num_ports: 5
|
||||
ports:
|
||||
1:
|
||||
ip_address: 192.168.1.1
|
||||
subnet_mask: 255.255.255.0
|
||||
2:
|
||||
ip_address: 192.168.10.1
|
||||
subnet_mask: 255.255.255.0
|
||||
acl:
|
||||
18:
|
||||
action: PERMIT
|
||||
src_port: POSTGRES_SERVER
|
||||
dst_port: POSTGRES_SERVER
|
||||
19:
|
||||
action: PERMIT
|
||||
src_port: DNS
|
||||
dst_port: DNS
|
||||
20:
|
||||
action: PERMIT
|
||||
src_port: FTP
|
||||
dst_port: FTP
|
||||
21:
|
||||
action: PERMIT
|
||||
src_port: HTTP
|
||||
dst_port: HTTP
|
||||
22:
|
||||
action: PERMIT
|
||||
src_port: ARP
|
||||
dst_port: ARP
|
||||
23:
|
||||
action: PERMIT
|
||||
protocol: ICMP
|
||||
|
||||
- hostname: switch_1
|
||||
type: switch
|
||||
num_ports: 8
|
||||
|
||||
- hostname: switch_2
|
||||
type: switch
|
||||
num_ports: 8
|
||||
|
||||
- hostname: domain_controller
|
||||
type: server
|
||||
ip_address: 192.168.1.10
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.1.1
|
||||
services:
|
||||
- type: DNSServer
|
||||
options:
|
||||
domain_mapping:
|
||||
arcd.com: 192.168.1.12 # web server
|
||||
|
||||
- hostname: web_server
|
||||
type: server
|
||||
ip_address: 192.168.1.12
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.1.1
|
||||
dns_server: 192.168.1.10
|
||||
services:
|
||||
- type: WebServer
|
||||
applications:
|
||||
- type: DatabaseClient
|
||||
options:
|
||||
db_server_ip: 192.168.1.14
|
||||
|
||||
|
||||
- hostname: database_server
|
||||
type: server
|
||||
ip_address: 192.168.1.14
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.1.1
|
||||
dns_server: 192.168.1.10
|
||||
services:
|
||||
- type: DatabaseService
|
||||
options:
|
||||
backup_server_ip: 192.168.1.16
|
||||
- type: FTPClient
|
||||
|
||||
- hostname: backup_server
|
||||
type: server
|
||||
ip_address: 192.168.1.16
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.1.1
|
||||
dns_server: 192.168.1.10
|
||||
services:
|
||||
- type: FTPServer
|
||||
|
||||
- hostname: security_suite
|
||||
type: server
|
||||
ip_address: 192.168.1.110
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.1.1
|
||||
dns_server: 192.168.1.10
|
||||
network_interfaces:
|
||||
2: # unfortunately this number is currently meaningless, they're just added in order and take up the next available slot
|
||||
ip_address: 192.168.10.110
|
||||
subnet_mask: 255.255.255.0
|
||||
|
||||
- hostname: client_1
|
||||
type: computer
|
||||
ip_address: 192.168.10.21
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
- type: DataManipulationBot
|
||||
options:
|
||||
port_scan_p_of_success: 0.8
|
||||
data_manipulation_p_of_success: 0.8
|
||||
payload: "DELETE"
|
||||
server_ip: 192.168.1.14
|
||||
- type: WebBrowser
|
||||
options:
|
||||
target_url: http://arcd.com/users/
|
||||
- type: DatabaseClient
|
||||
options:
|
||||
db_server_ip: 192.168.1.14
|
||||
services:
|
||||
- type: DNSClient
|
||||
|
||||
- hostname: client_2
|
||||
type: computer
|
||||
ip_address: 192.168.10.22
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
- type: WebBrowser
|
||||
options:
|
||||
target_url: http://arcd.com/users/
|
||||
- type: DataManipulationBot
|
||||
options:
|
||||
port_scan_p_of_success: 0.8
|
||||
data_manipulation_p_of_success: 0.8
|
||||
payload: "DELETE"
|
||||
server_ip: 192.168.1.14
|
||||
- type: DatabaseClient
|
||||
options:
|
||||
db_server_ip: 192.168.1.14
|
||||
services:
|
||||
- type: DNSClient
|
||||
|
||||
|
||||
|
||||
links:
|
||||
- endpoint_a_hostname: router_1
|
||||
endpoint_a_port: 1
|
||||
endpoint_b_hostname: switch_1
|
||||
endpoint_b_port: 8
|
||||
- endpoint_a_hostname: router_1
|
||||
endpoint_a_port: 2
|
||||
endpoint_b_hostname: switch_2
|
||||
endpoint_b_port: 8
|
||||
- endpoint_a_hostname: switch_1
|
||||
endpoint_a_port: 1
|
||||
endpoint_b_hostname: domain_controller
|
||||
endpoint_b_port: 1
|
||||
- endpoint_a_hostname: switch_1
|
||||
endpoint_a_port: 2
|
||||
endpoint_b_hostname: web_server
|
||||
endpoint_b_port: 1
|
||||
- endpoint_a_hostname: switch_1
|
||||
endpoint_a_port: 3
|
||||
endpoint_b_hostname: database_server
|
||||
endpoint_b_port: 1
|
||||
- endpoint_a_hostname: switch_1
|
||||
endpoint_a_port: 4
|
||||
endpoint_b_hostname: backup_server
|
||||
endpoint_b_port: 1
|
||||
- endpoint_a_hostname: switch_1
|
||||
endpoint_a_port: 7
|
||||
endpoint_b_hostname: security_suite
|
||||
endpoint_b_port: 1
|
||||
- endpoint_a_hostname: switch_2
|
||||
endpoint_a_port: 1
|
||||
endpoint_b_hostname: client_1
|
||||
endpoint_b_port: 1
|
||||
- endpoint_a_hostname: switch_2
|
||||
endpoint_a_port: 2
|
||||
endpoint_b_hostname: client_2
|
||||
endpoint_b_port: 1
|
||||
- endpoint_a_hostname: switch_2
|
||||
endpoint_a_port: 7
|
||||
endpoint_b_hostname: security_suite
|
||||
endpoint_b_port: 2
|
||||
248
tests/assets/configs/fix_duration_one_item.yaml
Normal file
248
tests/assets/configs/fix_duration_one_item.yaml
Normal file
@@ -0,0 +1,248 @@
|
||||
# Basic Switched network
|
||||
#
|
||||
# -------------- -------------- --------------
|
||||
# | client_1 |------| switch_1 |------| client_2 |
|
||||
# -------------- -------------- --------------
|
||||
#
|
||||
io_settings:
|
||||
save_step_metadata: false
|
||||
save_pcap_logs: true
|
||||
save_sys_logs: true
|
||||
sys_log_level: WARNING
|
||||
|
||||
|
||||
game:
|
||||
max_episode_length: 256
|
||||
ports:
|
||||
- ARP
|
||||
- DNS
|
||||
- HTTP
|
||||
- POSTGRES_SERVER
|
||||
protocols:
|
||||
- ICMP
|
||||
- TCP
|
||||
- UDP
|
||||
|
||||
agents:
|
||||
- ref: client_2_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
|
||||
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
type: ProxyAgent
|
||||
|
||||
observation_space:
|
||||
type: CUSTOM
|
||||
options:
|
||||
components:
|
||||
- type: NODES
|
||||
label: NODES
|
||||
options:
|
||||
hosts:
|
||||
- hostname: client_1
|
||||
- hostname: client_2
|
||||
- hostname: client_3
|
||||
num_services: 1
|
||||
num_applications: 0
|
||||
num_folders: 1
|
||||
num_files: 1
|
||||
num_nics: 2
|
||||
include_num_access: false
|
||||
monitored_traffic:
|
||||
icmp:
|
||||
- NONE
|
||||
tcp:
|
||||
- DNS
|
||||
include_nmne: true
|
||||
routers:
|
||||
- hostname: router_1
|
||||
num_ports: 0
|
||||
ip_list:
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.23
|
||||
wildcard_list:
|
||||
- 0.0.0.1
|
||||
port_list:
|
||||
- 80
|
||||
- 5432
|
||||
protocol_list:
|
||||
- ICMP
|
||||
- TCP
|
||||
- UDP
|
||||
num_rules: 10
|
||||
|
||||
- type: LINKS
|
||||
label: LINKS
|
||||
options:
|
||||
link_references:
|
||||
- switch_1:eth-1<->client_1:eth-1
|
||||
- switch_1:eth-2<->client_2:eth-1
|
||||
- type: "NONE"
|
||||
label: ICS
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
options: {}
|
||||
options:
|
||||
nodes:
|
||||
- node_name: switch
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
- node_name: client_3
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.23
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DATABASE_FILE_INTEGRITY
|
||||
weight: 0.5
|
||||
options:
|
||||
node_hostname: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
|
||||
|
||||
- type: WEB_SERVER_404_PENALTY
|
||||
weight: 0.5
|
||||
options:
|
||||
node_hostname: web_server
|
||||
service_name: web_server_web_service
|
||||
|
||||
|
||||
agent_settings:
|
||||
flatten_obs: true
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
|
||||
- type: switch
|
||||
hostname: switch_1
|
||||
num_ports: 8
|
||||
|
||||
- hostname: client_1
|
||||
type: computer
|
||||
ip_address: 192.168.10.21
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
- type: RansomwareScript
|
||||
- type: WebBrowser
|
||||
options:
|
||||
target_url: http://arcd.com/users/
|
||||
- type: DatabaseClient
|
||||
options:
|
||||
db_server_ip: 192.168.1.10
|
||||
server_password: arcd
|
||||
fix_duration: 1
|
||||
- type: DataManipulationBot
|
||||
options:
|
||||
port_scan_p_of_success: 0.8
|
||||
data_manipulation_p_of_success: 0.8
|
||||
payload: "DELETE"
|
||||
server_ip: 192.168.1.21
|
||||
server_password: arcd
|
||||
- type: DoSBot
|
||||
options:
|
||||
target_ip_address: 192.168.10.21
|
||||
payload: SPOOF DATA
|
||||
port_scan_p_of_success: 0.8
|
||||
services:
|
||||
- type: DNSClient
|
||||
options:
|
||||
dns_server: 192.168.1.10
|
||||
- type: DNSServer
|
||||
options:
|
||||
domain_mapping:
|
||||
arcd.com: 192.168.1.10
|
||||
- type: DatabaseService
|
||||
options:
|
||||
fix_duration: 5
|
||||
backup_server_ip: 192.168.1.10
|
||||
- type: WebServer
|
||||
- type: FTPClient
|
||||
- type: FTPServer
|
||||
options:
|
||||
server_password: arcd
|
||||
- type: NTPClient
|
||||
options:
|
||||
ntp_server_ip: 192.168.1.10
|
||||
- type: NTPServer
|
||||
- hostname: client_2
|
||||
type: computer
|
||||
ip_address: 192.168.10.22
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
- type: DatabaseClient
|
||||
options:
|
||||
db_server_ip: 192.168.1.10
|
||||
server_password: arcd
|
||||
services:
|
||||
- type: DNSClient
|
||||
options:
|
||||
dns_server: 192.168.1.10
|
||||
|
||||
links:
|
||||
- endpoint_a_hostname: switch_1
|
||||
endpoint_a_port: 1
|
||||
endpoint_b_hostname: client_1
|
||||
endpoint_b_port: 1
|
||||
bandwidth: 200
|
||||
- endpoint_a_hostname: switch_1
|
||||
endpoint_a_port: 2
|
||||
endpoint_b_hostname: client_2
|
||||
endpoint_b_port: 1
|
||||
bandwidth: 200
|
||||
142
tests/assets/configs/install_and_configure_apps.yaml
Normal file
142
tests/assets/configs/install_and_configure_apps.yaml
Normal file
@@ -0,0 +1,142 @@
|
||||
io_settings:
|
||||
save_step_metadata: false
|
||||
save_pcap_logs: false
|
||||
save_sys_logs: false
|
||||
save_agent_actions: false
|
||||
|
||||
game:
|
||||
max_episode_length: 256
|
||||
ports:
|
||||
- ARP
|
||||
- DNS
|
||||
protocols:
|
||||
- ICMP
|
||||
- TCP
|
||||
|
||||
agents:
|
||||
- ref: agent_1
|
||||
team: BLUE
|
||||
type: ProxyAgent
|
||||
|
||||
observation_space: null
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_INSTALL
|
||||
- type: CONFIGURE_DATABASE_CLIENT
|
||||
- type: CONFIGURE_DOSBOT
|
||||
- type: CONFIGURE_RANSOMWARE_SCRIPT
|
||||
- type: NODE_APPLICATION_REMOVE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_INSTALL
|
||||
options:
|
||||
node_id: 0
|
||||
application_name: DatabaseClient
|
||||
2:
|
||||
action: NODE_APPLICATION_INSTALL
|
||||
options:
|
||||
node_id: 1
|
||||
application_name: RansomwareScript
|
||||
3:
|
||||
action: NODE_APPLICATION_INSTALL
|
||||
options:
|
||||
node_id: 2
|
||||
application_name: DoSBot
|
||||
4:
|
||||
action: CONFIGURE_DATABASE_CLIENT
|
||||
options:
|
||||
node_id: 0
|
||||
config:
|
||||
server_ip_address: 10.0.0.5
|
||||
5:
|
||||
action: CONFIGURE_DATABASE_CLIENT
|
||||
options:
|
||||
node_id: 0
|
||||
config:
|
||||
server_password: correct_password
|
||||
6:
|
||||
action: CONFIGURE_RANSOMWARE_SCRIPT
|
||||
options:
|
||||
node_id: 1
|
||||
config:
|
||||
server_ip_address: 10.0.0.5
|
||||
server_password: correct_password
|
||||
payload: ENCRYPT
|
||||
7:
|
||||
action: CONFIGURE_DOSBOT
|
||||
options:
|
||||
node_id: 2
|
||||
config:
|
||||
target_ip_address: 10.0.0.5
|
||||
target_port: POSTGRES_SERVER
|
||||
payload: DELETE
|
||||
repeat: true
|
||||
port_scan_p_of_success: 1.0
|
||||
dos_intensity: 1.0
|
||||
max_sessions: 1000
|
||||
8:
|
||||
action: NODE_APPLICATION_INSTALL
|
||||
options:
|
||||
node_id: 1
|
||||
application_name: DatabaseClient
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
- node_name: client_3
|
||||
ip_list: []
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
- type: computer
|
||||
hostname: client_1
|
||||
ip_address: 10.0.0.2
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 10.0.0.1
|
||||
- type: computer
|
||||
hostname: client_2
|
||||
ip_address: 10.0.0.3
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 10.0.0.1
|
||||
- type: computer
|
||||
hostname: client_3
|
||||
ip_address: 10.0.0.4
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 10.0.0.1
|
||||
- type: switch
|
||||
hostname: switch_1
|
||||
num_ports: 8
|
||||
- type: server
|
||||
hostname: server_1
|
||||
ip_address: 10.0.0.5
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 10.0.0.1
|
||||
services:
|
||||
- type: DatabaseService
|
||||
options:
|
||||
db_password: correct_password
|
||||
links:
|
||||
- endpoint_a_hostname: client_1
|
||||
endpoint_a_port: 1
|
||||
endpoint_b_hostname: switch_1
|
||||
endpoint_b_port: 1
|
||||
- endpoint_a_hostname: client_2
|
||||
endpoint_a_port: 1
|
||||
endpoint_b_hostname: switch_1
|
||||
endpoint_b_port: 2
|
||||
- endpoint_a_hostname: client_3
|
||||
endpoint_a_port: 1
|
||||
endpoint_b_hostname: switch_1
|
||||
endpoint_b_port: 3
|
||||
- endpoint_a_hostname: server_1
|
||||
endpoint_a_port: 1
|
||||
endpoint_b_hostname: switch_1
|
||||
endpoint_b_port: 8
|
||||
263
tests/assets/configs/software_fix_duration.yaml
Normal file
263
tests/assets/configs/software_fix_duration.yaml
Normal file
@@ -0,0 +1,263 @@
|
||||
# Basic Switched network
|
||||
#
|
||||
# -------------- -------------- --------------
|
||||
# | client_1 |------| switch_1 |------| client_2 |
|
||||
# -------------- -------------- --------------
|
||||
#
|
||||
io_settings:
|
||||
save_step_metadata: false
|
||||
save_pcap_logs: true
|
||||
save_sys_logs: true
|
||||
sys_log_level: WARNING
|
||||
|
||||
|
||||
game:
|
||||
max_episode_length: 256
|
||||
ports:
|
||||
- ARP
|
||||
- DNS
|
||||
- HTTP
|
||||
- POSTGRES_SERVER
|
||||
protocols:
|
||||
- ICMP
|
||||
- TCP
|
||||
- UDP
|
||||
|
||||
agents:
|
||||
- ref: client_2_green_user
|
||||
team: GREEN
|
||||
type: ProbabilisticAgent
|
||||
observation_space: null
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
options: {}
|
||||
1:
|
||||
action: NODE_APPLICATION_EXECUTE
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
options:
|
||||
nodes:
|
||||
- node_name: client_2
|
||||
applications:
|
||||
- application_name: WebBrowser
|
||||
max_folders_per_node: 1
|
||||
max_files_per_folder: 1
|
||||
max_services_per_node: 1
|
||||
max_applications_per_node: 1
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DUMMY
|
||||
|
||||
agent_settings:
|
||||
start_settings:
|
||||
start_step: 5
|
||||
frequency: 4
|
||||
variance: 3
|
||||
|
||||
|
||||
|
||||
- ref: defender
|
||||
team: BLUE
|
||||
type: ProxyAgent
|
||||
|
||||
observation_space:
|
||||
type: CUSTOM
|
||||
options:
|
||||
components:
|
||||
- type: NODES
|
||||
label: NODES
|
||||
options:
|
||||
hosts:
|
||||
- hostname: client_1
|
||||
- hostname: client_2
|
||||
- hostname: client_3
|
||||
num_services: 1
|
||||
num_applications: 0
|
||||
num_folders: 1
|
||||
num_files: 1
|
||||
num_nics: 2
|
||||
include_num_access: false
|
||||
monitored_traffic:
|
||||
icmp:
|
||||
- NONE
|
||||
tcp:
|
||||
- DNS
|
||||
include_nmne: true
|
||||
routers:
|
||||
- hostname: router_1
|
||||
num_ports: 0
|
||||
ip_list:
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.23
|
||||
wildcard_list:
|
||||
- 0.0.0.1
|
||||
port_list:
|
||||
- 80
|
||||
- 5432
|
||||
protocol_list:
|
||||
- ICMP
|
||||
- TCP
|
||||
- UDP
|
||||
num_rules: 10
|
||||
|
||||
- type: LINKS
|
||||
label: LINKS
|
||||
options:
|
||||
link_references:
|
||||
- switch_1:eth-1<->client_1:eth-1
|
||||
- switch_1:eth-2<->client_2:eth-1
|
||||
- type: "NONE"
|
||||
label: ICS
|
||||
options: {}
|
||||
|
||||
action_space:
|
||||
action_list:
|
||||
- type: DONOTHING
|
||||
|
||||
action_map:
|
||||
0:
|
||||
action: DONOTHING
|
||||
options: {}
|
||||
options:
|
||||
nodes:
|
||||
- node_name: switch
|
||||
- node_name: client_1
|
||||
- node_name: client_2
|
||||
- node_name: client_3
|
||||
max_folders_per_node: 2
|
||||
max_files_per_folder: 2
|
||||
max_services_per_node: 2
|
||||
max_nics_per_node: 8
|
||||
max_acl_rules: 10
|
||||
ip_list:
|
||||
- 192.168.10.21
|
||||
- 192.168.10.22
|
||||
- 192.168.10.23
|
||||
|
||||
reward_function:
|
||||
reward_components:
|
||||
- type: DATABASE_FILE_INTEGRITY
|
||||
weight: 0.5
|
||||
options:
|
||||
node_hostname: database_server
|
||||
folder_name: database
|
||||
file_name: database.db
|
||||
|
||||
|
||||
- type: WEB_SERVER_404_PENALTY
|
||||
weight: 0.5
|
||||
options:
|
||||
node_hostname: web_server
|
||||
service_name: web_server_web_service
|
||||
|
||||
|
||||
agent_settings:
|
||||
flatten_obs: true
|
||||
|
||||
simulation:
|
||||
network:
|
||||
nodes:
|
||||
|
||||
- type: switch
|
||||
hostname: switch_1
|
||||
num_ports: 8
|
||||
|
||||
- hostname: client_1
|
||||
type: computer
|
||||
ip_address: 192.168.10.21
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
- type: RansomwareScript
|
||||
options:
|
||||
fix_duration: 1
|
||||
- type: WebBrowser
|
||||
options:
|
||||
target_url: http://arcd.com/users/
|
||||
fix_duration: 1
|
||||
- type: DatabaseClient
|
||||
options:
|
||||
db_server_ip: 192.168.1.10
|
||||
server_password: arcd
|
||||
fix_duration: 1
|
||||
- type: DataManipulationBot
|
||||
options:
|
||||
port_scan_p_of_success: 0.8
|
||||
data_manipulation_p_of_success: 0.8
|
||||
payload: "DELETE"
|
||||
server_ip: 192.168.1.21
|
||||
server_password: arcd
|
||||
fix_duration: 1
|
||||
- type: DoSBot
|
||||
options:
|
||||
target_ip_address: 192.168.10.21
|
||||
payload: SPOOF DATA
|
||||
port_scan_p_of_success: 0.8
|
||||
fix_duration: 1
|
||||
services:
|
||||
- type: DNSClient
|
||||
options:
|
||||
dns_server: 192.168.1.10
|
||||
fix_duration: 3
|
||||
- type: DNSServer
|
||||
options:
|
||||
fix_duration: 3
|
||||
domain_mapping:
|
||||
arcd.com: 192.168.1.10
|
||||
- type: DatabaseService
|
||||
options:
|
||||
backup_server_ip: 192.168.1.10
|
||||
fix_duration: 3
|
||||
- type: WebServer
|
||||
options:
|
||||
fix_duration: 3
|
||||
- type: FTPClient
|
||||
options:
|
||||
fix_duration: 3
|
||||
- type: FTPServer
|
||||
options:
|
||||
server_password: arcd
|
||||
fix_duration: 3
|
||||
- type: NTPClient
|
||||
options:
|
||||
ntp_server_ip: 192.168.1.10
|
||||
fix_duration: 3
|
||||
- type: NTPServer
|
||||
options:
|
||||
fix_duration: 3
|
||||
- hostname: client_2
|
||||
type: computer
|
||||
ip_address: 192.168.10.22
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
applications:
|
||||
- type: DatabaseClient
|
||||
options:
|
||||
db_server_ip: 192.168.1.10
|
||||
server_password: arcd
|
||||
services:
|
||||
- type: DNSClient
|
||||
options:
|
||||
dns_server: 192.168.1.10
|
||||
|
||||
links:
|
||||
- endpoint_a_hostname: switch_1
|
||||
endpoint_a_port: 1
|
||||
endpoint_b_hostname: client_1
|
||||
endpoint_b_port: 1
|
||||
bandwidth: 200
|
||||
- endpoint_a_hostname: switch_1
|
||||
endpoint_a_port: 2
|
||||
endpoint_b_hostname: client_2
|
||||
endpoint_b_port: 1
|
||||
bandwidth: 200
|
||||
@@ -260,6 +260,7 @@ agents:
|
||||
- type: NODE_APPLICATION_INSTALL
|
||||
- type: NODE_APPLICATION_REMOVE
|
||||
- type: NODE_APPLICATION_EXECUTE
|
||||
- type: CONFIGURE_DOSBOT
|
||||
|
||||
action_map:
|
||||
0:
|
||||
@@ -683,7 +684,6 @@ agents:
|
||||
options:
|
||||
node_id: 0
|
||||
application_name: DoSBot
|
||||
ip_address: 192.168.1.14
|
||||
79:
|
||||
action: NODE_APPLICATION_REMOVE
|
||||
options:
|
||||
@@ -699,6 +699,14 @@ agents:
|
||||
options:
|
||||
node_id: 0
|
||||
application_id: 0
|
||||
82:
|
||||
action: CONFIGURE_DOSBOT
|
||||
options:
|
||||
node_id: 0
|
||||
config:
|
||||
target_ip_address: 192.168.1.14
|
||||
target_port: POSTGRES_SERVER
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -51,11 +51,11 @@ class TestService(Service):
|
||||
pass
|
||||
|
||||
|
||||
class TestApplication(Application):
|
||||
class DummyApplication(Application, identifier="DummyApplication"):
|
||||
"""Test Application class"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
kwargs["name"] = "TestApplication"
|
||||
kwargs["name"] = "DummyApplication"
|
||||
kwargs["port"] = Port.HTTP
|
||||
kwargs["protocol"] = IPProtocol.TCP
|
||||
super().__init__(**kwargs)
|
||||
@@ -85,15 +85,15 @@ def service_class():
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def application(file_system) -> TestApplication:
|
||||
return TestApplication(
|
||||
name="TestApplication", port=Port.ARP, file_system=file_system, sys_log=SysLog(hostname="test_application")
|
||||
def application(file_system) -> DummyApplication:
|
||||
return DummyApplication(
|
||||
name="DummyApplication", port=Port.ARP, file_system=file_system, sys_log=SysLog(hostname="dummy_application")
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def application_class():
|
||||
return TestApplication
|
||||
return DummyApplication
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
|
||||
@@ -69,6 +69,7 @@ def test_application_install_uninstall_on_uc2():
|
||||
env.step(0)
|
||||
|
||||
# Test we can now execute the DoSBot app
|
||||
env.step(82) # configure dos bot with ip address and port
|
||||
_, _, _, _, info = env.step(81)
|
||||
assert info["agent_actions"]["defender"].response.status == "success"
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ from primaite.config.load import data_manipulation_config_path
|
||||
from primaite.game.agent.interface import ProxyAgent
|
||||
from primaite.game.agent.scripted_agents.data_manipulation_bot import DataManipulationAgent
|
||||
from primaite.game.agent.scripted_agents.probabilistic_agent import ProbabilisticAgent
|
||||
from primaite.game.game import APPLICATION_TYPES_MAPPING, PrimaiteGame, SERVICE_TYPES_MAPPING
|
||||
from primaite.game.game import PrimaiteGame, SERVICE_TYPES_MAPPING
|
||||
from primaite.simulator.network.container import Network
|
||||
from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
||||
from primaite.simulator.system.applications.application import Application
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.applications.red_applications.data_manipulation_bot import DataManipulationBot
|
||||
from primaite.simulator.system.applications.red_applications.dos_bot import DoSBot
|
||||
@@ -85,7 +86,7 @@ def test_node_software_install():
|
||||
assert client_2.software_manager.software.get(software.__name__) is not None
|
||||
|
||||
# check that applications have been installed on client 1
|
||||
for applications in APPLICATION_TYPES_MAPPING:
|
||||
for applications in Application._application_registry:
|
||||
assert client_1.software_manager.software.get(applications) is not None
|
||||
|
||||
# check that services have been installed on client 1
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
import copy
|
||||
from ipaddress import IPv4Address
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
import yaml
|
||||
|
||||
from primaite.config.load import data_manipulation_config_path
|
||||
from primaite.game.agent.interface import ProxyAgent
|
||||
from primaite.game.agent.scripted_agents.data_manipulation_bot import DataManipulationAgent
|
||||
from primaite.game.agent.scripted_agents.probabilistic_agent import ProbabilisticAgent
|
||||
from primaite.game.game import APPLICATION_TYPES_MAPPING, PrimaiteGame, SERVICE_TYPES_MAPPING
|
||||
from primaite.simulator.network.container import Network
|
||||
from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.applications.red_applications.data_manipulation_bot import DataManipulationBot
|
||||
from primaite.simulator.system.applications.red_applications.dos_bot import DoSBot
|
||||
from primaite.simulator.system.applications.web_browser import WebBrowser
|
||||
from primaite.simulator.system.services.database.database_service import DatabaseService
|
||||
from primaite.simulator.system.services.dns.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.dns.dns_server import DNSServer
|
||||
from primaite.simulator.system.services.ftp.ftp_client import FTPClient
|
||||
from primaite.simulator.system.services.ftp.ftp_server import FTPServer
|
||||
from primaite.simulator.system.services.ntp.ntp_client import NTPClient
|
||||
from primaite.simulator.system.services.ntp.ntp_server import NTPServer
|
||||
from primaite.simulator.system.services.web_server.web_server import WebServer
|
||||
from tests import TEST_ASSETS_ROOT
|
||||
|
||||
TEST_CONFIG = TEST_ASSETS_ROOT / "configs/software_fix_duration.yaml"
|
||||
ONE_ITEM_CONFIG = TEST_ASSETS_ROOT / "configs/fix_duration_one_item.yaml"
|
||||
|
||||
|
||||
def load_config(config_path: Union[str, Path]) -> PrimaiteGame:
|
||||
"""Returns a PrimaiteGame object which loads the contents of a given yaml path."""
|
||||
with open(config_path, "r") as f:
|
||||
cfg = yaml.safe_load(f)
|
||||
|
||||
return PrimaiteGame.from_config(cfg)
|
||||
|
||||
|
||||
def test_default_fix_duration():
|
||||
"""Test that software with no defined fix duration in config uses the default fix duration of 2."""
|
||||
game = load_config(TEST_CONFIG)
|
||||
client_2: Computer = game.simulation.network.get_node_by_hostname("client_2")
|
||||
|
||||
database_client: DatabaseClient = client_2.software_manager.software.get("DatabaseClient")
|
||||
assert database_client.fixing_duration == 2
|
||||
|
||||
dns_client: DNSClient = client_2.software_manager.software.get("DNSClient")
|
||||
assert dns_client.fixing_duration == 2
|
||||
|
||||
|
||||
def test_fix_duration_set_from_config():
|
||||
"""Test to check that the fix duration set for applications and services works as intended."""
|
||||
game = load_config(TEST_CONFIG)
|
||||
client_1: Computer = game.simulation.network.get_node_by_hostname("client_1")
|
||||
|
||||
# in config - services take 3 timesteps to fix
|
||||
for service in SERVICE_TYPES_MAPPING:
|
||||
assert client_1.software_manager.software.get(service) is not None
|
||||
assert client_1.software_manager.software.get(service).fixing_duration == 3
|
||||
|
||||
# in config - applications take 1 timestep to fix
|
||||
for applications in APPLICATION_TYPES_MAPPING:
|
||||
assert client_1.software_manager.software.get(applications) is not None
|
||||
assert client_1.software_manager.software.get(applications).fixing_duration == 1
|
||||
|
||||
|
||||
def test_fix_duration_for_one_item():
|
||||
"""Test that setting fix duration for one application does not affect other components."""
|
||||
game = load_config(ONE_ITEM_CONFIG)
|
||||
client_1: Computer = game.simulation.network.get_node_by_hostname("client_1")
|
||||
|
||||
# in config - services take 3 timesteps to fix
|
||||
services = copy.copy(SERVICE_TYPES_MAPPING)
|
||||
services.pop("DatabaseService")
|
||||
for service in services:
|
||||
assert client_1.software_manager.software.get(service) is not None
|
||||
assert client_1.software_manager.software.get(service).fixing_duration == 2
|
||||
|
||||
# in config - applications take 1 timestep to fix
|
||||
applications = copy.copy(APPLICATION_TYPES_MAPPING)
|
||||
applications.pop("DatabaseClient")
|
||||
for applications in applications:
|
||||
assert client_1.software_manager.software.get(applications) is not None
|
||||
assert client_1.software_manager.software.get(applications).fixing_duration == 2
|
||||
|
||||
database_client: DatabaseClient = client_1.software_manager.software.get("DatabaseClient")
|
||||
assert database_client.fixing_duration == 1
|
||||
|
||||
database_service: DatabaseService = client_1.software_manager.software.get("DatabaseService")
|
||||
assert database_service.fixing_duration == 5
|
||||
1
tests/integration_tests/game_layer/actions/__init__.py
Normal file
1
tests/integration_tests/game_layer/actions/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
@@ -0,0 +1,292 @@
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
from ipaddress import IPv4Address
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from primaite.game.agent.actions import (
|
||||
ConfigureDatabaseClientAction,
|
||||
ConfigureDoSBotAction,
|
||||
ConfigureRansomwareScriptAction,
|
||||
)
|
||||
from primaite.session.environment import PrimaiteGymEnv
|
||||
from primaite.simulator.file_system.file_system_item_abc import FileSystemItemHealthStatus
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.applications.application import ApplicationOperatingState
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.applications.red_applications.dos_bot import DoSBot
|
||||
from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript
|
||||
from primaite.simulator.system.services.database.database_service import DatabaseService
|
||||
from tests import TEST_ASSETS_ROOT
|
||||
from tests.conftest import ControlledAgent
|
||||
|
||||
APP_CONFIG_YAML = TEST_ASSETS_ROOT / "configs/install_and_configure_apps.yaml"
|
||||
|
||||
|
||||
class TestConfigureDatabaseAction:
|
||||
def test_configure_ip_password(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_DATABASE_CLIENT"] = ConfigureDatabaseClientAction(agent.action_manager)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
client_1.software_manager.install(DatabaseClient)
|
||||
db_client: DatabaseClient = client_1.software_manager.software["DatabaseClient"]
|
||||
|
||||
action = (
|
||||
"CONFIGURE_DATABASE_CLIENT",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {
|
||||
"server_ip_address": "192.168.1.99",
|
||||
"server_password": "admin123",
|
||||
},
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
|
||||
assert db_client.server_ip_address == IPv4Address("192.168.1.99")
|
||||
assert db_client.server_password == "admin123"
|
||||
|
||||
def test_configure_ip(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_DATABASE_CLIENT"] = ConfigureDatabaseClientAction(agent.action_manager)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
client_1.software_manager.install(DatabaseClient)
|
||||
db_client: DatabaseClient = client_1.software_manager.software["DatabaseClient"]
|
||||
|
||||
action = (
|
||||
"CONFIGURE_DATABASE_CLIENT",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {
|
||||
"server_ip_address": "192.168.1.99",
|
||||
},
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
|
||||
assert db_client.server_ip_address == IPv4Address("192.168.1.99")
|
||||
assert db_client.server_password is None
|
||||
|
||||
def test_configure_password(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_DATABASE_CLIENT"] = ConfigureDatabaseClientAction(agent.action_manager)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
client_1.software_manager.install(DatabaseClient)
|
||||
db_client: DatabaseClient = client_1.software_manager.software["DatabaseClient"]
|
||||
old_ip = db_client.server_ip_address
|
||||
|
||||
action = (
|
||||
"CONFIGURE_DATABASE_CLIENT",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {
|
||||
"server_password": "admin123",
|
||||
},
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
|
||||
assert db_client.server_ip_address == old_ip
|
||||
assert db_client.server_password is "admin123"
|
||||
|
||||
|
||||
class TestConfigureRansomwareScriptAction:
|
||||
@pytest.mark.parametrize(
|
||||
"config",
|
||||
[
|
||||
{},
|
||||
{"server_ip_address": "181.181.181.181"},
|
||||
{"server_password": "admin123"},
|
||||
{"payload": "ENCRYPT"},
|
||||
{
|
||||
"server_ip_address": "181.181.181.181",
|
||||
"server_password": "admin123",
|
||||
"payload": "ENCRYPT",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_configure_ip_password(self, game_and_agent, config):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_RANSOMWARE_SCRIPT"] = ConfigureRansomwareScriptAction(
|
||||
agent.action_manager
|
||||
)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
client_1.software_manager.install(RansomwareScript)
|
||||
ransomware_script: RansomwareScript = client_1.software_manager.software["RansomwareScript"]
|
||||
|
||||
old_ip = ransomware_script.server_ip_address
|
||||
old_pw = ransomware_script.server_password
|
||||
old_payload = ransomware_script.payload
|
||||
|
||||
action = (
|
||||
"CONFIGURE_RANSOMWARE_SCRIPT",
|
||||
{"node_id": 0, "config": config},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
|
||||
expected_ip = old_ip if "server_ip_address" not in config else IPv4Address(config["server_ip_address"])
|
||||
expected_pw = old_pw if "server_password" not in config else config["server_password"]
|
||||
expected_payload = old_payload if "payload" not in config else config["payload"]
|
||||
|
||||
assert ransomware_script.server_ip_address == expected_ip
|
||||
assert ransomware_script.server_password == expected_pw
|
||||
assert ransomware_script.payload == expected_payload
|
||||
|
||||
def test_invalid_config(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_RANSOMWARE_SCRIPT"] = ConfigureRansomwareScriptAction(
|
||||
agent.action_manager
|
||||
)
|
||||
|
||||
# make sure there is a database client on this node
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
client_1.software_manager.install(RansomwareScript)
|
||||
ransomware_script: RansomwareScript = client_1.software_manager.software["RansomwareScript"]
|
||||
action = (
|
||||
"CONFIGURE_RANSOMWARE_SCRIPT",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {"server_password": "admin123", "bad_option": 70},
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
with pytest.raises(ValidationError):
|
||||
game.step()
|
||||
|
||||
|
||||
class TestConfigureDoSBot:
|
||||
def test_configure_DoSBot(self, game_and_agent):
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
agent.action_manager.actions["CONFIGURE_DOSBOT"] = ConfigureDoSBotAction(agent.action_manager)
|
||||
|
||||
client_1 = game.simulation.network.get_node_by_hostname("client_1")
|
||||
client_1.software_manager.install(DoSBot)
|
||||
dos_bot: DoSBot = client_1.software_manager.software["DoSBot"]
|
||||
|
||||
action = (
|
||||
"CONFIGURE_DOSBOT",
|
||||
{
|
||||
"node_id": 0,
|
||||
"config": {
|
||||
"target_ip_address": "192.168.1.99",
|
||||
"target_port": "POSTGRES_SERVER",
|
||||
"payload": "HACC",
|
||||
"repeat": False,
|
||||
"port_scan_p_of_success": 0.875,
|
||||
"dos_intensity": 0.75,
|
||||
"max_sessions": 50,
|
||||
},
|
||||
},
|
||||
)
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
|
||||
assert dos_bot.target_ip_address == IPv4Address("192.168.1.99")
|
||||
assert dos_bot.target_port == Port.POSTGRES_SERVER
|
||||
assert dos_bot.payload == "HACC"
|
||||
assert not dos_bot.repeat
|
||||
assert dos_bot.port_scan_p_of_success == 0.875
|
||||
assert dos_bot.dos_intensity == 0.75
|
||||
assert dos_bot.max_sessions == 50
|
||||
|
||||
|
||||
class TestConfigureYAML:
|
||||
def test_configure_db_client(self):
|
||||
env = PrimaiteGymEnv(env_config=APP_CONFIG_YAML)
|
||||
|
||||
# make sure there's no db client on the node yet
|
||||
client_1 = env.game.simulation.network.get_node_by_hostname("client_1")
|
||||
assert client_1.software_manager.software.get("DatabaseClient") is None
|
||||
|
||||
# take the install action, check that the db gets installed, step to get it to finish installing
|
||||
env.step(1)
|
||||
db_client: DatabaseClient = client_1.software_manager.software.get("DatabaseClient")
|
||||
assert isinstance(db_client, DatabaseClient)
|
||||
assert db_client.operating_state == ApplicationOperatingState.INSTALLING
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
|
||||
# configure the ip address and check that it changes, but password doesn't change
|
||||
assert db_client.server_ip_address is None
|
||||
assert db_client.server_password is None
|
||||
env.step(4)
|
||||
assert db_client.server_ip_address == IPv4Address("10.0.0.5")
|
||||
assert db_client.server_password is None
|
||||
|
||||
# configure the password and check that it changes, make sure this lets us connect to the db
|
||||
assert not db_client.connect()
|
||||
env.step(5)
|
||||
assert db_client.server_password == "correct_password"
|
||||
assert db_client.connect()
|
||||
|
||||
def test_configure_ransomware_script(self):
|
||||
env = PrimaiteGymEnv(env_config=APP_CONFIG_YAML)
|
||||
client_2 = env.game.simulation.network.get_node_by_hostname("client_2")
|
||||
assert client_2.software_manager.software.get("RansomwareScript") is None
|
||||
|
||||
# install ransomware script
|
||||
env.step(2)
|
||||
ransom = client_2.software_manager.software.get("RansomwareScript")
|
||||
assert isinstance(ransom, RansomwareScript)
|
||||
assert ransom.operating_state == ApplicationOperatingState.INSTALLING
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
|
||||
# make sure it's not working yet because it's not configured and there's no db client
|
||||
assert not ransom.attack()
|
||||
env.step(8) # install db client on the same node
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
env.step(0) # let it finish installing
|
||||
assert not ransom.attack()
|
||||
|
||||
# finally, configure the ransomware script with ip and password
|
||||
env.step(6)
|
||||
assert ransom.attack()
|
||||
|
||||
db_server = env.game.simulation.network.get_node_by_hostname("server_1")
|
||||
db_service: DatabaseService = db_server.software_manager.software.get("DatabaseService")
|
||||
assert db_service.db_file.health_status == FileSystemItemHealthStatus.CORRUPT
|
||||
|
||||
def test_configure_dos_bot(self):
|
||||
env = PrimaiteGymEnv(env_config=APP_CONFIG_YAML)
|
||||
client_3 = env.game.simulation.network.get_node_by_hostname("client_3")
|
||||
assert client_3.software_manager.software.get("DoSBot") is None
|
||||
|
||||
# install DoSBot
|
||||
env.step(3)
|
||||
bot = client_3.software_manager.software.get("DoSBot")
|
||||
assert isinstance(bot, DoSBot)
|
||||
assert bot.operating_state == ApplicationOperatingState.INSTALLING
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
env.step(0)
|
||||
|
||||
# make sure dos bot doesn't work before being configured
|
||||
assert not bot.run()
|
||||
env.step(7)
|
||||
assert bot.run()
|
||||
@@ -557,7 +557,7 @@ def test_node_application_install_and_uninstall_integration(game_and_agent: Tupl
|
||||
|
||||
assert client_1.software_manager.software.get("DoSBot") is None
|
||||
|
||||
action = ("NODE_APPLICATION_INSTALL", {"node_id": 0, "application_name": "DoSBot", "ip_address": "192.168.1.14"})
|
||||
action = ("NODE_APPLICATION_INSTALL", {"node_id": 0, "application_name": "DoSBot"})
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
from primaite.game.agent.interface import AgentHistoryItem
|
||||
from primaite.game.agent.rewards import GreenAdminDatabaseUnreachablePenalty, WebpageUnavailablePenalty
|
||||
from primaite.game.agent.rewards import ActionPenalty, GreenAdminDatabaseUnreachablePenalty, WebpageUnavailablePenalty
|
||||
from primaite.game.game import PrimaiteGame
|
||||
from primaite.interface.request import RequestResponse
|
||||
from primaite.session.environment import PrimaiteGymEnv
|
||||
from primaite.simulator.network.hardware.nodes.host.server import Server
|
||||
from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router
|
||||
@@ -119,3 +121,77 @@ def test_shared_reward():
|
||||
g2_reward = env.game.agents["client_2_green_user"].reward_function.current_reward
|
||||
blue_reward = env.game.agents["defender"].reward_function.current_reward
|
||||
assert blue_reward == g1_reward + g2_reward
|
||||
|
||||
|
||||
def test_action_penalty_loads_from_config():
|
||||
"""Test to ensure that action penalty is correctly loaded from config into PrimaiteGymEnv"""
|
||||
CFG_PATH = TEST_ASSETS_ROOT / "configs/action_penalty.yaml"
|
||||
with open(CFG_PATH, "r") as f:
|
||||
cfg = yaml.safe_load(f)
|
||||
|
||||
env = PrimaiteGymEnv(env_config=cfg)
|
||||
|
||||
env.reset()
|
||||
defender = env.game.agents["defender"]
|
||||
act_penalty_obj = None
|
||||
for comp in defender.reward_function.reward_components:
|
||||
if isinstance(comp[0], ActionPenalty):
|
||||
act_penalty_obj = comp[0]
|
||||
if act_penalty_obj is None:
|
||||
pytest.fail("Action penalty reward component was not added to the agent from config.")
|
||||
assert act_penalty_obj.action_penalty == -0.75
|
||||
assert act_penalty_obj.do_nothing_penalty == 0.125
|
||||
|
||||
|
||||
def test_action_penalty():
|
||||
"""Test that the action penalty is correctly applied when agent performs any action"""
|
||||
|
||||
# Create an ActionPenalty Reward
|
||||
Penalty = ActionPenalty(action_penalty=-0.75, do_nothing_penalty=0.125)
|
||||
|
||||
# Assert that penalty is applied if action isn't DONOTHING
|
||||
reward_value = Penalty.calculate(
|
||||
state={},
|
||||
last_action_response=AgentHistoryItem(
|
||||
timestep=0,
|
||||
action="NODE_APPLICATION_EXECUTE",
|
||||
parameters={"node_id": 0, "application_id": 1},
|
||||
request=["execute"],
|
||||
response=RequestResponse.from_bool(True),
|
||||
),
|
||||
)
|
||||
|
||||
assert reward_value == -0.75
|
||||
|
||||
# Assert that no penalty applied for a DONOTHING action
|
||||
reward_value = Penalty.calculate(
|
||||
state={},
|
||||
last_action_response=AgentHistoryItem(
|
||||
timestep=0,
|
||||
action="DONOTHING",
|
||||
parameters={},
|
||||
request=["do_nothing"],
|
||||
response=RequestResponse.from_bool(True),
|
||||
),
|
||||
)
|
||||
|
||||
assert reward_value == 0.125
|
||||
|
||||
|
||||
def test_action_penalty_e2e(game_and_agent):
|
||||
"""Test that we get the right reward for doing actions to fetch a website."""
|
||||
game, agent = game_and_agent
|
||||
agent: ControlledAgent
|
||||
comp = ActionPenalty(action_penalty=-0.75, do_nothing_penalty=0.125)
|
||||
|
||||
agent.reward_function.register_component(comp, 1.0)
|
||||
|
||||
action = ("DONOTHING", {})
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
assert agent.reward_function.current_reward == 0.125
|
||||
|
||||
action = ("NODE_FILE_SCAN", {"node_id": 0, "folder_id": 0, "file_id": 0})
|
||||
agent.store_action(action)
|
||||
game.step()
|
||||
assert agent.reward_function.current_reward == -0.75
|
||||
|
||||
@@ -41,7 +41,7 @@ class BroadcastService(Service):
|
||||
super().send(payload="broadcast", dest_ip_address=ip_network, dest_port=Port.HTTP, ip_protocol=self.protocol)
|
||||
|
||||
|
||||
class BroadcastClient(Application):
|
||||
class BroadcastClient(Application, identifier="BroadcastClient"):
|
||||
"""A client application to receive broadcast and unicast messages."""
|
||||
|
||||
payloads_received: List = []
|
||||
|
||||
@@ -3,9 +3,9 @@ from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.host.server import Server
|
||||
from primaite.simulator.network.networks import multi_lan_internet_network_example
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.applications.web_browser import WebBrowser
|
||||
from primaite.simulator.system.services.dns.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.ftp.ftp_client import FTPClient
|
||||
from src.primaite.simulator.system.applications.web_browser import WebBrowser
|
||||
|
||||
|
||||
def test_all_with_configured_dns_server_ip_can_resolve_url():
|
||||
|
||||
@@ -21,7 +21,7 @@ def populated_node(application_class) -> Tuple[Application, Computer]:
|
||||
computer.power_on()
|
||||
computer.software_manager.install(application_class)
|
||||
|
||||
app = computer.software_manager.software.get("TestApplication")
|
||||
app = computer.software_manager.software.get("DummyApplication")
|
||||
app.run()
|
||||
|
||||
return app, computer
|
||||
@@ -39,7 +39,7 @@ def test_application_on_offline_node(application_class):
|
||||
)
|
||||
computer.software_manager.install(application_class)
|
||||
|
||||
app: Application = computer.software_manager.software.get("TestApplication")
|
||||
app: Application = computer.software_manager.software.get("DummyApplication")
|
||||
|
||||
computer.power_off()
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ from primaite.simulator.system.applications.database_client import DatabaseClien
|
||||
from primaite.simulator.system.services.database.database_service import DatabaseService
|
||||
from primaite.simulator.system.services.ftp.ftp_server import FTPServer
|
||||
from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
from primaite.simulator.system.software import SoftwareHealthState
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@@ -213,6 +214,110 @@ def test_restore_backup_after_deleting_file_without_updating_scan(uc2_network):
|
||||
assert db_service.db_file.visible_health_status == FileSystemItemHealthStatus.GOOD # now looks good
|
||||
|
||||
|
||||
def test_database_service_fix(uc2_network):
|
||||
"""Test that the software fix applies to database service."""
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = db_server.software_manager.software["DatabaseService"]
|
||||
|
||||
assert db_service.backup_database() is True
|
||||
|
||||
# delete database locally
|
||||
db_service.file_system.delete_file(folder_name="database", file_name="database.db")
|
||||
|
||||
# db file is gone, reduced to atoms
|
||||
assert db_service.db_file is None
|
||||
|
||||
db_service.fix() # fix the database service
|
||||
|
||||
assert db_service.health_state_actual == SoftwareHealthState.FIXING
|
||||
|
||||
# apply timestep until the fix is applied
|
||||
for i in range(db_service.fixing_duration + 1):
|
||||
uc2_network.apply_timestep(i)
|
||||
|
||||
assert db_service.db_file.health_status == FileSystemItemHealthStatus.GOOD
|
||||
assert db_service.health_state_actual == SoftwareHealthState.GOOD
|
||||
|
||||
|
||||
def test_database_cannot_be_queried_while_fixing(uc2_network):
|
||||
"""Tests that the database service cannot be queried if the service is being fixed."""
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = db_server.software_manager.software["DatabaseService"]
|
||||
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
db_client: DatabaseClient = web_server.software_manager.software["DatabaseClient"]
|
||||
|
||||
db_connection: DatabaseClientConnection = db_client.get_new_connection()
|
||||
|
||||
assert db_connection.query(sql="SELECT")
|
||||
|
||||
assert db_service.backup_database() is True
|
||||
|
||||
# delete database locally
|
||||
db_service.file_system.delete_file(folder_name="database", file_name="database.db")
|
||||
|
||||
# db file is gone, reduced to atoms
|
||||
assert db_service.db_file is None
|
||||
|
||||
db_service.fix() # fix the database service
|
||||
assert db_service.health_state_actual == SoftwareHealthState.FIXING
|
||||
|
||||
# fails to query because database is in FIXING state
|
||||
assert db_connection.query(sql="SELECT") is False
|
||||
|
||||
# apply timestep until the fix is applied
|
||||
for i in range(db_service.fixing_duration + 1):
|
||||
uc2_network.apply_timestep(i)
|
||||
|
||||
assert db_service.health_state_actual == SoftwareHealthState.GOOD
|
||||
|
||||
assert db_service.db_file.health_status == FileSystemItemHealthStatus.GOOD
|
||||
|
||||
assert db_connection.query(sql="SELECT")
|
||||
|
||||
|
||||
def test_database_can_create_connection_while_fixing(uc2_network):
|
||||
"""Tests that connections cannot be created while the database is being fixed."""
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = db_server.software_manager.software["DatabaseService"]
|
||||
|
||||
client_2: Server = uc2_network.get_node_by_hostname("client_2")
|
||||
db_client: DatabaseClient = client_2.software_manager.software["DatabaseClient"]
|
||||
|
||||
db_connection: DatabaseClientConnection = db_client.get_new_connection()
|
||||
|
||||
assert db_connection.query(sql="SELECT")
|
||||
|
||||
assert db_service.backup_database() is True
|
||||
|
||||
# delete database locally
|
||||
db_service.file_system.delete_file(folder_name="database", file_name="database.db")
|
||||
|
||||
# db file is gone, reduced to atoms
|
||||
assert db_service.db_file is None
|
||||
|
||||
db_service.fix() # fix the database service
|
||||
assert db_service.health_state_actual == SoftwareHealthState.FIXING
|
||||
|
||||
# fails to query because database is in FIXING state
|
||||
assert db_connection.query(sql="SELECT") is False
|
||||
|
||||
# should be able to create a new connection
|
||||
new_db_connection: DatabaseClientConnection = db_client.get_new_connection()
|
||||
assert new_db_connection is not None
|
||||
assert new_db_connection.query(sql="SELECT") is False # still should fail to query because FIXING
|
||||
|
||||
# apply timestep until the fix is applied
|
||||
for i in range(db_service.fixing_duration + 1):
|
||||
uc2_network.apply_timestep(i)
|
||||
|
||||
assert db_service.health_state_actual == SoftwareHealthState.GOOD
|
||||
assert db_service.db_file.health_status == FileSystemItemHealthStatus.GOOD
|
||||
|
||||
assert db_connection.query(sql="SELECT")
|
||||
assert new_db_connection.query(sql="SELECT")
|
||||
|
||||
|
||||
def test_database_client_cannot_query_offline_database_server(uc2_network):
|
||||
"""Tests DB query across the network returns HTTP status 404 when db server is offline."""
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
|
||||
@@ -16,6 +16,7 @@ from primaite.simulator.system.services.database.database_service import Databas
|
||||
from primaite.simulator.system.services.dns.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.dns.dns_server import DNSServer
|
||||
from primaite.simulator.system.services.web_server.web_server import WebServer
|
||||
from primaite.simulator.system.software import SoftwareHealthState
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@@ -110,6 +111,29 @@ def test_web_client_requests_users(web_client_web_server_database):
|
||||
assert web_browser.get_webpage()
|
||||
|
||||
|
||||
def test_database_fix_disrupts_web_client(uc2_network):
|
||||
"""Tests that the database service being in fixed state disrupts the web client."""
|
||||
computer: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
|
||||
web_browser: WebBrowser = computer.software_manager.software.get("WebBrowser")
|
||||
database_service: DatabaseService = db_server.software_manager.software.get("DatabaseService")
|
||||
|
||||
# fix the database service
|
||||
database_service.fix()
|
||||
|
||||
assert database_service.health_state_actual == SoftwareHealthState.FIXING
|
||||
|
||||
assert web_browser.get_webpage() is False
|
||||
|
||||
for i in range(database_service.fixing_duration + 1):
|
||||
uc2_network.apply_timestep(i)
|
||||
|
||||
assert database_service.health_state_actual == SoftwareHealthState.GOOD
|
||||
|
||||
assert web_browser.get_webpage()
|
||||
|
||||
|
||||
class TestWebBrowserHistory:
|
||||
def test_populating_history(self, web_client_web_server_database):
|
||||
network, computer, _, _ = web_client_web_server_database
|
||||
|
||||
@@ -13,7 +13,7 @@ from primaite.simulator.network.hardware.node_operating_state import NodeOperati
|
||||
from primaite.simulator.network.hardware.nodes.host.host_node import HostNode
|
||||
from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from tests.conftest import TestApplication, TestService
|
||||
from tests.conftest import DummyApplication, TestService
|
||||
|
||||
|
||||
def test_successful_node_file_system_creation_request(example_network):
|
||||
@@ -47,14 +47,14 @@ def test_successful_application_requests(example_network):
|
||||
net = example_network
|
||||
|
||||
client_1 = net.get_node_by_hostname("client_1")
|
||||
client_1.software_manager.install(TestApplication)
|
||||
client_1.software_manager.software.get("TestApplication").run()
|
||||
client_1.software_manager.install(DummyApplication)
|
||||
client_1.software_manager.software.get("DummyApplication").run()
|
||||
|
||||
resp_1 = net.apply_request(["node", "client_1", "application", "TestApplication", "scan"])
|
||||
resp_1 = net.apply_request(["node", "client_1", "application", "DummyApplication", "scan"])
|
||||
assert resp_1 == RequestResponse(status="success", data={})
|
||||
resp_2 = net.apply_request(["node", "client_1", "application", "TestApplication", "fix"])
|
||||
resp_2 = net.apply_request(["node", "client_1", "application", "DummyApplication", "fix"])
|
||||
assert resp_2 == RequestResponse(status="success", data={})
|
||||
resp_3 = net.apply_request(["node", "client_1", "application", "TestApplication", "compromise"])
|
||||
resp_3 = net.apply_request(["node", "client_1", "application", "DummyApplication", "compromise"])
|
||||
assert resp_3 == RequestResponse(status="success", data={})
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.system.applications.application import Application
|
||||
|
||||
|
||||
def test_adding_to_app_registry():
|
||||
class temp_application(Application, identifier="temp_app"):
|
||||
pass
|
||||
|
||||
assert Application._application_registry["temp_app"] is temp_application
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
|
||||
class another_application(Application, identifier="temp_app"):
|
||||
pass
|
||||
|
||||
# This is kinda evil...
|
||||
# Because pytest doesn't reimport classes from modules, registering this temporary test application will change the
|
||||
# state of the Application registry for all subsequently run tests. So, we have to delete and unregister the class.
|
||||
del temp_application
|
||||
Application._application_registry.pop("temp_app")
|
||||
Reference in New Issue
Block a user