From 0b35c483cb96696ca9e5207452bf933624a4c547 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Mon, 10 Jun 2024 09:39:53 -0400 Subject: [PATCH] Agent: Shorten reservation ID Per Issue #4187, there are cases when download strings must be shorter. In order to achieve this, random strings from a set of 62 characters are generated. Using 5 characters gives something like 916M possible values, which is more than enough for any single agent. --- monkey/infection_monkey/Pipfile | 2 +- monkey/infection_monkey/Pipfile.lock | 38 ++++++------------ .../exploit/http_agent_binary_server.py | 9 +++-- .../test_http_agent_binary_request_handler.py | 40 +++++++++---------- .../exploit/test_http_agent_binary_server.py | 8 ++-- 5 files changed, 44 insertions(+), 53 deletions(-) diff --git a/monkey/infection_monkey/Pipfile b/monkey/infection_monkey/Pipfile index e6bb68a5270..bffc5624475 100644 --- a/monkey/infection_monkey/Pipfile +++ b/monkey/infection_monkey/Pipfile @@ -26,7 +26,7 @@ email-validator = "*" monkey-types = "*" monkeyevents = "*" monkeytoolbox = "*" -monkey-agentpluginapi = ">=0.7.0" +monkey-agentpluginapi = "*" [dev-packages] mypy = "*" diff --git a/monkey/infection_monkey/Pipfile.lock b/monkey/infection_monkey/Pipfile.lock index bb536c60f06..d1e5422ff16 100644 --- a/monkey/infection_monkey/Pipfile.lock +++ b/monkey/infection_monkey/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "79aa0e416b8cb984edf5f326a374040a66940241f1f2d9317c8caaf7d868607d" + "sha256": "252e5b0bd15afb37a884b9f0e7c1c6ec970d54ab376587dea07e61f14e739a09" }, "pipfile-spec": 6, "requires": { @@ -25,11 +25,11 @@ }, "annotated-types": { "hashes": [ - "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43", - "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d" + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" ], "markers": "python_version >= '3.8'", - "version": "==0.6.0" + "version": "==0.7.0" }, "attrs": { "hashes": [ @@ -245,7 +245,6 @@ "sha256:8f0d8eebd3ef08054cc2251d04cc19105baaffb4792b2f88c56f40d680dd242a" ], "index": "pypi", - "markers": "python_version >= '3.7' and python_version < '4.0'", "version": "==1.3.0" }, "email-validator": { @@ -254,7 +253,6 @@ "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05" ], "index": "pypi", - "markers": "python_version >= '3.8'", "version": "==2.1.1" }, "idna": { @@ -300,12 +298,11 @@ }, "monkey-agentpluginapi": { "hashes": [ - "sha256:070e33af5c2ff4e828605e9661b9b37b6928666eb0d64008e8eca5328afd8cf5", - "sha256:1e6961cfe24944d2fb91a9a3d11c62ee98807839de27d364ed5a35e99fe4c438" + "sha256:6e4ed986fcacefa1bd043dc167a869ba2b3ccbe7f25a3c52cebdb275444d41f9", + "sha256:f4124176d84235318e7733f92c96451d4cf905ba6ce96089efced1e5ed851181" ], "index": "pypi", - "markers": "python_version >= '3.11' and python_version < '4.0'", - "version": "==0.7.0" + "version": "==0.8.0" }, "monkey-types": { "hashes": [ @@ -313,7 +310,6 @@ "sha256:7a2fd19772b444abb1d07c07d63cde7410ac05d2ae846292f4eda8423d5496b2" ], "index": "pypi", - "markers": "python_version >= '3.11' and python_version < '4.0'", "version": "==0.6.0" }, "monkeyevents": { @@ -322,7 +318,6 @@ "sha256:c4b156d8851bf1552eda8627a1463fbf85a015eea30c6ae4a344a13bdd40b894" ], "index": "pypi", - "markers": "python_version >= '3.11' and python_version < '4.0'", "version": "==0.4.0" }, "monkeytoolbox": { @@ -331,7 +326,6 @@ "sha256:ed00885331e938879330badf0ad6ad17cbfcc26d78eef1ccae0155282397a673" ], "index": "pypi", - "markers": "python_version >= '3.11' and python_version < '4.0'", "version": "==0.3.0" }, "odict": { @@ -377,7 +371,6 @@ "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8" ], "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==5.9.8" }, "pycparser": { @@ -388,15 +381,11 @@ "version": "==2.21" }, "pydantic": { - "extras": [ - "email" - ], "hashes": [ "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a", "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4" ], "index": "pypi", - "markers": "python_version >= '3.7'", "version": "==2.5.3" }, "pydantic-core": { @@ -701,7 +690,6 @@ "sha256:fa0fe2722ee1c3f57eac478820c3a5ae2f624af8264cbdf9000c980ff7f75e3f" ], "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.13.0" }, "serpentarium": { @@ -723,11 +711,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", - "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "markers": "python_version >= '3.8'", - "version": "==4.11.0" + "version": "==4.12.2" }, "urllib3": { "hashes": [ @@ -873,11 +861,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.11.0" } } } diff --git a/monkey/infection_monkey/exploit/http_agent_binary_server.py b/monkey/infection_monkey/exploit/http_agent_binary_server.py index 77047b392d3..35ee146fc7d 100644 --- a/monkey/infection_monkey/exploit/http_agent_binary_server.py +++ b/monkey/infection_monkey/exploit/http_agent_binary_server.py @@ -3,7 +3,6 @@ from http.server import HTTPServer from ipaddress import IPv4Address from typing import Callable, Optional, Type -from uuid import uuid4 from agentpluginapi import ( AgentBinaryDownloadReservation, @@ -12,7 +11,11 @@ LocalMachineInfo, ReservationID, ) -from monkeytoolbox import create_daemon_thread, insecure_generate_random_string +from monkeytoolbox import ( + create_daemon_thread, + insecure_generate_random_string, + secure_generate_random_string, +) from monkeytypes import Event, Lock, NetworkPort, OperatingSystem from .http_agent_binary_request_handler import AgentBinaryHTTPRequestHandler @@ -79,7 +82,7 @@ def register( if not self.server_is_running(): self._start_server() - reservation_id = uuid4() + reservation_id = secure_generate_random_string(n=5) url = self._build_request_url(reservation_id, operating_system, requestor_ip) reservation = AgentBinaryDownloadReservation( reservation_id, diff --git a/monkey/tests/unit_tests/infection_monkey/exploit/test_http_agent_binary_request_handler.py b/monkey/tests/unit_tests/infection_monkey/exploit/test_http_agent_binary_request_handler.py index d9ae13c153d..57e927531e6 100644 --- a/monkey/tests/unit_tests/infection_monkey/exploit/test_http_agent_binary_request_handler.py +++ b/monkey/tests/unit_tests/infection_monkey/exploit/test_http_agent_binary_request_handler.py @@ -2,7 +2,7 @@ from http import HTTPStatus from http.server import HTTPServer from io import BytesIO -from typing import Type +from typing import Final, Type from unittest.mock import MagicMock import pytest @@ -20,16 +20,15 @@ get_http_handler, ) -AGENT_BINARY = b"agent_binary" -DROPPER_BINARY = b"dropper_agent_binary" -IP = "127.0.0.1" -UUID_1 = ReservationID("00000000-0000-0000-0000-000000000001") -UUID_2 = ReservationID("00000000-0000-0000-0000-000000000002") -UUID_3 = ReservationID("00000000-0000-0000-0000-000000000003") +AGENT_BINARY: Final = b"agent_binary" +DROPPER_BINARY: Final = b"dropper_agent_binary" +IP: Final = "127.0.0.1" +RESERVATION_ID_1: Final = ReservationID("abcABC1") +RESERVATION_ID_2: Final = ReservationID("abcABC2") +RESERVATION_ID_3: Final = ReservationID("abcABC2") - -DEFAULT_AGENT_TEMPLATE = b"%(agent_binary)s" -DROPPER_AGENT_TEMPLATE = b"dropper_%(agent_binary)s" +DEFAULT_AGENT_TEMPLATE: Final = b"%(agent_binary)s" +DROPPER_AGENT_TEMPLATE: Final = b"dropper_%(agent_binary)s" @pytest.fixture @@ -40,10 +39,10 @@ def port(tcp_port_selector) -> int: @pytest.fixture def binary_request_1(port) -> AgentBinaryDownloadReservation: return AgentBinaryDownloadReservation( - UUID_1, + RESERVATION_ID_1, OperatingSystem.LINUX, DEFAULT_AGENT_TEMPLATE, - f"http://{IP}:{port}/{UUID_1}", + f"http://{IP}:{port}/{RESERVATION_ID_1}", threading.Event(), ) @@ -51,10 +50,10 @@ def binary_request_1(port) -> AgentBinaryDownloadReservation: @pytest.fixture def binary_request_2(port) -> AgentBinaryDownloadReservation: return AgentBinaryDownloadReservation( - UUID_2, + RESERVATION_ID_2, OperatingSystem.WINDOWS, DEFAULT_AGENT_TEMPLATE, - f"http://{IP}:{port}/{UUID_2}", + f"http://{IP}:{port}/{RESERVATION_ID_2}", threading.Event(), ) @@ -62,10 +61,10 @@ def binary_request_2(port) -> AgentBinaryDownloadReservation: @pytest.fixture def binary_request_3(port) -> AgentBinaryDownloadReservation: return AgentBinaryDownloadReservation( - UUID_2, + RESERVATION_ID_2, OperatingSystem.WINDOWS, None, - f"http://{IP}:{port}/{UUID_2}", + f"http://{IP}:{port}/{RESERVATION_ID_2}", threading.Event(), ) @@ -73,10 +72,10 @@ def binary_request_3(port) -> AgentBinaryDownloadReservation: @pytest.fixture def dropper_request_1(port) -> AgentBinaryDownloadReservation: return AgentBinaryDownloadReservation( - UUID_1, + RESERVATION_ID_1, OperatingSystem.LINUX, DROPPER_AGENT_TEMPLATE, - f"http://{IP}:{port}/{UUID_1}", + f"http://{IP}:{port}/{RESERVATION_ID_1}", threading.Event(), ) @@ -84,10 +83,10 @@ def dropper_request_1(port) -> AgentBinaryDownloadReservation: @pytest.fixture def dropper_request_2(port) -> AgentBinaryDownloadReservation: return AgentBinaryDownloadReservation( - UUID_2, + RESERVATION_ID_2, OperatingSystem.WINDOWS, DROPPER_AGENT_TEMPLATE, - f"http://{IP}:{port}/{UUID_2}", + f"http://{IP}:{port}/{RESERVATION_ID_2}", threading.Event(), ) @@ -302,3 +301,4 @@ def test_agent_binary_request__is_transformed( assert response.status_code == HTTPStatus.OK assert response.content == DROPPER_BINARY + assert response.content == DROPPER_BINARY diff --git a/monkey/tests/unit_tests/infection_monkey/exploit/test_http_agent_binary_server.py b/monkey/tests/unit_tests/infection_monkey/exploit/test_http_agent_binary_server.py index be573d45fe4..8e1245a1ab5 100644 --- a/monkey/tests/unit_tests/infection_monkey/exploit/test_http_agent_binary_server.py +++ b/monkey/tests/unit_tests/infection_monkey/exploit/test_http_agent_binary_server.py @@ -7,7 +7,7 @@ from multiprocessing.managers import SyncManager from pathlib import Path from queue import Queue -from typing import List, Tuple, Type +from typing import Final, List, Tuple, Type from unittest.mock import MagicMock import pytest @@ -19,8 +19,8 @@ from infection_monkey.exploit.http_agent_binary_server import HTTPAgentBinaryServer from infection_monkey.network import TCPPortSelector -REQUESTOR_IP = IPv4Address("1.1.1.1") -UUID_1 = ReservationID("00000000-0000-0000-0000-000000000001") +REQUESTOR_IP: Final = IPv4Address("1.1.1.1") +RESERVATION_ID_1: Final = ReservationID("abcdABCD1") def use_agent_binary(agent_binary: bytes) -> bytes: @@ -188,7 +188,7 @@ def test_deregister__raises_error_on_invalid_reservation_id( mock_http_handler = mock_agent_binary_http_handler mock_http_handler.clear_reservation_mock.side_effect = KeyError # type: ignore[attr-defined] with pytest.raises(KeyError): - http_agent_binary_server.deregister(UUID_1) + http_agent_binary_server.deregister(RESERVATION_ID_1) @pytest.mark.xdist_group(name="tcp_port_selector")