#2689 Updated actions E2E notebook and other additions
This commit is contained in:
@@ -1153,19 +1153,29 @@ class TerminalC2ServerAction(AbstractAction):
|
||||
class _Opts(BaseModel):
|
||||
"""Schema for options that can be passed to this action."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
commands: RequestFormat
|
||||
commands: List[RequestFormat]
|
||||
ip_address: Optional[str]
|
||||
username: Optional[str]
|
||||
password: Optional[str]
|
||||
|
||||
def __init__(self, manager: "ActionManager", **kwargs) -> None:
|
||||
super().__init__(manager=manager)
|
||||
|
||||
def form_request(self, node_id: int, config: Dict) -> RequestFormat:
|
||||
def form_request(self, node_id: int, commands: List, ip_address: Optional[str], account: dict) -> RequestFormat:
|
||||
"""Return the action formatted as a request that can be ingested by the simulation."""
|
||||
node_name = self.manager.get_node_name_by_idx(node_id)
|
||||
if node_name is None:
|
||||
return ["do_nothing"]
|
||||
TerminalC2ServerAction._Opts.model_validate(config) # check that options adhere to schema
|
||||
return ["network", "node", node_name, "application", "C2Server", "terminal_command", config]
|
||||
|
||||
command_model = {
|
||||
"commands": commands,
|
||||
"ip_address": ip_address,
|
||||
"username": account["username"],
|
||||
"password": account["password"],
|
||||
}
|
||||
|
||||
TerminalC2ServerAction._Opts.model_validate(command_model)
|
||||
return ["network", "node", node_name, "application", "C2Server", "terminal_command", command_model]
|
||||
|
||||
|
||||
class ActionManager:
|
||||
|
||||
@@ -20,15 +20,18 @@
|
||||
"# Imports\n",
|
||||
"from primaite.config.load import data_manipulation_config_path\n",
|
||||
"from primaite.session.environment import PrimaiteGymEnv\n",
|
||||
"from primaite.simulator.network.hardware.nodes.network.router import Router\n",
|
||||
"from primaite.game.agent.interface import AgentHistoryItem\n",
|
||||
"import yaml\n",
|
||||
"from pprint import pprint\n",
|
||||
"from primaite.simulator.network.container import Network\n",
|
||||
"from primaite.game.game import PrimaiteGame\n",
|
||||
"from primaite.simulator.system.applications.application import ApplicationOperatingState\n",
|
||||
"from primaite.simulator.system.applications.red_applications.c2.c2_beacon import C2Beacon\n",
|
||||
"from primaite.simulator.system.applications.red_applications.c2.c2_server import C2Server\n",
|
||||
"from primaite.simulator.system.applications.red_applications.c2.abstract_c2 import C2Command, C2Payload\n",
|
||||
"from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript\n",
|
||||
"from primaite.simulator.system.software import SoftwareHealthState\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.computer import Computer\n",
|
||||
"from primaite.simulator.network.hardware.nodes.host.server import Server"
|
||||
]
|
||||
@@ -66,10 +69,10 @@
|
||||
" - type: C2_SERVER_TERMINAL_COMMAND\n",
|
||||
" options:\n",
|
||||
" nodes:\n",
|
||||
" - node_name: client_1\n",
|
||||
" - node_name: web_server\n",
|
||||
" applications: \n",
|
||||
" - application_name: C2Beacon\n",
|
||||
" - node_name: domain_controller\n",
|
||||
" - node_name: client_1\n",
|
||||
" applications: \n",
|
||||
" - application_name: C2Server\n",
|
||||
" max_folders_per_node: 1\n",
|
||||
@@ -78,7 +81,7 @@
|
||||
" max_nics_per_node: 8\n",
|
||||
" max_acl_rules: 10\n",
|
||||
" ip_list:\n",
|
||||
" - 192.168.1.10\n",
|
||||
" - 192.168.1.21\n",
|
||||
" - 192.168.1.14\n",
|
||||
" action_map:\n",
|
||||
" 0:\n",
|
||||
@@ -94,7 +97,7 @@
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" config:\n",
|
||||
" c2_server_ip_address: 192.168.1.10\n",
|
||||
" c2_server_ip_address: 192.168.10.21\n",
|
||||
" keep_alive_frequency:\n",
|
||||
" masquerade_protocol:\n",
|
||||
" masquerade_port:\n",
|
||||
@@ -104,10 +107,19 @@
|
||||
" node_id: 0\n",
|
||||
" application_id: 0 \n",
|
||||
" 4:\n",
|
||||
" action: NODE_APPLICATION_INSTALL\n",
|
||||
" action: C2_SERVER_TERMINAL_COMMAND\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" application_name: RansomwareScript \n",
|
||||
" node_id: 1\n",
|
||||
" ip_address:\n",
|
||||
" account:\n",
|
||||
" username: test123\n",
|
||||
" password: pass123\n",
|
||||
" commands:\n",
|
||||
" - \n",
|
||||
" - software_manager\n",
|
||||
" - application\n",
|
||||
" - install\n",
|
||||
" - RansomwareScript\n",
|
||||
" 5:\n",
|
||||
" action: C2_SERVER_RANSOMWARE_CONFIGURE\n",
|
||||
" options:\n",
|
||||
@@ -119,11 +131,8 @@
|
||||
" action: C2_SERVER_RANSOMWARE_LAUNCH\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" 7:\n",
|
||||
" action: C2_SERVER_TERMINAL_COMMAND\n",
|
||||
" options:\n",
|
||||
" node_id: 1\n",
|
||||
" application_id: 0 \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" reward_function:\n",
|
||||
" reward_components:\n",
|
||||
@@ -158,7 +167,7 @@
|
||||
"\n",
|
||||
"This is because higher fidelity environments (and the real-world) a C2 server would not be accessible by private network blue agent and the C2 Server would already be in place before the an adversary (Red Agent) before the narrative of the use case.\n",
|
||||
"\n",
|
||||
"The cells below installs and runs the C2 Server on the domain controller server directly via the simulation API."
|
||||
"The cells below installs and runs the C2 Server on the client_1 directly via the simulation API."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -167,11 +176,11 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"domain_controller: Server = env.game.simulation.network.get_node_by_hostname(\"domain_controller\")\n",
|
||||
"domain_controller.software_manager.install(C2Server)\n",
|
||||
"c2_server: C2Server = domain_controller.software_manager.software[\"C2Server\"]\n",
|
||||
"client_1: Computer = env.game.simulation.network.get_node_by_hostname(\"client_1\")\n",
|
||||
"client_1.software_manager.install(C2Server)\n",
|
||||
"c2_server: C2Server = client_1.software_manager.software[\"C2Server\"]\n",
|
||||
"c2_server.run()\n",
|
||||
"domain_controller.software_manager.show()"
|
||||
"client_1.software_manager.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -185,16 +194,6 @@
|
||||
"This can be done by installing, configuring and then executing a C2 Beacon. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"c2_red_agent = env.game.agents[\"CustomC2Agent\"]\n",
|
||||
"client_1: Computer = env.game.simulation.network.get_node_by_hostname(\"client_1\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -209,8 +208,8 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(1)\n",
|
||||
"client_1.software_manager.show()\n",
|
||||
"c2_beacon: C2Beacon = client_1.software_manager.software[\"C2Beacon\"]"
|
||||
"web_server: Computer = env.game.simulation.network.get_node_by_hostname(\"web_server\")\n",
|
||||
"web_server.software_manager.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -227,6 +226,8 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(2)\n",
|
||||
"c2_beacon: C2Beacon = web_server.software_manager.software[\"C2Beacon\"]\n",
|
||||
"web_server.software_manager.show()\n",
|
||||
"c2_beacon.show()"
|
||||
]
|
||||
},
|
||||
@@ -243,7 +244,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"env.step(3)"
|
||||
"env.step(3) "
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -267,7 +268,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Server Actions | Configuring Ransomware"
|
||||
"### **Command and Control** | C2 Server Actions | Executing Terminal Commands"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -279,6 +280,22 @@
|
||||
"env.step(4)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"client_1.software_manager.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Server Actions | Configuring Ransomware"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -294,8 +311,17 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ransomware_script: RansomwareScript = client_1.software_manager.software[\"RansomwareScript\"]\n",
|
||||
"client_1.software_manager.show()\n",
|
||||
"env.step(6)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ransomware_script: RansomwareScript = web_server.software_manager.software[\"RansomwareScript\"]\n",
|
||||
"web_server.software_manager.show()\n",
|
||||
"ransomware_script.show()"
|
||||
]
|
||||
},
|
||||
@@ -329,7 +355,11 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | C2 Server Actions | Executing Terminal Commands"
|
||||
"## **Command and Control** | Blue Agent Relevance\n",
|
||||
"\n",
|
||||
"The next section of the notebook will demonstrate the impact that the command and control suite has to the Blue Agent's observation space as well as some potential actions that can be used to prevent the attack from being successfully.\n",
|
||||
"\n",
|
||||
"The code cell below re-creates the UC2 network and swaps out the previous custom red agent with a custom blue agent. \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -338,39 +368,652 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# TODO: Post Terminal.\n",
|
||||
"#env.step(7)"
|
||||
"custom_blue_agent_yaml = \"\"\" \n",
|
||||
" - ref: defender\n",
|
||||
" team: BLUE\n",
|
||||
" type: ProxyAgent\n",
|
||||
"\n",
|
||||
" observation_space:\n",
|
||||
" type: CUSTOM\n",
|
||||
" options:\n",
|
||||
" components:\n",
|
||||
" - type: NODES\n",
|
||||
" label: NODES\n",
|
||||
" options:\n",
|
||||
" hosts:\n",
|
||||
" - hostname: web_server\n",
|
||||
" applications:\n",
|
||||
" - application_name: C2Beacon\n",
|
||||
" - application_name: RansomwareScript\n",
|
||||
" - hostname: database_server\n",
|
||||
" folders:\n",
|
||||
" - folder_name: database\n",
|
||||
" files:\n",
|
||||
" - file_name: database.db\n",
|
||||
" - hostname: client_1\n",
|
||||
" - hostname: client_2\n",
|
||||
" num_services: 0\n",
|
||||
" num_applications: 2\n",
|
||||
" num_folders: 1\n",
|
||||
" num_files: 1\n",
|
||||
" num_nics: 0\n",
|
||||
" include_num_access: false\n",
|
||||
" include_nmne: false\n",
|
||||
" monitored_traffic:\n",
|
||||
" icmp:\n",
|
||||
" - NONE\n",
|
||||
" tcp:\n",
|
||||
" - HTTP\n",
|
||||
" routers:\n",
|
||||
" - hostname: router_1\n",
|
||||
" num_ports: 1\n",
|
||||
" ip_list:\n",
|
||||
" - 192.168.10.21\n",
|
||||
" - 192.168.1.12\n",
|
||||
" wildcard_list:\n",
|
||||
" - 0.0.0.1\n",
|
||||
" port_list:\n",
|
||||
" - 80\n",
|
||||
" protocol_list:\n",
|
||||
" - ICMP\n",
|
||||
" - TCP\n",
|
||||
" - UDP\n",
|
||||
" num_rules: 10\n",
|
||||
"\n",
|
||||
" - type: LINKS\n",
|
||||
" label: LINKS\n",
|
||||
" options:\n",
|
||||
" link_references:\n",
|
||||
" - router_1:eth-1<->switch_1:eth-8\n",
|
||||
" - router_1:eth-2<->switch_2:eth-8\n",
|
||||
" - switch_1:eth-1<->web_server:eth-1\n",
|
||||
" - switch_1:eth-2<->web_server:eth-1\n",
|
||||
" - switch_1:eth-3<->database_server:eth-1\n",
|
||||
" - switch_1:eth-4<->backup_server:eth-1\n",
|
||||
" - switch_1:eth-7<->security_suite:eth-1\n",
|
||||
" - switch_2:eth-1<->client_1:eth-1\n",
|
||||
" - switch_2:eth-2<->client_2:eth-1\n",
|
||||
" - switch_2:eth-7<->security_suite:eth-2\n",
|
||||
" - type: \"NONE\"\n",
|
||||
" label: ICS\n",
|
||||
" options: {}\n",
|
||||
" \n",
|
||||
" action_space:\n",
|
||||
" action_list:\n",
|
||||
" - type: NODE_APPLICATION_REMOVE\n",
|
||||
" - type: NODE_SHUTDOWN\n",
|
||||
" - type: ROUTER_ACL_ADDRULE\n",
|
||||
" - type: DONOTHING\n",
|
||||
" action_map:\n",
|
||||
" 0:\n",
|
||||
" action: DONOTHING\n",
|
||||
" options: {}\n",
|
||||
" 1:\n",
|
||||
" action: NODE_APPLICATION_REMOVE\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" application_name: C2Beacon\n",
|
||||
" 2:\n",
|
||||
" action: NODE_SHUTDOWN\n",
|
||||
" options:\n",
|
||||
" node_id: 0\n",
|
||||
" 3:\n",
|
||||
" action: ROUTER_ACL_ADDRULE\n",
|
||||
" options:\n",
|
||||
" target_router: router_1\n",
|
||||
" position: 1\n",
|
||||
" permission: 2\n",
|
||||
" source_ip_id: 2\n",
|
||||
" dest_ip_id: 3\n",
|
||||
" source_port_id: 2\n",
|
||||
" dest_port_id: 2\n",
|
||||
" protocol_id: 1\n",
|
||||
" source_wildcard_id: 0\n",
|
||||
" dest_wildcard_id: 0\n",
|
||||
"\n",
|
||||
" options:\n",
|
||||
" nodes:\n",
|
||||
" - node_name: web_server\n",
|
||||
" applications:\n",
|
||||
" - application_name: C2Beacon\n",
|
||||
"\n",
|
||||
" - node_name: database_server\n",
|
||||
" folders:\n",
|
||||
" - folder_name: database\n",
|
||||
" files:\n",
|
||||
" - file_name: database.db\n",
|
||||
" services:\n",
|
||||
" - service_name: DatabaseService\n",
|
||||
" - node_name: router_1\n",
|
||||
"\n",
|
||||
" max_folders_per_node: 2\n",
|
||||
" max_files_per_folder: 2\n",
|
||||
" max_services_per_node: 2\n",
|
||||
" max_nics_per_node: 8\n",
|
||||
" max_acl_rules: 10\n",
|
||||
" ip_list:\n",
|
||||
" - 192.168.10.21\n",
|
||||
" - 192.168.1.12\n",
|
||||
" wildcard_list:\n",
|
||||
" - 0.0.0.1\n",
|
||||
"\n",
|
||||
" reward_function:\n",
|
||||
" reward_components:\n",
|
||||
" - type: DUMMY\n",
|
||||
"\n",
|
||||
" agent_settings:\n",
|
||||
" flatten_obs: False\n",
|
||||
"\"\"\"\n",
|
||||
"custom_blue = yaml.safe_load(custom_blue_agent_yaml)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with open(data_manipulation_config_path()) as f:\n",
|
||||
" cfg = yaml.safe_load(f)\n",
|
||||
" # removing all agents & adding the custom agent.\n",
|
||||
" cfg['agents'] = {}\n",
|
||||
" cfg['agents'] = custom_blue\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"blue_env = PrimaiteGymEnv(env_config=cfg)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Utility function for showing OBS changes between each time step.\n",
|
||||
"\n",
|
||||
"from deepdiff.diff import DeepDiff\n",
|
||||
"\n",
|
||||
"def display_obs_diffs(old, new, step_counter):\n",
|
||||
" \"\"\"\n",
|
||||
" Use DeepDiff to extract and display differences in old and new instances of\n",
|
||||
" the observation space.\n",
|
||||
"\n",
|
||||
" :param old: observation space instance.\n",
|
||||
" :param new: observation space instance.\n",
|
||||
" :param step_counter: current step counter.\n",
|
||||
" \"\"\"\n",
|
||||
" print(\"\\nObservation space differences\")\n",
|
||||
" print(\"-----------------------------\")\n",
|
||||
" diff = DeepDiff(old, new)\n",
|
||||
" print(f\"Step {step_counter}\")\n",
|
||||
" for d,v in diff.get('values_changed', {}).items():\n",
|
||||
" print(f\"{d}: {v['old_value']} -> {v['new_value']}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## **Command and Control** | Blue Agent Relevance"
|
||||
"### **Command and Control** | Blue Agent Relevance | Observation Space\n",
|
||||
"\n",
|
||||
"This section demonstrates the OBS impact if the C2 suite is successfully installed and then used to install, configure and launch the ransomwarescript."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Resetting the environment and capturing the default observation space.\n",
|
||||
"blue_env.reset()\n",
|
||||
"default_obs, _, _, _, _ = blue_env.step(0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Setting up the C2 Suite via the simulation API.\n",
|
||||
"\n",
|
||||
"client_1: Computer = blue_env.game.simulation.network.get_node_by_hostname(\"client_1\")\n",
|
||||
"web_server: Server = blue_env.game.simulation.network.get_node_by_hostname(\"web_server\")\n",
|
||||
"\n",
|
||||
"# Installing the C2 Server.\n",
|
||||
"client_1.software_manager.install(C2Server)\n",
|
||||
"c2_server: C2Server = client_1.software_manager.software[\"C2Server\"]\n",
|
||||
"c2_server.run()\n",
|
||||
"\n",
|
||||
"# Installing the C2 Beacon.\n",
|
||||
"web_server.software_manager.install(C2Beacon)\n",
|
||||
"c2_beacon: C2Beacon = web_server.software_manager.software[\"C2Beacon\"]\n",
|
||||
"c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\")\n",
|
||||
"c2_beacon.establish()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Capturing the observation impacts of the previous code cell: C2 Suite setup.\n",
|
||||
"c2_configuration_obs, _, _, _, _ = blue_env.step(0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"display_obs_diffs(default_obs, c2_configuration_obs, blue_env.game.step_counter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Installing RansomwareScript via C2 Terminal Commands\n",
|
||||
"ransomware_install_command = {\"commands\":[[\"software_manager\", \"application\", \"install\", \"RansomwareScript\"]],\n",
|
||||
" \"username\": \"pass123\",\n",
|
||||
" \"password\": \"password123\"}\n",
|
||||
"c2_server._send_command(C2Command.TERMINAL, command_options=ransomware_install_command)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Configuring the RansomwareScript\n",
|
||||
"ransomware_config = {\"server_ip_address\": \"192.168.1.14\", \"payload\": \"ENCRYPT\"}\n",
|
||||
"c2_server._send_command(C2Command.RANSOMWARE_CONFIGURE, command_options=ransomware_config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Capturing the observation impacts of the previous code cell: Ransomware installation & configuration.\n",
|
||||
"c2_ransomware_obs, _, _, _, _ = blue_env.step(0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
"source": [
|
||||
"The code cell below demonstrates the differences between the default observation space and the configuration of the C2 Server and the Ransomware installation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"### **Command and Control** | Blue Agent Relevance | Observation Space"
|
||||
"display_obs_diffs(default_obs, c2_ransomware_obs, env.game.step_counter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Waiting for the ransomware to finish installing and then launching the RansomwareScript.\n",
|
||||
"blue_env.step(0)\n",
|
||||
"c2_server._send_command(C2Command.RANSOMWARE_LAUNCH, command_options={})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Capturing the observation impacts of the previous code cell: Launching the RansomwareScript.\n",
|
||||
"c2_final_obs, _, _, _, _ = blue_env.step(0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
"source": [
|
||||
"The code cell below demonstrates the differences between the default observation space and the configuration of the C2 Server, the ransomware script installation as well as the impact of RansomwareScript upon the database."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"display_obs_diffs(c2_ransomware_obs, c2_final_obs, blue_env.game.step_counter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Command and Control** | Blue Agent Relevance | Action Space"
|
||||
"### **Command and Control** | Blue Agent Relevance | Action Space\n",
|
||||
"\n",
|
||||
"The next section of this notebook will go over some potential blue agent actions that could be use to thwart the previously demonstrated attack."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# This method is used to shorthand setting up the C2Server and the C2 Beacon.\n",
|
||||
"def c2_setup(given_env: PrimaiteGymEnv):\n",
|
||||
" client_1: Computer = given_env.game.simulation.network.get_node_by_hostname(\"client_1\")\n",
|
||||
" web_server: Server = given_env.game.simulation.network.get_node_by_hostname(\"web_server\")\n",
|
||||
"\n",
|
||||
" client_1.software_manager.install(C2Server)\n",
|
||||
" c2_server: C2Server = client_1.software_manager.software[\"C2Server\"]\n",
|
||||
" c2_server.run()\n",
|
||||
"\n",
|
||||
" web_server.software_manager.install(C2Beacon)\n",
|
||||
" c2_beacon: C2Beacon = web_server.software_manager.software[\"C2Beacon\"]\n",
|
||||
" c2_beacon.configure(c2_server_ip_address=\"192.168.10.21\")\n",
|
||||
" c2_beacon.establish()\n",
|
||||
"\n",
|
||||
" return given_env, c2_server, c2_beacon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Removing the C2 Beacon.\n",
|
||||
"\n",
|
||||
"The simplest way a blue agent could prevent the C2 suite is by simply removing the C2 beacon from it's installation point. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"blue_env.reset()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Setting up the C2 Suite using the c2_setup method & capturing the OBS impacts\n",
|
||||
"\n",
|
||||
"blue_env, c2_server, c2_beacon = c2_setup(blue_env=blue_env)\n",
|
||||
"pre_blue_action_obs, _, _, _, _ = blue_env.step(0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The code cell below uses the custom blue agent defined at the start of this section perform NODE_APPLICATION_REMOVE on the C2 beacon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Using CAOS ACTION: NODE_APPLICATION_REMOVE & capturing the OBS\n",
|
||||
"post_blue_action_obs, _, _, _, _ = blue_env.step(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Which we can see after the effects of after stepping another timestep and looking at the web_servers software manager and the OBS differences."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"blue_env.step(0)\n",
|
||||
"web_server.software_manager.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"display_obs_diffs(pre_blue_action_obs, post_blue_action_obs, blue_env.game.step_counter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we are unable to do so as the C2 Server is unable has lost it's connection to the C2 Beacon:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Attempting to install the C2 RansomwareScript\n",
|
||||
"ransomware_install_command = {\"commands\":[[\"software_manager\", \"application\", \"install\", \"RansomwareScript\"]],\n",
|
||||
" \"username\": \"pass123\",\n",
|
||||
" \"password\": \"password123\"}\n",
|
||||
"\n",
|
||||
"c2_server: C2Server = client_1.software_manager.software[\"C2Server\"]\n",
|
||||
"c2_server._send_command(C2Command.TERMINAL, command_options=ransomware_install_command)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Shutting down the node infected with a C2 Beacon.\n",
|
||||
"\n",
|
||||
"Another way a blue agent can prevent the C2 suite is via shutting down the C2 beacon's host node. Whilst not as effective as the previous option, dependant on situation (such as multiple malicious applications) or other scenarios it may be more timestep efficient for a blue agent to shut down a node directly."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"blue_env.reset()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Setting up the C2 Suite using the c2_setup method & capturing the OBS impacts\n",
|
||||
"\n",
|
||||
"blue_env, c2_server, c2_beacon = c2_setup(blue_env=blue_env)\n",
|
||||
"pre_blue_action_obs, _, _, _, _ = blue_env.step(0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The code cell below uses the custom blue agent defined at the start of this section perform NODE_SHUT_DOWN on the web server."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Using CAOS ACTION: NODE_SHUT_DOWN & capturing the OBS\n",
|
||||
"post_blue_action_obs, _, _, _, _ = blue_env.step(2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Which we can see after the effects of after stepping another timestep and looking at the web_servers operating state & the OBS differences."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"web_server = blue_env.game.simulation.network.get_node_by_hostname(\"web_server\")\n",
|
||||
"print(web_server.operating_state)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"display_obs_diffs(pre_blue_action_obs, post_blue_action_obs, blue_env.game.step_counter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Attempting to install the C2 RansomwareScript\n",
|
||||
"ransomware_install_command = {\"commands\":[[\"software_manager\", \"application\", \"install\", \"RansomwareScript\"]],\n",
|
||||
" \"username\": \"pass123\",\n",
|
||||
" \"password\": \"password123\"}\n",
|
||||
"\n",
|
||||
"c2_server: C2Server = client_1.software_manager.software[\"C2Server\"]\n",
|
||||
"c2_server._send_command(C2Command.TERMINAL, command_options=ransomware_install_command)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Blocking C2 Traffic via ACL.\n",
|
||||
"\n",
|
||||
"Another potential option a blue agent could take is by placing an ACL rule which blocks traffic between the C2 Server can C2 Beacon.\n",
|
||||
"\n",
|
||||
"It's worth noting the potential effectiveness of approach is also linked by the current green agent traffic on the network. The same applies for the previous example."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"blue_env.reset()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Setting up the C2 Suite using the c2_setup method & capturing the OBS impacts\n",
|
||||
"\n",
|
||||
"blue_env, c2_server, c2_beacon = c2_setup(blue_env=blue_env)\n",
|
||||
"pre_blue_action_obs, _, _, _, _ = blue_env.step(0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The code cell below uses the custom blue agent defined at the start of this section to perform a ROUTER_ACL_ADDRULE on router 1."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Using CAOS ACTION: ROUTER_ACL_ADDRULE & capturing the OBS\n",
|
||||
"post_blue_action_obs, _, _, _, _ = blue_env.step(3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Which we can see after the effects of after stepping another timestep and looking at router 1's ACLs and the OBS differences."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"router_1: Router = blue_env.game.simulation.network.get_node_by_hostname(\"router_1\")\n",
|
||||
"router_1.acl.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"display_obs_diffs(default_obs, c2_ransomware_obs, env.game.step_counter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we can see that the C2 applications are unable to maintain connection - thus being unable to execute correctly."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Waiting for the ransomware to finish installing and then launching the RansomwareScript.\n",
|
||||
"blue_env.step(0)\n",
|
||||
"c2_server._send_command(C2Command.RANSOMWARE_LAUNCH, command_options={})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"router_1.acl.show()"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -3,7 +3,6 @@ from enum import Enum
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Dict, Optional
|
||||
|
||||
# from primaite.simulator.system.services.terminal.terminal import Terminal
|
||||
from prettytable import MARKDOWN, PrettyTable
|
||||
from pydantic import validate_call
|
||||
|
||||
@@ -15,6 +14,11 @@ from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.applications.application import ApplicationOperatingState
|
||||
from primaite.simulator.system.applications.red_applications.c2.abstract_c2 import AbstractC2, C2Command, C2Payload
|
||||
from primaite.simulator.system.applications.red_applications.ransomware_script import RansomwareScript
|
||||
from primaite.simulator.system.services.terminal.terminal import (
|
||||
LocalTerminalConnection,
|
||||
RemoteTerminalConnection,
|
||||
Terminal,
|
||||
)
|
||||
from primaite.simulator.system.software import SoftwareHealthState
|
||||
|
||||
|
||||
@@ -44,17 +48,19 @@ class C2Beacon(AbstractC2, identifier="C2Beacon"):
|
||||
keep_alive_frequency: int = 5
|
||||
"The frequency at which ``Keep Alive`` packets are sent to the C2 Server from the C2 Beacon."
|
||||
|
||||
# TODO:
|
||||
# Implement the placeholder command methods
|
||||
# Uncomment the terminal Import and the terminal property after terminal PR
|
||||
local_terminal_session: LocalTerminalConnection = None
|
||||
"""#TODO"""
|
||||
|
||||
# @property
|
||||
# def _host_terminal(self) -> Terminal:
|
||||
# """Return the Terminal that is installed on the same machine as the C2 Beacon."""
|
||||
# host_terminal: Terminal = self.software_manager.software.get("Terminal")
|
||||
# if host_terminal: is None:
|
||||
# self.sys_log.warning(f"{self.__class__.__name__} cannot find a terminal on its host.")
|
||||
# return host_terminal
|
||||
remote_terminal_session: RemoteTerminalConnection = None
|
||||
"""#TODO"""
|
||||
|
||||
@property
|
||||
def _host_terminal(self) -> Optional[Terminal]:
|
||||
"""Return the Terminal that is installed on the same machine as the C2 Beacon."""
|
||||
host_terminal: Terminal = self.software_manager.software.get("Terminal")
|
||||
if host_terminal is None:
|
||||
self.sys_log.warning(f"{self.__class__.__name__} cannot find a terminal on its host.")
|
||||
return host_terminal
|
||||
|
||||
@property
|
||||
def _host_ransomware_script(self) -> RansomwareScript:
|
||||
@@ -64,6 +70,26 @@ class C2Beacon(AbstractC2, identifier="C2Beacon"):
|
||||
self.sys_log.warning(f"{self.__class__.__name__} cannot find installed ransomware on its host.")
|
||||
return ransomware_script
|
||||
|
||||
def get_terminal_session(self, username: str, password: str) -> Optional[LocalTerminalConnection]:
|
||||
"""Return an instance of a Local Terminal Connection upon successful login. Otherwise returns None."""
|
||||
if self.local_terminal_session is None:
|
||||
host_terminal: Terminal = self._host_terminal
|
||||
self.local_terminal_session = host_terminal.login(username=username, password=password)
|
||||
|
||||
return self.local_terminal_session
|
||||
|
||||
def get_remote_terminal_session(
|
||||
self, username: str, password: str, ip_address: IPv4Address
|
||||
) -> Optional[RemoteTerminalConnection]:
|
||||
"""Return an instance of a Local Terminal Connection upon successful login. Otherwise returns None."""
|
||||
if self.remote_terminal_session is None:
|
||||
host_terminal: Terminal = self._host_terminal
|
||||
self.remote_terminal_session = host_terminal.login(
|
||||
username=username, password=password, ip_address=ip_address
|
||||
)
|
||||
|
||||
return self.remote_terminal_session
|
||||
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
"""
|
||||
Initialise the request manager.
|
||||
@@ -153,7 +179,6 @@ class C2Beacon(AbstractC2, identifier="C2Beacon"):
|
||||
)
|
||||
return True
|
||||
|
||||
# I THINK that once the application is running it can respond to incoming traffic but I'll need to test this later.
|
||||
def establish(self) -> bool:
|
||||
"""Establishes connection to the C2 server via a send alive. The C2 Beacon must already be configured."""
|
||||
if self.c2_remote_connection is None:
|
||||
@@ -269,7 +294,9 @@ class C2Beacon(AbstractC2, identifier="C2Beacon"):
|
||||
data={"Reason": "Cannot find any instances of a RansomwareScript. Have you installed one?"},
|
||||
)
|
||||
return RequestResponse.from_bool(
|
||||
self._host_ransomware_script.configure(server_ip_address=given_config["server_ip_address"])
|
||||
self._host_ransomware_script.configure(
|
||||
server_ip_address=given_config["server_ip_address"], payload=given_config["payload"]
|
||||
)
|
||||
)
|
||||
|
||||
def _command_ransomware_launch(self, payload: MasqueradePacket) -> RequestResponse:
|
||||
@@ -304,8 +331,44 @@ class C2Beacon(AbstractC2, identifier="C2Beacon"):
|
||||
:return: Returns the Request Response returned by the Terminal execute method.
|
||||
:rtype: Request Response
|
||||
"""
|
||||
# TODO: uncomment and replace (uses terminal)
|
||||
return RequestResponse(status="success", data={"Reason": "Placeholder."})
|
||||
terminal_output: Dict[int, RequestResponse] = {}
|
||||
given_commands: list[RequestFormat]
|
||||
|
||||
if self._host_terminal is None:
|
||||
return RequestResponse(
|
||||
status="failure",
|
||||
data={"Reason": "Host does not seem to have terminal installed. Unable to resolve command."},
|
||||
)
|
||||
|
||||
# TODO: Placeholder until further details on handling user sessions.
|
||||
given_commands = payload.payload.get("commands")
|
||||
given_username = payload.payload.get("username")
|
||||
given_password = payload.payload.get("password")
|
||||
remote_ip = payload.payload.get("ip_address")
|
||||
|
||||
# Creating a remote terminal session if given an IP Address, otherwise using a local terminal session.
|
||||
if payload.payload.get("ip_address") is None:
|
||||
terminal_session = self.get_terminal_session(username=given_username, password=given_password)
|
||||
else:
|
||||
terminal_session = self.get_remote_terminal_session(
|
||||
username=given_username, password=given_password, ip_address=remote_ip
|
||||
)
|
||||
|
||||
if terminal_session is None:
|
||||
RequestResponse(
|
||||
status="failure",
|
||||
data={"Reason": "Host cannot is unable to connect to terminal. Unable to resolve command."},
|
||||
)
|
||||
|
||||
for index, given_command in enumerate(given_commands):
|
||||
# A try catch exception ladder was used but was considered not the best approach
|
||||
# as it can end up obscuring visibility of actual bugs (Not the expected ones) and was a temporary solution.
|
||||
# TODO: Refactor + add further validation to ensure that a request is correct. (maybe a pydantic method?)
|
||||
terminal_output[index] = terminal_session.execute(given_command)
|
||||
|
||||
# Reset our remote terminal session.
|
||||
self.remote_terminal_session is None
|
||||
return RequestResponse(status="success", data=terminal_output)
|
||||
|
||||
def _handle_keep_alive(self, payload: MasqueradePacket, session_id: Optional[str]) -> bool:
|
||||
"""
|
||||
|
||||
@@ -47,8 +47,10 @@ class C2Server(AbstractC2, identifier="C2Server"):
|
||||
:return: RequestResponse object with a success code reflecting whether the configuration could be applied.
|
||||
:rtype: RequestResponse
|
||||
"""
|
||||
# TODO: Parse the parameters from the request to get the parameters
|
||||
ransomware_config = {"server_ip_address": request[-1].get("server_ip_address")}
|
||||
ransomware_config = {
|
||||
"server_ip_address": request[-1].get("server_ip_address"),
|
||||
"payload": request[-1].get("payload"),
|
||||
}
|
||||
return self._send_command(given_command=C2Command.RANSOMWARE_CONFIGURE, command_options=ransomware_config)
|
||||
|
||||
def _launch_ransomware_action(request: RequestFormat, context: Dict) -> RequestResponse:
|
||||
@@ -73,9 +75,8 @@ class C2Server(AbstractC2, identifier="C2Server"):
|
||||
:return: RequestResponse object with a success code reflecting whether the ransomware was launched.
|
||||
:rtype: RequestResponse
|
||||
"""
|
||||
# TODO: Parse the parameters from the request to get the parameters
|
||||
terminal_commands = {"commands": request[-1].get("commands")}
|
||||
return self._send_command(given_command=C2Command.TERMINAL, command_options=terminal_commands)
|
||||
command_payload = request[-1]
|
||||
return self._send_command(given_command=C2Command.TERMINAL, command_options=command_payload)
|
||||
|
||||
rm.add_request(
|
||||
name="ransomware_configure",
|
||||
@@ -174,7 +175,7 @@ class C2Server(AbstractC2, identifier="C2Server"):
|
||||
---------------------|------------------------
|
||||
RANSOMWARE_CONFIGURE | Configures an installed ransomware script based on the passed parameters.
|
||||
RANSOMWARE_LAUNCH | Launches the installed ransomware script.
|
||||
Terminal | Executes a command via the terminal installed on the C2 Beacons Host.
|
||||
TERMINAL | Executes a command via the terminal installed on the C2 Beacons Host.
|
||||
|
||||
For more information on the impact of these commands please refer to the terminal
|
||||
and the ransomware applications.
|
||||
@@ -198,6 +199,18 @@ class C2Server(AbstractC2, identifier="C2Server"):
|
||||
status="failure", data={"Reason": "Unable to access networking resources. Unable to send command."}
|
||||
)
|
||||
|
||||
if self.c2_remote_connection is False:
|
||||
self.sys_log.warning(f"{self.name}: C2 Beacon has yet to establish connection. Rejecting command.")
|
||||
return RequestResponse(
|
||||
status="failure", data={"Reason": "C2 Beacon has yet to establish connection. Unable to send command."}
|
||||
)
|
||||
|
||||
if self.current_c2_session is None:
|
||||
self.sys_log.warning(f"{self.name}: C2 Beacon cannot be reached. Rejecting command.")
|
||||
return RequestResponse(
|
||||
status="failure", data={"Reason": "C2 Beacon cannot be reached. Unable to send command."}
|
||||
)
|
||||
|
||||
self.sys_log.info(f"{self.name}: Attempting to send command {given_command}.")
|
||||
command_packet = self._craft_packet(given_command=given_command, command_options=command_options)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user