From 408de5f5ab3a32d152da026bb10d83f4ae8dcd41 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 11:51:50 +0530 Subject: [PATCH 01/14] Island: Change /api/log/island/download -> /api/island/log --- monkey/monkey_island/cc/resources/island_logs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/resources/island_logs.py b/monkey/monkey_island/cc/resources/island_logs.py index 24162ba3e..85184e0c5 100644 --- a/monkey/monkey_island/cc/resources/island_logs.py +++ b/monkey/monkey_island/cc/resources/island_logs.py @@ -8,8 +8,7 @@ logger = logging.getLogger(__name__) class IslandLog(AbstractResource): - # API Spec: Why the inconsistency in endpoints of IslandLog and Log? - urls = ["/api/log/island/download"] + urls = ["/api/island/log"] @jwt_required def get(self): From e7e424b358fab648ca23e8617ae24cb202aa4158 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 11:52:31 +0530 Subject: [PATCH 02/14] UI: Change /api/log/island/download -> /api/island/log --- .../cc/ui/src/components/map/preview-pane/PreviewPane.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/map/preview-pane/PreviewPane.js b/monkey/monkey_island/cc/ui/src/components/map/preview-pane/PreviewPane.js index f9a09bb4c..cc2074107 100644 --- a/monkey/monkey_island/cc/ui/src/components/map/preview-pane/PreviewPane.js +++ b/monkey/monkey_island/cc/ui/src/components/map/preview-pane/PreviewPane.js @@ -87,7 +87,7 @@ class PreviewPaneComponent extends AuthComponent { Download Island Server Log - + } From 988f393a20bd88af0de46093f444555981fdccf9 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 13:17:44 +0530 Subject: [PATCH 03/14] Island: Add get_log_file() to cc/server_utils/island_logger.py --- .../cc/server_utils/island_logger.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/monkey/monkey_island/cc/server_utils/island_logger.py b/monkey/monkey_island/cc/server_utils/island_logger.py index 513d5031c..c0f55a3aa 100644 --- a/monkey/monkey_island/cc/server_utils/island_logger.py +++ b/monkey/monkey_island/cc/server_utils/island_logger.py @@ -2,6 +2,7 @@ import logging import logging.handlers import sys from pathlib import Path +from typing import Mapping ISLAND_LOG_FILENAME = "monkey_island.log" LOG_FORMAT = "%(asctime)s - %(levelname)s - %(filename)s:%(lineno)s - %(funcName)s() - %(message)s" @@ -63,3 +64,26 @@ def reset_logger(): for handler in logger.handlers: logger.removeHandler(handler) + + +def get_log_file() -> Mapping: + """ + This is a helper function for the Monkey Island log download function. + It finds the logger handlers and checks if one of them is a fileHandler of any kind by + checking if the handler has the property handler.baseFilename. + + :return: A dict with log file contents + """ + logger = logging.getLogger(__name__) + + logger_handlers = logger.parent.handlers + for handler in logger_handlers: + if hasattr(handler, "baseFilename"): + logger.info("Log file found: {0}".format(handler.baseFilename)) + log_file_path = handler.baseFilename + with open(log_file_path, "rt") as f: + log_file = f.read() + return {"log_file": log_file} + + logger.warning("No log file could be found, check logger config.") + return None From 8da12a7970e8acb741f82abcf79b6dc5e74c8dab Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 13:24:13 +0530 Subject: [PATCH 04/14] Island: Modify function get_log_file() -> get_log_file_path() --- .../cc/server_utils/island_logger.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/monkey/monkey_island/cc/server_utils/island_logger.py b/monkey/monkey_island/cc/server_utils/island_logger.py index c0f55a3aa..cf89c76f7 100644 --- a/monkey/monkey_island/cc/server_utils/island_logger.py +++ b/monkey/monkey_island/cc/server_utils/island_logger.py @@ -2,7 +2,7 @@ import logging import logging.handlers import sys from pathlib import Path -from typing import Mapping +from typing import Optional ISLAND_LOG_FILENAME = "monkey_island.log" LOG_FORMAT = "%(asctime)s - %(levelname)s - %(filename)s:%(lineno)s - %(funcName)s() - %(message)s" @@ -66,14 +66,14 @@ def reset_logger(): logger.removeHandler(handler) -def get_log_file() -> Mapping: +def get_log_file_path() -> Optional[str]: """ - This is a helper function for the Monkey Island log download function. - It finds the logger handlers and checks if one of them is a fileHandler of any kind by - checking if the handler has the property handler.baseFilename. + Finds the log file by finding the logger handlers and checking if one of them is a fileHandler + of any kind by checking if the handler has the property handler.baseFilename. - :return: A dict with log file contents + :return: Log file path """ + logger = logging.getLogger(__name__) logger_handlers = logger.parent.handlers @@ -81,9 +81,7 @@ def get_log_file() -> Mapping: if hasattr(handler, "baseFilename"): logger.info("Log file found: {0}".format(handler.baseFilename)) log_file_path = handler.baseFilename - with open(log_file_path, "rt") as f: - log_file = f.read() - return {"log_file": log_file} + return log_file_path logger.warning("No log file could be found, check logger config.") return None From 24aea692205b01a30e0dcf6e0a97b139ed74d3a2 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 13:25:30 +0530 Subject: [PATCH 05/14] Island: Return Path in get_log_file_path() instead of str --- monkey/monkey_island/cc/server_utils/island_logger.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/server_utils/island_logger.py b/monkey/monkey_island/cc/server_utils/island_logger.py index cf89c76f7..06cb82fd8 100644 --- a/monkey/monkey_island/cc/server_utils/island_logger.py +++ b/monkey/monkey_island/cc/server_utils/island_logger.py @@ -66,7 +66,7 @@ def reset_logger(): logger.removeHandler(handler) -def get_log_file_path() -> Optional[str]: +def get_log_file_path() -> Optional[Path]: """ Finds the log file by finding the logger handlers and checking if one of them is a fileHandler of any kind by checking if the handler has the property handler.baseFilename. @@ -81,7 +81,7 @@ def get_log_file_path() -> Optional[str]: if hasattr(handler, "baseFilename"): logger.info("Log file found: {0}".format(handler.baseFilename)) log_file_path = handler.baseFilename - return log_file_path + return Path(log_file_path) logger.warning("No log file could be found, check logger config.") return None From b89ffbae241dddadba9b1a210fd8698b545be4a1 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 13:28:19 +0530 Subject: [PATCH 06/14] Island: Register Island log file path as convention in DI container and inject into IslandLog --- monkey/monkey_island/cc/resources/island_logs.py | 4 ++++ monkey/monkey_island/cc/services/initialize.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/monkey/monkey_island/cc/resources/island_logs.py b/monkey/monkey_island/cc/resources/island_logs.py index 85184e0c5..3e37e1748 100644 --- a/monkey/monkey_island/cc/resources/island_logs.py +++ b/monkey/monkey_island/cc/resources/island_logs.py @@ -1,4 +1,5 @@ import logging +from pathlib import Path from monkey_island.cc.resources.AbstractResource import AbstractResource from monkey_island.cc.resources.request_authentication import jwt_required @@ -10,6 +11,9 @@ logger = logging.getLogger(__name__) class IslandLog(AbstractResource): urls = ["/api/island/log"] + def __init__(self, island_log_file_path: Path): + self._island_log_file_path = island_log_file_path + @jwt_required def get(self): try: diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py index c3623e716..ff2872c7f 100644 --- a/monkey/monkey_island/cc/services/initialize.py +++ b/monkey/monkey_island/cc/services/initialize.py @@ -32,6 +32,7 @@ from monkey_island.cc.repository import ( ) from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH from monkey_island.cc.server_utils.encryption import ILockableEncryptor, RepositoryEncryptor +from monkey_island.cc.server_utils.island_logger import get_log_file_path from monkey_island.cc.services import AWSService, IslandModeService, RepositoryService from monkey_island.cc.services.attack.technique_reports.T1003 import T1003, T1003GetReportData from monkey_island.cc.services.run_local_monkey import LocalMonkeyRunService @@ -87,6 +88,7 @@ def _register_conventions(container: DIContainer, data_dir: Path): "default_ransomware_agent_configuration", DEFAULT_RANSOMWARE_AGENT_CONFIGURATION, ) + container.register_convention(Path, "island_log_file_path", get_log_file_path()) def _register_repositories(container: DIContainer, data_dir: Path): From 977860efb2c532ac7073a64843ccc5d561d7d817 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 13:33:24 +0530 Subject: [PATCH 07/14] Island: Modify IslandLog resource to fetch and return log file contents --- monkey/monkey_island/cc/resources/island_logs.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/resources/island_logs.py b/monkey/monkey_island/cc/resources/island_logs.py index 3e37e1748..bb10215fe 100644 --- a/monkey/monkey_island/cc/resources/island_logs.py +++ b/monkey/monkey_island/cc/resources/island_logs.py @@ -3,7 +3,6 @@ from pathlib import Path from monkey_island.cc.resources.AbstractResource import AbstractResource from monkey_island.cc.resources.request_authentication import jwt_required -from monkey_island.cc.services.island_logs import IslandLogService logger = logging.getLogger(__name__) @@ -17,6 +16,11 @@ class IslandLog(AbstractResource): @jwt_required def get(self): try: - return IslandLogService.get_log_file() + return self._get_log_file_contents() except Exception: logger.error("Monkey Island logs failed to download", exc_info=True) + + def _get_log_file_contents(self): + with open(self._island_log_file_path, "rt") as f: + log_file = f.read() + return {"log_file": log_file} From 7a2ff04978120f5b5165a594887cfd9b08b3bb36 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 13:34:56 +0530 Subject: [PATCH 08/14] Island: Remove IslandLogService --- .../monkey_island/cc/services/island_logs.py | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 monkey/monkey_island/cc/services/island_logs.py diff --git a/monkey/monkey_island/cc/services/island_logs.py b/monkey/monkey_island/cc/services/island_logs.py deleted file mode 100644 index 0bbf4ec0b..000000000 --- a/monkey/monkey_island/cc/services/island_logs.py +++ /dev/null @@ -1,30 +0,0 @@ -import logging - -logger = logging.getLogger(__name__) - - -class IslandLogService: - def __init__(self): - pass - - @staticmethod - def get_log_file(): - """ - This static function is a helper function for the monkey island log download function. - It finds the logger handlers and checks if one of them is a fileHandler of any kind by - checking if the handler - has the property handler.baseFilename. - :return: - a dict with the log file content. - """ - logger_handlers = logger.parent.handlers - for handler in logger_handlers: - if hasattr(handler, "baseFilename"): - logger.info("Log file found: {0}".format(handler.baseFilename)) - log_file_path = handler.baseFilename - with open(log_file_path, "rt") as f: - log_file = f.read() - return {"log_file": log_file} - - logger.warning("No log file could be found, check logger config.") - return None From acade35fbe6c8c8979271c37cd65445099f5fe9b Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 13:48:50 +0530 Subject: [PATCH 09/14] Changelog: Add entry for Island log api endpoint change --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66259a5a1..a1974f561 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/). - `/api/island-mode` to accept and return new "unset" mode. #2036 - `/api/version-update` to `api/island/version`. #2109 - The `/api/island-mode` to `/api/island/mode`. #2106 +- The `/api/log/island/download` endpoint to `/api/island/log`. #2107 ### Removed - VSFTPD exploiter. #1533 From 1d11dd227eeb4a7e415c8275393a7525840e31fd Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 16:51:35 +0530 Subject: [PATCH 10/14] Island: Simplify logic in get_log_file_path() --- .../cc/server_utils/island_logger.py | 28 ++++--------------- .../monkey_island/cc/services/initialize.py | 2 +- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/monkey/monkey_island/cc/server_utils/island_logger.py b/monkey/monkey_island/cc/server_utils/island_logger.py index 06cb82fd8..31b2a7a98 100644 --- a/monkey/monkey_island/cc/server_utils/island_logger.py +++ b/monkey/monkey_island/cc/server_utils/island_logger.py @@ -2,7 +2,6 @@ import logging import logging.handlers import sys from pathlib import Path -from typing import Optional ISLAND_LOG_FILENAME = "monkey_island.log" LOG_FORMAT = "%(asctime)s - %(levelname)s - %(filename)s:%(lineno)s - %(funcName)s() - %(message)s" @@ -24,12 +23,16 @@ def setup_logging(data_dir: Path, log_level: str): formatter = _get_log_formatter() - log_file_path = data_dir / ISLAND_LOG_FILENAME + log_file_path = get_log_file_path(data_dir) _add_file_handler(logger, formatter, log_file_path) _add_console_handler(logger, formatter) +def get_log_file_path(data_dir: Path) -> Path: + return data_dir / ISLAND_LOG_FILENAME + + def setup_default_failsafe_logging(): logger = logging.getLogger() logger.setLevel(logging.DEBUG) @@ -64,24 +67,3 @@ def reset_logger(): for handler in logger.handlers: logger.removeHandler(handler) - - -def get_log_file_path() -> Optional[Path]: - """ - Finds the log file by finding the logger handlers and checking if one of them is a fileHandler - of any kind by checking if the handler has the property handler.baseFilename. - - :return: Log file path - """ - - logger = logging.getLogger(__name__) - - logger_handlers = logger.parent.handlers - for handler in logger_handlers: - if hasattr(handler, "baseFilename"): - logger.info("Log file found: {0}".format(handler.baseFilename)) - log_file_path = handler.baseFilename - return Path(log_file_path) - - logger.warning("No log file could be found, check logger config.") - return None diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py index ff2872c7f..2d2678ac3 100644 --- a/monkey/monkey_island/cc/services/initialize.py +++ b/monkey/monkey_island/cc/services/initialize.py @@ -88,7 +88,7 @@ def _register_conventions(container: DIContainer, data_dir: Path): "default_ransomware_agent_configuration", DEFAULT_RANSOMWARE_AGENT_CONFIGURATION, ) - container.register_convention(Path, "island_log_file_path", get_log_file_path()) + container.register_convention(Path, "island_log_file_path", get_log_file_path(data_dir)) def _register_repositories(container: DIContainer, data_dir: Path): From 7967974c9dc1826956e31cdaafce4427e4bfe9f7 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 1 Aug 2022 17:15:46 +0530 Subject: [PATCH 11/14] Island: Move get_log_file_contents() from IslandLog to cc/server_utils/island_logger.py --- monkey/monkey_island/cc/resources/island_logs.py | 8 ++------ monkey/monkey_island/cc/server_utils/island_logger.py | 7 +++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/monkey/monkey_island/cc/resources/island_logs.py b/monkey/monkey_island/cc/resources/island_logs.py index bb10215fe..c44b80460 100644 --- a/monkey/monkey_island/cc/resources/island_logs.py +++ b/monkey/monkey_island/cc/resources/island_logs.py @@ -3,6 +3,7 @@ from pathlib import Path from monkey_island.cc.resources.AbstractResource import AbstractResource from monkey_island.cc.resources.request_authentication import jwt_required +from monkey_island.cc.server_utils.island_logger import get_log_file_contents logger = logging.getLogger(__name__) @@ -16,11 +17,6 @@ class IslandLog(AbstractResource): @jwt_required def get(self): try: - return self._get_log_file_contents() + return {"log_file": get_log_file_contents(self._island_log_file_path)} except Exception: logger.error("Monkey Island logs failed to download", exc_info=True) - - def _get_log_file_contents(self): - with open(self._island_log_file_path, "rt") as f: - log_file = f.read() - return {"log_file": log_file} diff --git a/monkey/monkey_island/cc/server_utils/island_logger.py b/monkey/monkey_island/cc/server_utils/island_logger.py index 31b2a7a98..568f4ddef 100644 --- a/monkey/monkey_island/cc/server_utils/island_logger.py +++ b/monkey/monkey_island/cc/server_utils/island_logger.py @@ -2,6 +2,7 @@ import logging import logging.handlers import sys from pathlib import Path +from typing import Mapping ISLAND_LOG_FILENAME = "monkey_island.log" LOG_FORMAT = "%(asctime)s - %(levelname)s - %(filename)s:%(lineno)s - %(funcName)s() - %(message)s" @@ -33,6 +34,12 @@ def get_log_file_path(data_dir: Path) -> Path: return data_dir / ISLAND_LOG_FILENAME +def get_log_file_contents(log_file_path: Path) -> Mapping: + with open(log_file_path, "rt") as f: + log_file = f.read() + return log_file + + def setup_default_failsafe_logging(): logger = logging.getLogger() logger.setLevel(logging.DEBUG) From 29646ecf43f9e0f5a279adaa32ba107ac5630182 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 2 Aug 2022 12:27:22 +0530 Subject: [PATCH 12/14] Island: Return string from IslandLog's GET instead of dict with redundant info --- monkey/monkey_island/cc/resources/island_logs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/resources/island_logs.py b/monkey/monkey_island/cc/resources/island_logs.py index c44b80460..e9eb7ea63 100644 --- a/monkey/monkey_island/cc/resources/island_logs.py +++ b/monkey/monkey_island/cc/resources/island_logs.py @@ -17,6 +17,6 @@ class IslandLog(AbstractResource): @jwt_required def get(self): try: - return {"log_file": get_log_file_contents(self._island_log_file_path)} + return get_log_file_contents(self._island_log_file_path) except Exception: logger.error("Monkey Island logs failed to download", exc_info=True) From 96bae42388c574957b912572a1c1d495d3e51477 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 2 Aug 2022 12:28:24 +0530 Subject: [PATCH 13/14] Island: Fix type hint in cc/server_utils/island_logger.py --- monkey/monkey_island/cc/server_utils/island_logger.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/server_utils/island_logger.py b/monkey/monkey_island/cc/server_utils/island_logger.py index 568f4ddef..07090214a 100644 --- a/monkey/monkey_island/cc/server_utils/island_logger.py +++ b/monkey/monkey_island/cc/server_utils/island_logger.py @@ -2,7 +2,6 @@ import logging import logging.handlers import sys from pathlib import Path -from typing import Mapping ISLAND_LOG_FILENAME = "monkey_island.log" LOG_FORMAT = "%(asctime)s - %(levelname)s - %(filename)s:%(lineno)s - %(funcName)s() - %(message)s" @@ -34,7 +33,7 @@ def get_log_file_path(data_dir: Path) -> Path: return data_dir / ISLAND_LOG_FILENAME -def get_log_file_contents(log_file_path: Path) -> Mapping: +def get_log_file_contents(log_file_path: Path) -> str: with open(log_file_path, "rt") as f: log_file = f.read() return log_file From eb20c9403db3992288835c31490f95bf10895049 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 2 Aug 2022 12:59:51 +0530 Subject: [PATCH 14/14] UI: Fix logic in IslandLogDownloadButton as per changes to IslandLog resource --- .../cc/ui/src/components/ui-components/LogDownloadButtons.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/LogDownloadButtons.tsx b/monkey/monkey_island/cc/ui/src/components/ui-components/LogDownloadButtons.tsx index 0e28973e1..1cca8d09b 100644 --- a/monkey/monkey_island/cc/ui/src/components/ui-components/LogDownloadButtons.tsx +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/LogDownloadButtons.tsx @@ -48,7 +48,7 @@ export const IslandLogDownloadButton = ({ url, variant = 'primary'}: Props) => { .then(res => res.json()) .then(res => { let filename = 'Island_log'; - let logContent = (res['log_file']); + let logContent = res; download(logContent, filename, 'text/plain'); }); }