From 78f792aee9c2b6a575b2543c0455dda27eb2f8d0 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Mon, 22 Aug 2022 13:23:08 -0400 Subject: [PATCH] Island: Add /api/agents endpoint --- CHANGELOG.md | 1 + monkey/monkey_island/cc/app.py | 2 + monkey/monkey_island/cc/resources/__init__.py | 1 + monkey/monkey_island/cc/resources/agents.py | 22 ++++++++++ .../monkey_island/cc/resources/test_agents.py | 42 +++++++++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 monkey/monkey_island/cc/resources/agents.py create mode 100644 monkey/tests/unit_tests/monkey_island/cc/resources/test_agents.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 095c32baa..8a7e48601 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/). - `/api/events` endpoint. #2155 - The ability to customize the file extension used by ransomware when encrypting files. #1242 +- `/api/agents` endpoint. ### Changed - Reset workflow. Now it's possible to delete data gathered by agents without diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index d27fd24bf..353b4ca73 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -13,6 +13,7 @@ from monkey_island.cc.database import database, mongo from monkey_island.cc.resources import ( AgentBinaries, AgentConfiguration, + Agents, ClearSimulationData, Events, IPAddresses, @@ -162,6 +163,7 @@ def init_restful_endpoints(api: FlaskDIWrapper): api.add_resource(Register) api.add_resource(RegistrationStatus) api.add_resource(Authenticate) + api.add_resource(Agents) api.add_resource(Monkey) api.add_resource(LocalRun) api.add_resource(Telemetry) diff --git a/monkey/monkey_island/cc/resources/__init__.py b/monkey/monkey_island/cc/resources/__init__.py index b58e159bc..980414a8f 100644 --- a/monkey/monkey_island/cc/resources/__init__.py +++ b/monkey/monkey_island/cc/resources/__init__.py @@ -9,3 +9,4 @@ from .agent_configuration import AgentConfiguration from .pba_file_upload import PBAFileUpload, LINUX_PBA_TYPE, WINDOWS_PBA_TYPE from .pba_file_download import PBAFileDownload from .events import Events +from .agents import Agents diff --git a/monkey/monkey_island/cc/resources/agents.py b/monkey/monkey_island/cc/resources/agents.py new file mode 100644 index 000000000..79d6fc872 --- /dev/null +++ b/monkey/monkey_island/cc/resources/agents.py @@ -0,0 +1,22 @@ +import json +from http import HTTPStatus + +from flask import make_response, request + +from common import AgentRegistrationData +from monkey_island.cc.resources.AbstractResource import AbstractResource + + +class Agents(AbstractResource): + urls = ["/api/agents"] + + def post(self): + try: + # Just parse for now + AgentRegistrationData(**request.json) + return make_response({}, HTTPStatus.NO_CONTENT) + except (TypeError, ValueError, json.JSONDecodeError) as err: + return make_response( + {"error": f"Invalid configuration supplied: {err}"}, + HTTPStatus.BAD_REQUEST, + ) diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agents.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agents.py new file mode 100644 index 000000000..3ab90feb6 --- /dev/null +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agents.py @@ -0,0 +1,42 @@ +from http import HTTPStatus +from uuid import UUID + +from tests.unit_tests.monkey_island.conftest import get_url_for_resource + +from monkey_island.cc.resources import Agents + +AGENTS_URL = get_url_for_resource(Agents) + +AGENT_REGISTRATION_DICT = { + "id": UUID("6bfd8b64-43d8-4449-8c70-d898aca74ad8"), + "machine_hardware_id": 1, + "start_time": 0, + "parent_id": UUID("9d55ba33-95c2-417d-bd86-d3d11e47daeb"), + "cc_server": "10.0.0.1:5000", + "network_interfaces": ["10.1.1.2/24"], +} + + +def test_agent_registration(flask_client): + print(AGENTS_URL) + resp = flask_client.post( + AGENTS_URL, + json=AGENT_REGISTRATION_DICT, + follow_redirects=True, + ) + + assert resp.status_code == HTTPStatus.NO_CONTENT + + +def test_agent_registration_invalid_data(flask_client): + agent_registration_dict = AGENT_REGISTRATION_DICT.copy() + + agent_registration_dict["id"] = 1 + + resp = flask_client.post( + AGENTS_URL, + json=agent_registration_dict, + follow_redirects=True, + ) + + assert resp.status_code == HTTPStatus.BAD_REQUEST