From 2ae796cd7f073a4e307fed3b930f905dadb97fc1 Mon Sep 17 00:00:00 2001 From: Kekoa Kaaikala Date: Thu, 6 Apr 2023 20:25:18 +0000 Subject: [PATCH] BB: Test agent role authentication --- .../blackbox/island_client/agent_requests.py | 83 +++++++++++++++++++ envs/monkey_zoo/blackbox/test_blackbox.py | 60 ++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 envs/monkey_zoo/blackbox/island_client/agent_requests.py diff --git a/envs/monkey_zoo/blackbox/island_client/agent_requests.py b/envs/monkey_zoo/blackbox/island_client/agent_requests.py new file mode 100644 index 00000000000..98b700306ea --- /dev/null +++ b/envs/monkey_zoo/blackbox/island_client/agent_requests.py @@ -0,0 +1,83 @@ +from http import HTTPStatus +from typing import Dict + +import requests + +from common.types import OTP, AgentID + +from .i_monkey_island_requests import IMonkeyIslandRequests + + +class InvalidRequestError(Exception): + pass + + +class AgentRequests(IMonkeyIslandRequests): + def __init__(self, server_address, agent_id: AgentID, otp: OTP): + self.addr = f"https://{server_address}/" + self.token = None + self.agent_id = agent_id + self.otp = otp + + def login(self): + self.token = self._try_register_otp() + + def _try_register_otp(self): + resp = requests.post( # noqa: DUO123 + self.addr + "api/agent-otp-login", + json={"agent_id": str(self.agent_id), "otp": self.otp.get_secret_value()}, + verify=False, + ) + if resp.status_code == HTTPStatus.CONFLICT: + # A user has already been registered + return self.get_token_from_server() + + if resp.status_code == HTTPStatus.BAD_REQUEST: + raise InvalidRequestError() + + token = resp.json()["response"]["user"]["authentication_token"] + return token + + def get_token_from_server(self): + return self.token + + def get(self, url, data=None): + return requests.get( # noqa: DUO123 + self.addr + url, + headers=self.get_auth_header(), + params=data, + verify=False, + ) + + def post(self, url, data): + return requests.post( # noqa: DUO123 + self.addr + url, data=data, headers=self.get_auth_header(), verify=False + ) + + def put(self, url, data): + return requests.put( # noqa: DUO123 + self.addr + url, data=data, headers=self.get_auth_header(), verify=False + ) + + def put_json(self, url, json: Dict): + return requests.put( # noqa: DUO123 + self.addr + url, json=json, headers=self.get_auth_header(), verify=False + ) + + def post_json(self, url, json: Dict): + return requests.post( # noqa: DUO123 + self.addr + url, json=json, headers=self.get_auth_header(), verify=False + ) + + def patch(self, url, data: Dict): + return requests.patch( # noqa: DUO123 + self.addr + url, data=data, headers=self.get_auth_header(), verify=False + ) + + def delete(self, url): + return requests.delete( # noqa: DUO123 + self.addr + url, headers=self.get_auth_header(), verify=False + ) + + def get_auth_header(self): + return {"Authentication-Token": self.token} diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index 2f2dd2892e2..5832da1b5e2 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -7,10 +7,13 @@ import pytest import requests +from common.types import OTP from envs.monkey_zoo.blackbox.analyzers.communication_analyzer import CommunicationAnalyzer from envs.monkey_zoo.blackbox.analyzers.zerologon_analyzer import ZerologonAnalyzer +from envs.monkey_zoo.blackbox.island_client.agent_requests import AgentRequests from envs.monkey_zoo.blackbox.island_client.i_monkey_island_requests import IMonkeyIslandRequests from envs.monkey_zoo.blackbox.island_client.monkey_island_client import ( + GET_AGENT_EVENTS_ENDPOINT, GET_AGENTS_ENDPOINT, GET_MACHINES_ENDPOINT, ISLAND_LOG_ENDPOINT, @@ -212,6 +215,63 @@ def test_island__cannot_access_nonisland_endpoints(island): assert requests.post(GET_AGENTS_ENDPOINT, data=None).status_code == HTTPStatus.FORBIDDEN +GET_AGENT_OTP_ENDPOINT = "/api/agent-otp" +REQUESTS_AGENT_ID = "00000000-0000-0000-0000-000000000001" +TERMINATE_AGENTS_ENDPOINT = "/api/agent-signals/terminate-all-agents" +CLEAR_SIMULATION_DATA_ENDPOINT = "/api/clear-simulation-data" +MONKEY_EXPLOITATION_ENDPOINT = "/api/exploitations/monkey" +GET_ISLAND_LOG_ENDPOINT = "/api/island/log" +ISLAND_MODE_ENDPOINT = "/api/island/mode" +ISLAND_RUN_ENDPOINT = "/api/local-monkey" +GET_NODES_ENDPOINT = "/api/nodes" +PROPAGATION_CREDENTIALS_ENDPOINT = "/api/propagation-credentials" +GET_RANSOMWARE_REPORT_ENDPOINT = "/api/report/ransomware" +REMOTE_RUN_ENDPOINT = "/api/remote-monkey" +GET_REPORT_STATUS_ENDPOINT = "/api/report-generation-status" +RESET_AGENT_CONFIG_ENDPOINT = "/api/reset-agent-configuration" +GET_SECURITY_REPORT_ENDPOINT = "/api/report/security" +GET_ISLAND_VERSION_ENDPOINT = "/api/island/version" +PUT_AGENT_CONFIG_ENDPOINT = "/api/agent-configuration" + + +def test_agent__cannot_access_nonagent_endpoints(island): + island_requests = MonkeyIslandRequests(island) + island_requests.login() + response = island_requests.get(GET_AGENT_OTP_ENDPOINT) + print(f"response: {response.json()}") + otp = response.json()["otp"] + + requests = AgentRequests(island, REQUESTS_AGENT_ID, OTP(otp)) + requests.login() + + assert requests.get(GET_AGENT_EVENTS_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.get(PUT_LOG_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.post(TERMINATE_AGENTS_ENDPOINT, data=None).status_code == HTTPStatus.FORBIDDEN + assert requests.get(GET_AGENTS_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert ( + requests.post(CLEAR_SIMULATION_DATA_ENDPOINT, data=None).status_code == HTTPStatus.FORBIDDEN + ) + assert requests.get(MONKEY_EXPLOITATION_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.get(GET_ISLAND_LOG_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.get(ISLAND_MODE_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.put(ISLAND_MODE_ENDPOINT, data=None).status_code == HTTPStatus.FORBIDDEN + assert requests.post(ISLAND_RUN_ENDPOINT, data=None).status_code == HTTPStatus.FORBIDDEN + assert requests.get(GET_MACHINES_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.get(GET_NODES_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert ( + requests.put(PROPAGATION_CREDENTIALS_ENDPOINT, data=None).status_code + == HTTPStatus.FORBIDDEN + ) + assert requests.get(GET_RANSOMWARE_REPORT_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.get(REMOTE_RUN_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.post(REMOTE_RUN_ENDPOINT, data=None).status_code == HTTPStatus.FORBIDDEN + assert requests.get(GET_REPORT_STATUS_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.post(RESET_AGENT_CONFIG_ENDPOINT, data=None).status_code == HTTPStatus.FORBIDDEN + assert requests.get(GET_SECURITY_REPORT_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.get(GET_ISLAND_VERSION_ENDPOINT).status_code == HTTPStatus.FORBIDDEN + assert requests.put(PUT_AGENT_CONFIG_ENDPOINT, data=None).status_code == HTTPStatus.FORBIDDEN + + # NOTE: These test methods are ordered to give time for the slower zoo machines # to boot up and finish starting services. # noinspection PyUnresolvedReferences