forked from p15670423/monkey
Merge pull request #1991 from guardicore/1974-log-hashes-on-initialize
1974 log hashes on initialize
This commit is contained in:
commit
ee38c31ed5
|
@ -1,7 +1,9 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterable
|
from typing import BinaryIO, Iterable
|
||||||
|
|
||||||
|
MAX_BLOCK_SIZE = 65536
|
||||||
|
|
||||||
|
|
||||||
class InvalidPath(Exception):
|
class InvalidPath(Exception):
|
||||||
|
@ -15,10 +17,26 @@ def expand_path(path: str) -> Path:
|
||||||
return Path(os.path.expandvars(os.path.expanduser(path)))
|
return Path(os.path.expandvars(os.path.expanduser(path)))
|
||||||
|
|
||||||
|
|
||||||
def get_file_sha256_hash(filepath: Path):
|
def get_file_sha256_hash(filepath: Path) -> str:
|
||||||
sha256 = hashlib.sha256()
|
"""
|
||||||
|
Calculates sha256 hash from a file path
|
||||||
|
|
||||||
|
:param filepath: A Path object which defines file on the system
|
||||||
|
:return sha256 hash of the file
|
||||||
|
"""
|
||||||
with open(filepath, "rb") as f:
|
with open(filepath, "rb") as f:
|
||||||
for block in iter(lambda: f.read(65536), b""):
|
return get_binary_io_sha256_hash(f)
|
||||||
|
|
||||||
|
|
||||||
|
def get_binary_io_sha256_hash(binary: BinaryIO) -> str:
|
||||||
|
"""
|
||||||
|
Calculates sha256 hash from a file-like object
|
||||||
|
|
||||||
|
:param binary: file-like object from which we calculate the hash
|
||||||
|
:return: sha256 hash from the file-like object
|
||||||
|
"""
|
||||||
|
sha256 = hashlib.sha256()
|
||||||
|
for block in iter(lambda: binary.read(MAX_BLOCK_SIZE), b""):
|
||||||
sha256.update(block)
|
sha256.update(block)
|
||||||
|
|
||||||
return sha256.hexdigest()
|
return sha256.hexdigest()
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
from .file_storage import FileRetrievalError, IFileRepository, LocalStorageFileRepository
|
from .file_storage import FileRetrievalError, IFileRepository, LocalStorageFileRepository
|
||||||
from .i_agent_binary_repository import IAgentBinaryRepository, AgentRetrivalError
|
from .i_agent_binary_repository import IAgentBinaryRepository, AgentRetrievalError
|
||||||
|
from .agent_binary_repository import AgentBinaryRepository
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from typing import BinaryIO
|
from typing import BinaryIO
|
||||||
|
|
||||||
from . import AgentRetrivalError, FileRetrivalError, IAgentBinaryRepository, IFileRepository
|
from . import AgentRetrievalError, FileRetrievalError, IAgentBinaryRepository, IFileRepository
|
||||||
|
|
||||||
LINUX_AGENT_FILE_NAME = "monkey-linux-64"
|
LINUX_AGENT_FILE_NAME = "monkey-linux-64"
|
||||||
WINDOWS_AGENT_FILE_NAME = "monkey-windows-64.exe"
|
WINDOWS_AGENT_FILE_NAME = "monkey-windows-64.exe"
|
||||||
|
@ -10,18 +10,18 @@ class AgentBinaryRepository(IAgentBinaryRepository):
|
||||||
def __init__(self, file_repository: IFileRepository):
|
def __init__(self, file_repository: IFileRepository):
|
||||||
self._file_repository = file_repository
|
self._file_repository = file_repository
|
||||||
|
|
||||||
def __get_binary(self, filename) -> BinaryIO:
|
def get_linux_binary(self) -> BinaryIO:
|
||||||
|
return self._get_binary(LINUX_AGENT_FILE_NAME)
|
||||||
|
|
||||||
|
def get_windows_binary(self) -> BinaryIO:
|
||||||
|
return self._get_binary(WINDOWS_AGENT_FILE_NAME)
|
||||||
|
|
||||||
|
def _get_binary(self, filename: str) -> BinaryIO:
|
||||||
try:
|
try:
|
||||||
agent_binary = self._file_repository.open_file(filename)
|
agent_binary = self._file_repository.open_file(filename)
|
||||||
return agent_binary
|
return agent_binary
|
||||||
except FileRetrivalError as err:
|
except FileRetrievalError as err:
|
||||||
raise AgentRetrivalError(
|
raise AgentRetrievalError(
|
||||||
f"An error occurred while retrieving the {filename}"
|
f"An error occurred while retrieving the {filename}"
|
||||||
f" agent binary from {self._file_repository}: {err}"
|
f" agent binary from {self._file_repository}: {err}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_linux_binary(self) -> BinaryIO:
|
|
||||||
self.__get_binary(LINUX_AGENT_FILE_NAME)
|
|
||||||
|
|
||||||
def get_windows_binary(self) -> BinaryIO:
|
|
||||||
self.__get_binary(WINDOWS_AGENT_FILE_NAME)
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import abc
|
||||||
from typing import BinaryIO
|
from typing import BinaryIO
|
||||||
|
|
||||||
|
|
||||||
class AgentRetrivalError(IOError):
|
class AgentRetrievalError(IOError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import hashlib
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
@ -31,23 +30,6 @@ class AgentBinaries(AbstractResource):
|
||||||
logger.error(ex)
|
logger.error(ex)
|
||||||
return make_response({"error": str(ex)}, 404)
|
return make_response({"error": str(ex)}, 404)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def log_executable_hashes():
|
|
||||||
"""
|
|
||||||
Logs all the hashes of the monkey executables for debugging ease (can check what Monkey
|
|
||||||
version you have etc.).
|
|
||||||
"""
|
|
||||||
filenames = set(AGENTS.values())
|
|
||||||
for filename in filenames:
|
|
||||||
filepath = get_executable_full_path(filename)
|
|
||||||
if filepath.is_file():
|
|
||||||
with open(filepath, "rb") as monkey_exec_file:
|
|
||||||
file_contents = monkey_exec_file.read()
|
|
||||||
file_sha256_hash = hashlib.sha256(file_contents).hexdigest()
|
|
||||||
logger.debug(f"{filename} SHA-256 hash: {file_sha256_hash}")
|
|
||||||
else:
|
|
||||||
logger.debug(f"No monkey executable for {filepath}")
|
|
||||||
|
|
||||||
|
|
||||||
def get_agent_executable_path(os: str) -> Path:
|
def get_agent_executable_path(os: str) -> Path:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -21,7 +21,6 @@ from common.version import get_version # noqa: E402
|
||||||
from monkey_island.cc.app import init_app # noqa: E402
|
from monkey_island.cc.app import init_app # noqa: E402
|
||||||
from monkey_island.cc.arg_parser import IslandCmdArgs # noqa: E402
|
from monkey_island.cc.arg_parser import IslandCmdArgs # noqa: E402
|
||||||
from monkey_island.cc.arg_parser import parse_cli_args # noqa: E402
|
from monkey_island.cc.arg_parser import parse_cli_args # noqa: E402
|
||||||
from monkey_island.cc.resources import AgentBinaries # noqa: E402
|
|
||||||
from monkey_island.cc.server_utils.consts import ( # noqa: E402
|
from monkey_island.cc.server_utils.consts import ( # noqa: E402
|
||||||
GEVENT_EXCEPTION_LOG,
|
GEVENT_EXCEPTION_LOG,
|
||||||
MONGO_CONNECTION_TIMEOUT,
|
MONGO_CONNECTION_TIMEOUT,
|
||||||
|
@ -154,8 +153,6 @@ def _start_island_server(
|
||||||
|
|
||||||
|
|
||||||
def _log_init_info():
|
def _log_init_info():
|
||||||
AgentBinaries.log_executable_hashes()
|
|
||||||
|
|
||||||
logger.info("Monkey Island Server is running!")
|
logger.info("Monkey Island Server is running!")
|
||||||
logger.info(f"version: {get_version()}")
|
logger.info(f"version: {get_version()}")
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from common import DIContainer
|
from common import DIContainer
|
||||||
from common.aws import AWSInstance
|
from common.aws import AWSInstance
|
||||||
|
from common.utils.file_utils import get_binary_io_sha256_hash
|
||||||
from monkey_island.cc.repository import (
|
from monkey_island.cc.repository import (
|
||||||
AgentBinaryRepository,
|
AgentBinaryRepository,
|
||||||
|
AgentRetrievalError,
|
||||||
IAgentBinaryRepository,
|
IAgentBinaryRepository,
|
||||||
IFileRepository,
|
IFileRepository,
|
||||||
LocalStorageFileRepository,
|
LocalStorageFileRepository,
|
||||||
|
@ -16,6 +19,8 @@ from monkey_island.cc.services.run_local_monkey import LocalMonkeyRunService
|
||||||
from . import AuthenticationService, JsonFileUserDatastore
|
from . import AuthenticationService, JsonFileUserDatastore
|
||||||
from .reporting.report import ReportService
|
from .reporting.report import ReportService
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
AGENT_BINARIES_PATH = Path(MONKEY_ISLAND_ABS_PATH) / "cc" / "binaries"
|
AGENT_BINARIES_PATH = Path(MONKEY_ISLAND_ABS_PATH) / "cc" / "binaries"
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,4 +45,32 @@ def initialize_services(data_dir: Path) -> DIContainer:
|
||||||
|
|
||||||
def _build_agent_binary_repository():
|
def _build_agent_binary_repository():
|
||||||
file_repository = LocalStorageFileRepository(AGENT_BINARIES_PATH)
|
file_repository = LocalStorageFileRepository(AGENT_BINARIES_PATH)
|
||||||
return AgentBinaryRepository(file_repository)
|
agent_binary_repository = AgentBinaryRepository(file_repository)
|
||||||
|
|
||||||
|
_log_agent_binary_hashes(agent_binary_repository)
|
||||||
|
|
||||||
|
return agent_binary_repository
|
||||||
|
|
||||||
|
|
||||||
|
def _log_agent_binary_hashes(agent_binary_repository: IAgentBinaryRepository):
|
||||||
|
"""
|
||||||
|
Logs all the hashes of the agent executables for debbuging ease
|
||||||
|
|
||||||
|
:param agent_binary_repository: Used to retrieve the agent binaries
|
||||||
|
"""
|
||||||
|
agent_binaries = {
|
||||||
|
"Linux": agent_binary_repository.get_linux_binary,
|
||||||
|
"Windows": agent_binary_repository.get_windows_binary,
|
||||||
|
}
|
||||||
|
agent_hashes = {}
|
||||||
|
|
||||||
|
for os, get_agent_binary in agent_binaries.items():
|
||||||
|
try:
|
||||||
|
agent_binary = get_agent_binary()
|
||||||
|
binary_sha256_hash = get_binary_io_sha256_hash(agent_binary)
|
||||||
|
agent_hashes[os] = binary_sha256_hash
|
||||||
|
except AgentRetrievalError as err:
|
||||||
|
logger.error(f"No agent available for {os}: {err}")
|
||||||
|
|
||||||
|
for os, binary_sha256_hash in agent_hashes.items():
|
||||||
|
logger.info(f"{os} agent: SHA-256 hash: {binary_sha256_hash}")
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from tests.utils import add_files_to_dir, add_subdirs_to_dir
|
from tests.utils import add_files_to_dir, add_subdirs_to_dir
|
||||||
|
@ -7,6 +8,7 @@ from common.utils.file_utils import (
|
||||||
InvalidPath,
|
InvalidPath,
|
||||||
expand_path,
|
expand_path,
|
||||||
get_all_regular_files_in_directory,
|
get_all_regular_files_in_directory,
|
||||||
|
get_binary_io_sha256_hash,
|
||||||
get_file_sha256_hash,
|
get_file_sha256_hash,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -34,6 +36,11 @@ def test_get_file_sha256_hash(stable_file, stable_file_sha256_hash):
|
||||||
assert get_file_sha256_hash(stable_file) == stable_file_sha256_hash
|
assert get_file_sha256_hash(stable_file) == stable_file_sha256_hash
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_binary_sha256_hash():
|
||||||
|
expected_hash = "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e"
|
||||||
|
assert get_binary_io_sha256_hash(BytesIO(b"Hello World")) == expected_hash
|
||||||
|
|
||||||
|
|
||||||
SUBDIRS = ["subdir1", "subdir2"]
|
SUBDIRS = ["subdir1", "subdir2"]
|
||||||
FILES = ["file.jpg.zip", "file.xyz", "1.tar", "2.tgz", "2.png", "2.mpg"]
|
FILES = ["file.jpg.zip", "file.xyz", "1.tar", "2.tgz", "2.png", "2.mpg"]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue