diff --git a/monkey/common/BUILD b/monkey/common/BUILD new file mode 100644 index 000000000..90012116c --- /dev/null +++ b/monkey/common/BUILD @@ -0,0 +1 @@ +dev \ No newline at end of file diff --git a/monkey/common/version.py b/monkey/common/version.py new file mode 100644 index 000000000..9d60e636c --- /dev/null +++ b/monkey/common/version.py @@ -0,0 +1,25 @@ +# To get the version from shell, run `python ./version.py` (see `python ./version.py -h` for details). +import argparse +from pathlib import Path + +MAJOR = "1" +MINOR = "8" +PATCH = "0" +build_file_path = Path(__file__).parent.joinpath("BUILD") +with open(build_file_path, "r") as build_file: + BUILD = build_file.read() + + +def get_version(build=BUILD): + return f"{MAJOR}.{MINOR}.{PATCH}+{build}" + + +def print_version(): + parser = argparse.ArgumentParser() + parser.add_argument("-b", "--build", default=BUILD, help="Choose the build string for this version.", type=str) + args = parser.parse_args() + print(get_version(args.build)) + + +if __name__ == '__main__': + print_version() diff --git a/monkey/infection_monkey/build_linux.sh b/monkey/infection_monkey/build_linux.sh index fcaf4c75d..68abd4758 100644 --- a/monkey/infection_monkey/build_linux.sh +++ b/monkey/infection_monkey/build_linux.sh @@ -1,2 +1,17 @@ #!/bin/bash + +# Allow custom build ID +# If the first argument is not empty... +if [[ -n "$1" ]] +then + # Validate argument is a valid build string + if [[ "$1" =~ ^[\da-zA-Z]*$ ]] + then + # And put it in the BUILD file + echo "$1" > ../common/BUILD + else + echo "Build ID $1 invalid!" + fi +fi + pyinstaller -F --log-level=DEBUG --clean monkey.spec diff --git a/monkey/infection_monkey/build_windows.bat b/monkey/infection_monkey/build_windows.bat index f763bda6b..93e4e4a42 100644 --- a/monkey/infection_monkey/build_windows.bat +++ b/monkey/infection_monkey/build_windows.bat @@ -1 +1,12 @@ +REM Check if build ID was passed to the build script. +if "%1"=="" GOTO START_BUILD + +REM Validate build ID +echo %1|findstr /r "^[0-9a-zA-Z]*$" +if %errorlevel% neq 0 (exit /b %errorlevel%) + +REM replace build ID +echo %1> ../common/BUILD + +:START_BUILD pyinstaller -F --log-level=DEBUG --clean --upx-dir=.\bin monkey.spec diff --git a/monkey/infection_monkey/main.py b/monkey/infection_monkey/main.py index 928425535..21871d857 100644 --- a/monkey/infection_monkey/main.py +++ b/monkey/infection_monkey/main.py @@ -12,6 +12,7 @@ from infection_monkey.config import WormConfiguration, EXTERNAL_CONFIG_FILE from infection_monkey.dropper import MonkeyDrops from infection_monkey.model import MONKEY_ARG, DROPPER_ARG from infection_monkey.monkey import InfectionMonkey +from common.version import get_version # noinspection PyUnresolvedReferences import infection_monkey.post_breach # dummy import for pyinstaller @@ -117,6 +118,8 @@ def main(): LOG.info(">>>>>>>>>> Initializing monkey (%s): PID %s <<<<<<<<<<", monkey_cls.__name__, os.getpid()) + LOG.info(f"version: {get_version()}") + monkey = monkey_cls(monkey_args) monkey.initialize() diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index 06a08f131..6b8803a9f 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -30,6 +30,7 @@ from infection_monkey.network.tools import get_interface_to_target from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError, FailedExploitationError from infection_monkey.telemetry.attack.t1106_telem import T1106Telem from common.utils.attack_utils import ScanStatus, UsageEnum +from common.version import get_version from infection_monkey.exploit.HostExploiter import HostExploiter MAX_DEPTH_REACHED_MESSAGE = "Reached max depth, shutting down" @@ -121,7 +122,7 @@ class InfectionMonkey(object): if monkey_tunnel: monkey_tunnel.start() - StateTelem(is_done=False).send() + StateTelem(is_done=False, version=get_version()).send() TunnelTelem().send() LOG.debug("Starting the post-breach phase.") @@ -254,7 +255,7 @@ class InfectionMonkey(object): InfectionMonkey.close_tunnel() firewall.close() else: - StateTelem(is_done=True).send() # Signal the server (before closing the tunnel) + StateTelem(is_done=True, version=get_version()).send() # Signal the server (before closing the tunnel) InfectionMonkey.close_tunnel() firewall.close() if WormConfiguration.send_log_to_server: diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 004cffa4c..e5873c9c5 100644 --- a/monkey/infection_monkey/monkey.spec +++ b/monkey/infection_monkey/monkey.spec @@ -19,7 +19,9 @@ def main(): hookspath=['./pyinstaller_hooks'], runtime_hooks=None, binaries=None, - datas=None, + datas=[ + ("../common/BUILD", "/common") + ], excludes=None, win_no_prefer_redirects=None, win_private_assemblies=None, diff --git a/monkey/infection_monkey/telemetry/state_telem.py b/monkey/infection_monkey/telemetry/state_telem.py index 3bd63d2f9..4d4224288 100644 --- a/monkey/infection_monkey/telemetry/state_telem.py +++ b/monkey/infection_monkey/telemetry/state_telem.py @@ -5,15 +5,19 @@ __author__ = "itay.mizeretz" class StateTelem(BaseTelem): - def __init__(self, is_done): + def __init__(self, is_done, version="Unknown"): """ Default state telemetry constructor :param is_done: Whether the state of monkey is done. """ super(StateTelem, self).__init__() self.is_done = is_done + self.version = version telem_category = 'state' def get_data(self): - return {'done': self.is_done} + return { + 'done': self.is_done, + 'version': self.version + } diff --git a/monkey/monkey_island/cc/environment/__init__.py b/monkey/monkey_island/cc/environment/__init__.py index 26d33f78c..ec7c7a0f4 100644 --- a/monkey/monkey_island/cc/environment/__init__.py +++ b/monkey/monkey_island/cc/environment/__init__.py @@ -26,8 +26,6 @@ class Environment(object, metaclass=ABCMeta): def testing(self, value): self._testing = value - _MONKEY_VERSION = "1.7.0" - def __init__(self): self.config = None self._testing = False # Assume env is not for unit testing. @@ -58,9 +56,6 @@ class Environment(object, metaclass=ABCMeta): def is_develop(self): return self.get_deployment() == 'develop' - def get_version(self): - return self._MONKEY_VERSION + ('-dev' if self.is_develop() else '') - def _get_from_config(self, key, default_value=None): val = default_value if self.config is not None: diff --git a/monkey/monkey_island/cc/main.py b/monkey/monkey_island/cc/main.py index 17c537aeb..f06d36ea3 100644 --- a/monkey/monkey_island/cc/main.py +++ b/monkey/monkey_island/cc/main.py @@ -25,6 +25,7 @@ from monkey_island.cc.utils import local_ip_addresses from monkey_island.cc.environment.environment import env from monkey_island.cc.database import is_db_server_up, get_db_version from monkey_island.cc.resources.monkey_download import MonkeyDownload +from common.version import get_version def main(): @@ -54,8 +55,9 @@ def main(): def log_init_info(): - logger.info( - 'Monkey Island Server is running. Listening on the following URLs: {}'.format( + logger.info('Monkey Island Server is running!') + logger.info(f"version: {get_version()}") + logger.info('Listening on the following URLs: {}'.format( ", ".join(["https://{}:{}".format(x, env.get_island_port()) for x in local_ip_addresses()]) ) ) diff --git a/monkey/monkey_island/cc/resources/version_update.py b/monkey/monkey_island/cc/resources/version_update.py index b1fbfdf82..a88f8830c 100644 --- a/monkey/monkey_island/cc/resources/version_update.py +++ b/monkey/monkey_island/cc/resources/version_update.py @@ -1,7 +1,7 @@ import flask_restful import logging -from monkey_island.cc.environment.environment import env +from common.version import get_version from monkey_island.cc.services.version_update import VersionUpdateService __author__ = 'itay.mizeretz' @@ -17,7 +17,7 @@ class VersionUpdate(flask_restful.Resource): # even when not authenticated def get(self): return { - 'current_version': env.get_version(), + 'current_version': get_version(), 'newer_version': VersionUpdateService.get_newer_version(), 'download_link': VersionUpdateService.get_download_link() } diff --git a/monkey/monkey_island/cc/services/telemetry/processing/state.py b/monkey/monkey_island/cc/services/telemetry/processing/state.py index 4e164e900..b7e341483 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/state.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/state.py @@ -1,9 +1,14 @@ +import logging + from monkey_island.cc.models import Monkey from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.telemetry.zero_trust_tests.segmentation import \ test_passed_findings_for_unreached_segments +logger = logging.getLogger(__name__) + + def process_state_telemetry(telemetry_json): monkey = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid']) NodeService.add_communication_info(monkey, telemetry_json['command_control_channel']) @@ -15,3 +20,6 @@ def process_state_telemetry(telemetry_json): if telemetry_json['data']['done']: current_monkey = Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']) test_passed_findings_for_unreached_segments(current_monkey) + + if telemetry_json['data']['version']: + logger.info(f"monkey {telemetry_json['monkey_guid']} has version {telemetry_json['data']['version']}") diff --git a/monkey/monkey_island/cc/services/version_update.py b/monkey/monkey_island/cc/services/version_update.py index c1dab52a9..ddd60d5c0 100644 --- a/monkey/monkey_island/cc/services/version_update.py +++ b/monkey/monkey_island/cc/services/version_update.py @@ -2,6 +2,7 @@ import logging import requests +from common.version import get_version from monkey_island.cc.environment.environment import env __author__ = "itay.mizeretz" @@ -39,7 +40,7 @@ class VersionUpdateService: Checks if newer monkey version is available :return: False if not, version in string format ('1.6.2') otherwise """ - url = VersionUpdateService.VERSION_SERVER_CHECK_NEW_URL % (env.get_deployment(), env.get_version()) + url = VersionUpdateService.VERSION_SERVER_CHECK_NEW_URL % (env.get_deployment(), get_version()) reply = requests.get(url, timeout=15) @@ -53,4 +54,4 @@ class VersionUpdateService: @staticmethod def get_download_link(): - return VersionUpdateService.VERSION_SERVER_DOWNLOAD_URL % (env.get_deployment(), env.get_version()) + return VersionUpdateService.VERSION_SERVER_DOWNLOAD_URL % (env.get_deployment(), get_version()) diff --git a/monkey/monkey_island/deb-package/DEBIAN/postinst b/monkey/monkey_island/deb-package/DEBIAN/postinst index 4a3a8ab50..fe62a6100 100644 --- a/monkey/monkey_island/deb-package/DEBIAN/postinst +++ b/monkey/monkey_island/deb-package/DEBIAN/postinst @@ -6,7 +6,7 @@ PYTHON_FOLDER=/var/monkey/monkey_island/bin/python # Prepare python virtualenv pip3 install virtualenv --no-index --find-links file://$INSTALLATION_FOLDER -virtualenv -p python3 ${PYTHON_FOLDER} +python3 -m virtualenv -p python3 ${PYTHON_FOLDER} # install pip requirements ${PYTHON_FOLDER}/bin/python -m pip install -r $MONKEY_FOLDER/monkey_island/requirements.txt --no-index --find-links file://$INSTALLATION_FOLDER diff --git a/monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst b/monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst index 25d10f791..f79a71913 100644 --- a/monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst +++ b/monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst @@ -6,7 +6,7 @@ PYTHON_FOLDER=/var/monkey/monkey_island/bin/python # Prepare python virtualenv pip3 install virtualenv --no-index --find-links file://$INSTALLATION_FOLDER -virtualenv -p python3 ${PYTHON_FOLDER} +python3 -m virtualenv -p python3 ${PYTHON_FOLDER} # install pip requirements ${PYTHON_FOLDER}/bin/python -m pip install -r $MONKEY_FOLDER/monkey_island/requirements.txt --no-index --find-links file://$INSTALLATION_FOLDER diff --git a/monkey/monkey_island/linux/install_mongo.sh b/monkey/monkey_island/linux/install_mongo.sh index 98a497d84..8fcef9633 100755 --- a/monkey/monkey_island/linux/install_mongo.sh +++ b/monkey/monkey_island/linux/install_mongo.sh @@ -23,6 +23,9 @@ elif [[ ${os_version_monkey} == "Debian GNU/Linux 9"* ]]; then elif [[ ${os_version_monkey} == "Debian GNU/Linux 10"* ]]; then echo Detected Debian 10 export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-4.2.3.tgz" +elif [[ ${os_version_monkey} == "Kali GNU/Linux"* ]]; then + echo Detected Kali Linux + export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-4.2.3.tgz" else echo Unsupported OS exit 1 diff --git a/monkey/monkey_island/monkey_island.spec b/monkey/monkey_island/monkey_island.spec index 08ab03ff2..2d8e73e0a 100644 --- a/monkey/monkey_island/monkey_island.spec +++ b/monkey/monkey_island/monkey_island.spec @@ -15,7 +15,9 @@ def main(): hookspath=None, runtime_hooks=None, binaries=None, - datas=None, + datas=[ + ("../common/BUILD", "../common/BUILD") + ], excludes=None, win_no_prefer_redirects=None, win_private_assemblies=None,