From 5dc6fffc2a2547d7001b4781c494ccaa624f7cd4 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 20 Dec 2019 12:12:26 +0200 Subject: [PATCH 001/119] Added config won't change warning --- .../ui/src/components/pages/ConfigurePage.js | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index 6d9325487..a49e198a6 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -30,7 +30,7 @@ class ConfigurePageComponent extends AuthComponent { lastAction: 'none', sections: [], selectedSection: 'attack', - allMonkeysAreDead: true, + monkeysRan: false, PBAwinFile: [], PBAlinuxFile: [], showAttackAlert: false @@ -363,13 +363,7 @@ class ConfigurePageComponent extends AuthComponent { this.authFetch('/api') .then(res => res.json()) .then(res => { - // This check is used to prevent unnecessary re-rendering - let allMonkeysAreDead = (!res['completed_steps']['run_monkey']) || (res['completed_steps']['infection_done']); - if (allMonkeysAreDead !== this.state.allMonkeysAreDead) { - this.setState({ - allMonkeysAreDead: allMonkeysAreDead - }); - } + this.setState({monkeysRan: res['completed_steps']['run_monkey']}); }); }; @@ -470,15 +464,15 @@ class ConfigurePageComponent extends AuthComponent { ) }; - renderRunningMonkeysWarning = () => { + renderConfigWontChangeWarning = () => { return (
- {this.state.allMonkeysAreDead ? - '' : + {this.state.monkeysRan ?
- Some monkeys are currently running. Note that changing the configuration will only apply to new - infections. + Changed configuration will only apply to new infections. + "Start over" to run again with different configuration.
+ : '' }
) }; @@ -520,7 +514,7 @@ class ConfigurePageComponent extends AuthComponent { {this.renderAttackAlertModal()}

Monkey Configuration

{this.renderNav()} - {this.renderRunningMonkeysWarning()} + {this.renderConfigWontChangeWarning()} {content}
+ +
+ + + ) + + }; +} From 18731a430bf2e431623d66a499a6cd3f1692aabc Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 7 Jan 2020 16:06:50 +0200 Subject: [PATCH 010/119] Fixed start over modal and start over page, added stylesheet --- .../ui/src/components/pages/StartOverPage.js | 63 ++++++----------- .../ui-components/StartOverModal.js | 67 +++++++++++++------ .../cc/ui/src/styles/StartOverPage.scss | 9 +++ 3 files changed, 77 insertions(+), 62 deletions(-) create mode 100644 monkey/monkey_island/cc/ui/src/styles/StartOverPage.scss diff --git a/monkey/monkey_island/cc/ui/src/components/pages/StartOverPage.js b/monkey/monkey_island/cc/ui/src/components/pages/StartOverPage.js index eca159133..2aaeddec7 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/StartOverPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/StartOverPage.js @@ -1,7 +1,9 @@ import React from 'react'; -import {Col, Modal} from 'react-bootstrap'; +import {Col} from 'react-bootstrap'; import {Link} from 'react-router-dom'; import AuthComponent from '../AuthComponent'; +import StartOverModal from '../ui-components/StartOverModal'; +import '../../styles/StartOverPage.scss'; class StartOverPageComponent extends AuthComponent { constructor(props) { @@ -12,6 +14,9 @@ class StartOverPageComponent extends AuthComponent { showCleanDialog: false, allMonkeysAreDead: false }; + + this.cleanup = this.cleanup.bind(this); + this.closeModal = this.closeModal.bind(this); } updateMonkeysRunning = () => { @@ -25,48 +30,14 @@ class StartOverPageComponent extends AuthComponent { }); }; - renderCleanDialogModal = () => { - return ( - this.setState({showCleanDialog: false})}> - -

-
Reset environment
-

-

- Are you sure you want to reset the environment? -

- { - !this.state.allMonkeysAreDead ? -
- - Some monkeys are still running. It's advised to kill all monkeys before resetting. -
- : -
- } -
- - -
- - - ) - - }; - render() { return ( - {this.renderCleanDialogModal()} +

Start Over

@@ -104,7 +75,7 @@ class StartOverPageComponent extends AuthComponent { this.setState({ cleaned: false }); - this.authFetch('/api?action=reset') + return this.authFetch('/api?action=reset') .then(res => res.json()) .then(res => { if (res['status'] === 'OK') { @@ -112,8 +83,14 @@ class StartOverPageComponent extends AuthComponent { cleaned: true }); } - }); - } + }).then(this.updateMonkeysRunning()); + }; + + closeModal = () => { + this.setState({ + showCleanDialog: false, + }) + }; } export default StartOverPageComponent; diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/StartOverModal.js b/monkey/monkey_island/cc/ui/src/components/ui-components/StartOverModal.js index 057d45779..5c0ae1cb2 100644 --- a/monkey/monkey_island/cc/ui/src/components/ui-components/StartOverModal.js +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/StartOverModal.js @@ -1,13 +1,30 @@ import {Modal} from "react-bootstrap"; -import Modal from "react-bootstrap/es/Modal"; -import ReactComponent from "react"; -import AuthComponent from "../AuthComponent"; +import React from "react"; +import {GridLoader} from 'react-spinners'; -class StartOverModal extends ReactComponent { +class StartOverModal extends React.PureComponent { + + constructor(props) { + super(props); + + this.state = { + showCleanDialog: this.props.showCleanDialog, + allMonkeysAreDead: this.props.allMonkeysAreDead, + loading: false + }; + } + + componentDidUpdate(prevProps) { + if (this.props !== prevProps) { + this.setState({ showCleanDialog: this.props.showCleanDialog, + allMonkeysAreDead: this.props.allMonkeysAreDead}) + } + } + render = () => { return ( - this.setState({showCleanDialog: false})}> + this.props.onClose()}>

Reset environment
@@ -24,22 +41,34 @@ class StartOverModal extends ReactComponent { :
} -
- - -
+ { + this.state.loading ?
: this.showModalButtons() + } ) - }; + + showModalButtons() { + return (
+ + +
) + } + + modalVerificationOnClick = async () => { + this.setState({loading: true}); + this.props.onVerify() + .then(() => {this.setState({loading: false}); + this.props.onClose();}) + + } } + +export default StartOverModal; diff --git a/monkey/monkey_island/cc/ui/src/styles/StartOverPage.scss b/monkey/monkey_island/cc/ui/src/styles/StartOverPage.scss new file mode 100644 index 000000000..ee4ab65ea --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/styles/StartOverPage.scss @@ -0,0 +1,9 @@ +$yellow: #ffcc00; + +.modalLoader div{ + margin-left: auto; + margin-right: auto; +} +.modalLoader div>div{ + background-color: $yellow; +} From b130dd35ec8456f6c4870ee12af0c4312cefc547 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 8 Jan 2020 08:57:25 +0200 Subject: [PATCH 011/119] double quotes to single quotes in StartOverModal --- .../components/ui-components/StartOverModal.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/StartOverModal.js b/monkey/monkey_island/cc/ui/src/components/ui-components/StartOverModal.js index 5c0ae1cb2..5694d463a 100644 --- a/monkey/monkey_island/cc/ui/src/components/ui-components/StartOverModal.js +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/StartOverModal.js @@ -1,5 +1,5 @@ -import {Modal} from "react-bootstrap"; -import React from "react"; +import {Modal} from 'react-bootstrap'; +import React from 'react'; import {GridLoader} from 'react-spinners'; @@ -27,22 +27,22 @@ class StartOverModal extends React.PureComponent { this.props.onClose()}>

-
Reset environment
+
Reset environment

Are you sure you want to reset the environment?

{ !this.state.allMonkeysAreDead ? -
- +
+ Some monkeys are still running. It's advised to kill all monkeys before resetting.
:
} { - this.state.loading ?
: this.showModalButtons() + this.state.loading ?
: this.showModalButtons() } @@ -50,12 +50,12 @@ class StartOverModal extends React.PureComponent { }; showModalButtons() { - return (
- - From 91c05ae0f4651ef133b3912d8de34f125fa38461 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 8 Jan 2020 09:19:29 +0200 Subject: [PATCH 012/119] dangling comma removed from StartOverPage --- .../monkey_island/cc/ui/src/components/pages/StartOverPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/StartOverPage.js b/monkey/monkey_island/cc/ui/src/components/pages/StartOverPage.js index 2aaeddec7..a57c81ca5 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/StartOverPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/StartOverPage.js @@ -88,7 +88,7 @@ class StartOverPageComponent extends AuthComponent { closeModal = () => { this.setState({ - showCleanDialog: false, + showCleanDialog: false }) }; } From b9d2614271689d3752cbf0f57b3e2f4f07f37a9c Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Wed, 8 Jan 2020 11:09:52 +0200 Subject: [PATCH 013/119] CR: Moved AWS classes to own package, create generic CloudInstance class --- monkey/common/cloud/aws/__init__.py | 0 monkey/common/cloud/{ => aws}/aws_instance.py | 6 ++++-- monkey/common/cloud/{ => aws}/aws_service.py | 2 +- monkey/common/cloud/{ => aws}/aws_service_test.py | 0 monkey/common/cloud/azure/azure_instance.py | 8 +++++--- monkey/common/cloud/environment_names.py | 7 ++++++- monkey/common/cloud/instance.py | 3 +++ monkey/common/cmd/aws/aws_cmd_runner.py | 2 +- monkey/infection_monkey/system_info/aws_collector.py | 4 ++-- .../system_info/collectors/environment_collector.py | 6 +++--- monkey/monkey_island/cc/environment/aws.py | 2 +- monkey/monkey_island/cc/resources/remote_run.py | 2 +- monkey/monkey_island/cc/services/remote_run_aws.py | 6 +++--- .../monkey_island/cc/services/reporting/aws_exporter.py | 2 +- 14 files changed, 31 insertions(+), 19 deletions(-) create mode 100644 monkey/common/cloud/aws/__init__.py rename monkey/common/cloud/{ => aws}/aws_instance.py (96%) rename monkey/common/cloud/{ => aws}/aws_service.py (98%) rename monkey/common/cloud/{ => aws}/aws_service_test.py (100%) create mode 100644 monkey/common/cloud/instance.py diff --git a/monkey/common/cloud/aws/__init__.py b/monkey/common/cloud/aws/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/common/cloud/aws_instance.py b/monkey/common/cloud/aws/aws_instance.py similarity index 96% rename from monkey/common/cloud/aws_instance.py rename to monkey/common/cloud/aws/aws_instance.py index 4339fbcf4..301881894 100644 --- a/monkey/common/cloud/aws_instance.py +++ b/monkey/common/cloud/aws/aws_instance.py @@ -6,6 +6,8 @@ import logging __author__ = 'itay.mizeretz' +from common.cloud.instance import CloudInstance + AWS_INSTANCE_METADATA_LOCAL_IP_ADDRESS = "169.254.169.254" AWS_LATEST_METADATA_URI_PREFIX = 'http://{0}/latest/'.format(AWS_INSTANCE_METADATA_LOCAL_IP_ADDRESS) ACCOUNT_ID_KEY = "accountId" @@ -13,7 +15,7 @@ ACCOUNT_ID_KEY = "accountId" logger = logging.getLogger(__name__) -class AwsInstance(object): +class AwsInstance(CloudInstance): """ Class which gives useful information about the current instance you're on. """ @@ -57,7 +59,7 @@ class AwsInstance(object): def get_region(self): return self.region - def is_aws_instance(self): + def is_instance(self): return self.instance_id is not None @staticmethod diff --git a/monkey/common/cloud/aws_service.py b/monkey/common/cloud/aws/aws_service.py similarity index 98% rename from monkey/common/cloud/aws_service.py rename to monkey/common/cloud/aws/aws_service.py index 6ef385542..a42c2e1dd 100644 --- a/monkey/common/cloud/aws_service.py +++ b/monkey/common/cloud/aws/aws_service.py @@ -4,7 +4,7 @@ import boto3 import botocore from botocore.exceptions import ClientError -from common.cloud.aws_instance import AwsInstance +from common.cloud.aws.aws_instance import AwsInstance __author__ = ['itay.mizeretz', 'shay.nehmad'] diff --git a/monkey/common/cloud/aws_service_test.py b/monkey/common/cloud/aws/aws_service_test.py similarity index 100% rename from monkey/common/cloud/aws_service_test.py rename to monkey/common/cloud/aws/aws_service_test.py diff --git a/monkey/common/cloud/azure/azure_instance.py b/monkey/common/cloud/azure/azure_instance.py index a58e0e126..5222c7620 100644 --- a/monkey/common/cloud/azure/azure_instance.py +++ b/monkey/common/cloud/azure/azure_instance.py @@ -1,13 +1,15 @@ import logging import requests -LATEST_AZURE_METADATA_API_VERSION = "2019-06-04" +from common.cloud.instance import CloudInstance + +LATEST_AZURE_METADATA_API_VERSION = "2019-04-30" AZURE_METADATA_SERVICE_URL = "http://169.254.169.254/metadata/instance?api-version=%s" % LATEST_AZURE_METADATA_API_VERSION logger = logging.getLogger(__name__) -class AzureInstance(object): +class AzureInstance(CloudInstance): """ Access to useful information about the current machine if it's an Azure VM. Based on Azure metadata service: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service @@ -46,5 +48,5 @@ class AzureInstance(object): except KeyError: logger.exception("Error while parsing response from Azure metadata service.") - def is_azure_instance(self): + def is_instance(self): return self.on_azure diff --git a/monkey/common/cloud/environment_names.py b/monkey/common/cloud/environment_names.py index 1745eed62..0c8655753 100644 --- a/monkey/common/cloud/environment_names.py +++ b/monkey/common/cloud/environment_names.py @@ -1,7 +1,12 @@ +# When adding a new environment to this file, make sure to add it to ALL_ENV_NAMES as well! + UNKNOWN = "Unknown" ON_PREMISE = "On Premise" AZURE = "Azure" AWS = "AWS" GCP = "GCP" +ALIBABA = "Alibaba Cloud" +IBM = "IBM Cloud" +DigitalOcean = "Digital Ocean" -ALL_ENV_NAMES = [UNKNOWN, ON_PREMISE, AZURE, AWS, GCP] +ALL_ENV_NAMES = [UNKNOWN, ON_PREMISE, AZURE, AWS, GCP, ALIBABA, IBM, DigitalOcean] diff --git a/monkey/common/cloud/instance.py b/monkey/common/cloud/instance.py new file mode 100644 index 000000000..52dd56b02 --- /dev/null +++ b/monkey/common/cloud/instance.py @@ -0,0 +1,3 @@ +class CloudInstance(object): + def is_instance(self) -> bool: + raise NotImplementedError() diff --git a/monkey/common/cmd/aws/aws_cmd_runner.py b/monkey/common/cmd/aws/aws_cmd_runner.py index 459a42129..1ab680c4d 100644 --- a/monkey/common/cmd/aws/aws_cmd_runner.py +++ b/monkey/common/cmd/aws/aws_cmd_runner.py @@ -1,6 +1,6 @@ import logging -from common.cloud.aws_service import AwsService +from common.cloud.aws.aws_service import AwsService from common.cmd.aws.aws_cmd_result import AwsCmdResult from common.cmd.cmd_runner import CmdRunner from common.cmd.cmd_status import CmdStatus diff --git a/monkey/infection_monkey/system_info/aws_collector.py b/monkey/infection_monkey/system_info/aws_collector.py index df90e5913..f39662d13 100644 --- a/monkey/infection_monkey/system_info/aws_collector.py +++ b/monkey/infection_monkey/system_info/aws_collector.py @@ -1,6 +1,6 @@ import logging -from common.cloud.aws_instance import AwsInstance +from common.cloud.aws.aws_instance import AwsInstance __author__ = 'itay.mizeretz' @@ -17,7 +17,7 @@ class AwsCollector(object): LOG.info("Collecting AWS info") aws = AwsInstance() info = {} - if aws.is_aws_instance(): + if aws.is_instance(): LOG.info("Machine is an AWS instance") info = \ { diff --git a/monkey/infection_monkey/system_info/collectors/environment_collector.py b/monkey/infection_monkey/system_info/collectors/environment_collector.py index 523989f61..208bbfa42 100644 --- a/monkey/infection_monkey/system_info/collectors/environment_collector.py +++ b/monkey/infection_monkey/system_info/collectors/environment_collector.py @@ -1,4 +1,4 @@ -from common.cloud.aws_instance import AwsInstance +from common.cloud.aws.aws_instance import AwsInstance from common.cloud.azure.azure_instance import AzureInstance from common.cloud.environment_names import ON_PREMISE, AZURE, AWS from infection_monkey.system_info.system_info_collector import SystemInfoCollector @@ -6,9 +6,9 @@ from infection_monkey.system_info.system_info_collector import SystemInfoCollect def get_monkey_environment(): # Check if on any cloud env. Default is on prem. - if AwsInstance().is_aws_instance(): + if AwsInstance().is_instance(): env = AWS - elif AzureInstance().is_azure_instance(): + elif AzureInstance().is_instance(): env = AZURE # TODO: elif GcpInstance().is_gcp_instance(): else: diff --git a/monkey/monkey_island/cc/environment/aws.py b/monkey/monkey_island/cc/environment/aws.py index 18db5c376..5608bddcd 100644 --- a/monkey/monkey_island/cc/environment/aws.py +++ b/monkey/monkey_island/cc/environment/aws.py @@ -1,6 +1,6 @@ import monkey_island.cc.auth from monkey_island.cc.environment import Environment -from common.cloud.aws_instance import AwsInstance +from common.cloud.aws.aws_instance import AwsInstance __author__ = 'itay.mizeretz' diff --git a/monkey/monkey_island/cc/resources/remote_run.py b/monkey/monkey_island/cc/resources/remote_run.py index c41699add..98d3694bf 100644 --- a/monkey/monkey_island/cc/resources/remote_run.py +++ b/monkey/monkey_island/cc/resources/remote_run.py @@ -6,7 +6,7 @@ import flask_restful from monkey_island.cc.auth import jwt_required from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService -from common.cloud.aws_service import AwsService +from common.cloud.aws.aws_service import AwsService CLIENT_ERROR_FORMAT = "ClientError, error message: '{}'. Probably, the IAM role that has been associated with the " \ "instance doesn't permit SSM calls. " diff --git a/monkey/monkey_island/cc/services/remote_run_aws.py b/monkey/monkey_island/cc/services/remote_run_aws.py index 9627bf74c..0ba6fa4ef 100644 --- a/monkey/monkey_island/cc/services/remote_run_aws.py +++ b/monkey/monkey_island/cc/services/remote_run_aws.py @@ -1,7 +1,7 @@ import logging -from common.cloud.aws_instance import AwsInstance -from common.cloud.aws_service import AwsService +from common.cloud.aws.aws_instance import AwsInstance +from common.cloud.aws.aws_service import AwsService from common.cmd.aws.aws_cmd_runner import AwsCmdRunner from common.cmd.cmd import Cmd from common.cmd.cmd_runner import CmdRunner @@ -54,7 +54,7 @@ class RemoteRunAwsService: @staticmethod def is_running_on_aws(): - return RemoteRunAwsService.aws_instance.is_aws_instance() + return RemoteRunAwsService.aws_instance.is_instance() @staticmethod def update_aws_region_authless(): diff --git a/monkey/monkey_island/cc/services/reporting/aws_exporter.py b/monkey/monkey_island/cc/services/reporting/aws_exporter.py index 1df12e2eb..86486b9ba 100644 --- a/monkey/monkey_island/cc/services/reporting/aws_exporter.py +++ b/monkey/monkey_island/cc/services/reporting/aws_exporter.py @@ -5,7 +5,7 @@ from datetime import datetime import boto3 from botocore.exceptions import UnknownServiceError -from common.cloud.aws_instance import AwsInstance +from common.cloud.aws.aws_instance import AwsInstance from monkey_island.cc.environment.environment import load_server_configuration_from_file from monkey_island.cc.services.reporting.exporter import Exporter From 676d46307bf4c761bf59f56226e53dc314022155 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Wed, 8 Jan 2020 11:20:49 +0200 Subject: [PATCH 014/119] Using the generic CloudInstance class to determine environment --- monkey/common/cloud/aws/aws_instance.py | 9 ++++++--- monkey/common/cloud/azure/azure_instance.py | 9 ++++++--- monkey/common/cloud/instance.py | 15 +++++++++++++++ .../collectors/environment_collector.py | 15 ++++++--------- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/monkey/common/cloud/aws/aws_instance.py b/monkey/common/cloud/aws/aws_instance.py index 301881894..c77220d17 100644 --- a/monkey/common/cloud/aws/aws_instance.py +++ b/monkey/common/cloud/aws/aws_instance.py @@ -6,6 +6,7 @@ import logging __author__ = 'itay.mizeretz' +from common.cloud.environment_names import AWS from common.cloud.instance import CloudInstance AWS_INSTANCE_METADATA_LOCAL_IP_ADDRESS = "169.254.169.254" @@ -19,6 +20,11 @@ class AwsInstance(CloudInstance): """ Class which gives useful information about the current instance you're on. """ + def is_instance(self): + return self.instance_id is not None + + def get_cloud_provider_name(self) -> str: + return AWS def __init__(self): self.instance_id = None @@ -59,9 +65,6 @@ class AwsInstance(CloudInstance): def get_region(self): return self.region - def is_instance(self): - return self.instance_id is not None - @staticmethod def _extract_account_id(instance_identity_document_response): """ diff --git a/monkey/common/cloud/azure/azure_instance.py b/monkey/common/cloud/azure/azure_instance.py index 5222c7620..f0d5a8044 100644 --- a/monkey/common/cloud/azure/azure_instance.py +++ b/monkey/common/cloud/azure/azure_instance.py @@ -1,6 +1,7 @@ import logging import requests +from common.cloud.environment_names import AZURE from common.cloud.instance import CloudInstance LATEST_AZURE_METADATA_API_VERSION = "2019-04-30" @@ -14,6 +15,11 @@ class AzureInstance(CloudInstance): Access to useful information about the current machine if it's an Azure VM. Based on Azure metadata service: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service """ + def is_instance(self): + return self.on_azure + + def get_cloud_provider_name(self) -> str: + return AZURE def __init__(self): """ @@ -47,6 +53,3 @@ class AzureInstance(CloudInstance): self.location = response_data["compute"]["location"] except KeyError: logger.exception("Error while parsing response from Azure metadata service.") - - def is_instance(self): - return self.on_azure diff --git a/monkey/common/cloud/instance.py b/monkey/common/cloud/instance.py index 52dd56b02..2e702b867 100644 --- a/monkey/common/cloud/instance.py +++ b/monkey/common/cloud/instance.py @@ -1,3 +1,18 @@ +from typing import List + +from common.cloud.aws.aws_instance import AwsInstance +from common.cloud.azure.azure_instance import AzureInstance + + class CloudInstance(object): def is_instance(self) -> bool: raise NotImplementedError() + + def get_cloud_provider_name(self) -> str: + raise NotImplementedError() + + all_cloud_instances = [AwsInstance(), AzureInstance()] + + @staticmethod + def get_all_cloud_instances() -> List['CloudInstance']: + return CloudInstance.all_cloud_instances diff --git a/monkey/infection_monkey/system_info/collectors/environment_collector.py b/monkey/infection_monkey/system_info/collectors/environment_collector.py index 208bbfa42..56df5906b 100644 --- a/monkey/infection_monkey/system_info/collectors/environment_collector.py +++ b/monkey/infection_monkey/system_info/collectors/environment_collector.py @@ -1,18 +1,15 @@ from common.cloud.aws.aws_instance import AwsInstance from common.cloud.azure.azure_instance import AzureInstance from common.cloud.environment_names import ON_PREMISE, AZURE, AWS +from common.cloud.instance import CloudInstance from infection_monkey.system_info.system_info_collector import SystemInfoCollector -def get_monkey_environment(): - # Check if on any cloud env. Default is on prem. - if AwsInstance().is_instance(): - env = AWS - elif AzureInstance().is_instance(): - env = AZURE - # TODO: elif GcpInstance().is_gcp_instance(): - else: - env = ON_PREMISE +def get_monkey_environment() -> str: + env = ON_PREMISE + for instance in CloudInstance.get_all_cloud_instances(): + if instance.is_instance(): + env = instance.get_cloud_provider_name() return env From 875cf3318d4a6373922c99ba6f58a88d0af1b234 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Wed, 8 Jan 2020 12:21:38 +0200 Subject: [PATCH 015/119] Fixed circular import --- monkey/common/cloud/all_instances.py | 11 +++++++++++ monkey/common/cloud/instance.py | 17 +++++------------ .../collectors/environment_collector.py | 3 ++- 3 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 monkey/common/cloud/all_instances.py diff --git a/monkey/common/cloud/all_instances.py b/monkey/common/cloud/all_instances.py new file mode 100644 index 000000000..986bf1a80 --- /dev/null +++ b/monkey/common/cloud/all_instances.py @@ -0,0 +1,11 @@ +from typing import List + +from common.cloud.aws.aws_instance import AwsInstance +from common.cloud.azure.azure_instance import AzureInstance +from common.cloud.instance import CloudInstance + +all_cloud_instances = [AwsInstance(), AzureInstance()] + + +def get_all_cloud_instances() -> List[CloudInstance]: + return all_cloud_instances diff --git a/monkey/common/cloud/instance.py b/monkey/common/cloud/instance.py index 2e702b867..61ab4c734 100644 --- a/monkey/common/cloud/instance.py +++ b/monkey/common/cloud/instance.py @@ -1,18 +1,11 @@ -from typing import List - -from common.cloud.aws.aws_instance import AwsInstance -from common.cloud.azure.azure_instance import AzureInstance - - class CloudInstance(object): + """ + This is an abstract class which represents a cloud instance. + + The current machine can be a cloud instance (for example EC2 instance or Azure VM). + """ def is_instance(self) -> bool: raise NotImplementedError() def get_cloud_provider_name(self) -> str: raise NotImplementedError() - - all_cloud_instances = [AwsInstance(), AzureInstance()] - - @staticmethod - def get_all_cloud_instances() -> List['CloudInstance']: - return CloudInstance.all_cloud_instances diff --git a/monkey/infection_monkey/system_info/collectors/environment_collector.py b/monkey/infection_monkey/system_info/collectors/environment_collector.py index 56df5906b..c679e04f7 100644 --- a/monkey/infection_monkey/system_info/collectors/environment_collector.py +++ b/monkey/infection_monkey/system_info/collectors/environment_collector.py @@ -1,3 +1,4 @@ +from common.cloud.all_instances import get_all_cloud_instances from common.cloud.aws.aws_instance import AwsInstance from common.cloud.azure.azure_instance import AzureInstance from common.cloud.environment_names import ON_PREMISE, AZURE, AWS @@ -7,7 +8,7 @@ from infection_monkey.system_info.system_info_collector import SystemInfoCollect def get_monkey_environment() -> str: env = ON_PREMISE - for instance in CloudInstance.get_all_cloud_instances(): + for instance in get_all_cloud_instances(): if instance.is_instance(): env = instance.get_cloud_provider_name() return env From a3d81a00864c4f8b33bd158b4eb11a1d68921a33 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Wed, 8 Jan 2020 14:00:12 +0200 Subject: [PATCH 016/119] Renamed PlannedShutdown to PlannedShutdownException --- monkey/infection_monkey/monkey.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index 8543505a7..06a08f131 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -39,7 +39,7 @@ __author__ = 'itamar' LOG = logging.getLogger(__name__) -class PlannedShutdown(Exception): +class PlannedShutdownException(Exception): pass @@ -216,14 +216,14 @@ class InfectionMonkey(object): if monkey_tunnel: monkey_tunnel.stop() monkey_tunnel.join() - except PlannedShutdown: + except PlannedShutdownException: LOG.info("A planned shutdown of the Monkey occurred. Logging the reason and finishing execution.") LOG.exception("Planned shutdown, reason:") def shutdown_by_max_depth_reached(self): if 0 == WormConfiguration.depth: TraceTelem(MAX_DEPTH_REACHED_MESSAGE).send() - raise PlannedShutdown(MAX_DEPTH_REACHED_MESSAGE) + raise PlannedShutdownException(MAX_DEPTH_REACHED_MESSAGE) else: LOG.debug("Running with depth: %d" % WormConfiguration.depth) @@ -236,7 +236,7 @@ class InfectionMonkey(object): def shutdown_by_not_alive_config(self): if not WormConfiguration.alive: - raise PlannedShutdown("Marked 'not alive' from configuration.") + raise PlannedShutdownException("Marked 'not alive' from configuration.") def upgrade_to_64_if_needed(self): if WindowsUpgrader.should_upgrade(): @@ -244,7 +244,7 @@ class InfectionMonkey(object): self._singleton.unlock() LOG.info("32bit monkey running on 64bit Windows. Upgrading.") WindowsUpgrader.upgrade(self._opts) - raise PlannedShutdown("Finished upgrading from 32bit to 64bit.") + raise PlannedShutdownException("Finished upgrading from 32bit to 64bit.") def cleanup(self): LOG.info("Monkey cleanup started") @@ -369,9 +369,9 @@ class InfectionMonkey(object): def set_default_server(self): """ Sets the default server for the Monkey to communicate back to. - :raises PlannedShutdown if couldn't find the server. + :raises PlannedShutdownException if couldn't find the server. """ if not ControlClient.find_server(default_tunnel=self._default_tunnel): - raise PlannedShutdown("Monkey couldn't find server with {} default tunnel.".format(self._default_tunnel)) + raise PlannedShutdownException("Monkey couldn't find server with {} default tunnel.".format(self._default_tunnel)) self._default_server = WormConfiguration.current_server LOG.debug("default server set to: %s" % self._default_server) From 41fa1d3e3fe92e96f8c8de99640e06ec910b0303 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Wed, 8 Jan 2020 14:08:53 +0200 Subject: [PATCH 017/119] Made collect an abstract method --- .../infection_monkey/system_info/system_info_collector.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/system_info/system_info_collector.py b/monkey/infection_monkey/system_info/system_info_collector.py index 3a977fcde..f65b4c080 100644 --- a/monkey/infection_monkey/system_info/system_info_collector.py +++ b/monkey/infection_monkey/system_info/system_info_collector.py @@ -1,11 +1,11 @@ from config import WormConfiguration from infection_monkey.utils.plugins.plugin import Plugin - +from abc import ABCMeta, abstractmethod import infection_monkey.system_info.collectors -class SystemInfoCollector(Plugin): +class SystemInfoCollector(Plugin, metaclass=ABCMeta): def __init__(self, name="unknown"): self.name = name @@ -21,10 +21,10 @@ class SystemInfoCollector(Plugin): def base_package_name(): return infection_monkey.system_info.collectors.__package__ + @abstractmethod def collect(self) -> dict: """ Collect the relevant information and return it in a dictionary. To be implemented by each collector. - TODO should this be an abstractmethod, or will that ruin the plugin system somehow? if can be abstract should add UT """ raise NotImplementedError() From 26355540bd70081f32563c6041696a46c8bf3a80 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Wed, 8 Jan 2020 21:06:02 +0200 Subject: [PATCH 018/119] Update system_info_collectors_handler.py --- .../system_info/system_info_collectors_handler.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/monkey/infection_monkey/system_info/system_info_collectors_handler.py b/monkey/infection_monkey/system_info/system_info_collectors_handler.py index 1fdc74cfa..792024b12 100644 --- a/monkey/infection_monkey/system_info/system_info_collectors_handler.py +++ b/monkey/infection_monkey/system_info/system_info_collectors_handler.py @@ -2,14 +2,11 @@ import logging from typing import Sequence from infection_monkey.system_info.system_info_collector import SystemInfoCollector -from telemetry.system_info_telem import SystemInfoTelem +from infection_monkey.telemetry.system_info_telem import SystemInfoTelem LOG = logging.getLogger(__name__) -PATH_TO_COLLECTORS = "infection_monkey.system_info.collectors." - -# TODO Add new collectors to config and config schema class SystemInfoCollectorsHandler(object): def __init__(self): self.collectors_list = self.config_to_collectors_list() From 422fe6ff06e45d7d91164af4090140f70247bafb Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 19 Jan 2020 16:22:28 +0200 Subject: [PATCH 019/119] Added GCP instance as well --- monkey/common/cloud/all_instances.py | 3 +- monkey/common/cloud/gcp/__init__.py | 0 monkey/common/cloud/gcp/gcp_instance.py | 41 +++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 monkey/common/cloud/gcp/__init__.py create mode 100644 monkey/common/cloud/gcp/gcp_instance.py diff --git a/monkey/common/cloud/all_instances.py b/monkey/common/cloud/all_instances.py index 986bf1a80..6387730f6 100644 --- a/monkey/common/cloud/all_instances.py +++ b/monkey/common/cloud/all_instances.py @@ -2,9 +2,10 @@ from typing import List from common.cloud.aws.aws_instance import AwsInstance from common.cloud.azure.azure_instance import AzureInstance +from common.cloud.gcp.gcp_instance import GcpInstance from common.cloud.instance import CloudInstance -all_cloud_instances = [AwsInstance(), AzureInstance()] +all_cloud_instances = [AwsInstance(), AzureInstance(), GcpInstance()] def get_all_cloud_instances() -> List[CloudInstance]: diff --git a/monkey/common/cloud/gcp/__init__.py b/monkey/common/cloud/gcp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/common/cloud/gcp/gcp_instance.py b/monkey/common/cloud/gcp/gcp_instance.py new file mode 100644 index 000000000..5f04aabd0 --- /dev/null +++ b/monkey/common/cloud/gcp/gcp_instance.py @@ -0,0 +1,41 @@ +import logging +import requests + +from common.cloud.environment_names import GCP +from common.cloud.instance import CloudInstance + +logger = logging.getLogger(__name__) +GCP_METADATA_SERVICE_URL = "http://metadata.google.internal/" + + +class GcpInstance(CloudInstance): + def is_instance(self): + return self.on_gcp + + def get_cloud_provider_name(self) -> str: + return GCP + + def __init__(self): + """ + Determines if on GCP. + """ + self.on_gcp = False + + try: + # If not on GCP, this domain shouldn't resolve. + response = requests.get(GCP_METADATA_SERVICE_URL) + + if response: + logger.debug("Got response, so probably on GCP. Trying to parse.") + self.on_gcp = True + + if "Metadata-Flavor" not in response.headers: + logger.warning("Got unexpected GCP Metadata format") + else: + if not response.headers["Metadata-Flavor"] == "Google": + logger.warning("Got unexpected Metadata flavor: {}".format(response.headers["Metadata-Flavor"])) + else: + logger.warning("On GCP, but metadata response not ok: {}".format(response.status_code)) + except requests.RequestException: + logger.debug("Failed to get response from GCP metadata service: This instance is not on GCP.") + self.on_gcp = False From d52672f4d765d77eb5b602fc99c9287eb4a84e6b Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 19 Jan 2020 16:28:04 +0200 Subject: [PATCH 020/119] Added some documentation --- monkey/common/cloud/gcp/gcp_instance.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/monkey/common/cloud/gcp/gcp_instance.py b/monkey/common/cloud/gcp/gcp_instance.py index 5f04aabd0..26738db43 100644 --- a/monkey/common/cloud/gcp/gcp_instance.py +++ b/monkey/common/cloud/gcp/gcp_instance.py @@ -5,10 +5,15 @@ from common.cloud.environment_names import GCP from common.cloud.instance import CloudInstance logger = logging.getLogger(__name__) + + GCP_METADATA_SERVICE_URL = "http://metadata.google.internal/" class GcpInstance(CloudInstance): + """ + Used to determine if on GCP. See https://cloud.google.com/compute/docs/storing-retrieving-metadata#runninggce + """ def is_instance(self): return self.on_gcp @@ -16,9 +21,6 @@ class GcpInstance(CloudInstance): return GCP def __init__(self): - """ - Determines if on GCP. - """ self.on_gcp = False try: @@ -26,7 +28,7 @@ class GcpInstance(CloudInstance): response = requests.get(GCP_METADATA_SERVICE_URL) if response: - logger.debug("Got response, so probably on GCP. Trying to parse.") + logger.debug("Got ok metadata response: on GCP") self.on_gcp = True if "Metadata-Flavor" not in response.headers: @@ -37,5 +39,5 @@ class GcpInstance(CloudInstance): else: logger.warning("On GCP, but metadata response not ok: {}".format(response.status_code)) except requests.RequestException: - logger.debug("Failed to get response from GCP metadata service: This instance is not on GCP.") + logger.debug("Failed to get response from GCP metadata service: This instance is not on GCP") self.on_gcp = False From 9583956683676c2a559b4c88714bbdbdc669f188 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 19 Jan 2020 18:14:59 +0200 Subject: [PATCH 021/119] Optimised imports and added some documentation --- .../system_info/collectors/environment_collector.py | 5 +---- .../infection_monkey/system_info/system_info_collector.py | 8 ++++++++ .../system_info/system_info_collectors_handler.py | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/monkey/infection_monkey/system_info/collectors/environment_collector.py b/monkey/infection_monkey/system_info/collectors/environment_collector.py index c679e04f7..ac5a5433d 100644 --- a/monkey/infection_monkey/system_info/collectors/environment_collector.py +++ b/monkey/infection_monkey/system_info/collectors/environment_collector.py @@ -1,8 +1,5 @@ from common.cloud.all_instances import get_all_cloud_instances -from common.cloud.aws.aws_instance import AwsInstance -from common.cloud.azure.azure_instance import AzureInstance -from common.cloud.environment_names import ON_PREMISE, AZURE, AWS -from common.cloud.instance import CloudInstance +from common.cloud.environment_names import ON_PREMISE from infection_monkey.system_info.system_info_collector import SystemInfoCollector diff --git a/monkey/infection_monkey/system_info/system_info_collector.py b/monkey/infection_monkey/system_info/system_info_collector.py index f65b4c080..c511c1e86 100644 --- a/monkey/infection_monkey/system_info/system_info_collector.py +++ b/monkey/infection_monkey/system_info/system_info_collector.py @@ -6,6 +6,14 @@ import infection_monkey.system_info.collectors class SystemInfoCollector(Plugin, metaclass=ABCMeta): + """ + ABC for system info collection. See system_info_collector_handler for more info. Basically, to implement a new system info + collector, inherit from this class in an implementation in the infection_monkey.system_info.collectors class, and override + the 'collect' method. Don't forget to parse your results in the Monkey Island and to add the collector to the configuration + as well - see monkey_island.cc.services.processing.system_info_collectors for examples. + + See the Wiki page "How to add a new System Info Collector to the Monkey?" for a detailed guide. + """ def __init__(self, name="unknown"): self.name = name diff --git a/monkey/infection_monkey/system_info/system_info_collectors_handler.py b/monkey/infection_monkey/system_info/system_info_collectors_handler.py index 792024b12..cc007ff86 100644 --- a/monkey/infection_monkey/system_info/system_info_collectors_handler.py +++ b/monkey/infection_monkey/system_info/system_info_collectors_handler.py @@ -21,6 +21,7 @@ class SystemInfoCollectorsHandler(object): system_info_telemetry[collector.name] = collected_info successful_collections += 1 except Exception as e: + # If we failed one collector, no need to stop execution. Log and continue. LOG.error("Collector {} failed. Error info: {}".format(collector.name, e)) LOG.info("All system info collectors executed. Total {} executed, out of which {} collected successfully.". format(len(self.collectors_list), successful_collections)) From 3496a78f6c0fdf2b0ee4128da2c14c9a77b72d6e Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 19 Jan 2020 21:36:01 +0200 Subject: [PATCH 022/119] Added generic collector processing functions, a dispatcher (name to function) with unit tests, and moved AWS to collector from regular sysinfo --- monkey/infection_monkey/config.py | 2 +- .../infection_monkey/system_info/__init__.py | 10 --- .../system_info/collectors/aws_collector.py | 30 +++++++++ monkey/monkey_island/cc/server_config.json | 2 +- .../cc/services/config_schema.py | 11 +++- .../telemetry/processing/system_info.py | 11 +--- .../processing/system_info_collectors/aws.py | 15 +++++ .../system_info_collectors/environment.py | 12 ++-- .../system_info_telemetry_dispatcher.py | 36 ++++++++++ .../test_system_info_telemetry_dispatcher.py | 65 +++++++++++++++++++ 10 files changed, 165 insertions(+), 29 deletions(-) create mode 100644 monkey/infection_monkey/system_info/collectors/aws_collector.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/aws.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py index e76ed8101..e1b1ece83 100644 --- a/monkey/infection_monkey/config.py +++ b/monkey/infection_monkey/config.py @@ -125,7 +125,7 @@ class Configuration(object): finger_classes = [] exploiter_classes = [] - system_info_collectors_classes = ["EnvironmentCollector"] + system_info_collectors_classes = ["EnvironmentCollector", "AwsCollector"] # how many victims to look for in a single scan iteration victims_max_find = 100 diff --git a/monkey/infection_monkey/system_info/__init__.py b/monkey/infection_monkey/system_info/__init__.py index ccec45cde..fc4aa1caf 100644 --- a/monkey/infection_monkey/system_info/__init__.py +++ b/monkey/infection_monkey/system_info/__init__.py @@ -6,7 +6,6 @@ import psutil from enum import IntEnum from infection_monkey.network.info import get_host_subnets -from infection_monkey.system_info.aws_collector import AwsCollector from infection_monkey.system_info.azure_cred_collector import AzureCollector from infection_monkey.system_info.netstat_collector import NetstatCollector from system_info.system_info_collectors_handler import SystemInfoCollectorsHandler @@ -67,7 +66,6 @@ class InfoCollector(object): self.get_process_list() self.get_network_info() self.get_azure_info() - self.get_aws_info() # Collect all plugins SystemInfoCollectorsHandler().execute_all_configured() @@ -155,11 +153,3 @@ class InfoCollector(object): except Exception: # If we failed to collect azure info, no reason to fail all the collection. Log and continue. LOG.error("Failed collecting Azure info.", exc_info=True) - - def get_aws_info(self): - # noinspection PyBroadException - try: - self.info['aws'] = AwsCollector().get_aws_info() - except Exception: - # If we failed to collect aws info, no reason to fail all the collection. Log and continue. - LOG.error("Failed collecting AWS info.", exc_info=True) diff --git a/monkey/infection_monkey/system_info/collectors/aws_collector.py b/monkey/infection_monkey/system_info/collectors/aws_collector.py new file mode 100644 index 000000000..71f9e58c1 --- /dev/null +++ b/monkey/infection_monkey/system_info/collectors/aws_collector.py @@ -0,0 +1,30 @@ +import logging + +from common.cloud.aws.aws_instance import AwsInstance +from infection_monkey.system_info.system_info_collector import SystemInfoCollector + + +logger = logging.getLogger(__name__) + + +class AwsCollector(SystemInfoCollector): + """ + Extract info from AWS machines. + """ + def __init__(self): + super(AwsCollector, self).__init__(name="AwsCollector") + + def collect(self) -> dict: + logger.info("Collecting AWS info") + aws = AwsInstance() + info = {} + if aws.is_instance(): + logger.info("Machine is an AWS instance") + info = \ + { + 'instance_id': aws.get_instance_id() + } + else: + logger.info("Machine is NOT an AWS instance") + + return info diff --git a/monkey/monkey_island/cc/server_config.json b/monkey/monkey_island/cc/server_config.json index 420f1b303..7bf106194 100644 --- a/monkey/monkey_island/cc/server_config.json +++ b/monkey/monkey_island/cc/server_config.json @@ -1,4 +1,4 @@ { - "server_config": "standard", + "server_config": "testing", "deployment": "develop" } diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index 5de57e26b..d5e015866 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -111,6 +111,14 @@ SCHEMA = { "title": "Which Environment this machine is on (on prem/cloud)", "attack_techniques": [] }, + { + "type": "string", + "enum": [ + "AwsCollector" + ], + "title": "If on AWS, collect more information about the instance", + "attack_techniques": [] + }, ], }, "post_breach_acts": { @@ -455,7 +463,8 @@ SCHEMA = { "$ref": "#/definitions/system_info_collectors_classes" }, "default": [ - "EnvironmentCollector" + "EnvironmentCollector", + "AwsCollector" ], "description": "Determines which system information collectors will collect information." }, diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index 04ab27d95..915fa7a25 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -5,6 +5,7 @@ from monkey_island.cc.models import Monkey from monkey_island.cc.services import mimikatz_utils from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.config import ConfigService +from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import process_aws_telemetry from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import process_environment_telemetry from monkey_island.cc.services.telemetry.zero_trust_tests.antivirus_existence import test_antivirus_existence from monkey_island.cc.services.wmi_handler import WMIHandler @@ -18,7 +19,7 @@ def process_system_info_telemetry(telemetry_json): process_ssh_info, process_credential_info, process_mimikatz_and_wmi_info, - process_aws_data, + process_aws_telemetry, update_db_with_new_hostname, test_antivirus_existence, process_environment_telemetry @@ -116,13 +117,5 @@ def process_mimikatz_and_wmi_info(telemetry_json): wmi_handler.process_and_handle_wmi_info() -def process_aws_data(telemetry_json): - if 'aws' in telemetry_json['data']: - if 'instance_id' in telemetry_json['data']['aws']: - monkey_id = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid']).get('_id') - mongo.db.monkey.update_one({'_id': monkey_id}, - {'$set': {'aws_instance_id': telemetry_json['data']['aws']['instance_id']}}) - - def update_db_with_new_hostname(telemetry_json): Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']).set_hostname(telemetry_json['data']['hostname']) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/aws.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/aws.py new file mode 100644 index 000000000..2b4d8085e --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/aws.py @@ -0,0 +1,15 @@ +import logging + +from monkey_island.cc.models.monkey import Monkey + +logger = logging.getLogger(__name__) + + +def process_aws_telemetry(collector_results, monkey_guid): + relevant_monkey = Monkey.get_single_monkey_by_guid(monkey_guid) + + if "instance_id" in collector_results: + instance_id = collector_results["instance_id"] + relevant_monkey.aws_instance_id = instance_id + relevant_monkey.save() + logger.debug("Updated Monkey {} with aws instance id {}".format(str(relevant_monkey), instance_id)) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/environment.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/environment.py index d66019b39..9ddee70ce 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/environment.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/environment.py @@ -5,10 +5,8 @@ from monkey_island.cc.models.monkey import Monkey logger = logging.getLogger(__name__) -def process_environment_telemetry(telemetry_json): - if "EnvironmentCollector" in telemetry_json["data"]["collectors"]: - env = telemetry_json["data"]["collectors"]["EnvironmentCollector"]["environment"] - relevant_monkey = Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']) - relevant_monkey.environment = env - relevant_monkey.save() - logger.debug("Updated Monkey {} with env {}".format(str(relevant_monkey), env)) +def process_environment_telemetry(collector_results, monkey_guid): + relevant_monkey = Monkey.get_single_monkey_by_guid(monkey_guid) + relevant_monkey.environment = collector_results + relevant_monkey.save() + logger.debug("Updated Monkey {} with env {}".format(str(relevant_monkey), collector_results)) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py new file mode 100644 index 000000000..661034efb --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py @@ -0,0 +1,36 @@ +import logging + +from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import process_aws_telemetry +from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import process_environment_telemetry + +logger = logging.getLogger(__name__) + +SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSOR = { + "AwsCollector": process_aws_telemetry, + "EnvironmentCollector": process_environment_telemetry, +} + + +class SystemInfoTelemetryDispatcher(object): + def __init__(self, collector_to_parsing_function=None): + if collector_to_parsing_function is None: + collector_to_parsing_function = SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSOR + self.collector_to_parsing_function = collector_to_parsing_function + + def dispatch_to_relevant_collector(self, telemetry_json): + if "collectors" in telemetry_json["data"]: + self.send_each_result_to_relevant_processor(telemetry_json) + + def send_each_result_to_relevant_processor(self, telemetry_json): + relevant_monkey_guid = telemetry_json['monkey_guid'] + for collector_name, collector_results in telemetry_json["data"]["collectors"].items(): + if collector_name in self.collector_to_parsing_function: + # noinspection PyBroadException + try: + self.collector_to_parsing_function[collector_name](collector_results, relevant_monkey_guid) + except Exception as e: + logger.error( + "Error {} while processing {} system info telemetry".format(str(e), collector_name), + exc_info=True) + else: + logger.warning("Unknown system info collector name: {}".format(collector_name)) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py new file mode 100644 index 000000000..db36cd5bb --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py @@ -0,0 +1,65 @@ +from importlib import reload +from unittest import mock +from unittest.mock import MagicMock + +import uuid + +from monkey_island.cc.models import Monkey +from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import \ + SystemInfoTelemetryDispatcher +from monkey_island.cc.testing.IslandTestCase import IslandTestCase +from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import \ + process_aws_telemetry + +TEST_SYS_INFO_TO_PROCESSING = { + "AwsCollector": process_aws_telemetry, +} + + +def do_nothing(x, y): + pass + + +class SystemInfoTelemetryDispatcherTest(IslandTestCase): + def test_dispatch_to_relevant_collector_bad_inputs(self): + self.fail_if_not_testing_env() + + dispatcher = SystemInfoTelemetryDispatcher(TEST_SYS_INFO_TO_PROCESSING) + + # Bad format telem JSONs - throws + bad_empty_telem_json = {} + self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collector, bad_empty_telem_json) + bad_no_data_telem_json = {"monkey_guid": "bla"} + self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collector, bad_no_data_telem_json) + bad_no_monkey_telem_json = {"data": {"collectors": {"AwsCollector": "Bla"}}} + self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collector, bad_no_monkey_telem_json) + + # Telem JSON with no collectors - nothing gets dispatched + good_telem_no_collectors = {"monkey_guid": "bla", "data": {"bla": "bla"}} + good_telem_empty_collectors = {"monkey_guid": "bla", "data": {"bla": "bla", "collectors": {}}} + + dispatcher.dispatch_to_relevant_collector(good_telem_no_collectors) + dispatcher.dispatch_to_relevant_collector(good_telem_empty_collectors) + + def test_dispatch_to_relevant_collector(self): + self.fail_if_not_testing_env() + self.clean_monkey_db() + + a_monkey = Monkey(guid=str(uuid.uuid4())) + a_monkey.save() + + dispatcher = SystemInfoTelemetryDispatcher() + + # JSON with results - make sure functions are called + instance_id = "i-0bd2c14bd4c7d703f" + telem_json = { + "data": { + "collectors": { + "AwsCollector": {"instance_id": instance_id}, + } + }, + "monkey_guid": a_monkey.guid + } + dispatcher.dispatch_to_relevant_collector(telem_json) + + self.assertEquals(Monkey.get_single_monkey_by_guid(a_monkey.guid).aws_instance_id, instance_id) From 6815433a85d493778f085c908cbd79f1d4c58f0b Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 19 Jan 2020 21:39:36 +0200 Subject: [PATCH 023/119] Using the dispatcher instead of naming the functions one by one + optimize imports --- .../telemetry/processing/system_info.py | 13 +++++------ .../system_info_telemetry_dispatcher.py | 2 +- .../test_system_info_telemetry_dispatcher.py | 22 ++++++------------- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index 915fa7a25..6734c6725 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -1,28 +1,27 @@ import logging -from monkey_island.cc.database import mongo +from monkey_island.cc.encryptor import encryptor from monkey_island.cc.models import Monkey from monkey_island.cc.services import mimikatz_utils -from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import process_aws_telemetry -from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import process_environment_telemetry +from monkey_island.cc.services.node import NodeService +from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import \ + SystemInfoTelemetryDispatcher from monkey_island.cc.services.telemetry.zero_trust_tests.antivirus_existence import test_antivirus_existence from monkey_island.cc.services.wmi_handler import WMIHandler -from monkey_island.cc.encryptor import encryptor logger = logging.getLogger(__name__) def process_system_info_telemetry(telemetry_json): + dispatcher = SystemInfoTelemetryDispatcher() telemetry_processing_stages = [ process_ssh_info, process_credential_info, process_mimikatz_and_wmi_info, - process_aws_telemetry, update_db_with_new_hostname, test_antivirus_existence, - process_environment_telemetry + dispatcher.dispatch_to_relevant_collectors ] # Calling safe_process_telemetry so if one of the stages fail, we log and move on instead of failing the rest of diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py index 661034efb..64fb146ab 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py @@ -17,7 +17,7 @@ class SystemInfoTelemetryDispatcher(object): collector_to_parsing_function = SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSOR self.collector_to_parsing_function = collector_to_parsing_function - def dispatch_to_relevant_collector(self, telemetry_json): + def dispatch_to_relevant_collectors(self, telemetry_json): if "collectors" in telemetry_json["data"]: self.send_each_result_to_relevant_processor(telemetry_json) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py index db36cd5bb..4db5352c8 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py @@ -1,25 +1,17 @@ -from importlib import reload -from unittest import mock -from unittest.mock import MagicMock - import uuid from monkey_island.cc.models import Monkey from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import \ SystemInfoTelemetryDispatcher -from monkey_island.cc.testing.IslandTestCase import IslandTestCase from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import \ process_aws_telemetry +from monkey_island.cc.testing.IslandTestCase import IslandTestCase TEST_SYS_INFO_TO_PROCESSING = { "AwsCollector": process_aws_telemetry, } -def do_nothing(x, y): - pass - - class SystemInfoTelemetryDispatcherTest(IslandTestCase): def test_dispatch_to_relevant_collector_bad_inputs(self): self.fail_if_not_testing_env() @@ -28,18 +20,18 @@ class SystemInfoTelemetryDispatcherTest(IslandTestCase): # Bad format telem JSONs - throws bad_empty_telem_json = {} - self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collector, bad_empty_telem_json) + self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collectors, bad_empty_telem_json) bad_no_data_telem_json = {"monkey_guid": "bla"} - self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collector, bad_no_data_telem_json) + self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collectors, bad_no_data_telem_json) bad_no_monkey_telem_json = {"data": {"collectors": {"AwsCollector": "Bla"}}} - self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collector, bad_no_monkey_telem_json) + self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collectors, bad_no_monkey_telem_json) # Telem JSON with no collectors - nothing gets dispatched good_telem_no_collectors = {"monkey_guid": "bla", "data": {"bla": "bla"}} good_telem_empty_collectors = {"monkey_guid": "bla", "data": {"bla": "bla", "collectors": {}}} - dispatcher.dispatch_to_relevant_collector(good_telem_no_collectors) - dispatcher.dispatch_to_relevant_collector(good_telem_empty_collectors) + dispatcher.dispatch_to_relevant_collectors(good_telem_no_collectors) + dispatcher.dispatch_to_relevant_collectors(good_telem_empty_collectors) def test_dispatch_to_relevant_collector(self): self.fail_if_not_testing_env() @@ -60,6 +52,6 @@ class SystemInfoTelemetryDispatcherTest(IslandTestCase): }, "monkey_guid": a_monkey.guid } - dispatcher.dispatch_to_relevant_collector(telem_json) + dispatcher.dispatch_to_relevant_collectors(telem_json) self.assertEquals(Monkey.get_single_monkey_by_guid(a_monkey.guid).aws_instance_id, instance_id) From 2a09d54ed12587eaf6ed6c69397a500d638b49ae Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 19 Jan 2020 21:45:31 +0200 Subject: [PATCH 024/119] Fixed dict bugs + server config --- monkey/monkey_island/cc/server_config.json | 2 +- .../cc/services/telemetry/processing/system_info.py | 3 ++- .../telemetry/processing/system_info_collectors/environment.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/server_config.json b/monkey/monkey_island/cc/server_config.json index 7bf106194..420f1b303 100644 --- a/monkey/monkey_island/cc/server_config.json +++ b/monkey/monkey_island/cc/server_config.json @@ -1,4 +1,4 @@ { - "server_config": "testing", + "server_config": "standard", "deployment": "develop" } diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index 6734c6725..d4368469e 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -117,4 +117,5 @@ def process_mimikatz_and_wmi_info(telemetry_json): def update_db_with_new_hostname(telemetry_json): - Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']).set_hostname(telemetry_json['data']['hostname']) + if 'hostname' in telemetry_json['data']: + Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']).set_hostname(telemetry_json['data']['hostname']) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/environment.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/environment.py index 9ddee70ce..4c685a01b 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/environment.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/environment.py @@ -7,6 +7,6 @@ logger = logging.getLogger(__name__) def process_environment_telemetry(collector_results, monkey_guid): relevant_monkey = Monkey.get_single_monkey_by_guid(monkey_guid) - relevant_monkey.environment = collector_results + relevant_monkey.environment = collector_results["environment"] relevant_monkey.save() logger.debug("Updated Monkey {} with env {}".format(str(relevant_monkey), collector_results)) From 3191b2d94ec3c84e473140a92291c9287cb6db4c Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sat, 4 Jan 2020 23:17:48 +0200 Subject: [PATCH 025/119] Make deploy_linux.sh download the configuration, avoiding need for duplicate git clone. --- deployment_scripts/README.md | 4 +++- deployment_scripts/deploy_linux.sh | 36 +++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/deployment_scripts/README.md b/deployment_scripts/README.md index f69a48b77..f51bd151e 100644 --- a/deployment_scripts/README.md +++ b/deployment_scripts/README.md @@ -15,7 +15,9 @@ Don't forget to add python to PATH or do so while installing it via this script. Linux deployment script is meant for Ubuntu 16.x machines. You must have root permissions, but don't run the script as root.
-Launch deploy_linux.sh from scripts directory.
+`wget https://raw.githubusercontent.com/guardicore/monkey/develop/deployment_scripts/deploy_linux.sh` + +Then execute the resulting script with your shell. First argument should be an absolute path of an empty directory (script will create one if doesn't exist, default is ./infection_monkey). Second parameter is the branch you want to clone (develop by default). Example usages:
diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 834d811a7..c41774393 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -1,10 +1,31 @@ #!/bin/bash -source config exists() { command -v "$1" >/dev/null 2>&1 } +is_root() { + return $(id -u) +} + +has_sudo() { + # 0 true, 1 false + timeout 1 sudo id && return 0 || return 1 +} + +config_branch=${2:-"develop"} +config_url="https://raw.githubusercontent.com/guardicore/monkey/"$config_branch"/deployment_scripts/config" + +if exists curl; then + file=$(mktemp) + curl -s -o $file "$config_url" + source $file + rm $file +else + echo 'Your system does not have curl, exiting' + exit 1 +fi + # Setup monkey either in dir required or current dir monkey_home=${1:-$(pwd)} if [[ $monkey_home == $(pwd) ]]; then @@ -30,8 +51,13 @@ log_message() { echo -e "-------------------------------------------\n" } -sudo -v -if [[ $? != 0 ]]; then +if is_root; then + echo "Please don't runt this script as root" + exit 1 +fi + +HAS_SUDO=$(has_sudo) +if [[ ! $HAS_SUDO ]]; then echo "You need root permissions for some of this script operations. Quiting." exit 1 fi @@ -46,8 +72,8 @@ if ! exists git; then fi if ! exists wget; then - echo 'Your system does have wget, please install and re-run this script' - exit 1 + echo 'Your system does have wget, please install and re-run this script' + exit 1 fi log_message "Cloning files from git" From 43adea072882629b67b1c43551d6eaa2b29cb08b Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sat, 4 Jan 2020 23:27:19 +0200 Subject: [PATCH 026/119] Ran format on PS1 script --- deployment_scripts/deploy_windows.ps1 | 221 +++++++++++++++----------- 1 file changed, 124 insertions(+), 97 deletions(-) diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index dd602e199..fb0f29305 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -1,77 +1,92 @@ -function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, [String] $branch = "develop"){ - # Import the config variables - . ./config.ps1 - "Config variables from config.ps1 imported" - - # If we want monkey in current dir we need to create an empty folder for source files - if ( (Join-Path $monkey_home '') -eq (Join-Path (Get-Item -Path ".\").FullName '') ){ - $monkey_home = Join-Path -Path $monkey_home -ChildPath $MONKEY_FOLDER_NAME - } +function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, [String] $branch = "develop") +{ # Set variables for script execution [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $webClient = New-Object System.Net.WebClient + + # Import the config variables + . ./config.ps1 + "Config variables from config.ps1 imported" + + # If we want monkey in current dir we need to create an empty folder for source files + if ((Join-Path $monkey_home '') -eq (Join-Path (Get-Item -Path ".\").FullName '')) + { + $monkey_home = Join-Path -Path $monkey_home -ChildPath $MONKEY_FOLDER_NAME + } + + # We check if git is installed try { - git | Out-Null -ErrorAction Stop - "Git requirement satisfied" + git | Out-Null -ErrorAction Stop + "Git requirement satisfied" } catch [System.Management.Automation.CommandNotFoundException] { - "Please install git before running this script or add it to path and restart cmd" - return + "Please install git before running this script or add it to path and restart cmd" + return } # Download the monkey $output = cmd.exe /c "git clone --single-branch -b $branch $MONKEY_GIT_URL $monkey_home 2>&1" $binDir = (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\bin") - if ( $output -like "*already exists and is not an empty directory.*"){ - "Assuming you already have the source directory. If not, make sure to set an empty directory as monkey's home directory." - } elseif ($output -like "fatal:*"){ - "Error while cloning monkey from the repository:" - $output - return - } else { - "Monkey cloned from the repository" - # Create bin directory - New-Item -ItemType directory -path $binDir - "Bin directory added" + if ($output -like "*already exists and is not an empty directory.*") + { + "Assuming you already have the source directory. If not, make sure to set an empty directory as monkey's home directory." + } + elseif ($output -like "fatal:*") + { + "Error while cloning monkey from the repository:" + $output + return + } + else + { + "Monkey cloned from the repository" + # Create bin directory + New-Item -ItemType directory -path $binDir + "Bin directory added" } # We check if python is installed try { - $version = cmd.exe /c '"python" --version 2>&1' - if ( $version -like 'Python 3.*' ) { - "Python 3.* was found, installing dependencies" - } else { - throw System.Management.Automation.CommandNotFoundException - } + $version = cmd.exe /c '"python" --version 2>&1' + if ($version -like 'Python 3.*') + { + "Python 3.* was found, installing dependencies" + } + else + { + throw System.Management.Automation.CommandNotFoundException + } } catch [System.Management.Automation.CommandNotFoundException] { - "Downloading python 3 ..." - "Select 'add to PATH' when installing" - $webClient.DownloadFile($PYTHON_URL, $TEMP_PYTHON_INSTALLER) - Start-Process -Wait $TEMP_PYTHON_INSTALLER -ErrorAction Stop - $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") - Remove-Item $TEMP_PYTHON_INSTALLER - # Check if installed correctly - $version = cmd.exe /c '"python" --version 2>&1' - if ( $version -like '* is not recognized*' ) { - "Python is not found in PATH. Add it to PATH and relaunch the script." - return - } + "Downloading python 3 ..." + "Select 'add to PATH' when installing" + $webClient.DownloadFile($PYTHON_URL, $TEMP_PYTHON_INSTALLER) + Start-Process -Wait $TEMP_PYTHON_INSTALLER -ErrorAction Stop + $env: Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") + Remove-Item $TEMP_PYTHON_INSTALLER + # Check if installed correctly + $version = cmd.exe /c '"python" --version 2>&1' + if ($version -like '* is not recognized*') + { + "Python is not found in PATH. Add it to PATH and relaunch the script." + return + } } "Upgrading pip..." $output = cmd.exe /c 'python -m pip install --user --upgrade pip 2>&1' $output - if ( $output -like '*No module named pip*' ) { - "Make sure pip module is installed and re-run this script." - return + if ($output -like '*No module named pip*') + { + "Make sure pip module is installed and re-run this script." + return } "Installing python packages for island" @@ -83,28 +98,32 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, $user_python_dir = cmd.exe /c 'py -m site --user-site' $user_python_dir = Join-Path (Split-Path $user_python_dir) -ChildPath "\Scripts" - if(!($ENV:PATH | Select-String -SimpleMatch $user_python_dir)){ - "Adding python scripts path to user's env" - $env:Path += ";"+$user_python_dir - [Environment]::SetEnvironmentVariable("Path",$env:Path,"User") + if (!($ENV: PATH | Select-String -SimpleMatch $user_python_dir)) + { + "Adding python scripts path to user's env" + $env: Path += ";" + $user_python_dir + [Environment]::SetEnvironmentVariable("Path", $env:Path, "User") } # Download mongodb - if(!(Test-Path -Path (Join-Path -Path $binDir -ChildPath "mongodb") )){ - "Downloading mongodb ..." - $webClient.DownloadFile($MONGODB_URL, $TEMP_MONGODB_ZIP) - "Unzipping mongodb" - Expand-Archive $TEMP_MONGODB_ZIP -DestinationPath $binDir - # Get unzipped folder's name - $mongodb_folder = Get-ChildItem -Path $binDir | Where-Object -FilterScript {($_.Name -like "mongodb*")} | Select-Object -ExpandProperty Name - # Move all files from extracted folder to mongodb folder - New-Item -ItemType directory -Path (Join-Path -Path $binDir -ChildPath "mongodb") - New-Item -ItemType directory -Path (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "db") - "Moving extracted files" - Move-Item -Path (Join-Path -Path $binDir -ChildPath $mongodb_folder | Join-Path -ChildPath "\bin\*") -Destination (Join-Path -Path $binDir -ChildPath "mongodb\") - "Removing zip file" - Remove-Item $TEMP_MONGODB_ZIP - Remove-Item (Join-Path -Path $binDir -ChildPath $mongodb_folder) -Recurse + if (!(Test-Path -Path (Join-Path -Path $binDir -ChildPath "mongodb"))) + { + "Downloading mongodb ..." + $webClient.DownloadFile($MONGODB_URL, $TEMP_MONGODB_ZIP) + "Unzipping mongodb" + Expand-Archive $TEMP_MONGODB_ZIP -DestinationPath $binDir + # Get unzipped folder's name + $mongodb_folder = Get-ChildItem -Path $binDir | Where-Object -FilterScript { + ($_.Name -like "mongodb*") + } | Select-Object -ExpandProperty Name + # Move all files from extracted folder to mongodb folder + New-Item -ItemType directory -Path (Join-Path -Path $binDir -ChildPath "mongodb") + New-Item -ItemType directory -Path (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "db") + "Moving extracted files" + Move-Item -Path (Join-Path -Path $binDir -ChildPath $mongodb_folder | Join-Path -ChildPath "\bin\*") -Destination (Join-Path -Path $binDir -ChildPath "mongodb\") + "Removing zip file" + Remove-Item $TEMP_MONGODB_ZIP + Remove-Item (Join-Path -Path $binDir -ChildPath $mongodb_folder) -Recurse } # Download OpenSSL @@ -140,20 +159,23 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, "Installing npm" try { - $version = cmd.exe /c '"npm" --version 2>&1' - if ( $version -like "*is not recognized*"){ - throw System.Management.Automation.CommandNotFoundException - } else { - "Npm already installed" - } + $version = cmd.exe /c '"npm" --version 2>&1' + if ($version -like "*is not recognized*") + { + throw System.Management.Automation.CommandNotFoundException + } + else + { + "Npm already installed" + } } catch [System.Management.Automation.CommandNotFoundException] { - "Downloading npm ..." - $webClient.DownloadFile($NPM_URL, $TEMP_NPM_INSTALLER) - Start-Process -Wait $TEMP_NPM_INSTALLER - $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") - Remove-Item $TEMP_NPM_INSTALLER + "Downloading npm ..." + $webClient.DownloadFile($NPM_URL, $TEMP_NPM_INSTALLER) + Start-Process -Wait $TEMP_NPM_INSTALLER + $env: Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + Remove-Item $TEMP_NPM_INSTALLER } "Updating npm" @@ -173,41 +195,46 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, New-Item -ItemType directory -path $binaries -ErrorAction SilentlyContinue # Download upx - if(!(Test-Path -Path (Join-Path -Path $binDir -ChildPath "upx.exe") )){ - "Downloading upx ..." - $webClient.DownloadFile($UPX_URL, $TEMP_UPX_ZIP) - "Unzipping upx" - Expand-Archive $TEMP_UPX_ZIP -DestinationPath $binDir -ErrorAction SilentlyContinue - Move-Item -Path (Join-Path -Path $binDir -ChildPath $UPX_FOLDER | Join-Path -ChildPath "upx.exe") -Destination $binDir - # Remove unnecessary files - Remove-Item -Recurse -Force (Join-Path -Path $binDir -ChildPath $UPX_FOLDER) - "Removing zip file" - Remove-Item $TEMP_UPX_ZIP + if (!(Test-Path -Path (Join-Path -Path $binDir -ChildPath "upx.exe"))) + { + "Downloading upx ..." + $webClient.DownloadFile($UPX_URL, $TEMP_UPX_ZIP) + "Unzipping upx" + Expand-Archive $TEMP_UPX_ZIP -DestinationPath $binDir -ErrorAction SilentlyContinue + Move-Item -Path (Join-Path -Path $binDir -ChildPath $UPX_FOLDER | Join-Path -ChildPath "upx.exe") -Destination $binDir + # Remove unnecessary files + Remove-Item -Recurse -Force (Join-Path -Path $binDir -ChildPath $UPX_FOLDER) + "Removing zip file" + Remove-Item $TEMP_UPX_ZIP } # Download mimikatz binaries $mk32_path = Join-Path -Path $binDir -ChildPath $MK32_DLL - if(!(Test-Path -Path $mk32_path )){ - "Downloading mimikatz 32 binary" - $webClient.DownloadFile($MK32_DLL_URL, $mk32_path) + if (!(Test-Path -Path $mk32_path)) + { + "Downloading mimikatz 32 binary" + $webClient.DownloadFile($MK32_DLL_URL, $mk32_path) } $mk64_path = Join-Path -Path $binDir -ChildPath $MK64_DLL - if(!(Test-Path -Path $mk64_path )){ - "Downloading mimikatz 64 binary" - $webClient.DownloadFile($MK64_DLL_URL, $mk64_path) + if (!(Test-Path -Path $mk64_path)) + { + "Downloading mimikatz 64 binary" + $webClient.DownloadFile($MK64_DLL_URL, $mk64_path) } # Download sambacry binaries $samba_path = Join-Path -Path $monkey_home -ChildPath $SAMBA_BINARIES_DIR $samba32_path = Join-Path -Path $samba_path -ChildPath $SAMBA_32_BINARY_NAME - if(!(Test-Path -Path $samba32_path )){ - "Downloading sambacry 32 binary" - $webClient.DownloadFile($SAMBA_32_BINARY_URL, $samba32_path) + if (!(Test-Path -Path $samba32_path)) + { + "Downloading sambacry 32 binary" + $webClient.DownloadFile($SAMBA_32_BINARY_URL, $samba32_path) } $samba64_path = Join-Path -Path $samba_path -ChildPath $SAMBA_64_BINARY_NAME - if(!(Test-Path -Path $samba64_path )){ - "Downloading sambacry 64 binary" - $webClient.DownloadFile($SAMBA_64_BINARY_URL, $samba64_path) + if (!(Test-Path -Path $samba64_path)) + { + "Downloading sambacry 64 binary" + $webClient.DownloadFile($SAMBA_64_BINARY_URL, $samba64_path) } "Script finished" From cb8d2eb0ef6e2ae584497e7bc654dc41a2f65c73 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sat, 4 Jan 2020 23:27:26 +0200 Subject: [PATCH 027/119] Make deploy_windows.ps1.sh download the configuration, avoiding need for duplicate git clone. --- deployment_scripts/deploy_windows.ps1 | 177 +++++++++++++------------- 1 file changed, 90 insertions(+), 87 deletions(-) diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index fb0f29305..b04d04e0f 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -7,26 +7,29 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, # Import the config variables + $config_filename = "config.ps1" + $config_url = "https://raw.githubusercontent.com/guardicore/monkey/" + $branch + "/deployment_scripts/config.ps1" + $webClient.DownloadFile($config_url, $config_filename) . ./config.ps1 "Config variables from config.ps1 imported" # If we want monkey in current dir we need to create an empty folder for source files if ((Join-Path $monkey_home '') -eq (Join-Path (Get-Item -Path ".\").FullName '')) { - $monkey_home = Join-Path -Path $monkey_home -ChildPath $MONKEY_FOLDER_NAME + $monkey_home = Join-Path -Path $monkey_home -ChildPath $MONKEY_FOLDER_NAME } # We check if git is installed try { - git | Out-Null -ErrorAction Stop - "Git requirement satisfied" + git | Out-Null -ErrorAction Stop + "Git requirement satisfied" } catch [System.Management.Automation.CommandNotFoundException] { - "Please install git before running this script or add it to path and restart cmd" - return + "Please install git before running this script or add it to path and restart cmd" + return } # Download the monkey @@ -34,50 +37,50 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, $binDir = (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\bin") if ($output -like "*already exists and is not an empty directory.*") { - "Assuming you already have the source directory. If not, make sure to set an empty directory as monkey's home directory." + "Assuming you already have the source directory. If not, make sure to set an empty directory as monkey's home directory." } elseif ($output -like "fatal:*") { - "Error while cloning monkey from the repository:" - $output - return + "Error while cloning monkey from the repository:" + $output + return } else { - "Monkey cloned from the repository" - # Create bin directory - New-Item -ItemType directory -path $binDir - "Bin directory added" + "Monkey cloned from the repository" + # Create bin directory + New-Item -ItemType directory -path $binDir + "Bin directory added" } # We check if python is installed try { - $version = cmd.exe /c '"python" --version 2>&1' - if ($version -like 'Python 3.*') - { - "Python 3.* was found, installing dependencies" - } - else - { - throw System.Management.Automation.CommandNotFoundException - } + $version = cmd.exe /c '"python" --version 2>&1' + if ($version -like 'Python 3.*') + { + "Python 3.* was found, installing dependencies" + } + else + { + throw System.Management.Automation.CommandNotFoundException + } } catch [System.Management.Automation.CommandNotFoundException] { - "Downloading python 3 ..." - "Select 'add to PATH' when installing" - $webClient.DownloadFile($PYTHON_URL, $TEMP_PYTHON_INSTALLER) - Start-Process -Wait $TEMP_PYTHON_INSTALLER -ErrorAction Stop - $env: Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") - Remove-Item $TEMP_PYTHON_INSTALLER - # Check if installed correctly - $version = cmd.exe /c '"python" --version 2>&1' - if ($version -like '* is not recognized*') - { - "Python is not found in PATH. Add it to PATH and relaunch the script." - return - } + "Downloading python 3 ..." + "Select 'add to PATH' when installing" + $webClient.DownloadFile($PYTHON_URL, $TEMP_PYTHON_INSTALLER) + Start-Process -Wait $TEMP_PYTHON_INSTALLER -ErrorAction Stop + $env: Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") + Remove-Item $TEMP_PYTHON_INSTALLER + # Check if installed correctly + $version = cmd.exe /c '"python" --version 2>&1' + if ($version -like '* is not recognized*') + { + "Python is not found in PATH. Add it to PATH and relaunch the script." + return + } } "Upgrading pip..." @@ -85,8 +88,8 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, $output if ($output -like '*No module named pip*') { - "Make sure pip module is installed and re-run this script." - return + "Make sure pip module is installed and re-run this script." + return } "Installing python packages for island" @@ -100,30 +103,30 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, $user_python_dir = Join-Path (Split-Path $user_python_dir) -ChildPath "\Scripts" if (!($ENV: PATH | Select-String -SimpleMatch $user_python_dir)) { - "Adding python scripts path to user's env" - $env: Path += ";" + $user_python_dir - [Environment]::SetEnvironmentVariable("Path", $env:Path, "User") + "Adding python scripts path to user's env" + $env: Path += ";" + $user_python_dir + [Environment]::SetEnvironmentVariable("Path", $env:Path, "User") } # Download mongodb if (!(Test-Path -Path (Join-Path -Path $binDir -ChildPath "mongodb"))) { - "Downloading mongodb ..." - $webClient.DownloadFile($MONGODB_URL, $TEMP_MONGODB_ZIP) - "Unzipping mongodb" - Expand-Archive $TEMP_MONGODB_ZIP -DestinationPath $binDir - # Get unzipped folder's name - $mongodb_folder = Get-ChildItem -Path $binDir | Where-Object -FilterScript { - ($_.Name -like "mongodb*") - } | Select-Object -ExpandProperty Name - # Move all files from extracted folder to mongodb folder - New-Item -ItemType directory -Path (Join-Path -Path $binDir -ChildPath "mongodb") - New-Item -ItemType directory -Path (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "db") - "Moving extracted files" - Move-Item -Path (Join-Path -Path $binDir -ChildPath $mongodb_folder | Join-Path -ChildPath "\bin\*") -Destination (Join-Path -Path $binDir -ChildPath "mongodb\") - "Removing zip file" - Remove-Item $TEMP_MONGODB_ZIP - Remove-Item (Join-Path -Path $binDir -ChildPath $mongodb_folder) -Recurse + "Downloading mongodb ..." + $webClient.DownloadFile($MONGODB_URL, $TEMP_MONGODB_ZIP) + "Unzipping mongodb" + Expand-Archive $TEMP_MONGODB_ZIP -DestinationPath $binDir + # Get unzipped folder's name + $mongodb_folder = Get-ChildItem -Path $binDir | Where-Object -FilterScript { + ($_.Name -like "mongodb*") + } | Select-Object -ExpandProperty Name + # Move all files from extracted folder to mongodb folder + New-Item -ItemType directory -Path (Join-Path -Path $binDir -ChildPath "mongodb") + New-Item -ItemType directory -Path (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "db") + "Moving extracted files" + Move-Item -Path (Join-Path -Path $binDir -ChildPath $mongodb_folder | Join-Path -ChildPath "\bin\*") -Destination (Join-Path -Path $binDir -ChildPath "mongodb\") + "Removing zip file" + Remove-Item $TEMP_MONGODB_ZIP + Remove-Item (Join-Path -Path $binDir -ChildPath $mongodb_folder) -Recurse } # Download OpenSSL @@ -159,23 +162,23 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, "Installing npm" try { - $version = cmd.exe /c '"npm" --version 2>&1' - if ($version -like "*is not recognized*") - { - throw System.Management.Automation.CommandNotFoundException - } - else - { - "Npm already installed" - } + $version = cmd.exe /c '"npm" --version 2>&1' + if ($version -like "*is not recognized*") + { + throw System.Management.Automation.CommandNotFoundException + } + else + { + "Npm already installed" + } } catch [System.Management.Automation.CommandNotFoundException] { - "Downloading npm ..." - $webClient.DownloadFile($NPM_URL, $TEMP_NPM_INSTALLER) - Start-Process -Wait $TEMP_NPM_INSTALLER - $env: Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") - Remove-Item $TEMP_NPM_INSTALLER + "Downloading npm ..." + $webClient.DownloadFile($NPM_URL, $TEMP_NPM_INSTALLER) + Start-Process -Wait $TEMP_NPM_INSTALLER + $env: Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + Remove-Item $TEMP_NPM_INSTALLER } "Updating npm" @@ -197,29 +200,29 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, # Download upx if (!(Test-Path -Path (Join-Path -Path $binDir -ChildPath "upx.exe"))) { - "Downloading upx ..." - $webClient.DownloadFile($UPX_URL, $TEMP_UPX_ZIP) - "Unzipping upx" - Expand-Archive $TEMP_UPX_ZIP -DestinationPath $binDir -ErrorAction SilentlyContinue - Move-Item -Path (Join-Path -Path $binDir -ChildPath $UPX_FOLDER | Join-Path -ChildPath "upx.exe") -Destination $binDir - # Remove unnecessary files - Remove-Item -Recurse -Force (Join-Path -Path $binDir -ChildPath $UPX_FOLDER) - "Removing zip file" - Remove-Item $TEMP_UPX_ZIP + "Downloading upx ..." + $webClient.DownloadFile($UPX_URL, $TEMP_UPX_ZIP) + "Unzipping upx" + Expand-Archive $TEMP_UPX_ZIP -DestinationPath $binDir -ErrorAction SilentlyContinue + Move-Item -Path (Join-Path -Path $binDir -ChildPath $UPX_FOLDER | Join-Path -ChildPath "upx.exe") -Destination $binDir + # Remove unnecessary files + Remove-Item -Recurse -Force (Join-Path -Path $binDir -ChildPath $UPX_FOLDER) + "Removing zip file" + Remove-Item $TEMP_UPX_ZIP } # Download mimikatz binaries $mk32_path = Join-Path -Path $binDir -ChildPath $MK32_DLL if (!(Test-Path -Path $mk32_path)) { - "Downloading mimikatz 32 binary" - $webClient.DownloadFile($MK32_DLL_URL, $mk32_path) + "Downloading mimikatz 32 binary" + $webClient.DownloadFile($MK32_DLL_URL, $mk32_path) } $mk64_path = Join-Path -Path $binDir -ChildPath $MK64_DLL if (!(Test-Path -Path $mk64_path)) { - "Downloading mimikatz 64 binary" - $webClient.DownloadFile($MK64_DLL_URL, $mk64_path) + "Downloading mimikatz 64 binary" + $webClient.DownloadFile($MK64_DLL_URL, $mk64_path) } # Download sambacry binaries @@ -227,14 +230,14 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, $samba32_path = Join-Path -Path $samba_path -ChildPath $SAMBA_32_BINARY_NAME if (!(Test-Path -Path $samba32_path)) { - "Downloading sambacry 32 binary" - $webClient.DownloadFile($SAMBA_32_BINARY_URL, $samba32_path) + "Downloading sambacry 32 binary" + $webClient.DownloadFile($SAMBA_32_BINARY_URL, $samba32_path) } $samba64_path = Join-Path -Path $samba_path -ChildPath $SAMBA_64_BINARY_NAME if (!(Test-Path -Path $samba64_path)) { - "Downloading sambacry 64 binary" - $webClient.DownloadFile($SAMBA_64_BINARY_URL, $samba64_path) + "Downloading sambacry 64 binary" + $webClient.DownloadFile($SAMBA_64_BINARY_URL, $samba64_path) } "Script finished" From 1c4c22d8e916bff7d8d0822e591499934b75305c Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sat, 4 Jan 2020 23:31:09 +0200 Subject: [PATCH 028/119] Update deployment README.md --- deployment_scripts/README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/deployment_scripts/README.md b/deployment_scripts/README.md index f51bd151e..750979a4d 100644 --- a/deployment_scripts/README.md +++ b/deployment_scripts/README.md @@ -2,13 +2,15 @@ ## Windows Before running the script you must have git installed.
-Cd to scripts directory and use the scripts.
+`Invoke-WebRequest https://raw.githubusercontent.com/guardicore/monkey/develop/deployment_scripts/deploy_windows.ps1 -OutFile deploy_windows.ps1` +Then execute the resulting script with your shell. First argument is an empty directory (script can create one) and second is branch you want to clone. Example usages:
-./run_script.bat (Sets up monkey in current directory under .\infection_monkey)
-./run_script.bat "C:\test" (Sets up monkey in C:\test)
-powershell -ExecutionPolicy ByPass -Command ". .\deploy_windows.ps1; Deploy-Windows -monkey_home C:\test" (Same as above)
-./run_script.bat "" "master"(Sets up master branch instead of develop in current dir) +`./run_script.bat` (Sets up monkey in current directory under .\infection_monkey)
+`./run_script.bat "C:\test"` (Sets up monkey in C:\test)
+`powershell -ExecutionPolicy ByPass -Command ". .\deploy_windows.ps1; Deploy-Windows -monkey_home C:\test"` (Same as above)
+`./run_script.bat "" "master"` (Sets up master branch instead of develop in current dir) + Don't forget to add python to PATH or do so while installing it via this script.
## Linux @@ -16,12 +18,11 @@ Don't forget to add python to PATH or do so while installing it via this script. Linux deployment script is meant for Ubuntu 16.x machines. You must have root permissions, but don't run the script as root.
`wget https://raw.githubusercontent.com/guardicore/monkey/develop/deployment_scripts/deploy_linux.sh` - Then execute the resulting script with your shell. First argument should be an absolute path of an empty directory (script will create one if doesn't exist, default is ./infection_monkey). Second parameter is the branch you want to clone (develop by default). Example usages:
-./deploy_linux.sh (deploys under ./infection_monkey)
-./deploy_linux.sh "/home/test/monkey" (deploys under /home/test/monkey)
-./deploy_linux.sh "" "master" (deploys master branch in script directory)
-./deploy_linux.sh "/home/user/new" "master" (if directory "new" is not found creates it and clones master branch into it)
+`./deploy_linux.sh` (deploys under ./infection_monkey)
+`./deploy_linux.sh "/home/test/monkey"` (deploys under /home/test/monkey)
+`./deploy_linux.sh "" "master"` (deploys master branch in script directory)
+`./deploy_linux.sh "/home/user/new" "master"` (if directory "new" is not found creates it and clones master branch into it)
From 291ce9a1994173604641afbbc6f5fbfbc4730ec0 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 20 Jan 2020 09:43:45 +0200 Subject: [PATCH 029/119] Minimize log messages. --- deployment_scripts/deploy_linux.sh | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index c41774393..cc0674ac4 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -13,13 +13,25 @@ has_sudo() { timeout 1 sudo id && return 0 || return 1 } +handle_error() { + echo "Fix the errors above and rerun the script" + exit 1 +} + +log_message() { + echo -e "\n\n" + echo -e "DEPLOYMENT SCRIPT: $1" +} + config_branch=${2:-"develop"} config_url="https://raw.githubusercontent.com/guardicore/monkey/"$config_branch"/deployment_scripts/config" if exists curl; then file=$(mktemp) curl -s -o $file "$config_url" + log_message "downloaded configuration" source $file + log_message "loaded configuration" rm $file else echo 'Your system does not have curl, exiting' @@ -40,16 +52,7 @@ ISLAND_BINARIES_PATH="$ISLAND_PATH/cc/binaries" INFECTION_MONKEY_DIR="$monkey_home/monkey/infection_monkey" MONKEY_BIN_DIR="$INFECTION_MONKEY_DIR/bin" -handle_error() { - echo "Fix the errors above and rerun the script" - exit 1 -} -log_message() { - echo -e "\n\n-------------------------------------------" - echo -e "DEPLOYMENT SCRIPT: $1" - echo -e "-------------------------------------------\n" -} if is_root; then echo "Please don't runt this script as root" From ed138de8c45673e1016b4be8bfa88386fff6aa7d Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 20 Jan 2020 11:57:19 +0200 Subject: [PATCH 030/119] Deleted the old (unused) aws collector --- .../system_info/aws_collector.py | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 monkey/infection_monkey/system_info/aws_collector.py diff --git a/monkey/infection_monkey/system_info/aws_collector.py b/monkey/infection_monkey/system_info/aws_collector.py deleted file mode 100644 index f39662d13..000000000 --- a/monkey/infection_monkey/system_info/aws_collector.py +++ /dev/null @@ -1,29 +0,0 @@ -import logging - -from common.cloud.aws.aws_instance import AwsInstance - -__author__ = 'itay.mizeretz' - -LOG = logging.getLogger(__name__) - - -class AwsCollector(object): - """ - Extract info from AWS machines - """ - - @staticmethod - def get_aws_info(): - LOG.info("Collecting AWS info") - aws = AwsInstance() - info = {} - if aws.is_instance(): - LOG.info("Machine is an AWS instance") - info = \ - { - 'instance_id': aws.get_instance_id() - } - else: - LOG.info("Machine is NOT an AWS instance") - - return info From 99785236720bfe4c4912832298573b24e8dccd6b Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 20 Jan 2020 15:58:06 +0200 Subject: [PATCH 031/119] Fixed configuration bug - didn't use the same instance of WormConfiguration --- monkey/infection_monkey/config.py | 4 ++-- monkey/infection_monkey/system_info/system_info_collector.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py index e1b1ece83..49aa38426 100644 --- a/monkey/infection_monkey/config.py +++ b/monkey/infection_monkey/config.py @@ -1,6 +1,6 @@ import hashlib -import os import json +import os import sys import uuid from abc import ABCMeta @@ -125,7 +125,7 @@ class Configuration(object): finger_classes = [] exploiter_classes = [] - system_info_collectors_classes = ["EnvironmentCollector", "AwsCollector"] + system_info_collectors_classes = [] # how many victims to look for in a single scan iteration victims_max_find = 100 diff --git a/monkey/infection_monkey/system_info/system_info_collector.py b/monkey/infection_monkey/system_info/system_info_collector.py index c511c1e86..8c0b6aa65 100644 --- a/monkey/infection_monkey/system_info/system_info_collector.py +++ b/monkey/infection_monkey/system_info/system_info_collector.py @@ -1,4 +1,4 @@ -from config import WormConfiguration +from infection_monkey.config import WormConfiguration from infection_monkey.utils.plugins.plugin import Plugin from abc import ABCMeta, abstractmethod From d584890dca5c9e8c0f6b99ba6013718e9ba262ce Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 20 Jan 2020 15:58:28 +0200 Subject: [PATCH 032/119] Added hostname collector + moved collector names to common file --- .../common/data/system_info_collectors_names.py | 3 +++ .../system_info/collectors/hostname_collector.py | 16 ++++++++++++++++ .../monkey_island/cc/services/config_schema.py | 13 +++++++++++-- .../services/telemetry/processing/system_info.py | 6 ------ .../system_info_collectors/hostname.py | 9 +++++++++ .../system_info_telemetry_dispatcher.py | 7 +++++-- 6 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 monkey/common/data/system_info_collectors_names.py create mode 100644 monkey/infection_monkey/system_info/collectors/hostname_collector.py create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py diff --git a/monkey/common/data/system_info_collectors_names.py b/monkey/common/data/system_info_collectors_names.py new file mode 100644 index 000000000..8bdf757c7 --- /dev/null +++ b/monkey/common/data/system_info_collectors_names.py @@ -0,0 +1,3 @@ +AWS_COLLECTOR = "AwsCollector" +HOSTNAME_COLLECTOR = "HostnameCollector" +ENVIRONMENT_COLLECTOR = "EnvironmentCollector" diff --git a/monkey/infection_monkey/system_info/collectors/hostname_collector.py b/monkey/infection_monkey/system_info/collectors/hostname_collector.py new file mode 100644 index 000000000..92a522bf9 --- /dev/null +++ b/monkey/infection_monkey/system_info/collectors/hostname_collector.py @@ -0,0 +1,16 @@ +import logging +import socket + +from common.data.system_info_collectors_names import HOSTNAME_COLLECTOR +from infection_monkey.system_info.system_info_collector import SystemInfoCollector + + +logger = logging.getLogger(__name__) + + +class HostnameCollector(SystemInfoCollector): + def __init__(self): + super(HostnameCollector, self).__init__(name=HOSTNAME_COLLECTOR) + + def collect(self) -> dict: + return {"hostname": socket.getfqdn()} diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index d5e015866..86e6225e0 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -108,7 +108,7 @@ SCHEMA = { "enum": [ "EnvironmentCollector" ], - "title": "Which Environment this machine is on (on prem/cloud)", + "title": "Collect which environment this machine is on (on prem/cloud)", "attack_techniques": [] }, { @@ -119,6 +119,14 @@ SCHEMA = { "title": "If on AWS, collect more information about the instance", "attack_techniques": [] }, + { + "type": "string", + "enum": [ + "HostnameCollector" + ], + "title": "Collect the machine's hostname", + "attack_techniques": [] + }, ], }, "post_breach_acts": { @@ -464,7 +472,8 @@ SCHEMA = { }, "default": [ "EnvironmentCollector", - "AwsCollector" + "AwsCollector", + "HostnameCollector" ], "description": "Determines which system information collectors will collect information." }, diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index d4368469e..c490b1d69 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -1,7 +1,6 @@ import logging from monkey_island.cc.encryptor import encryptor -from monkey_island.cc.models import Monkey from monkey_island.cc.services import mimikatz_utils from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.node import NodeService @@ -19,7 +18,6 @@ def process_system_info_telemetry(telemetry_json): process_ssh_info, process_credential_info, process_mimikatz_and_wmi_info, - update_db_with_new_hostname, test_antivirus_existence, dispatcher.dispatch_to_relevant_collectors ] @@ -115,7 +113,3 @@ def process_mimikatz_and_wmi_info(telemetry_json): wmi_handler = WMIHandler(monkey_id, telemetry_json['data']['wmi'], users_secrets) wmi_handler.process_and_handle_wmi_info() - -def update_db_with_new_hostname(telemetry_json): - if 'hostname' in telemetry_json['data']: - Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']).set_hostname(telemetry_json['data']['hostname']) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py new file mode 100644 index 000000000..e2de4519c --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py @@ -0,0 +1,9 @@ +import logging + +from monkey_island.cc.models.monkey import Monkey + +logger = logging.getLogger(__name__) + + +def process_hostname_telemetry(collector_results, monkey_guid): + Monkey.get_single_monkey_by_guid(monkey_guid).set_hostname(collector_results["hostname"]) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py index 64fb146ab..6a3890491 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py @@ -1,13 +1,16 @@ import logging +from common.data.system_info_collectors_names import AWS_COLLECTOR, ENVIRONMENT_COLLECTOR, HOSTNAME_COLLECTOR from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import process_aws_telemetry from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import process_environment_telemetry +from monkey_island.cc.services.telemetry.processing.system_info_collectors.hostname import process_hostname_telemetry logger = logging.getLogger(__name__) SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSOR = { - "AwsCollector": process_aws_telemetry, - "EnvironmentCollector": process_environment_telemetry, + AWS_COLLECTOR: process_aws_telemetry, + ENVIRONMENT_COLLECTOR: process_environment_telemetry, + HOSTNAME_COLLECTOR: process_hostname_telemetry, } From 476c6e7a4b69552c4a612aed7f3be6319b680866 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 20 Jan 2020 16:43:25 +0200 Subject: [PATCH 033/119] Deleted hostname old collection, moved to collector --- monkey/infection_monkey/system_info/__init__.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/monkey/infection_monkey/system_info/__init__.py b/monkey/infection_monkey/system_info/__init__.py index fc4aa1caf..66056828e 100644 --- a/monkey/infection_monkey/system_info/__init__.py +++ b/monkey/infection_monkey/system_info/__init__.py @@ -62,7 +62,6 @@ class InfoCollector(object): def get_info(self): # Collect all hardcoded - self.get_hostname() self.get_process_list() self.get_network_info() self.get_azure_info() @@ -70,14 +69,6 @@ class InfoCollector(object): # Collect all plugins SystemInfoCollectorsHandler().execute_all_configured() - def get_hostname(self): - """ - Adds the fully qualified computer hostname to the system information. - :return: None. Updates class information - """ - LOG.debug("Reading hostname") - self.info['hostname'] = socket.getfqdn() - def get_process_list(self): """ Adds process information from the host to the system information. From f8aff44e8b80331fc46b129231dbd086fc756308 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 20 Jan 2020 16:44:30 +0200 Subject: [PATCH 034/119] Changed dispatcher to use a list of processing functions to support multiple processing functions --- .../system_info_telemetry_dispatcher.py | 54 +++++++++++++------ .../test_system_info_telemetry_dispatcher.py | 14 ++--- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py index 6a3890491..e20231d8b 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py @@ -1,39 +1,61 @@ import logging +import typing -from common.data.system_info_collectors_names import AWS_COLLECTOR, ENVIRONMENT_COLLECTOR, HOSTNAME_COLLECTOR +from common.data.system_info_collectors_names import * from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import process_aws_telemetry from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import process_environment_telemetry from monkey_island.cc.services.telemetry.processing.system_info_collectors.hostname import process_hostname_telemetry logger = logging.getLogger(__name__) -SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSOR = { - AWS_COLLECTOR: process_aws_telemetry, - ENVIRONMENT_COLLECTOR: process_environment_telemetry, - HOSTNAME_COLLECTOR: process_hostname_telemetry, +SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS = { + AWS_COLLECTOR: [process_aws_telemetry], + ENVIRONMENT_COLLECTOR: [process_environment_telemetry], + HOSTNAME_COLLECTOR: [process_hostname_telemetry], } class SystemInfoTelemetryDispatcher(object): - def __init__(self, collector_to_parsing_function=None): - if collector_to_parsing_function is None: - collector_to_parsing_function = SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSOR - self.collector_to_parsing_function = collector_to_parsing_function + def __init__(self, collector_to_parsing_functions: typing.Mapping[str, typing.List[typing.Callable]] = None): + """ + :param collector_to_parsing_functions: Map between collector names and a list of functions that process the output of + that collector. If `None` is supplied, uses the default one; This should be the normal flow, overriding the + collector->functions mapping is useful mostly for testing. + """ + if collector_to_parsing_functions is None: + collector_to_parsing_functions = SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS + self.collector_to_processing_functions = collector_to_parsing_functions - def dispatch_to_relevant_collectors(self, telemetry_json): + def dispatch_collector_results_to_relevant_processors(self, telemetry_json): + """ + If the telemetry has collectors' results, dispatches the results to the relevant processing functions. + :param telemetry_json: Telemetry sent from the Monkey + """ if "collectors" in telemetry_json["data"]: - self.send_each_result_to_relevant_processor(telemetry_json) + self.dispatch_each_result_to_relevant_processors(telemetry_json) - def send_each_result_to_relevant_processor(self, telemetry_json): + def dispatch_each_result_to_relevant_processors(self, telemetry_json): relevant_monkey_guid = telemetry_json['monkey_guid'] + for collector_name, collector_results in telemetry_json["data"]["collectors"].items(): - if collector_name in self.collector_to_parsing_function: + self.dispatch_result_of_single_collector_to_processing_functions( + collector_name, + collector_results, + relevant_monkey_guid) + + def dispatch_result_of_single_collector_to_processing_functions( + self, + collector_name, + collector_results, + relevant_monkey_guid): + if collector_name in self.collector_to_processing_functions: + for processing_function in self.collector_to_processing_functions[collector_name]: # noinspection PyBroadException try: - self.collector_to_parsing_function[collector_name](collector_results, relevant_monkey_guid) + processing_function(collector_results, relevant_monkey_guid) except Exception as e: logger.error( "Error {} while processing {} system info telemetry".format(str(e), collector_name), exc_info=True) - else: - logger.warning("Unknown system info collector name: {}".format(collector_name)) + else: + logger.warning("Unknown system info collector name: {}".format(collector_name)) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py index 4db5352c8..c5cc7aca2 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_system_info_telemetry_dispatcher.py @@ -8,7 +8,7 @@ from monkey_island.cc.services.telemetry.processing.system_info_collectors.syste from monkey_island.cc.testing.IslandTestCase import IslandTestCase TEST_SYS_INFO_TO_PROCESSING = { - "AwsCollector": process_aws_telemetry, + "AwsCollector": [process_aws_telemetry], } @@ -20,18 +20,18 @@ class SystemInfoTelemetryDispatcherTest(IslandTestCase): # Bad format telem JSONs - throws bad_empty_telem_json = {} - self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collectors, bad_empty_telem_json) + self.assertRaises(KeyError, dispatcher.dispatch_collector_results_to_relevant_processors, bad_empty_telem_json) bad_no_data_telem_json = {"monkey_guid": "bla"} - self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collectors, bad_no_data_telem_json) + self.assertRaises(KeyError, dispatcher.dispatch_collector_results_to_relevant_processors, bad_no_data_telem_json) bad_no_monkey_telem_json = {"data": {"collectors": {"AwsCollector": "Bla"}}} - self.assertRaises(KeyError, dispatcher.dispatch_to_relevant_collectors, bad_no_monkey_telem_json) + self.assertRaises(KeyError, dispatcher.dispatch_collector_results_to_relevant_processors, bad_no_monkey_telem_json) # Telem JSON with no collectors - nothing gets dispatched good_telem_no_collectors = {"monkey_guid": "bla", "data": {"bla": "bla"}} good_telem_empty_collectors = {"monkey_guid": "bla", "data": {"bla": "bla", "collectors": {}}} - dispatcher.dispatch_to_relevant_collectors(good_telem_no_collectors) - dispatcher.dispatch_to_relevant_collectors(good_telem_empty_collectors) + dispatcher.dispatch_collector_results_to_relevant_processors(good_telem_no_collectors) + dispatcher.dispatch_collector_results_to_relevant_processors(good_telem_empty_collectors) def test_dispatch_to_relevant_collector(self): self.fail_if_not_testing_env() @@ -52,6 +52,6 @@ class SystemInfoTelemetryDispatcherTest(IslandTestCase): }, "monkey_guid": a_monkey.guid } - dispatcher.dispatch_to_relevant_collectors(telem_json) + dispatcher.dispatch_collector_results_to_relevant_processors(telem_json) self.assertEquals(Monkey.get_single_monkey_by_guid(a_monkey.guid).aws_instance_id, instance_id) From 04b737057540435ba0d429588d77b2d610170fe4 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 20 Jan 2020 17:11:30 +0200 Subject: [PATCH 035/119] Fixed bug in report generation, added lock release for exceptions in report generation --- .../cc/services/reporting/report.py | 5 ++-- .../report_generation_synchronisation.py | 26 ++++++++++++------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index 6a44679a4..97e8fa4f1 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -386,10 +386,11 @@ class ReportService: @staticmethod def get_monkey_subnets(monkey_guid): network_info = mongo.db.telemetry.find_one( - {'telem_category': 'system_info', 'monkey_guid': monkey_guid}, + {'telem_category': 'system_info', + 'monkey_guid': monkey_guid}, {'data.network_info.networks': 1} ) - if network_info is None: + if network_info is None or not network_info["data"]: return [] return \ diff --git a/monkey/monkey_island/cc/services/reporting/report_generation_synchronisation.py b/monkey/monkey_island/cc/services/reporting/report_generation_synchronisation.py index 9025ff68f..1a041bb3b 100644 --- a/monkey/monkey_island/cc/services/reporting/report_generation_synchronisation.py +++ b/monkey/monkey_island/cc/services/reporting/report_generation_synchronisation.py @@ -15,28 +15,34 @@ __regular_report_generating_lock = threading.Semaphore() def safe_generate_reports(): # Entering the critical section; Wait until report generation is available. __report_generating_lock.acquire() - report = safe_generate_regular_report() - attack_report = safe_generate_attack_report() - # Leaving the critical section. - __report_generating_lock.release() + try: + report = safe_generate_regular_report() + attack_report = safe_generate_attack_report() + finally: + # Leaving the critical section. + __report_generating_lock.release() return report, attack_report def safe_generate_regular_report(): # Local import to avoid circular imports from monkey_island.cc.services.reporting.report import ReportService - __regular_report_generating_lock.acquire() - report = ReportService.generate_report() - __regular_report_generating_lock.release() + try: + __regular_report_generating_lock.acquire() + report = ReportService.generate_report() + finally: + __regular_report_generating_lock.release() return report def safe_generate_attack_report(): # Local import to avoid circular imports from monkey_island.cc.services.attack.attack_report import AttackReportService - __attack_report_generating_lock.acquire() - attack_report = AttackReportService.generate_new_report() - __attack_report_generating_lock.release() + try: + __attack_report_generating_lock.acquire() + attack_report = AttackReportService.generate_new_report() + finally: + __attack_report_generating_lock.release() return attack_report From 2286571a72030d4497470c3c9611c3ee1e5e9a44 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 20 Jan 2020 17:12:12 +0200 Subject: [PATCH 036/119] Refactored process list collector --- .../data/system_info_collectors_names.py | 1 + .../infection_monkey/system_info/__init__.py | 32 ------------ .../collectors/process_list_collector.py | 50 +++++++++++++++++++ .../cc/services/config_schema.py | 23 ++++++--- .../telemetry/processing/system_info.py | 4 +- .../system_info_telemetry_dispatcher.py | 6 ++- .../zero_trust_tests/antivirus_existence.py | 50 +++++++++---------- 7 files changed, 98 insertions(+), 68 deletions(-) create mode 100644 monkey/infection_monkey/system_info/collectors/process_list_collector.py diff --git a/monkey/common/data/system_info_collectors_names.py b/monkey/common/data/system_info_collectors_names.py index 8bdf757c7..831bbe142 100644 --- a/monkey/common/data/system_info_collectors_names.py +++ b/monkey/common/data/system_info_collectors_names.py @@ -1,3 +1,4 @@ AWS_COLLECTOR = "AwsCollector" HOSTNAME_COLLECTOR = "HostnameCollector" ENVIRONMENT_COLLECTOR = "EnvironmentCollector" +PROCESS_LIST_COLLECTOR = "ProcessListCollector" diff --git a/monkey/infection_monkey/system_info/__init__.py b/monkey/infection_monkey/system_info/__init__.py index 66056828e..889b558a1 100644 --- a/monkey/infection_monkey/system_info/__init__.py +++ b/monkey/infection_monkey/system_info/__init__.py @@ -62,44 +62,12 @@ class InfoCollector(object): def get_info(self): # Collect all hardcoded - self.get_process_list() self.get_network_info() self.get_azure_info() # Collect all plugins SystemInfoCollectorsHandler().execute_all_configured() - def get_process_list(self): - """ - Adds process information from the host to the system information. - Currently lists process name, ID, parent ID, command line - and the full image path of each process. - :return: None. Updates class information - """ - LOG.debug("Reading process list") - processes = {} - for process in psutil.process_iter(): - try: - processes[process.pid] = {"name": process.name(), - "pid": process.pid, - "ppid": process.ppid(), - "cmdline": " ".join(process.cmdline()), - "full_image_path": process.exe(), - } - except (psutil.AccessDenied, WindowsError): - # we may be running as non root - # and some processes are impossible to acquire in Windows/Linux - # in this case we'll just add what we can - processes[process.pid] = {"name": "null", - "pid": process.pid, - "ppid": process.ppid(), - "cmdline": "ACCESS DENIED", - "full_image_path": "null", - } - continue - - self.info['process_list'] = processes - def get_network_info(self): """ Adds network information from the host to the system information. diff --git a/monkey/infection_monkey/system_info/collectors/process_list_collector.py b/monkey/infection_monkey/system_info/collectors/process_list_collector.py new file mode 100644 index 000000000..93f836376 --- /dev/null +++ b/monkey/infection_monkey/system_info/collectors/process_list_collector.py @@ -0,0 +1,50 @@ +import logging +import psutil + +from common.data.system_info_collectors_names import PROCESS_LIST_COLLECTOR +from infection_monkey.system_info.system_info_collector import SystemInfoCollector + +logger = logging.getLogger(__name__) + +# Linux doesn't have WindowsError +try: + WindowsError +except NameError: + # noinspection PyShadowingBuiltins + WindowsError = psutil.AccessDenied + + +class ProcessListCollector(SystemInfoCollector): + def __init__(self): + super(ProcessListCollector, self).__init__(name=PROCESS_LIST_COLLECTOR) + + def collect(self) -> dict: + """ + Adds process information from the host to the system information. + Currently lists process name, ID, parent ID, command line + and the full image path of each process. + """ + logger.debug("Reading process list") + processes = {} + for process in psutil.process_iter(): + try: + processes[process.pid] = { + "name": process.name(), + "pid": process.pid, + "ppid": process.ppid(), + "cmdline": " ".join(process.cmdline()), + "full_image_path": process.exe(), + } + except (psutil.AccessDenied, WindowsError): + # we may be running as non root and some processes are impossible to acquire in Windows/Linux. + # In this case we'll just add what we know. + processes[process.pid] = { + "name": "null", + "pid": process.pid, + "ppid": process.ppid(), + "cmdline": "ACCESS DENIED", + "full_image_path": "null", + } + continue + + return {'process_list': processes} diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index 86e6225e0..e7d599cc5 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -1,3 +1,5 @@ +from common.data.system_info_collectors_names import * + WARNING_SIGN = " \u26A0" SCHEMA = { @@ -106,7 +108,7 @@ SCHEMA = { { "type": "string", "enum": [ - "EnvironmentCollector" + ENVIRONMENT_COLLECTOR ], "title": "Collect which environment this machine is on (on prem/cloud)", "attack_techniques": [] @@ -114,7 +116,7 @@ SCHEMA = { { "type": "string", "enum": [ - "AwsCollector" + AWS_COLLECTOR ], "title": "If on AWS, collect more information about the instance", "attack_techniques": [] @@ -122,11 +124,19 @@ SCHEMA = { { "type": "string", "enum": [ - "HostnameCollector" + HOSTNAME_COLLECTOR ], "title": "Collect the machine's hostname", "attack_techniques": [] }, +{ + "type": "string", + "enum": [ + PROCESS_LIST_COLLECTOR + ], + "title": "Collect running processes on the machine", + "attack_techniques": [] + }, ], }, "post_breach_acts": { @@ -471,9 +481,10 @@ SCHEMA = { "$ref": "#/definitions/system_info_collectors_classes" }, "default": [ - "EnvironmentCollector", - "AwsCollector", - "HostnameCollector" + ENVIRONMENT_COLLECTOR, + AWS_COLLECTOR, + HOSTNAME_COLLECTOR, + PROCESS_LIST_COLLECTOR ], "description": "Determines which system information collectors will collect information." }, diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py index c490b1d69..b923b6395 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info.py @@ -6,7 +6,6 @@ from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import \ SystemInfoTelemetryDispatcher -from monkey_island.cc.services.telemetry.zero_trust_tests.antivirus_existence import test_antivirus_existence from monkey_island.cc.services.wmi_handler import WMIHandler logger = logging.getLogger(__name__) @@ -18,8 +17,7 @@ def process_system_info_telemetry(telemetry_json): process_ssh_info, process_credential_info, process_mimikatz_and_wmi_info, - test_antivirus_existence, - dispatcher.dispatch_to_relevant_collectors + dispatcher.dispatch_collector_results_to_relevant_processors ] # Calling safe_process_telemetry so if one of the stages fail, we log and move on instead of failing the rest of diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py index e20231d8b..d67979e8d 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py @@ -5,6 +5,7 @@ from common.data.system_info_collectors_names import * from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import process_aws_telemetry from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import process_environment_telemetry from monkey_island.cc.services.telemetry.processing.system_info_collectors.hostname import process_hostname_telemetry +from monkey_island.cc.services.telemetry.zero_trust_tests.antivirus_existence import test_antivirus_existence logger = logging.getLogger(__name__) @@ -12,6 +13,7 @@ SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS = { AWS_COLLECTOR: [process_aws_telemetry], ENVIRONMENT_COLLECTOR: [process_environment_telemetry], HOSTNAME_COLLECTOR: [process_hostname_telemetry], + PROCESS_LIST_COLLECTOR: [test_antivirus_existence] } @@ -32,9 +34,9 @@ class SystemInfoTelemetryDispatcher(object): :param telemetry_json: Telemetry sent from the Monkey """ if "collectors" in telemetry_json["data"]: - self.dispatch_each_result_to_relevant_processors(telemetry_json) + self.dispatch_single_result_to_relevant_processor(telemetry_json) - def dispatch_each_result_to_relevant_processors(self, telemetry_json): + def dispatch_single_result_to_relevant_processor(self, telemetry_json): relevant_monkey_guid = telemetry_json['monkey_guid'] for collector_name, collector_results in telemetry_json["data"]["collectors"].items(): diff --git a/monkey/monkey_island/cc/services/telemetry/zero_trust_tests/antivirus_existence.py b/monkey/monkey_island/cc/services/telemetry/zero_trust_tests/antivirus_existence.py index ddc1af65b..1916291e2 100644 --- a/monkey/monkey_island/cc/services/telemetry/zero_trust_tests/antivirus_existence.py +++ b/monkey/monkey_island/cc/services/telemetry/zero_trust_tests/antivirus_existence.py @@ -7,36 +7,36 @@ from monkey_island.cc.models.zero_trust.event import Event from monkey_island.cc.services.telemetry.zero_trust_tests.known_anti_viruses import ANTI_VIRUS_KNOWN_PROCESS_NAMES -def test_antivirus_existence(telemetry_json): - current_monkey = Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']) - if 'process_list' in telemetry_json['data']: - process_list_event = Event.create_event( - title="Process list", - message="Monkey on {} scanned the process list".format(current_monkey.hostname), - event_type=zero_trust_consts.EVENT_TYPE_MONKEY_LOCAL) - events = [process_list_event] +def test_antivirus_existence(process_list_json, monkey_guid): + current_monkey = Monkey.get_single_monkey_by_guid(monkey_guid) - av_processes = filter_av_processes(telemetry_json) + process_list_event = Event.create_event( + title="Process list", + message="Monkey on {} scanned the process list".format(current_monkey.hostname), + event_type=zero_trust_consts.EVENT_TYPE_MONKEY_LOCAL) + events = [process_list_event] - for process in av_processes: - events.append(Event.create_event( - title="Found AV process", - message="The process '{}' was recognized as an Anti Virus process. Process " - "details: {}".format(process[1]['name'], json.dumps(process[1])), - event_type=zero_trust_consts.EVENT_TYPE_MONKEY_LOCAL - )) + av_processes = filter_av_processes(process_list_json["process_list"]) - if len(av_processes) > 0: - test_status = zero_trust_consts.STATUS_PASSED - else: - test_status = zero_trust_consts.STATUS_FAILED - AggregateFinding.create_or_add_to_existing( - test=zero_trust_consts.TEST_ENDPOINT_SECURITY_EXISTS, status=test_status, events=events - ) + for process in av_processes: + events.append(Event.create_event( + title="Found AV process", + message="The process '{}' was recognized as an Anti Virus process. Process " + "details: {}".format(process[1]['name'], json.dumps(process[1])), + event_type=zero_trust_consts.EVENT_TYPE_MONKEY_LOCAL + )) + + if len(av_processes) > 0: + test_status = zero_trust_consts.STATUS_PASSED + else: + test_status = zero_trust_consts.STATUS_FAILED + AggregateFinding.create_or_add_to_existing( + test=zero_trust_consts.TEST_ENDPOINT_SECURITY_EXISTS, status=test_status, events=events + ) -def filter_av_processes(telemetry_json): - all_processes = list(telemetry_json['data']['process_list'].items()) +def filter_av_processes(process_list): + all_processes = list(process_list.items()) av_processes = [] for process in all_processes: process_name = process[1]['name'] From 18232424fad06ad41ec91e2d4459b762660e9f74 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 20 Jan 2020 20:54:41 +0200 Subject: [PATCH 037/119] Bugfix, spec should not check kernel version using platform.architecture but rather the python interpreter version. This handles cases where we run 32b python on 64b machines --- monkey/infection_monkey/monkey.spec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 9c5fa9a18..3a376a73b 100644 --- a/monkey/infection_monkey/monkey.spec +++ b/monkey/infection_monkey/monkey.spec @@ -1,5 +1,6 @@ # -*- mode: python -*- import os +import sys import platform @@ -48,7 +49,7 @@ def is_windows(): def is_32_bit(): - return platform.architecture()[0] == "32bit" + return sys.maxsize <= 2**32 def get_bin_folder(): From ab330219d5ec322773abf9021b42a6fa4e4b0aa7 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Tue, 21 Jan 2020 15:27:41 +0200 Subject: [PATCH 038/119] Using new style `super` calles --- .../infection_monkey/system_info/collectors/aws_collector.py | 3 ++- .../system_info/collectors/environment_collector.py | 3 ++- .../system_info/collectors/hostname_collector.py | 2 +- .../system_info/collectors/process_list_collector.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/monkey/infection_monkey/system_info/collectors/aws_collector.py b/monkey/infection_monkey/system_info/collectors/aws_collector.py index 71f9e58c1..68d125279 100644 --- a/monkey/infection_monkey/system_info/collectors/aws_collector.py +++ b/monkey/infection_monkey/system_info/collectors/aws_collector.py @@ -1,6 +1,7 @@ import logging from common.cloud.aws.aws_instance import AwsInstance +from common.data.system_info_collectors_names import AWS_COLLECTOR from infection_monkey.system_info.system_info_collector import SystemInfoCollector @@ -12,7 +13,7 @@ class AwsCollector(SystemInfoCollector): Extract info from AWS machines. """ def __init__(self): - super(AwsCollector, self).__init__(name="AwsCollector") + super().__init__(name=AWS_COLLECTOR) def collect(self) -> dict: logger.info("Collecting AWS info") diff --git a/monkey/infection_monkey/system_info/collectors/environment_collector.py b/monkey/infection_monkey/system_info/collectors/environment_collector.py index ac5a5433d..5567477d3 100644 --- a/monkey/infection_monkey/system_info/collectors/environment_collector.py +++ b/monkey/infection_monkey/system_info/collectors/environment_collector.py @@ -1,5 +1,6 @@ from common.cloud.all_instances import get_all_cloud_instances from common.cloud.environment_names import ON_PREMISE +from common.data.system_info_collectors_names import ENVIRONMENT_COLLECTOR from infection_monkey.system_info.system_info_collector import SystemInfoCollector @@ -13,7 +14,7 @@ def get_monkey_environment() -> str: class EnvironmentCollector(SystemInfoCollector): def __init__(self): - super(EnvironmentCollector, self).__init__(name="EnvironmentCollector") + super().__init__(name=ENVIRONMENT_COLLECTOR) def collect(self) -> dict: return {"environment": get_monkey_environment()} diff --git a/monkey/infection_monkey/system_info/collectors/hostname_collector.py b/monkey/infection_monkey/system_info/collectors/hostname_collector.py index 92a522bf9..21d03aac7 100644 --- a/monkey/infection_monkey/system_info/collectors/hostname_collector.py +++ b/monkey/infection_monkey/system_info/collectors/hostname_collector.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) class HostnameCollector(SystemInfoCollector): def __init__(self): - super(HostnameCollector, self).__init__(name=HOSTNAME_COLLECTOR) + super().__init__(name=HOSTNAME_COLLECTOR) def collect(self) -> dict: return {"hostname": socket.getfqdn()} diff --git a/monkey/infection_monkey/system_info/collectors/process_list_collector.py b/monkey/infection_monkey/system_info/collectors/process_list_collector.py index 93f836376..c0610cc74 100644 --- a/monkey/infection_monkey/system_info/collectors/process_list_collector.py +++ b/monkey/infection_monkey/system_info/collectors/process_list_collector.py @@ -16,7 +16,7 @@ except NameError: class ProcessListCollector(SystemInfoCollector): def __init__(self): - super(ProcessListCollector, self).__init__(name=PROCESS_LIST_COLLECTOR) + super().__init__(name=PROCESS_LIST_COLLECTOR) def collect(self) -> dict: """ From db5c0f478626f3dc9c3ce1cd5db52d4f44f52f34 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Tue, 21 Jan 2020 15:29:46 +0200 Subject: [PATCH 039/119] Changed get_monkey_env logic to return as soon as a results is found and added docs --- .../system_info/collectors/environment_collector.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/system_info/collectors/environment_collector.py b/monkey/infection_monkey/system_info/collectors/environment_collector.py index 5567477d3..12a58b6d5 100644 --- a/monkey/infection_monkey/system_info/collectors/environment_collector.py +++ b/monkey/infection_monkey/system_info/collectors/environment_collector.py @@ -5,11 +5,15 @@ from infection_monkey.system_info.system_info_collector import SystemInfoCollect def get_monkey_environment() -> str: - env = ON_PREMISE + """ + Get the Monkey's running environment. + :return: One of the cloud providers if on cloud; otherwise, assumes "on premise". + """ for instance in get_all_cloud_instances(): if instance.is_instance(): - env = instance.get_cloud_provider_name() - return env + return instance.get_cloud_provider_name() + + return ON_PREMISE class EnvironmentCollector(SystemInfoCollector): From 6f289915fc404bfc68d1276eaedb8a8f3d443b90 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Tue, 21 Jan 2020 16:19:10 +0200 Subject: [PATCH 040/119] Made envs an enum --- monkey/common/cloud/aws/aws_instance.py | 6 ++--- monkey/common/cloud/azure/azure_instance.py | 6 ++--- monkey/common/cloud/environment_names.py | 23 +++++++++++-------- monkey/common/cloud/gcp/gcp_instance.py | 6 ++--- monkey/common/cloud/instance.py | 5 +++- .../collectors/environment_collector.py | 6 ++--- monkey/monkey_island/cc/models/monkey.py | 2 +- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/monkey/common/cloud/aws/aws_instance.py b/monkey/common/cloud/aws/aws_instance.py index c77220d17..03c5482ba 100644 --- a/monkey/common/cloud/aws/aws_instance.py +++ b/monkey/common/cloud/aws/aws_instance.py @@ -6,7 +6,7 @@ import logging __author__ = 'itay.mizeretz' -from common.cloud.environment_names import AWS +from common.cloud.environment_names import Environment from common.cloud.instance import CloudInstance AWS_INSTANCE_METADATA_LOCAL_IP_ADDRESS = "169.254.169.254" @@ -23,8 +23,8 @@ class AwsInstance(CloudInstance): def is_instance(self): return self.instance_id is not None - def get_cloud_provider_name(self) -> str: - return AWS + def get_cloud_provider_name(self) -> Environment: + return Environment.AWS def __init__(self): self.instance_id = None diff --git a/monkey/common/cloud/azure/azure_instance.py b/monkey/common/cloud/azure/azure_instance.py index f0d5a8044..ec910fb98 100644 --- a/monkey/common/cloud/azure/azure_instance.py +++ b/monkey/common/cloud/azure/azure_instance.py @@ -1,7 +1,7 @@ import logging import requests -from common.cloud.environment_names import AZURE +from common.cloud.environment_names import Environment from common.cloud.instance import CloudInstance LATEST_AZURE_METADATA_API_VERSION = "2019-04-30" @@ -18,8 +18,8 @@ class AzureInstance(CloudInstance): def is_instance(self): return self.on_azure - def get_cloud_provider_name(self) -> str: - return AZURE + def get_cloud_provider_name(self) -> Environment: + return Environment.AZURE def __init__(self): """ diff --git a/monkey/common/cloud/environment_names.py b/monkey/common/cloud/environment_names.py index 0c8655753..945d438ce 100644 --- a/monkey/common/cloud/environment_names.py +++ b/monkey/common/cloud/environment_names.py @@ -1,12 +1,15 @@ -# When adding a new environment to this file, make sure to add it to ALL_ENV_NAMES as well! +from enum import Enum -UNKNOWN = "Unknown" -ON_PREMISE = "On Premise" -AZURE = "Azure" -AWS = "AWS" -GCP = "GCP" -ALIBABA = "Alibaba Cloud" -IBM = "IBM Cloud" -DigitalOcean = "Digital Ocean" -ALL_ENV_NAMES = [UNKNOWN, ON_PREMISE, AZURE, AWS, GCP, ALIBABA, IBM, DigitalOcean] +class Environment(Enum): + UNKNOWN = "Unknown" + ON_PREMISE = "On Premise" + AZURE = "Azure" + AWS = "AWS" + GCP = "GCP" + ALIBABA = "Alibaba Cloud" + IBM = "IBM Cloud" + DigitalOcean = "Digital Ocean" + + +ALL_ENVIRONMENTS_NAMES = [x.value for x in Environment] diff --git a/monkey/common/cloud/gcp/gcp_instance.py b/monkey/common/cloud/gcp/gcp_instance.py index 26738db43..184465bf5 100644 --- a/monkey/common/cloud/gcp/gcp_instance.py +++ b/monkey/common/cloud/gcp/gcp_instance.py @@ -1,7 +1,7 @@ import logging import requests -from common.cloud.environment_names import GCP +from common.cloud.environment_names import Environment from common.cloud.instance import CloudInstance logger = logging.getLogger(__name__) @@ -17,8 +17,8 @@ class GcpInstance(CloudInstance): def is_instance(self): return self.on_gcp - def get_cloud_provider_name(self) -> str: - return GCP + def get_cloud_provider_name(self) -> Environment: + return Environment.GCP def __init__(self): self.on_gcp = False diff --git a/monkey/common/cloud/instance.py b/monkey/common/cloud/instance.py index 61ab4c734..abe0c7910 100644 --- a/monkey/common/cloud/instance.py +++ b/monkey/common/cloud/instance.py @@ -1,3 +1,6 @@ +from common.cloud.environment_names import Environment + + class CloudInstance(object): """ This is an abstract class which represents a cloud instance. @@ -7,5 +10,5 @@ class CloudInstance(object): def is_instance(self) -> bool: raise NotImplementedError() - def get_cloud_provider_name(self) -> str: + def get_cloud_provider_name(self) -> Environment: raise NotImplementedError() diff --git a/monkey/infection_monkey/system_info/collectors/environment_collector.py b/monkey/infection_monkey/system_info/collectors/environment_collector.py index 12a58b6d5..7a953fce9 100644 --- a/monkey/infection_monkey/system_info/collectors/environment_collector.py +++ b/monkey/infection_monkey/system_info/collectors/environment_collector.py @@ -1,10 +1,10 @@ from common.cloud.all_instances import get_all_cloud_instances -from common.cloud.environment_names import ON_PREMISE +from common.cloud.environment_names import Environment from common.data.system_info_collectors_names import ENVIRONMENT_COLLECTOR from infection_monkey.system_info.system_info_collector import SystemInfoCollector -def get_monkey_environment() -> str: +def get_monkey_environment() -> Environment: """ Get the Monkey's running environment. :return: One of the cloud providers if on cloud; otherwise, assumes "on premise". @@ -13,7 +13,7 @@ def get_monkey_environment() -> str: if instance.is_instance(): return instance.get_cloud_provider_name() - return ON_PREMISE + return Environment.ON_PREMISE class EnvironmentCollector(SystemInfoCollector): diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py index 65dda0850..da6d880b4 100644 --- a/monkey/monkey_island/cc/models/monkey.py +++ b/monkey/monkey_island/cc/models/monkey.py @@ -45,7 +45,7 @@ class Monkey(Document): command_control_channel = EmbeddedDocumentField(CommandControlChannel) # Environment related fields - environment = StringField(default=environment_names.UNKNOWN, choices=environment_names.ALL_ENV_NAMES) + environment = StringField(default=environment_names.Environment.UNKNOWN, choices=environment_names.ALL_ENVIRONMENTS_NAMES) aws_instance_id = StringField(required=False) # This field only exists when the monkey is running on an AWS # instance. See https://github.com/guardicore/monkey/issues/426. From a51c1c0629ec18efd442a707d4e0e61142ae8fbc Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Tue, 21 Jan 2020 16:31:06 +0200 Subject: [PATCH 041/119] Used star imports by accident :-1: --- monkey/monkey_island/cc/services/config_schema.py | 3 ++- .../system_info_collectors/system_info_telemetry_dispatcher.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index e7d599cc5..3d0220ee2 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -1,4 +1,5 @@ -from common.data.system_info_collectors_names import * +from common.data.system_info_collectors_names \ + import AWS_COLLECTOR, ENVIRONMENT_COLLECTOR, HOSTNAME_COLLECTOR, PROCESS_LIST_COLLECTOR WARNING_SIGN = " \u26A0" diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py index d67979e8d..b5f2d24ea 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py @@ -1,7 +1,8 @@ import logging import typing -from common.data.system_info_collectors_names import * +from common.data.system_info_collectors_names \ + import AWS_COLLECTOR, ENVIRONMENT_COLLECTOR, HOSTNAME_COLLECTOR, PROCESS_LIST_COLLECTOR from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import process_aws_telemetry from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import process_environment_telemetry from monkey_island.cc.services.telemetry.processing.system_info_collectors.hostname import process_hostname_telemetry From 0f73567ad4b2b86d8265848374866cd5a3a58bc5 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Tue, 21 Jan 2020 16:32:41 +0200 Subject: [PATCH 042/119] Line too long fix --- monkey/monkey_island/cc/services/remote_run_aws.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/remote_run_aws.py b/monkey/monkey_island/cc/services/remote_run_aws.py index 0ba6fa4ef..dfaa0e327 100644 --- a/monkey/monkey_island/cc/services/remote_run_aws.py +++ b/monkey/monkey_island/cc/services/remote_run_aws.py @@ -130,7 +130,8 @@ class RemoteRunAwsService: return r"[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {" \ r"$true}; (New-Object System.Net.WebClient).DownloadFile('https://" + island_ip + \ r":5000/api/monkey/download/monkey-windows-" + bit_text + r".exe','.\\monkey.exe'); " \ - r";Start-Process -FilePath '.\\monkey.exe' -ArgumentList 'm0nk3y -s " + island_ip + r":5000'; " + r";Start-Process -FilePath '.\\monkey.exe' " \ + r"-ArgumentList 'm0nk3y -s " + island_ip + r":5000'; " @staticmethod def _get_run_monkey_cmd_line(is_linux, is_64bit, island_ip): From 5548cf2acfee76dcd120b9494d9c0d049b4a200a Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Tue, 21 Jan 2020 16:53:00 +0200 Subject: [PATCH 043/119] Fixed UTs - enum change wasn't 100% correct --- .../system_info/collectors/environment_collector.py | 6 +++--- monkey/monkey_island/cc/models/monkey.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/monkey/infection_monkey/system_info/collectors/environment_collector.py b/monkey/infection_monkey/system_info/collectors/environment_collector.py index 7a953fce9..100d23175 100644 --- a/monkey/infection_monkey/system_info/collectors/environment_collector.py +++ b/monkey/infection_monkey/system_info/collectors/environment_collector.py @@ -4,16 +4,16 @@ from common.data.system_info_collectors_names import ENVIRONMENT_COLLECTOR from infection_monkey.system_info.system_info_collector import SystemInfoCollector -def get_monkey_environment() -> Environment: +def get_monkey_environment() -> str: """ Get the Monkey's running environment. :return: One of the cloud providers if on cloud; otherwise, assumes "on premise". """ for instance in get_all_cloud_instances(): if instance.is_instance(): - return instance.get_cloud_provider_name() + return instance.get_cloud_provider_name().value - return Environment.ON_PREMISE + return Environment.ON_PREMISE.value class EnvironmentCollector(SystemInfoCollector): diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py index da6d880b4..f658a3d06 100644 --- a/monkey/monkey_island/cc/models/monkey.py +++ b/monkey/monkey_island/cc/models/monkey.py @@ -45,7 +45,8 @@ class Monkey(Document): command_control_channel = EmbeddedDocumentField(CommandControlChannel) # Environment related fields - environment = StringField(default=environment_names.Environment.UNKNOWN, choices=environment_names.ALL_ENVIRONMENTS_NAMES) + environment = StringField(default=environment_names.Environment.UNKNOWN.value, + choices=environment_names.ALL_ENVIRONMENTS_NAMES) aws_instance_id = StringField(required=False) # This field only exists when the monkey is running on an AWS # instance. See https://github.com/guardicore/monkey/issues/426. From ef69058f91c2ce1b4d7054df764b623baa5f986d Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Tue, 21 Jan 2020 17:31:57 +0200 Subject: [PATCH 044/119] Add pyinstaller hook for systeminfo plugins --- .../hook-infection_monkey.system_info.collectors.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 monkey/infection_monkey/pyinstaller_hooks/hook-infection_monkey.system_info.collectors.py diff --git a/monkey/infection_monkey/pyinstaller_hooks/hook-infection_monkey.system_info.collectors.py b/monkey/infection_monkey/pyinstaller_hooks/hook-infection_monkey.system_info.collectors.py new file mode 100644 index 000000000..97cf81bfb --- /dev/null +++ b/monkey/infection_monkey/pyinstaller_hooks/hook-infection_monkey.system_info.collectors.py @@ -0,0 +1,6 @@ +from PyInstaller.utils.hooks import collect_submodules, collect_data_files + +# Import all actions as modules +hiddenimports = collect_submodules('infection_monkey.system_info.collectors') +# Add action files that we enumerate +datas = (collect_data_files('infection_monkey.system_info.collectors', include_py_files=True)) From f999e7221d04414b37743bdcd49bac16c86af5fc Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Tue, 21 Jan 2020 17:38:24 +0200 Subject: [PATCH 045/119] Fully explicit imports all the way --- monkey/infection_monkey/system_info/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/system_info/__init__.py b/monkey/infection_monkey/system_info/__init__.py index 889b558a1..d9107e7bf 100644 --- a/monkey/infection_monkey/system_info/__init__.py +++ b/monkey/infection_monkey/system_info/__init__.py @@ -8,7 +8,7 @@ from enum import IntEnum from infection_monkey.network.info import get_host_subnets from infection_monkey.system_info.azure_cred_collector import AzureCollector from infection_monkey.system_info.netstat_collector import NetstatCollector -from system_info.system_info_collectors_handler import SystemInfoCollectorsHandler +from infection_monkey.system_info.system_info_collectors_handler import SystemInfoCollectorsHandler LOG = logging.getLogger(__name__) From 61a41b407b8a4f330ba93f81aec4bc8e383cdf3f Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 23 Jan 2020 15:50:56 +0200 Subject: [PATCH 046/119] Change filename to account for bitness. --- monkey/infection_monkey/monkey.spec | 9 ++++++++- monkey/infection_monkey/readme.md | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 3a376a73b..2157b697c 100644 --- a/monkey/infection_monkey/monkey.spec +++ b/monkey/infection_monkey/monkey.spec @@ -94,7 +94,14 @@ def get_traceroute_binaries(): def get_monkey_filename(): - return 'monkey.exe' if is_windows() else 'monkey' + name = 'monkey' + if is_32_bit(): + name = name+"32" + else: + name = name+"64" + if is_windows(): + name = name+".exe" + return name def get_exe_strip(): diff --git a/monkey/infection_monkey/readme.md b/monkey/infection_monkey/readme.md index d6e17acdb..8522767dd 100644 --- a/monkey/infection_monkey/readme.md +++ b/monkey/infection_monkey/readme.md @@ -34,7 +34,7 @@ The monkey is composed of three separate parts. 6. To build the final exe: - `cd monkey\infection_monkey` - `build_windows.bat` - - `output is placed under dist\monkey.exe` + - output is placed under `dist\monkey32.exe` or `dist\monkey64.exe` depending on your version of Python ## Linux @@ -66,7 +66,7 @@ Tested on Ubuntu 16.04. - `chmod +x build_linux.sh` - `./build_linux.sh` - output is placed under dist/monkey + output is placed under `dist/monkey32` or `dist/monkey64` depending on your version of python ### Sambacry From 2e8582cd410f68909d5bd6cb8d4c1b82a5a56a20 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 28 Jan 2020 19:11:15 +0200 Subject: [PATCH 047/119] fixes notification bug that routes to wrong route --- monkey/monkey_island/cc/ui/src/components/Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/Main.js b/monkey/monkey_island/cc/ui/src/components/Main.js index 2c54822a5..b4325e55c 100644 --- a/monkey/monkey_island/cc/ui/src/components/Main.js +++ b/monkey/monkey_island/cc/ui/src/components/Main.js @@ -30,7 +30,7 @@ let infectionMonkeyImage = require('../images/infection-monkey.svg'); let guardicoreLogoImage = require('../images/guardicore-logo.png'); let notificationIcon = require('../images/notification-logo-512x512.png'); -const reportZeroTrustRoute = '/report/zero_trust'; +const reportZeroTrustRoute = '/report/zeroTrust'; class AppComponent extends AuthComponent { updateStatus = () => { From b420a83e2265d32f278ba9307efaad16e00651eb Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 08:36:42 +0200 Subject: [PATCH 048/119] Fix typos --- deployment_scripts/deploy_linux.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index cc0674ac4..bb7a31307 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -55,7 +55,7 @@ MONKEY_BIN_DIR="$INFECTION_MONKEY_DIR/bin" if is_root; then - echo "Please don't runt this script as root" + echo "Please don't run this script as root" exit 1 fi @@ -75,7 +75,7 @@ if ! exists git; then fi if ! exists wget; then - echo 'Your system does have wget, please install and re-run this script' + echo 'Your system does not have wget, please install and re-run this script' exit 1 fi @@ -115,10 +115,6 @@ fi log_message "Updating package list" sudo apt-get update -log_message "Installing pip" -sudo apt install python3-pip -${python_cmd} -m pip install pip - log_message "Install python3.7-dev" sudo apt-get install python3.7-dev From 5002a7c17360a50450762c225a841f756ecb571b Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 08:43:35 +0200 Subject: [PATCH 049/119] Consistency cleanups --- deployment_scripts/deploy_linux.sh | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index bb7a31307..da14a7acc 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -24,7 +24,7 @@ log_message() { } config_branch=${2:-"develop"} -config_url="https://raw.githubusercontent.com/guardicore/monkey/"$config_branch"/deployment_scripts/config" +config_url="https://raw.githubusercontent.com/guardicore/monkey/${config_branch}/deployment_scripts/config" if exists curl; then file=$(mktemp) @@ -46,14 +46,11 @@ fi # We can set main paths after we know the home dir ISLAND_PATH="$monkey_home/monkey/monkey_island" -MONKEY_COMMON_PATH="$monkey_home/monkey/common/" MONGO_PATH="$ISLAND_PATH/bin/mongodb" ISLAND_BINARIES_PATH="$ISLAND_PATH/cc/binaries" INFECTION_MONKEY_DIR="$monkey_home/monkey/infection_monkey" MONKEY_BIN_DIR="$INFECTION_MONKEY_DIR/bin" - - if is_root; then echo "Please don't run this script as root" exit 1 @@ -118,14 +115,14 @@ sudo apt-get update log_message "Install python3.7-dev" sudo apt-get install python3.7-dev -log_message "Installing island requirements" -requirements="$ISLAND_PATH/requirements.txt" -${python_cmd} -m pip install --user --upgrade -r ${requirements} || handle_error +log_message "Installing island requirements_island" +requirements_island="$ISLAND_PATH/requirements.txt" +${python_cmd} -m pip install -r "${requirements_island}" --user --upgrade || handle_error -log_message "Installing monkey requirements" +log_message "Installing monkey requirements_island" sudo apt-get install libffi-dev upx libssl-dev libc++1 -cd "${monkey_home}"/monkey/infection_monkey || handle_error -${python_cmd} -m pip install -r requirements.txt --user --upgrade || handle_error +requirements_monkey="$INFECTION_MONKEY_DIR/requirements.txt" +${python_cmd} -m pip install -r "${requirements_monkey}" --user --upgrade || handle_error # Download binaries log_message "Downloading binaries" @@ -183,7 +180,7 @@ log_message "Downloading traceroute binaries" wget -c -N -P "${MONKEY_BIN_DIR}" "${TRACEROUTE_64_BINARY_URL}" wget -c -N -P "${MONKEY_BIN_DIR}" "${TRACEROUTE_32_BINARY_URL}" -sudo chmod +x "${monkey_home}"/monkey/infection_monkey/build_linux.sh +sudo chmod +x "${INFECTION_MONKEY_DIR}/build_linux.sh" log_message "Deployment script finished." exit 0 From 2d5dbf0b537a9c1c2cd48a15b2b34741cfd02d1c Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 08:47:32 +0200 Subject: [PATCH 050/119] Remove unused variables --- deployment_scripts/config | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/deployment_scripts/config b/deployment_scripts/config index fb7a3d5b6..079359355 100644 --- a/deployment_scripts/config +++ b/deployment_scripts/config @@ -18,8 +18,4 @@ WINDOWS_64_BINARY_NAME="monkey-windows-64.exe" TRACEROUTE_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute64" TRACEROUTE_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute32" SAMBACRY_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner64.so" -SAMBACRY_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner32.so" - -# Mongo url's -MONGO_DEBIAN_URL="https://downloads.mongodb.org/linux/mongodb-linux-x86_64-debian81-latest.tgz" -MONGO_UBUNTU_URL="https://downloads.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-latest.tgz" +SAMBACRY_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner32.so" \ No newline at end of file From fb98a9fa123f57c3a50477ac6dc191bfb3149cb7 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 09:15:22 +0200 Subject: [PATCH 051/119] Consolidate apt install commands --- deployment_scripts/deploy_linux.sh | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index da14a7acc..a00793a2c 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -104,17 +104,11 @@ if [[ ${python_cmd} == "" ]]; then log_message "Python 3.7 command not found. Installing python 3.7." sudo add-apt-repository ppa:deadsnakes/ppa sudo apt-get update - sudo apt install python3.7 + sudo apt install python3.7 python3.7-dev log_message "Python 3.7 is now available with command 'python3.7'." python_cmd="python3.7" fi -log_message "Updating package list" -sudo apt-get update - -log_message "Install python3.7-dev" -sudo apt-get install python3.7-dev - log_message "Installing island requirements_island" requirements_island="$ISLAND_PATH/requirements.txt" ${python_cmd} -m pip install -r "${requirements_island}" --user --upgrade || handle_error From 2a6c2d5836dc896dc8d29ae7272f1ed4e622a435 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 09:16:11 +0200 Subject: [PATCH 052/119] Add get-pip command --- deployment_scripts/deploy_linux.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index a00793a2c..63f3d9ef0 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -109,6 +109,9 @@ if [[ ${python_cmd} == "" ]]; then python_cmd="python3.7" fi +curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +${python_cmd} get-pip.py + log_message "Installing island requirements_island" requirements_island="$ISLAND_PATH/requirements.txt" ${python_cmd} -m pip install -r "${requirements_island}" --user --upgrade || handle_error From 5ecbc5f7a4b2acff8604b28fa3e9f88617db87e9 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 09:49:01 +0200 Subject: [PATCH 053/119] Add build-essential command --- deployment_scripts/deploy_linux.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 63f3d9ef0..2e1a5a1f8 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -109,6 +109,8 @@ if [[ ${python_cmd} == "" ]]; then python_cmd="python3.7" fi +sudo apt install build-essentials + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py ${python_cmd} get-pip.py From 59f9e487bb735c7aef1809d92adbfb5274fbe784 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 09:59:09 +0200 Subject: [PATCH 054/119] Update binary links for Windows --- deployment_scripts/config.ps1 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deployment_scripts/config.ps1 b/deployment_scripts/config.ps1 index 095f7b899..869593a9b 100644 --- a/deployment_scripts/config.ps1 +++ b/deployment_scripts/config.ps1 @@ -14,10 +14,12 @@ $WINDOWS_32_BINARY_URL = "https://github.com/guardicore/monkey/releases/download $WINDOWS_32_BINARY_PATH = "monkey-windows-32.exe" $WINDOWS_64_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/monkey-windows-64.exe" $WINDOWS_64_BINARY_PATH = "monkey-windows-64.exe" -$SAMBA_32_BINARY_URL = "https://github.com/VakarisZ/tempBinaries/raw/master/sc_monkey_runner32.so" +$SAMBA_32_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner32.so" $SAMBA_32_BINARY_NAME= "sc_monkey_runner32.so" -$SAMBA_64_BINARY_URL = "https://github.com/VakarisZ/tempBinaries/raw/master/sc_monkey_runner64.so" +$SAMBA_64_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner64.so" $SAMBA_64_BINARY_NAME = "sc_monkey_runner64.so" +$TRACEROUTE_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute64" +$TRACEROUTE_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute32" # Other directories and paths ( most likely you dont need to configure) $MONKEY_ISLAND_DIR = "\monkey\monkey_island" From aa3442195b65996f7db6807a1e41b84e9e4a1cb9 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 09:59:19 +0200 Subject: [PATCH 055/119] Fix syntax errors in PS --- deployment_scripts/deploy_windows.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index b04d04e0f..b4b3c9b8c 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -72,7 +72,7 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, "Select 'add to PATH' when installing" $webClient.DownloadFile($PYTHON_URL, $TEMP_PYTHON_INSTALLER) Start-Process -Wait $TEMP_PYTHON_INSTALLER -ErrorAction Stop - $env: Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") + $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") Remove-Item $TEMP_PYTHON_INSTALLER # Check if installed correctly $version = cmd.exe /c '"python" --version 2>&1' @@ -101,10 +101,10 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, $user_python_dir = cmd.exe /c 'py -m site --user-site' $user_python_dir = Join-Path (Split-Path $user_python_dir) -ChildPath "\Scripts" - if (!($ENV: PATH | Select-String -SimpleMatch $user_python_dir)) + if (!($ENV:Path | Select-String -SimpleMatch $user_python_dir)) { "Adding python scripts path to user's env" - $env: Path += ";" + $user_python_dir + $env:Path += ";" + $user_python_dir [Environment]::SetEnvironmentVariable("Path", $env:Path, "User") } @@ -177,7 +177,7 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, "Downloading npm ..." $webClient.DownloadFile($NPM_URL, $TEMP_NPM_INSTALLER) Start-Process -Wait $TEMP_NPM_INSTALLER - $env: Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") Remove-Item $TEMP_NPM_INSTALLER } From 66a5133a61320e6204cc9f0840769e6deb968d8d Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 10:32:34 +0200 Subject: [PATCH 056/119] Update a lot of URLs and restructure them --- deployment_scripts/config.ps1 | 41 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/deployment_scripts/config.ps1 b/deployment_scripts/config.ps1 index 869593a9b..ab98eaffb 100644 --- a/deployment_scripts/config.ps1 +++ b/deployment_scripts/config.ps1 @@ -2,30 +2,33 @@ $MONKEY_FOLDER_NAME = "infection_monkey" # Url of public git repository that contains monkey's source code $MONKEY_GIT_URL = "https://github.com/guardicore/monkey" +$MONKEY_RELEASES_URL = $MONKEY_GIT_URL + "/releases" +$MONKEY_LATEST_VERSION = "1.7.0" +$MONKEY_DOWNLOAD_URL = $MONKEY_RELEASES_URL + "/" + $MONKEY_LATEST_VERSION + "/" # Link to the latest python download or install it manually -$PYTHON_URL = "https://www.python.org/ftp/python/3.7.4/python-3.7.4-amd64.exe" +$PYTHON_URL = "https://www.python.org/ftp/python/3.7.6/python-3.7.6-amd64.exe" + # Monkey binaries -$LINUX_32_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/monkey-linux-32" +$LINUX_32_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-linux-32" $LINUX_32_BINARY_PATH = "monkey-linux-32" -$LINUX_64_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/monkey-linux-64" +$LINUX_64_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-linux-64" $LINUX_64_BINARY_PATH = "monkey-linux-64" -$WINDOWS_32_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/monkey-windows-32.exe" +$WINDOWS_32_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-windows-32.exe" $WINDOWS_32_BINARY_PATH = "monkey-windows-32.exe" -$WINDOWS_64_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/monkey-windows-64.exe" +$WINDOWS_64_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-windows-64.exe" $WINDOWS_64_BINARY_PATH = "monkey-windows-64.exe" -$SAMBA_32_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner32.so" -$SAMBA_32_BINARY_NAME= "sc_monkey_runner32.so" -$SAMBA_64_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner64.so" +$SAMBA_32_BINARY_URL = $MONKEY_DOWNLOAD_URL + "sc_monkey_runner32.so" +$SAMBA_32_BINARY_NAME = "sc_monkey_runner32.so" +$SAMBA_64_BINARY_URL = $MONKEY_DOWNLOAD_URL + "sc_monkey_runner64.so" $SAMBA_64_BINARY_NAME = "sc_monkey_runner64.so" -$TRACEROUTE_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute64" -$TRACEROUTE_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute32" +$TRACEROUTE_64_BINARY_URL = $MONKEY_DOWNLOAD_URL + "traceroute64" +$TRACEROUTE_32_BINARY_URL = $MONKEY_DOWNLOAD_URL + "traceroute32" # Other directories and paths ( most likely you dont need to configure) -$MONKEY_ISLAND_DIR = "\monkey\monkey_island" -$MONKEY_DIR = "\monkey\infection_monkey" +$MONKEY_ISLAND_DIR = Join-Path "\monkey" -ChildPath "monkey_island" +$MONKEY_DIR = Join-Path "\monkey" -ChildPath "infection_monkey" $SAMBA_BINARIES_DIR = Join-Path -Path $MONKEY_DIR -ChildPath "\bin" -$PYTHON_DLL = "C:\Windows\System32\python27.dll" $MK32_DLL = "mk32.zip" $MK64_DLL = "mk64.zip" $TEMP_PYTHON_INSTALLER = ".\python.exe" @@ -33,16 +36,14 @@ $TEMP_MONGODB_ZIP = ".\mongodb.zip" $TEMP_OPEN_SSL_ZIP = ".\openssl.zip" $TEMP_CPP_INSTALLER = "cpp.exe" $TEMP_NPM_INSTALLER = "node.msi" -$TEMP_PYWIN32_INSTALLER = "pywin32.exe" $TEMP_UPX_ZIP = "upx.zip" -$UPX_FOLDER = "upx394w" +$UPX_FOLDER = "upx-3.96-win64" # Other url's -$MONGODB_URL = "https://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-latest.zip" -$OPEN_SSL_URL = "https://indy.fulgan.com/SSL/Archive/openssl-1.0.2l-i386-win32.zip" +$MONGODB_URL = "https://downloads.mongodb.org/win32/mongodb-win32-x86_64-2012plus-v4.2-latest.zip" +$OPEN_SSL_URL = "https://indy.fulgan.com/SSL/openssl-1.0.2u-x64_86-win64.zip" $CPP_URL = "https://go.microsoft.com/fwlink/?LinkId=746572" -$NPM_URL = "https://nodejs.org/dist/v10.13.0/node-v10.13.0-x64.msi" -$PYWIN32_URL = "https://github.com/mhammond/pywin32/releases/download/b225/pywin32-225.win-amd64-py3.7.exe" +$NPM_URL = "https://nodejs.org/dist/v12.14.1/node-v12.14.1-x64.msi" $MK32_DLL_URL = "https://github.com/guardicore/mimikatz/releases/download/1.1.0/mk32.zip" $MK64_DLL_URL = "https://github.com/guardicore/mimikatz/releases/download/1.1.0/mk64.zip" -$UPX_URL = "https://github.com/upx/upx/releases/download/v3.94/upx394w.zip" +$UPX_URL = "https://github.com/upx/upx/releases/download/v3.96/upx-3.96-win64.zip" From 9edce17297f158b0a8b4293cd74f150f0f62bd4d Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 10:32:47 +0200 Subject: [PATCH 057/119] Install Pywin32 using pip now --- deployment_scripts/deploy_windows.ps1 | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index b4b3c9b8c..971f4917d 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -92,6 +92,9 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, return } + "Installing pywin32" + python -m pip install --user pywin32 + "Installing python packages for island" $islandRequirements = Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\requirements.txt" -ErrorAction Stop & python -m pip install --user -r $islandRequirements @@ -187,12 +190,6 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, & npm run dist Pop-Location - # Install pywin32 - "Downloading pywin32" - $webClient.DownloadFile($PYWIN32_URL, $TEMP_PYWIN32_INSTALLER) - Start-Process -Wait $TEMP_PYWIN32_INSTALLER -ErrorAction Stop - Remove-Item $TEMP_PYWIN32_INSTALLER - # Create infection_monkey/bin directory if not already present $binDir = (Join-Path -Path $monkey_home -ChildPath $MONKEY_DIR | Join-Path -ChildPath "\bin") New-Item -ItemType directory -path $binaries -ErrorAction SilentlyContinue From c53806e789b680ee3f4ff13ce7865ce99d949f9d Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 11:15:46 +0200 Subject: [PATCH 058/119] Missing URL path parameter --- deployment_scripts/config.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment_scripts/config.ps1 b/deployment_scripts/config.ps1 index ab98eaffb..a50f3e935 100644 --- a/deployment_scripts/config.ps1 +++ b/deployment_scripts/config.ps1 @@ -4,7 +4,7 @@ $MONKEY_FOLDER_NAME = "infection_monkey" $MONKEY_GIT_URL = "https://github.com/guardicore/monkey" $MONKEY_RELEASES_URL = $MONKEY_GIT_URL + "/releases" $MONKEY_LATEST_VERSION = "1.7.0" -$MONKEY_DOWNLOAD_URL = $MONKEY_RELEASES_URL + "/" + $MONKEY_LATEST_VERSION + "/" +$MONKEY_DOWNLOAD_URL = $MONKEY_RELEASES_URL + "/download/" + $MONKEY_LATEST_VERSION + "/" # Link to the latest python download or install it manually $PYTHON_URL = "https://www.python.org/ftp/python/3.7.6/python-3.7.6-amd64.exe" From 161265e4c4a819f37c6492c9c098f8b116a7ec1d Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 11:16:00 +0200 Subject: [PATCH 059/119] Remove config.ps1 after loading the configuration --- deployment_scripts/deploy_windows.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index 971f4917d..987a9b70b 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -12,6 +12,8 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, $webClient.DownloadFile($config_url, $config_filename) . ./config.ps1 "Config variables from config.ps1 imported" + Remove-Item $config_filename + # If we want monkey in current dir we need to create an empty folder for source files if ((Join-Path $monkey_home '') -eq (Join-Path (Get-Item -Path ".\").FullName '')) From e226e7410010b1d0f385568e14c2be981017ce12 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 3 Feb 2020 12:18:02 +0200 Subject: [PATCH 060/119] No more need for run_script.bat. Cleaned up README.md visually --- deployment_scripts/README.md | 12 ++++++++---- deployment_scripts/deploy_windows.ps1 | 19 ++++++++++++++++--- deployment_scripts/run_script.bat | 8 -------- 3 files changed, 24 insertions(+), 15 deletions(-) delete mode 100644 deployment_scripts/run_script.bat diff --git a/deployment_scripts/README.md b/deployment_scripts/README.md index 750979a4d..812337eba 100644 --- a/deployment_scripts/README.md +++ b/deployment_scripts/README.md @@ -3,13 +3,17 @@ Before running the script you must have git installed.
`Invoke-WebRequest https://raw.githubusercontent.com/guardicore/monkey/develop/deployment_scripts/deploy_windows.ps1 -OutFile deploy_windows.ps1` + Then execute the resulting script with your shell. First argument is an empty directory (script can create one) and second is branch you want to clone. + Example usages:
-`./run_script.bat` (Sets up monkey in current directory under .\infection_monkey)
-`./run_script.bat "C:\test"` (Sets up monkey in C:\test)
-`powershell -ExecutionPolicy ByPass -Command ". .\deploy_windows.ps1; Deploy-Windows -monkey_home C:\test"` (Same as above)
-`./run_script.bat "" "master"` (Sets up master branch instead of develop in current dir) +`.\deploy_windows.ps1` (Sets up monkey in current directory under .\infection_monkey)
+`.\deploy_windows.ps1 -monkey_home "C:\test"` (Sets up monkey in C:\test)
+`.\deploy_windows.ps1 -branch "master"` (Sets up master branch instead of develop in current dir) + +If you run into Execution Policy warnings, you can disable them by prefixing the following snippet +`powershell -ExecutionPolicy ByPass -Command "[original command here]"` Don't forget to add python to PATH or do so while installing it via this script.
diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index 987a9b70b..9272533fd 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -1,18 +1,28 @@ +param( + [Parameter(Mandatory = $false, Position = 0)] + [String] $monkey_home = (Get-Item -Path ".\").FullName, + + [Parameter(Mandatory = $false, Position = 1)] + [System.String] + $branch = "develop" +) function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, [String] $branch = "develop") { - + Write-Output "Downloading to $monkey_home" + Write-Output "Branch $branch" # Set variables for script execution [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $webClient = New-Object System.Net.WebClient # Import the config variables + $config_filename = New-TemporaryFile $config_filename = "config.ps1" $config_url = "https://raw.githubusercontent.com/guardicore/monkey/" + $branch + "/deployment_scripts/config.ps1" $webClient.DownloadFile($config_url, $config_filename) . ./config.ps1 "Config variables from config.ps1 imported" - Remove-Item $config_filename + #Remove-Item $config_filename # If we want monkey in current dir we need to create an empty folder for source files @@ -35,7 +45,9 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, } # Download the monkey - $output = cmd.exe /c "git clone --single-branch -b $branch $MONKEY_GIT_URL $monkey_home 2>&1" + $command = "git clone --single-branch -b $branch $MONKEY_GIT_URL $monkey_home 2>&1" + Write-Output $command + $output = cmd.exe /c $command $binDir = (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\bin") if ($output -like "*already exists and is not an empty directory.*") { @@ -242,3 +254,4 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, "Script finished" } +Deploy-Windows -monkey_home $monkey_home -branch $branch \ No newline at end of file diff --git a/deployment_scripts/run_script.bat b/deployment_scripts/run_script.bat deleted file mode 100644 index 3dcd62760..000000000 --- a/deployment_scripts/run_script.bat +++ /dev/null @@ -1,8 +0,0 @@ -SET command=. .\deploy_windows.ps1; Deploy-Windows -if NOT "%~1" == "" ( - SET "command=%command% -monkey_home %~1" -) -if NOT "%~2" == "" ( - SET "command=%command% -branch %~2" -) -powershell -ExecutionPolicy ByPass -Command %command% \ No newline at end of file From e183f44d145ed0c3780d3eb845a61bec1b53dfaf Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Tue, 4 Feb 2020 15:08:59 +0200 Subject: [PATCH 061/119] Improved deployment_scripts/README.md Fix linter errors and improve English + security recommendations. --- deployment_scripts/README.md | 67 ++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/deployment_scripts/README.md b/deployment_scripts/README.md index 812337eba..fa8c898f1 100644 --- a/deployment_scripts/README.md +++ b/deployment_scripts/README.md @@ -1,32 +1,49 @@ -# Files used to deploy development version of infection monkey -## Windows +# Deployment guide for a development environemnt -Before running the script you must have git installed.
-`Invoke-WebRequest https://raw.githubusercontent.com/guardicore/monkey/develop/deployment_scripts/deploy_windows.ps1 -OutFile deploy_windows.ps1` +This guide is for you if you wish to develop for Infection Monkey. If you only want to use it, please download the relevant version from [our website](https://infectionmonkey.com). -Then execute the resulting script with your shell. -First argument is an empty directory (script can create one) and second is branch you want to clone. +## Prerequisites -Example usages:
-`.\deploy_windows.ps1` (Sets up monkey in current directory under .\infection_monkey)
-`.\deploy_windows.ps1 -monkey_home "C:\test"` (Sets up monkey in C:\test)
-`.\deploy_windows.ps1 -branch "master"` (Sets up master branch instead of develop in current dir) +Before running the script you must have `git` installed. If you don't have `git` installed, please follow [this guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). -If you run into Execution Policy warnings, you can disable them by prefixing the following snippet -`powershell -ExecutionPolicy ByPass -Command "[original command here]"` +## Deploy on Windows -Don't forget to add python to PATH or do so while installing it via this script.
+Run the following command in powershell: -## Linux +```powershell +Invoke-WebRequest https://raw.githubusercontent.com/guardicore/monkey/develop/deployment_scripts/deploy_windows.ps1 -OutFile deploy_windows.ps1 +``` -Linux deployment script is meant for Ubuntu 16.x machines. -You must have root permissions, but don't run the script as root.
-`wget https://raw.githubusercontent.com/guardicore/monkey/develop/deployment_scripts/deploy_linux.sh` -Then execute the resulting script with your shell. -First argument should be an absolute path of an empty directory (script will create one if doesn't exist, default is ./infection_monkey). -Second parameter is the branch you want to clone (develop by default). -Example usages:
-`./deploy_linux.sh` (deploys under ./infection_monkey)
-`./deploy_linux.sh "/home/test/monkey"` (deploys under /home/test/monkey)
-`./deploy_linux.sh "" "master"` (deploys master branch in script directory)
-`./deploy_linux.sh "/home/user/new" "master"` (if directory "new" is not found creates it and clones master branch into it)
+This will download our deploy script. It's a good idea to read it quickly before executing it! + +After downloading that script, execute it in a shell (like `cmd` or `powershell`). The first argument is an empty directory (script can create one). The second argument is which branch you want to clone - by default, the script will check out the `develop` branch. Some example usages: + +- `.\deploy_windows.ps1` (Sets up monkey in current directory under .\infection_monkey) +- `.\deploy_windows.ps1 -monkey_home "C:\test"` (Sets up monkey in C:\test) +- `.\deploy_windows.ps1 -branch "master"` (Sets up master branch instead of develop in current dir) + +### Troubleshooting + +- If you run into Execution Policy warnings, you can disable them by prefixing the following snippet: `powershell -ExecutionPolicy ByPass -Command "[original command here]"` +- Don't forget to add python to PATH or do so while installing it via this script. + +## Deploy on Linux + +Linux deployment script is meant for Ubuntu 16 and Ubuntu 18 machines. + +Your user must have root permissions; however, don't run the script as root! + +```sh +wget https://raw.githubusercontent.com/guardicore/monkey/develop/deployment_scripts/deploy_linux.sh +``` + +This will download our deploy script. It's a good idea to read it quickly before executing it! + +Then execute the resulting script with your shell. + +After downloading that script, execute it in a shell. The first argument should be an absolute path of an empty directory (the script will create one if doesn't exist, default is ./infection_monkey). The second parameter is the branch you want to clone (develop by default). Some example usages: + +- `./deploy_linux.sh` (deploys under ./infection_monkey) +- `./deploy_linux.sh "/home/test/monkey"` (deploys under /home/test/monkey) +- `./deploy_linux.sh "" "master"` (deploys master branch in script directory) +- `./deploy_linux.sh "/home/user/new" "master"` (if directory "new" is not found creates it and clones master branch into it) From 52d2b6f73d82ea41cdfb7ab7f568065e14aae71e Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sat, 8 Feb 2020 22:37:01 +0200 Subject: [PATCH 062/119] Remove reference to CMD. It's 2020 --- deployment_scripts/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deployment_scripts/README.md b/deployment_scripts/README.md index fa8c898f1..c533605db 100644 --- a/deployment_scripts/README.md +++ b/deployment_scripts/README.md @@ -16,7 +16,9 @@ Invoke-WebRequest https://raw.githubusercontent.com/guardicore/monkey/develop/de This will download our deploy script. It's a good idea to read it quickly before executing it! -After downloading that script, execute it in a shell (like `cmd` or `powershell`). The first argument is an empty directory (script can create one). The second argument is which branch you want to clone - by default, the script will check out the `develop` branch. Some example usages: +After downloading that script, execute it in `powershell`. + +The first argument is an empty directory (script can create one). The second argument is which branch you want to clone - by default, the script will check out the `develop` branch. Some example usages: - `.\deploy_windows.ps1` (Sets up monkey in current directory under .\infection_monkey) - `.\deploy_windows.ps1 -monkey_home "C:\test"` (Sets up monkey in C:\test) From 9af93be7f6b5bbfd86f0ae2b0fe356f7b38d832e Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sat, 8 Feb 2020 23:24:25 +0200 Subject: [PATCH 063/119] Handle either curl or wget seemlessly. --- deployment_scripts/deploy_linux.sh | 89 +++++++++++++++++++----------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 2e1a5a1f8..7b1171e5b 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -26,18 +26,30 @@ log_message() { config_branch=${2:-"develop"} config_url="https://raw.githubusercontent.com/guardicore/monkey/${config_branch}/deployment_scripts/config" -if exists curl; then - file=$(mktemp) - curl -s -o $file "$config_url" - log_message "downloaded configuration" - source $file - log_message "loaded configuration" - rm $file -else - echo 'Your system does not have curl, exiting' +curl_exists=$(exists curl) +wget_exists=$(exists wget) +if [[ ! $curl_exists && ! $wget_exists ]]; then + echo 'Your system does not have curl or wget, exiting' exit 1 fi +file=$(mktemp) +if [ $curl_exists ]; then + # shellcheck disable=SC2086 + curl -s -o $file "$config_url" +else + # shellcheck disable=SC2086 + wget --output-file=$file --output-file= +fi + +log_message "downloaded configuration" +# shellcheck source=deployment_scripts/config +# shellcheck disable=SC2086 +source $file +log_message "loaded configuration" +# shellcheck disable=SC2086 +rm $file + # Setup monkey either in dir required or current dir monkey_home=${1:-$(pwd)} if [[ $monkey_home == $(pwd) ]]; then @@ -71,11 +83,6 @@ if ! exists git; then exit 1 fi -if ! exists wget; then - echo 'Your system does not have wget, please install and re-run this script' - exit 1 -fi - log_message "Cloning files from git" branch=${2:-"develop"} if [[ ! -d "$monkey_home/monkey" ]]; then # If not already cloned @@ -110,9 +117,13 @@ if [[ ${python_cmd} == "" ]]; then fi sudo apt install build-essentials - -curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +if [ $curl_exists ]; then + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +else + wget --output-file=get-pip.py https://bootstrap.pypa.io/get-pip.py +fi ${python_cmd} get-pip.py +rm get-pip.py log_message "Installing island requirements_island" requirements_island="$ISLAND_PATH/requirements.txt" @@ -125,18 +136,22 @@ ${python_cmd} -m pip install -r "${requirements_monkey}" --user --upgrade || han # Download binaries log_message "Downloading binaries" -wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_32_BINARY_URL} -wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_64_BINARY_URL} -wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_32_BINARY_URL} -wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_64_BINARY_URL} +if [ $wget_exists ]; then + wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_32_BINARY_URL} + wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_64_BINARY_URL} + wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_32_BINARY_URL} + wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_64_BINARY_URL} +else + curl -o ${ISLAND_BINARIES_PATH}\monkey-linux-32 ${LINUX_32_BINARY_URL} + curl -o ${ISLAND_BINARIES_PATH}\monkey-linux-64 ${LINUX_64_BINARY_URL} + curl -o ${ISLAND_BINARIES_PATH}\monkey-windows-32.exe ${WINDOWS_32_BINARY_URL} + curl -o ${ISLAND_BINARIES_PATH}\monkey-windows-64.exe ${WINDOWS_64_BINARY_URL} +fi + # Allow them to be executed chmod a+x "$ISLAND_BINARIES_PATH/$LINUX_32_BINARY_NAME" chmod a+x "$ISLAND_BINARIES_PATH/$LINUX_64_BINARY_NAME" -# Get machine type/kernel version -kernel=$(uname -m) -linux_dist=$(lsb_release -a 2>/dev/null) - # If a user haven't installed mongo manually check if we can install it with our script log_message "Installing MongoDB" "${ISLAND_PATH}"/linux/install_mongo.sh ${MONGO_PATH} || handle_error @@ -157,8 +172,11 @@ openssl x509 -req -days 366 -in cc/server.csr -signkey cc/server.key -out cc/ser # Update node log_message "Installing nodejs" cd "$ISLAND_PATH/cc/ui" || handle_error -sudo apt-get install curl -curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - +if [ $curl_exists ]; then + curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - +else + wget -q -O - https://deb.nodesource.com/setup_12.x | sudo -E bash - +fi sudo apt-get install -y nodejs npm install sass-loader node-sass webpack --save-dev npm update @@ -171,13 +189,22 @@ mkdir "${MONKEY_BIN_DIR}" # Download sambacry binaries log_message "Downloading sambacry binaries" -wget -c -N -P "${MONKEY_BIN_DIR}" "${SAMBACRY_64_BINARY_URL}" -wget -c -N -P "${MONKEY_BIN_DIR}" "${SAMBACRY_32_BINARY_URL}" - +if [ $wget_exists ]; then + wget -c -N -P "${MONKEY_BIN_DIR}" ${SAMBACRY_64_BINARY_URL} + wget -c -N -P "${MONKEY_BIN_DIR}" ${SAMBACRY_32_BINARY_URL} +else + curl -o ${MONKEY_BIN_DIR}\sc_monkey_runner64.so ${SAMBACRY_64_BINARY_URL} + curl -o ${MONKEY_BIN_DIR}\sc_monkey_runner32.so ${SAMBACRY_32_BINARY_URL} +fi # Download traceroute binaries log_message "Downloading traceroute binaries" -wget -c -N -P "${MONKEY_BIN_DIR}" "${TRACEROUTE_64_BINARY_URL}" -wget -c -N -P "${MONKEY_BIN_DIR}" "${TRACEROUTE_32_BINARY_URL}" +if [ $wget_exists ]; then + wget -c -N -P "${MONKEY_BIN_DIR}" ${TRACEROUTE_64_BINARY_URL} + wget -c -N -P "${MONKEY_BIN_DIR}" ${TRACEROUTE_32_BINARY_URL} +else + curl -o ${MONKEY_BIN_DIR}\traceroute64 ${TRACEROUTE_64_BINARY_URL} + curl -o ${MONKEY_BIN_DIR}\traceroute32 ${TRACEROUTE_32_BINARY_URL} +fi sudo chmod +x "${INFECTION_MONKEY_DIR}/build_linux.sh" From 5f8453dbaefc841beacbeee474d016a8ed70fe4c Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sat, 8 Feb 2020 23:25:10 +0200 Subject: [PATCH 064/119] Delete temp config file from PS script --- deployment_scripts/deploy_windows.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index 9272533fd..210453e8d 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -22,7 +22,7 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, $webClient.DownloadFile($config_url, $config_filename) . ./config.ps1 "Config variables from config.ps1 imported" - #Remove-Item $config_filename + Remove-Item $config_filename # If we want monkey in current dir we need to create an empty folder for source files From e51f2e927f3819e8f4b36514fe56685f4e4bb64d Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 10:52:31 +0200 Subject: [PATCH 065/119] Change homepage to be InfectionMonkey related --- monkey/monkey_island/deb-package/DEBIAN/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/deb-package/DEBIAN/control b/monkey/monkey_island/deb-package/DEBIAN/control index 88723149c..16aed4614 100644 --- a/monkey/monkey_island/deb-package/DEBIAN/control +++ b/monkey/monkey_island/deb-package/DEBIAN/control @@ -1,7 +1,7 @@ Package: gc-monkey-island Architecture: amd64 -Maintainer: Guardicore -Homepage: http://www.guardicore.com +Maintainer: Guardicore +Homepage: http://www.infectionmonkey.com Priority: optional Version: 1.0 Description: Guardicore Infection Monkey Island installation package From 0c9a33397614c58d3aac2d8578a381f383511ce8 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 09:13:13 +0200 Subject: [PATCH 066/119] Prefer wget/curl depending on situation (saving files) Revert using curl/wget exists variables. typo fix when pulling config with wget --- deployment_scripts/deploy_linux.sh | 31 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 7b1171e5b..d1c73a653 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -26,20 +26,19 @@ log_message() { config_branch=${2:-"develop"} config_url="https://raw.githubusercontent.com/guardicore/monkey/${config_branch}/deployment_scripts/config" -curl_exists=$(exists curl) -wget_exists=$(exists wget) -if [[ ! $curl_exists && ! $wget_exists ]]; then +if (! exists curl) && (! exists wget); then echo 'Your system does not have curl or wget, exiting' exit 1 fi file=$(mktemp) -if [ $curl_exists ]; then +# shellcheck disable=SC2086 +if exists wget; then # shellcheck disable=SC2086 - curl -s -o $file "$config_url" + wget --output-document=$file "$config_url" else # shellcheck disable=SC2086 - wget --output-file=$file --output-file= + curl -s -o $file "$config_url" fi log_message "downloaded configuration" @@ -48,7 +47,7 @@ log_message "downloaded configuration" source $file log_message "loaded configuration" # shellcheck disable=SC2086 -rm $file +# rm $file # Setup monkey either in dir required or current dir monkey_home=${1:-$(pwd)} @@ -117,10 +116,11 @@ if [[ ${python_cmd} == "" ]]; then fi sudo apt install build-essentials -if [ $curl_exists ]; then - curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +# shellcheck disable=SC2086 +if exists wget; then + wget --output-document=get-pip.py https://bootstrap.pypa.io/get-pip.py else - wget --output-file=get-pip.py https://bootstrap.pypa.io/get-pip.py + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py fi ${python_cmd} get-pip.py rm get-pip.py @@ -136,7 +136,7 @@ ${python_cmd} -m pip install -r "${requirements_monkey}" --user --upgrade || han # Download binaries log_message "Downloading binaries" -if [ $wget_exists ]; then +if exists wget; then wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_32_BINARY_URL} wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_64_BINARY_URL} wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_32_BINARY_URL} @@ -172,7 +172,8 @@ openssl x509 -req -days 366 -in cc/server.csr -signkey cc/server.key -out cc/ser # Update node log_message "Installing nodejs" cd "$ISLAND_PATH/cc/ui" || handle_error -if [ $curl_exists ]; then +# shellcheck disable=SC2086 +if exists curl; then curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - else wget -q -O - https://deb.nodesource.com/setup_12.x | sudo -E bash - @@ -189,7 +190,8 @@ mkdir "${MONKEY_BIN_DIR}" # Download sambacry binaries log_message "Downloading sambacry binaries" -if [ $wget_exists ]; then +# shellcheck disable=SC2086 +if exists wget; then wget -c -N -P "${MONKEY_BIN_DIR}" ${SAMBACRY_64_BINARY_URL} wget -c -N -P "${MONKEY_BIN_DIR}" ${SAMBACRY_32_BINARY_URL} else @@ -198,7 +200,8 @@ else fi # Download traceroute binaries log_message "Downloading traceroute binaries" -if [ $wget_exists ]; then +# shellcheck disable=SC2086 +if exists wget; then wget -c -N -P "${MONKEY_BIN_DIR}" ${TRACEROUTE_64_BINARY_URL} wget -c -N -P "${MONKEY_BIN_DIR}" ${TRACEROUTE_32_BINARY_URL} else From e4812d401add274a28e9890dcc37762e0d0d54f7 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 11:04:45 +0200 Subject: [PATCH 067/119] Add some log comments --- deployment_scripts/deploy_linux.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index d1c73a653..664b30926 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -115,7 +115,10 @@ if [[ ${python_cmd} == "" ]]; then python_cmd="python3.7" fi +log_message "Installing build-essentials" sudo apt install build-essentials +log_message "Installing or updating pip" + # shellcheck disable=SC2086 if exists wget; then wget --output-document=get-pip.py https://bootstrap.pypa.io/get-pip.py @@ -125,6 +128,7 @@ fi ${python_cmd} get-pip.py rm get-pip.py + log_message "Installing island requirements_island" requirements_island="$ISLAND_PATH/requirements.txt" ${python_cmd} -m pip install -r "${requirements_island}" --user --upgrade || handle_error From 798babe4cc5bd9f526a8050681b936517c8c7824 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 11:07:41 +0200 Subject: [PATCH 068/119] Updated mongodb downloads. Support deb10 --- monkey/monkey_island/linux/install_mongo.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/monkey/monkey_island/linux/install_mongo.sh b/monkey/monkey_island/linux/install_mongo.sh index 51091d144..28a7a1237 100755 --- a/monkey/monkey_island/linux/install_mongo.sh +++ b/monkey/monkey_island/linux/install_mongo.sh @@ -10,16 +10,19 @@ MONGODB_DIR=$1 # If using deb, this should be: /var/monkey/monkey_island/bin/mon if [[ ${os_version_monkey} == "Ubuntu 16.04"* ]]; then echo Detected Ubuntu 16.04 - export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-3.6.12.tgz" + export tgz_url="https://repo.mongodb.org/apt/ubuntu/dists/xenial/mongodb-org/4.2/multiverse/binary-amd64/mongodb-org-server_4.2.3_amd64.deb" elif [[ ${os_version_monkey} == "Ubuntu 18.04"* ]]; then echo Detected Ubuntu 18.04 - export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.0.tgz" + export tgz_url="https://repo.mongodb.org/apt/ubuntu/dists/bionic/mongodb-org/4.2/multiverse/binary-amd64/mongodb-org-server_4.2.3_amd64.deb" elif [[ ${os_version_monkey} == "Debian GNU/Linux 8"* ]]; then echo Detected Debian 8 - export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian81-3.6.12.tgz" + export tgz_url="https://repo.mongodb.org/apt/debian/dists/jessie/mongodb-org/4.0/main/binary-amd64/mongodb-org-server_4.0.16_amd64.deb" elif [[ ${os_version_monkey} == "Debian GNU/Linux 9"* ]]; then echo Detected Debian 9 - export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-3.6.12.tgz" + export tgz_url="https://repo.mongodb.org/apt/debian/dists/stretch/mongodb-org/4.2/main/binary-amd64/mongodb-org-server_4.2.3_amd64.deb" +elif [[ ${os_version_monkey} == "Debian GNU/Linux 10"* ]]; then + echo Detected Debian 9 + export tgz_url="https://repo.mongodb.org/apt/debian/dists/buster/mongodb-org/4.2/main/binary-amd64/mongodb-org-server_4.2.3_amd64.deb" else echo Unsupported OS exit 1 From c10f20f4b74a85e5ef9515e8fbaaefe3a3703278 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 11:13:17 +0200 Subject: [PATCH 069/119] First install NPM then change directories --- deployment_scripts/deploy_linux.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 664b30926..48991c890 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -175,7 +175,6 @@ openssl x509 -req -days 366 -in cc/server.csr -signkey cc/server.key -out cc/ser # Update node log_message "Installing nodejs" -cd "$ISLAND_PATH/cc/ui" || handle_error # shellcheck disable=SC2086 if exists curl; then curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - @@ -183,6 +182,8 @@ else wget -q -O - https://deb.nodesource.com/setup_12.x | sudo -E bash - fi sudo apt-get install -y nodejs + +cd "$ISLAND_PATH/cc/ui" || handle_error npm install sass-loader node-sass webpack --save-dev npm update From fe9ff0d32982dc30f217173ad98f8e5b0b7247ac Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 11:14:30 +0200 Subject: [PATCH 070/119] Newline at end of deploy_windows.ps1 --- deployment_scripts/deploy_windows.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index 210453e8d..d978042b3 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -254,4 +254,4 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, "Script finished" } -Deploy-Windows -monkey_home $monkey_home -branch $branch \ No newline at end of file +Deploy-Windows -monkey_home $monkey_home -branch $branch From bd9400403df9ee9834914d89df0d2c623f445fb6 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 9 Feb 2020 11:20:12 +0200 Subject: [PATCH 071/119] Added version file to common. It's also executable so it's accessible from shell. --- monkey/common/version.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 monkey/common/version.py diff --git a/monkey/common/version.py b/monkey/common/version.py new file mode 100644 index 000000000..317afe99a --- /dev/null +++ b/monkey/common/version.py @@ -0,0 +1,22 @@ +# To get the version from shell, run `python ./version.py` (see `python ./version.py -h` for details). +import argparse + +MAJOR = "1" +MINOR = "8" +PATCH = "0" +BUILD = "dev" + + +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() From cea33d4540539fca664ad23cee65028488dbc5b5 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 9 Feb 2020 11:20:29 +0200 Subject: [PATCH 072/119] Logging version when initializing Monkey and Island. --- monkey/infection_monkey/main.py | 3 +++ monkey/monkey_island/cc/main.py | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) 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/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()]) ) ) From 0c82f0e98f8cc5b7cb2551552122f8721316badc Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 11:20:43 +0200 Subject: [PATCH 073/119] Don't randomly install mongod unless required --- deployment_scripts/deploy_linux.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 48991c890..8e9e4c845 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -117,8 +117,8 @@ fi log_message "Installing build-essentials" sudo apt install build-essentials -log_message "Installing or updating pip" +log_message "Installing or updating pip" # shellcheck disable=SC2086 if exists wget; then wget --output-document=get-pip.py https://bootstrap.pypa.io/get-pip.py @@ -128,7 +128,6 @@ fi ${python_cmd} get-pip.py rm get-pip.py - log_message "Installing island requirements_island" requirements_island="$ISLAND_PATH/requirements.txt" ${python_cmd} -m pip install -r "${requirements_island}" --user --upgrade || handle_error @@ -157,9 +156,10 @@ chmod a+x "$ISLAND_BINARIES_PATH/$LINUX_32_BINARY_NAME" chmod a+x "$ISLAND_BINARIES_PATH/$LINUX_64_BINARY_NAME" # If a user haven't installed mongo manually check if we can install it with our script -log_message "Installing MongoDB" -"${ISLAND_PATH}"/linux/install_mongo.sh ${MONGO_PATH} || handle_error - +if ! exists mongod; then + log_message "Installing MongoDB" + "${ISLAND_PATH}"/linux/install_mongo.sh ${MONGO_PATH} || handle_error +fi log_message "Installing openssl" sudo apt-get install openssl From 6429bb559765fe16e54f44af7e6c9f7193f00e0e Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 11:27:10 +0200 Subject: [PATCH 074/119] Typofix on where to download binaries --- deployment_scripts/deploy_linux.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 8e9e4c845..20b5e030a 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -200,8 +200,8 @@ if exists wget; then wget -c -N -P "${MONKEY_BIN_DIR}" ${SAMBACRY_64_BINARY_URL} wget -c -N -P "${MONKEY_BIN_DIR}" ${SAMBACRY_32_BINARY_URL} else - curl -o ${MONKEY_BIN_DIR}\sc_monkey_runner64.so ${SAMBACRY_64_BINARY_URL} - curl -o ${MONKEY_BIN_DIR}\sc_monkey_runner32.so ${SAMBACRY_32_BINARY_URL} + curl -o ${MONKEY_BIN_DIR}/sc_monkey_runner64.so ${SAMBACRY_64_BINARY_URL} + curl -o ${MONKEY_BIN_DIR}/sc_monkey_runner32.so ${SAMBACRY_32_BINARY_URL} fi # Download traceroute binaries log_message "Downloading traceroute binaries" @@ -210,8 +210,8 @@ if exists wget; then wget -c -N -P "${MONKEY_BIN_DIR}" ${TRACEROUTE_64_BINARY_URL} wget -c -N -P "${MONKEY_BIN_DIR}" ${TRACEROUTE_32_BINARY_URL} else - curl -o ${MONKEY_BIN_DIR}\traceroute64 ${TRACEROUTE_64_BINARY_URL} - curl -o ${MONKEY_BIN_DIR}\traceroute32 ${TRACEROUTE_32_BINARY_URL} + curl -o ${MONKEY_BIN_DIR}/traceroute64 ${TRACEROUTE_64_BINARY_URL} + curl -o ${MONKEY_BIN_DIR}/traceroute32 ${TRACEROUTE_32_BINARY_URL} fi sudo chmod +x "${INFECTION_MONKEY_DIR}/build_linux.sh" From a7aeb7d7ffeebd8f678410d2f975fbfa0f77ef44 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 9 Feb 2020 11:28:47 +0200 Subject: [PATCH 075/119] Report version as part of state telem and log it in island. --- monkey/infection_monkey/monkey.py | 5 +++-- monkey/infection_monkey/telemetry/state_telem.py | 8 ++++++-- .../cc/services/telemetry/processing/state.py | 8 ++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) 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/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/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']}") From 8e109c48243ddbf7db8f8bebf92e4f5828a28994 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 11:31:12 +0200 Subject: [PATCH 076/119] Don't randomly install npm unless required --- deployment_scripts/deploy_linux.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 20b5e030a..085c30b3a 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -174,14 +174,16 @@ openssl req -new -key cc/server.key -out cc/server.csr -subj "/C=GB/ST=London/L= openssl x509 -req -days 366 -in cc/server.csr -signkey cc/server.key -out cc/server.crt # Update node -log_message "Installing nodejs" -# shellcheck disable=SC2086 -if exists curl; then - curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - -else - wget -q -O - https://deb.nodesource.com/setup_12.x | sudo -E bash - +if ! exists npm; then + log_message "Installing nodejs" + # shellcheck disable=SC2086 + if exists curl; then + curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - + else + wget -q -O - https://deb.nodesource.com/setup_12.x | sudo -E bash - + fi + sudo apt-get install -y nodejs fi -sudo apt-get install -y nodejs cd "$ISLAND_PATH/cc/ui" || handle_error npm install sass-loader node-sass webpack --save-dev From fcef4f154f8d02a83a39e4484d656c742aa036a3 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 9 Feb 2020 11:32:41 +0200 Subject: [PATCH 077/119] Delete old Monkey Island-centric version and replace with common.version --- monkey/monkey_island/cc/environment/__init__.py | 5 ----- monkey/monkey_island/cc/resources/version_update.py | 4 ++-- monkey/monkey_island/cc/services/version_update.py | 5 +++-- 3 files changed, 5 insertions(+), 9 deletions(-) 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/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/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()) From f745f4594064b670aad71c1abb641f7998083ab7 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 11:37:25 +0200 Subject: [PATCH 078/119] Move to single line of code for creating certs on linux --- deployment_scripts/deploy_linux.sh | 5 ++--- monkey/monkey_island/linux/create_certificate.sh | 9 ++++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 085c30b3a..90a6f0769 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -169,9 +169,8 @@ cd "${ISLAND_PATH}" || { echo "cd failed" exit 1 } -openssl genrsa -out cc/server.key 2048 -openssl req -new -key cc/server.key -out cc/server.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=Monkey Department/CN=monkey.com" -openssl x509 -req -days 366 -in cc/server.csr -signkey cc/server.key -out cc/server.crt + +"${ISLAND_PATH}"/linux/create_certificate.sh ${ISLAND_PATH}/cc # Update node if ! exists npm; then diff --git a/monkey/monkey_island/linux/create_certificate.sh b/monkey/monkey_island/linux/create_certificate.sh index 72aace118..427915340 100644 --- a/monkey/monkey_island/linux/create_certificate.sh +++ b/monkey/monkey_island/linux/create_certificate.sh @@ -1,6 +1,9 @@ #!/bin/bash -openssl genrsa -out ./cc/server.key 2048 -openssl req -new -key ./cc/server.key -out ./cc/server.csr -subj "/OU=Monkey Department/CN=monkey.com" -openssl x509 -req -days 366 -in ./cc/server.csr -signkey ./cc/server.key -out ./cc/server.crt +server_root=${1:-"./cc"} + + +openssl genrsa -out $server_root/server.key 2048 +openssl req -new -key $server_root/server.key -out $server_root/server.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=Monkey Department/CN=monkey.com" +openssl x509 -req -days 366 -in $server_root/server.csr -signkey $server_root/server.key -out $server_root/server.crt From 46952ed0aeef53f1625781b416fe8d841738baa9 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 9 Feb 2020 11:51:00 +0200 Subject: [PATCH 079/119] Changed build to static file so that build scripts can change it dynamically --- monkey/common/BUILD | 1 + monkey/common/version.py | 5 ++++- monkey/infection_monkey/monkey.spec | 4 +++- monkey/monkey_island/monkey_island.spec | 4 +++- 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 monkey/common/BUILD 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 index 317afe99a..9d60e636c 100644 --- a/monkey/common/version.py +++ b/monkey/common/version.py @@ -1,10 +1,13 @@ # 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 = "dev" +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): diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 2157b697c..4baa205e2 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/BUILD") + ], excludes=None, win_no_prefer_redirects=None, win_private_assemblies=None, diff --git a/monkey/monkey_island/monkey_island.spec b/monkey/monkey_island/monkey_island.spec index 342df5ab3..e74763160 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, From 3990e354b2d6e7a8b0cbec5bc41d1210b8984284 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 11:53:06 +0200 Subject: [PATCH 080/119] Add error handling. Remove usage of cd --- deployment_scripts/deploy_linux.sh | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 90a6f0769..28dabc0f6 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -91,7 +91,7 @@ fi # Create folders log_message "Creating island dirs under $ISLAND_PATH" -mkdir -p "${MONGO_PATH}" +mkdir -p "${MONGO_PATH}" || handle_error mkdir -p "${ISLAND_BINARIES_PATH}" || handle_error # Detecting command that calls python 3.7 @@ -165,10 +165,6 @@ sudo apt-get install openssl # Generate SSL certificate log_message "Generating certificate" -cd "${ISLAND_PATH}" || { - echo "cd failed" - exit 1 -} "${ISLAND_PATH}"/linux/create_certificate.sh ${ISLAND_PATH}/cc @@ -184,12 +180,13 @@ if ! exists npm; then sudo apt-get install -y nodejs fi -cd "$ISLAND_PATH/cc/ui" || handle_error +pushd "$ISLAND_PATH/cc/ui" || handle_error npm install sass-loader node-sass webpack --save-dev npm update log_message "Generating front end" npm run dist +popd || handle_error # Making dir for binaries mkdir "${MONKEY_BIN_DIR}" From 4b0de32c3d79cf769a94420f74b948e08d88f808 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 12:02:57 +0200 Subject: [PATCH 081/119] Fix mistake in log message --- deployment_scripts/deploy_linux.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 28dabc0f6..a4b355b04 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -128,11 +128,11 @@ fi ${python_cmd} get-pip.py rm get-pip.py -log_message "Installing island requirements_island" +log_message "Installing island requirements" requirements_island="$ISLAND_PATH/requirements.txt" ${python_cmd} -m pip install -r "${requirements_island}" --user --upgrade || handle_error -log_message "Installing monkey requirements_island" +log_message "Installing monkey requirements" sudo apt-get install libffi-dev upx libssl-dev libc++1 requirements_monkey="$INFECTION_MONKEY_DIR/requirements.txt" ${python_cmd} -m pip install -r "${requirements_monkey}" --user --upgrade || handle_error From 78352a250abde5e85e68d3065eed9649e60c8a03 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 12:06:05 +0200 Subject: [PATCH 082/119] Update linux binary URLs to be 1.7 --- deployment_scripts/config | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/deployment_scripts/config b/deployment_scripts/config index 079359355..d8b09c28a 100644 --- a/deployment_scripts/config +++ b/deployment_scripts/config @@ -5,17 +5,17 @@ MONKEY_FOLDER_NAME="infection_monkey" MONKEY_GIT_URL="https://github.com/guardicore/monkey" # Monkey binaries -LINUX_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/monkey-linux-32" +LINUX_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/monkey-linux-32" LINUX_32_BINARY_NAME="monkey-linux-32" -LINUX_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/monkey-linux-64" +LINUX_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/monkey-linux-64" LINUX_64_BINARY_NAME="monkey-linux-64" -WINDOWS_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/monkey-windows-32.exe" +WINDOWS_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/monkey-windows-32.exe" WINDOWS_32_BINARY_NAME="monkey-windows-32.exe" -WINDOWS_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/monkey-windows-64.exe" +WINDOWS_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/monkey-windows-64.exe" WINDOWS_64_BINARY_NAME="monkey-windows-64.exe" # Other binaries for monkey -TRACEROUTE_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute64" -TRACEROUTE_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute32" -SAMBACRY_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner64.so" -SAMBACRY_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner32.so" \ No newline at end of file +TRACEROUTE_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/traceroute64" +TRACEROUTE_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/traceroute32" +SAMBACRY_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/sc_monkey_runner64.so" +SAMBACRY_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/sc_monkey_runner32.so" \ No newline at end of file From 290eddf2497d0e1c61431eb18910a16c73d2444b Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 12:47:30 +0200 Subject: [PATCH 083/119] Fix to be HTTPS --- monkey/monkey_island/deb-package/DEBIAN/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/deb-package/DEBIAN/control b/monkey/monkey_island/deb-package/DEBIAN/control index 16aed4614..a47371005 100644 --- a/monkey/monkey_island/deb-package/DEBIAN/control +++ b/monkey/monkey_island/deb-package/DEBIAN/control @@ -1,7 +1,7 @@ Package: gc-monkey-island Architecture: amd64 Maintainer: Guardicore -Homepage: http://www.infectionmonkey.com +Homepage: https://www.infectionmonkey.com Priority: optional Version: 1.0 Description: Guardicore Infection Monkey Island installation package From 5b6c6a34f6ba10b1422710c82e9ab8aafb15887d Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 15:16:16 +0200 Subject: [PATCH 084/119] Make shellcheck shut up by double quoting all the things --- monkey/monkey_island/linux/create_certificate.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/linux/create_certificate.sh b/monkey/monkey_island/linux/create_certificate.sh index 427915340..7e306a822 100644 --- a/monkey/monkey_island/linux/create_certificate.sh +++ b/monkey/monkey_island/linux/create_certificate.sh @@ -3,7 +3,7 @@ server_root=${1:-"./cc"} -openssl genrsa -out $server_root/server.key 2048 -openssl req -new -key $server_root/server.key -out $server_root/server.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=Monkey Department/CN=monkey.com" -openssl x509 -req -days 366 -in $server_root/server.csr -signkey $server_root/server.key -out $server_root/server.crt +openssl genrsa -out "$server_root"/server.key 2048 +openssl req -new -key "$server_root"/server.key -out "$server_root"/server.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=Monkey Department/CN=monkey.com" +openssl x509 -req -days 366 -in "$server_root"/server.csr -signkey "$server_root"/server.key -out $server_root/server.crt From abbb68ecb8aa177754319fe1dddd6e90ea5cb543 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 15:17:14 +0200 Subject: [PATCH 085/119] Random fixups in run.sh --- monkey/monkey_island/linux/run.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/linux/run.sh b/monkey/monkey_island/linux/run.sh index 54e1cdd65..2a5c45bbe 100644 --- a/monkey/monkey_island/linux/run.sh +++ b/monkey/monkey_island/linux/run.sh @@ -2,13 +2,13 @@ # Detecting command that calls python 3.7 python_cmd="" -if [[ `python --version 2>&1` == *"Python 3.7"* ]]; then +if [[ $(python --version 2>&1) == *"Python 3.7"* ]]; then python_cmd="python" fi -if [[ `python37 --version 2>&1` == *"Python 3.7"* ]]; then +if [[ $(python37 --version 2>&1) == *"Python 3.7"* ]]; then python_cmd="python37" fi -if [[ `python3.7 --version 2>&1` == *"Python 3.7"* ]]; then +if [[ $(python3.7 --version 2>&1) == *"Python 3.7"* ]]; then python_cmd="python3.7" fi From 0859050a654bdbde1d4de317cc6a5f6580d43394 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 9 Feb 2020 15:20:34 +0200 Subject: [PATCH 086/119] Added version argument to monkey build scripts --- monkey/infection_monkey/build_linux.sh | 15 +++++++++++++++ monkey/infection_monkey/build_windows.bat | 11 +++++++++++ 2 files changed, 26 insertions(+) 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 From ad9450a77e1a49ebb53327cab4722ccb4cab6a76 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 9 Feb 2020 18:40:44 +0200 Subject: [PATCH 087/119] Fix names to match island naming conventions --- monkey/infection_monkey/monkey.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 2157b697c..004cffa4c 100644 --- a/monkey/infection_monkey/monkey.spec +++ b/monkey/infection_monkey/monkey.spec @@ -94,7 +94,11 @@ def get_traceroute_binaries(): def get_monkey_filename(): - name = 'monkey' + name = 'monkey-' + if is_windows(): + name = name+"windows-" + else: + name = name+"linux-" if is_32_bit(): name = name+"32" else: From 2aa729910344eff4da152fbda02bd325905de957 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 10 Feb 2020 13:48:12 +0200 Subject: [PATCH 088/119] Turn agent download into optional, default parameter to true --- deployment_scripts/README.md | 4 ++++ deployment_scripts/deploy_linux.sh | 26 +++++++++++++++----------- deployment_scripts/deploy_windows.ps1 | 25 ++++++++++++++++--------- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/deployment_scripts/README.md b/deployment_scripts/README.md index c533605db..16b150852 100644 --- a/deployment_scripts/README.md +++ b/deployment_scripts/README.md @@ -24,6 +24,8 @@ The first argument is an empty directory (script can create one). The second arg - `.\deploy_windows.ps1 -monkey_home "C:\test"` (Sets up monkey in C:\test) - `.\deploy_windows.ps1 -branch "master"` (Sets up master branch instead of develop in current dir) +You may also pass in an optional `agents=$false` parameter to disable downloading the latest agent binaries. + ### Troubleshooting - If you run into Execution Policy warnings, you can disable them by prefixing the following snippet: `powershell -ExecutionPolicy ByPass -Command "[original command here]"` @@ -49,3 +51,5 @@ After downloading that script, execute it in a shell. The first argument should - `./deploy_linux.sh "/home/test/monkey"` (deploys under /home/test/monkey) - `./deploy_linux.sh "" "master"` (deploys master branch in script directory) - `./deploy_linux.sh "/home/user/new" "master"` (if directory "new" is not found creates it and clones master branch into it) + +You may also pass in an optional third `false` parameter to disable downloading the latest agent binaries. \ No newline at end of file diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index a4b355b04..88136d9a1 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -137,18 +137,22 @@ sudo apt-get install libffi-dev upx libssl-dev libc++1 requirements_monkey="$INFECTION_MONKEY_DIR/requirements.txt" ${python_cmd} -m pip install -r "${requirements_monkey}" --user --upgrade || handle_error + +agents=${3:-true} # Download binaries -log_message "Downloading binaries" -if exists wget; then - wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_32_BINARY_URL} - wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_64_BINARY_URL} - wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_32_BINARY_URL} - wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_64_BINARY_URL} -else - curl -o ${ISLAND_BINARIES_PATH}\monkey-linux-32 ${LINUX_32_BINARY_URL} - curl -o ${ISLAND_BINARIES_PATH}\monkey-linux-64 ${LINUX_64_BINARY_URL} - curl -o ${ISLAND_BINARIES_PATH}\monkey-windows-32.exe ${WINDOWS_32_BINARY_URL} - curl -o ${ISLAND_BINARIES_PATH}\monkey-windows-64.exe ${WINDOWS_64_BINARY_URL} +if [ "$agents" = true ] ; then + log_message "Downloading binaries" + if exists wget; then + wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_32_BINARY_URL} + wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_64_BINARY_URL} + wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_32_BINARY_URL} + wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_64_BINARY_URL} + else + curl -o ${ISLAND_BINARIES_PATH}\monkey-linux-32 ${LINUX_32_BINARY_URL} + curl -o ${ISLAND_BINARIES_PATH}\monkey-linux-64 ${LINUX_64_BINARY_URL} + curl -o ${ISLAND_BINARIES_PATH}\monkey-windows-32.exe ${WINDOWS_32_BINARY_URL} + curl -o ${ISLAND_BINARIES_PATH}\monkey-windows-64.exe ${WINDOWS_64_BINARY_URL} + fi fi # Allow them to be executed diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index d978042b3..b15538d13 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -4,7 +4,10 @@ param( [Parameter(Mandatory = $false, Position = 1)] [System.String] - $branch = "develop" + $branch = "develop", + [Parameter(Mandatory = $false, Position = 2)] + [Bool] + $agents = $true ) function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, [String] $branch = "develop") { @@ -166,14 +169,18 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, . .\windows\create_certificate.bat Pop-Location - # Adding binaries - "Adding binaries" - $binaries = (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\cc\binaries") - New-Item -ItemType directory -path $binaries -ErrorAction SilentlyContinue - $webClient.DownloadFile($LINUX_32_BINARY_URL, (Join-Path -Path $binaries -ChildPath $LINUX_32_BINARY_PATH)) - $webClient.DownloadFile($LINUX_64_BINARY_URL, (Join-Path -Path $binaries -ChildPath $LINUX_64_BINARY_PATH)) - $webClient.DownloadFile($WINDOWS_32_BINARY_URL, (Join-Path -Path $binaries -ChildPath $WINDOWS_32_BINARY_PATH)) - $webClient.DownloadFile($WINDOWS_64_BINARY_URL, (Join-Path -Path $binaries -ChildPath $WINDOWS_64_BINARY_PATH)) + if ($agents) + { + # Adding binaries + "Adding binaries" + $binaries = (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\cc\binaries") + New-Item -ItemType directory -path $binaries -ErrorAction SilentlyContinue + $webClient.DownloadFile($LINUX_32_BINARY_URL, (Join-Path -Path $binaries -ChildPath $LINUX_32_BINARY_PATH)) + $webClient.DownloadFile($LINUX_64_BINARY_URL, (Join-Path -Path $binaries -ChildPath $LINUX_64_BINARY_PATH)) + $webClient.DownloadFile($WINDOWS_32_BINARY_URL, (Join-Path -Path $binaries -ChildPath $WINDOWS_32_BINARY_PATH)) + $webClient.DownloadFile($WINDOWS_64_BINARY_URL, (Join-Path -Path $binaries -ChildPath $WINDOWS_64_BINARY_PATH)) + } + # Check if NPM installed "Installing npm" From 892096a3b310d4ab9aca7aa43a08985ada2c3465 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 10 Feb 2020 13:50:32 +0200 Subject: [PATCH 089/119] Make sure all echo statements are prefixed with the log_message prefix --- deployment_scripts/deploy_linux.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 88136d9a1..829f42bfe 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -27,7 +27,7 @@ config_branch=${2:-"develop"} config_url="https://raw.githubusercontent.com/guardicore/monkey/${config_branch}/deployment_scripts/config" if (! exists curl) && (! exists wget); then - echo 'Your system does not have curl or wget, exiting' + log_message 'Your system does not have curl or wget, exiting' exit 1 fi @@ -63,13 +63,13 @@ INFECTION_MONKEY_DIR="$monkey_home/monkey/infection_monkey" MONKEY_BIN_DIR="$INFECTION_MONKEY_DIR/bin" if is_root; then - echo "Please don't run this script as root" + log_message "Please don't run this script as root" exit 1 fi HAS_SUDO=$(has_sudo) if [[ ! $HAS_SUDO ]]; then - echo "You need root permissions for some of this script operations. Quiting." + log_message "You need root permissions for some of this script operations. Quiting." exit 1 fi @@ -78,7 +78,7 @@ if [[ ! -d ${monkey_home} ]]; then fi if ! exists git; then - echo "Please install git and re-run this script" + log_message "Please install git and re-run this script" exit 1 fi From bd79ead2e656d352fe46241e576539fa20a16a42 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 10 Feb 2020 13:53:24 +0200 Subject: [PATCH 090/119] Shell script cleanups --- deployment_scripts/deploy_linux.sh | 11 ++++++----- deployment_scripts/deploy_windows.ps1 | 3 --- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 829f42bfe..995d28140 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -120,10 +120,11 @@ sudo apt install build-essentials log_message "Installing or updating pip" # shellcheck disable=SC2086 +pip_url=https://bootstrap.pypa.io/get-pip.py if exists wget; then - wget --output-document=get-pip.py https://bootstrap.pypa.io/get-pip.py + wget --output-document=get-pip.py $pip_url else - curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + curl $pip_url -o get-pip.py fi ${python_cmd} get-pip.py rm get-pip.py @@ -175,11 +176,11 @@ log_message "Generating certificate" # Update node if ! exists npm; then log_message "Installing nodejs" - # shellcheck disable=SC2086 + node_src=https://deb.nodesource.com/setup_12.x if exists curl; then - curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - + curl -sL $node_src | sudo -E bash - else - wget -q -O - https://deb.nodesource.com/setup_12.x | sudo -E bash - + wget -q -O - $node_src | sudo -E bash - fi sudo apt-get install -y nodejs fi diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1 index b15538d13..003fdd061 100644 --- a/deployment_scripts/deploy_windows.ps1 +++ b/deployment_scripts/deploy_windows.ps1 @@ -109,9 +109,6 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName, return } - "Installing pywin32" - python -m pip install --user pywin32 - "Installing python packages for island" $islandRequirements = Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\requirements.txt" -ErrorAction Stop & python -m pip install --user -r $islandRequirements From c4d42f5c33f449c60f38c87ad5a699bb1e148448 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 10 Feb 2020 19:06:39 +0200 Subject: [PATCH 091/119] Fix stupid typo --- deployment_scripts/deploy_linux.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 995d28140..65fdd48e6 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -115,8 +115,8 @@ if [[ ${python_cmd} == "" ]]; then python_cmd="python3.7" fi -log_message "Installing build-essentials" -sudo apt install build-essentials +log_message "Installing build-essential" +sudo apt install build-essential log_message "Installing or updating pip" # shellcheck disable=SC2086 From dbcb3fc92cb15319c17c465db3287cd16263f690 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Wed, 12 Feb 2020 10:27:12 +0200 Subject: [PATCH 092/119] Fix stupidly broken links --- deployment_scripts/config | 16 ++++++++-------- deployment_scripts/config.ps1 | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deployment_scripts/config b/deployment_scripts/config index d8b09c28a..5607d37fd 100644 --- a/deployment_scripts/config +++ b/deployment_scripts/config @@ -5,17 +5,17 @@ MONKEY_FOLDER_NAME="infection_monkey" MONKEY_GIT_URL="https://github.com/guardicore/monkey" # Monkey binaries -LINUX_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/monkey-linux-32" +LINUX_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/v1.7.0/monkey-linux-32" LINUX_32_BINARY_NAME="monkey-linux-32" -LINUX_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/monkey-linux-64" +LINUX_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/v1.7.0/monkey-linux-64" LINUX_64_BINARY_NAME="monkey-linux-64" -WINDOWS_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/monkey-windows-32.exe" +WINDOWS_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/v1.7.0/monkey-windows-32.exe" WINDOWS_32_BINARY_NAME="monkey-windows-32.exe" -WINDOWS_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/monkey-windows-64.exe" +WINDOWS_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/v1.7.0/monkey-windows-64.exe" WINDOWS_64_BINARY_NAME="monkey-windows-64.exe" # Other binaries for monkey -TRACEROUTE_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/traceroute64" -TRACEROUTE_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/traceroute32" -SAMBACRY_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/sc_monkey_runner64.so" -SAMBACRY_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.7/sc_monkey_runner32.so" \ No newline at end of file +TRACEROUTE_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/v1.7.0/traceroute64" +TRACEROUTE_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/v1.7.0/traceroute32" +SAMBACRY_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/v1.7.0/sc_monkey_runner64.so" +SAMBACRY_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/v1.7.0/sc_monkey_runner32.so" \ No newline at end of file diff --git a/deployment_scripts/config.ps1 b/deployment_scripts/config.ps1 index a50f3e935..b18b7c63c 100644 --- a/deployment_scripts/config.ps1 +++ b/deployment_scripts/config.ps1 @@ -3,7 +3,7 @@ $MONKEY_FOLDER_NAME = "infection_monkey" # Url of public git repository that contains monkey's source code $MONKEY_GIT_URL = "https://github.com/guardicore/monkey" $MONKEY_RELEASES_URL = $MONKEY_GIT_URL + "/releases" -$MONKEY_LATEST_VERSION = "1.7.0" +$MONKEY_LATEST_VERSION = "v1.7.0" $MONKEY_DOWNLOAD_URL = $MONKEY_RELEASES_URL + "/download/" + $MONKEY_LATEST_VERSION + "/" # Link to the latest python download or install it manually $PYTHON_URL = "https://www.python.org/ftp/python/3.7.6/python-3.7.6-amd64.exe" From 4e28571623abc0aa36f14d5a314299db70d64f50 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Wed, 12 Feb 2020 15:19:47 +0200 Subject: [PATCH 093/119] Fix totally broken part of the install_mongo.sh. Now download tgz again --- monkey/monkey_island/linux/install_mongo.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/monkey/monkey_island/linux/install_mongo.sh b/monkey/monkey_island/linux/install_mongo.sh index 28a7a1237..df2c0160e 100755 --- a/monkey/monkey_island/linux/install_mongo.sh +++ b/monkey/monkey_island/linux/install_mongo.sh @@ -10,19 +10,19 @@ MONGODB_DIR=$1 # If using deb, this should be: /var/monkey/monkey_island/bin/mon if [[ ${os_version_monkey} == "Ubuntu 16.04"* ]]; then echo Detected Ubuntu 16.04 - export tgz_url="https://repo.mongodb.org/apt/ubuntu/dists/xenial/mongodb-org/4.2/multiverse/binary-amd64/mongodb-org-server_4.2.3_amd64.deb" + export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.2.3.tgz" elif [[ ${os_version_monkey} == "Ubuntu 18.04"* ]]; then echo Detected Ubuntu 18.04 - export tgz_url="https://repo.mongodb.org/apt/ubuntu/dists/bionic/mongodb-org/4.2/multiverse/binary-amd64/mongodb-org-server_4.2.3_amd64.deb" + export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.3.tgz" elif [[ ${os_version_monkey} == "Debian GNU/Linux 8"* ]]; then echo Detected Debian 8 - export tgz_url="https://repo.mongodb.org/apt/debian/dists/jessie/mongodb-org/4.0/main/binary-amd64/mongodb-org-server_4.0.16_amd64.deb" + export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian81-4.0.16.tgz" elif [[ ${os_version_monkey} == "Debian GNU/Linux 9"* ]]; then echo Detected Debian 9 - export tgz_url="https://repo.mongodb.org/apt/debian/dists/stretch/mongodb-org/4.2/main/binary-amd64/mongodb-org-server_4.2.3_amd64.deb" + export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.2.3.tgz" elif [[ ${os_version_monkey} == "Debian GNU/Linux 10"* ]]; then - echo Detected Debian 9 - export tgz_url="https://repo.mongodb.org/apt/debian/dists/buster/mongodb-org/4.2/main/binary-amd64/mongodb-org-server_4.2.3_amd64.deb" + echo Detected Debian 10 + export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-4.2.3.tgz" else echo Unsupported OS exit 1 From 6f745d0e50f5527e19d0962af2756f4e02c68635 Mon Sep 17 00:00:00 2001 From: Shreya Date: Thu, 13 Feb 2020 01:07:19 +0530 Subject: [PATCH 094/119] Fix typo in deployment script for linux --- deployment_scripts/deploy_linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh index 834d811a7..67eeaa957 100755 --- a/deployment_scripts/deploy_linux.sh +++ b/deployment_scripts/deploy_linux.sh @@ -46,7 +46,7 @@ if ! exists git; then fi if ! exists wget; then - echo 'Your system does have wget, please install and re-run this script' + echo 'Your system does not have wget, please install and re-run this script' exit 1 fi From d187e8d234678f386e4204386cc3ff1d64c5ccee Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 23 Feb 2020 10:31:56 +0200 Subject: [PATCH 095/119] Remove assumption on virtualenv being on path --- monkey/monkey_island/deb-package/DEBIAN/postinst | 2 +- monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/deb-package/DEBIAN/postinst b/monkey/monkey_island/deb-package/DEBIAN/postinst index 93053a76e..bb09d9193 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 42dc2d5a2..1ad12a7e2 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 From e66dc6bad16043e27e2439c3c599d41fc76ca50f Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 23 Feb 2020 10:32:07 +0200 Subject: [PATCH 096/119] Hardcode Kali mongo installation. --- monkey/monkey_island/linux/install_mongo.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/monkey/monkey_island/linux/install_mongo.sh b/monkey/monkey_island/linux/install_mongo.sh index df2c0160e..f9e72928d 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 From 9fa935e50746b93e68f8ac0f59c52e317844f0bd Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 23 Feb 2020 14:57:48 +0200 Subject: [PATCH 097/119] Move generic files to where it makes sense. --- monkey/monkey_island/deb-package/{DEBIAN => DEBIAN_MONGO}/control | 0 .../{service => service_mongo}/systemd/start_server.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename monkey/monkey_island/deb-package/{DEBIAN => DEBIAN_MONGO}/control (100%) rename monkey/monkey_island/deb-package/{service => service_mongo}/systemd/start_server.sh (100%) diff --git a/monkey/monkey_island/deb-package/DEBIAN/control b/monkey/monkey_island/deb-package/DEBIAN_MONGO/control similarity index 100% rename from monkey/monkey_island/deb-package/DEBIAN/control rename to monkey/monkey_island/deb-package/DEBIAN_MONGO/control diff --git a/monkey/monkey_island/deb-package/service/systemd/start_server.sh b/monkey/monkey_island/deb-package/service_mongo/systemd/start_server.sh similarity index 100% rename from monkey/monkey_island/deb-package/service/systemd/start_server.sh rename to monkey/monkey_island/deb-package/service_mongo/systemd/start_server.sh From b93c91237f07de32421f14d0549dfaaeb2fd34a2 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 23 Feb 2020 19:00:39 +0200 Subject: [PATCH 098/119] Hide output --- monkey/monkey_island/linux/install_mongo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/linux/install_mongo.sh b/monkey/monkey_island/linux/install_mongo.sh index df2c0160e..98a497d84 100755 --- a/monkey/monkey_island/linux/install_mongo.sh +++ b/monkey/monkey_island/linux/install_mongo.sh @@ -35,7 +35,7 @@ pushd "${TEMP_MONGO}" || { } if exists wget; then - wget ${tgz_url} -O mongodb.tgz + wget -q ${tgz_url} -O mongodb.tgz else if exists curl; then curl --output mongodb.tgz ${tgz_url} From c9dbd8ee639e8e0107328ff84631e322371d0a40 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 23 Feb 2020 19:13:11 +0200 Subject: [PATCH 099/119] More deb installation hotfixes --- monkey/monkey_island/deb-package/DEBIAN/postinst | 2 +- monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/deb-package/DEBIAN/postinst b/monkey/monkey_island/deb-package/DEBIAN/postinst index 93053a76e..4a3a8ab50 100644 --- a/monkey/monkey_island/deb-package/DEBIAN/postinst +++ b/monkey/monkey_island/deb-package/DEBIAN/postinst @@ -22,7 +22,7 @@ if [ -d "/etc/systemd/network" ]; then systemctl enable monkey-island fi -${MONKEY_FOLDER}/monkey_island/create_certificate.sh +${MONKEY_FOLDER}/monkey_island/create_certificate.sh ${MONKEY_FOLDER}/monkey_island/ service monkey-island start diff --git a/monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst b/monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst index 42dc2d5a2..25d10f791 100644 --- a/monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst +++ b/monkey/monkey_island/deb-package/DEBIAN_MONGO/postinst @@ -25,7 +25,7 @@ if [ -d "/etc/systemd/network" ]; then systemctl enable monkey-island fi -${MONKEY_FOLDER}/monkey_island/create_certificate.sh +${MONKEY_FOLDER}/monkey_island/create_certificate.sh ${MONKEY_FOLDER}/monkey_island/ service monkey-island start service monkey-mongo start From 160d645fc20e9cc41c2870fab954b15761e2faa6 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 1 Mar 2020 18:00:57 +0200 Subject: [PATCH 100/119] The tuple is from source file to dst folder https://stackoverflow.com/a/59710336/4119906 --- monkey/infection_monkey/monkey.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 48deda9ba..e5873c9c5 100644 --- a/monkey/infection_monkey/monkey.spec +++ b/monkey/infection_monkey/monkey.spec @@ -20,7 +20,7 @@ def main(): runtime_hooks=None, binaries=None, datas=[ - ("../common/BUILD", "../common/BUILD") + ("../common/BUILD", "/common") ], excludes=None, win_no_prefer_redirects=None, From 20fff43fa986f25846f5e459c93bf76fbd60f50e Mon Sep 17 00:00:00 2001 From: Shreya Date: Thu, 20 Feb 2020 12:24:58 +0530 Subject: [PATCH 101/119] Remove `None` values from list of networks to scan Fixes #540 --- monkey/common/network/network_range.py | 2 +- monkey/infection_monkey/network/network_scanner.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/monkey/common/network/network_range.py b/monkey/common/network/network_range.py index 6a1201e07..15e04f893 100644 --- a/monkey/common/network/network_range.py +++ b/monkey/common/network/network_range.py @@ -44,9 +44,9 @@ class NetworkRange(object, metaclass=ABCMeta): @staticmethod def get_range_obj(address_str): - address_str = address_str.strip() if not address_str: # Empty string return None + address_str = address_str.strip() if NetworkRange.check_if_range(address_str): return IpRange(ip_range=address_str) if -1 != address_str.find('/'): diff --git a/monkey/infection_monkey/network/network_scanner.py b/monkey/infection_monkey/network/network_scanner.py index faa5e9a5f..ec42e1e54 100644 --- a/monkey/infection_monkey/network/network_scanner.py +++ b/monkey/infection_monkey/network/network_scanner.py @@ -34,6 +34,7 @@ class NetworkScanner(object): LOG.info("Found local IP addresses of the machine: %r", self._ip_addresses) # for fixed range, only scan once. self._ranges = [NetworkRange.get_range_obj(address_str=x) for x in WormConfiguration.subnet_scan_list] + self._ranges = list(filter(None, self._ranges)) if WormConfiguration.local_network_scan: self._ranges += get_interfaces_ranges() self._ranges += self._get_inaccessible_subnets_ips() From 16b2b87adcd0d6a34dfd21c9ead44bd40f5f836f Mon Sep 17 00:00:00 2001 From: Shreya Date: Fri, 21 Feb 2020 12:37:42 +0530 Subject: [PATCH 102/119] Remove `None` values from list of TCP ports --- monkey/infection_monkey/network/tcp_scanner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/infection_monkey/network/tcp_scanner.py b/monkey/infection_monkey/network/tcp_scanner.py index 69a659bf8..5605d5654 100644 --- a/monkey/infection_monkey/network/tcp_scanner.py +++ b/monkey/infection_monkey/network/tcp_scanner.py @@ -31,6 +31,7 @@ class TcpScanner(HostScanner, HostFinger): # maybe hide under really bad detection systems target_ports = self._config.tcp_target_ports[:] + target_ports = list(filter(None, target_ports)) # remove None values shuffle(target_ports) ports, banners = check_tcp_ports(host.ip_addr, target_ports, self._config.tcp_scan_timeout / 1000.0, From 6ff2bbf92e8ddfbd004cdc6d46730a18d6da5b7b Mon Sep 17 00:00:00 2001 From: Shreya Date: Fri, 21 Feb 2020 14:51:58 +0530 Subject: [PATCH 103/119] Discard all 'None' values in Monkey configuration lists Instead of checking individually for problems arising due to 'None' values and fixing them, all 'None' values in all lists in the configuration are discarded. --- monkey/infection_monkey/config.py | 2 ++ monkey/infection_monkey/network/network_scanner.py | 1 - monkey/infection_monkey/network/tcp_scanner.py | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py index 5c5b5a392..0612bf01e 100644 --- a/monkey/infection_monkey/config.py +++ b/monkey/infection_monkey/config.py @@ -27,6 +27,8 @@ class Configuration(object): if self._depth_from_commandline and key == "depth": continue if hasattr(self, key): + if type(value) == list: + value = list(filter(None, value)) setattr(self, key, value) else: unknown_items.append(key) diff --git a/monkey/infection_monkey/network/network_scanner.py b/monkey/infection_monkey/network/network_scanner.py index ec42e1e54..faa5e9a5f 100644 --- a/monkey/infection_monkey/network/network_scanner.py +++ b/monkey/infection_monkey/network/network_scanner.py @@ -34,7 +34,6 @@ class NetworkScanner(object): LOG.info("Found local IP addresses of the machine: %r", self._ip_addresses) # for fixed range, only scan once. self._ranges = [NetworkRange.get_range_obj(address_str=x) for x in WormConfiguration.subnet_scan_list] - self._ranges = list(filter(None, self._ranges)) if WormConfiguration.local_network_scan: self._ranges += get_interfaces_ranges() self._ranges += self._get_inaccessible_subnets_ips() diff --git a/monkey/infection_monkey/network/tcp_scanner.py b/monkey/infection_monkey/network/tcp_scanner.py index 5605d5654..69a659bf8 100644 --- a/monkey/infection_monkey/network/tcp_scanner.py +++ b/monkey/infection_monkey/network/tcp_scanner.py @@ -31,7 +31,6 @@ class TcpScanner(HostScanner, HostFinger): # maybe hide under really bad detection systems target_ports = self._config.tcp_target_ports[:] - target_ports = list(filter(None, target_ports)) # remove None values shuffle(target_ports) ports, banners = check_tcp_ports(host.ip_addr, target_ports, self._config.tcp_scan_timeout / 1000.0, From 5f3458349dc90107bc2414c6400606ea158354d7 Mon Sep 17 00:00:00 2001 From: Shreya Date: Tue, 3 Mar 2020 01:40:05 +0530 Subject: [PATCH 104/119] Filter out `None` values from configuration before saving Configuration is filtered before being saved (can be seen when adding empty fields and pressing the `Submit` button -> empty fields are removed) --- monkey/monkey_island/cc/services/config.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index fd2ed5b8d..96c59cad6 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -153,9 +153,18 @@ class ConfigService: def ssh_key_exists(keys, user, ip): return [key for key in keys if key['user'] == user and key['ip'] == ip] + def _filter_none_values(data): + if isinstance(data, dict): + return {k: ConfigService._filter_none_values(v) for k, v in data.items() if k is not None and v is not None} + elif isinstance(data, list): + return [ConfigService._filter_none_values(item) for item in data if item is not None] + else: + return data + @staticmethod def update_config(config_json, should_encrypt): # PBA file upload happens on pba_file_upload endpoint and corresponding config options are set there + config_json = ConfigService._filter_none_values(config_json) monkey_island.cc.services.post_breach_files.set_config_PBA_files(config_json) if should_encrypt: try: From 4592c218293d5bf098580dcb4913dbaeeb23deca Mon Sep 17 00:00:00 2001 From: Shreya Date: Tue, 3 Mar 2020 01:49:35 +0530 Subject: [PATCH 105/119] Undo old logic `None` values in the configuration are now checked before being saved --- monkey/infection_monkey/config.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py index 0612bf01e..5c5b5a392 100644 --- a/monkey/infection_monkey/config.py +++ b/monkey/infection_monkey/config.py @@ -27,8 +27,6 @@ class Configuration(object): if self._depth_from_commandline and key == "depth": continue if hasattr(self, key): - if type(value) == list: - value = list(filter(None, value)) setattr(self, key, value) else: unknown_items.append(key) From ed2a2b457677e8d42df3d66c3be0d4a13251516d Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 5 Mar 2020 19:46:09 +0200 Subject: [PATCH 106/119] Hotpatch, no need to compress UCRT DLLs --- monkey/monkey_island/monkey_island.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/monkey_island/monkey_island.spec b/monkey/monkey_island/monkey_island.spec index 342df5ab3..08ab03ff2 100644 --- a/monkey/monkey_island/monkey_island.spec +++ b/monkey/monkey_island/monkey_island.spec @@ -35,6 +35,7 @@ def main(): debug=False, strip=get_exe_strip(), upx=True, + upx_exclude=['vcruntime140.dll'], console=True, icon=get_exe_icon()) From f767482513eeef4366df1b1d15e9f77016d67680 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 5 Mar 2020 20:20:37 +0200 Subject: [PATCH 107/119] Hotpatch, don't check the host OS for bitness in island spec file but check python version. --- monkey/monkey_island/monkey_island.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/monkey_island.spec b/monkey/monkey_island/monkey_island.spec index 2d8e73e0a..cac232674 100644 --- a/monkey/monkey_island/monkey_island.spec +++ b/monkey/monkey_island/monkey_island.spec @@ -47,7 +47,7 @@ def is_windows(): def is_32_bit(): - return platform.architecture()[0] == "32bit" + return sys.maxsize <= 2**32 def process_datas(orig_datas): From 51ee88632e412c4f1d42995cde25d387dc418471 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 5 Mar 2020 20:21:38 +0200 Subject: [PATCH 108/119] Hotpatch, fix BUILD notice in Island as well --- monkey/monkey_island/monkey_island.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/monkey_island.spec b/monkey/monkey_island/monkey_island.spec index cac232674..ef6d9c2d3 100644 --- a/monkey/monkey_island/monkey_island.spec +++ b/monkey/monkey_island/monkey_island.spec @@ -16,7 +16,7 @@ def main(): runtime_hooks=None, binaries=None, datas=[ - ("../common/BUILD", "../common/BUILD") + ("../common/BUILD", "/common") ], excludes=None, win_no_prefer_redirects=None, From 80aaffd8debf3481b837e367dddd40b1525fa449 Mon Sep 17 00:00:00 2001 From: PrajwalM2212 Date: Sat, 7 Mar 2020 14:44:01 +0530 Subject: [PATCH 109/119] dev-setup: Fix minor issues in dev-setup readme This PR sets replaces windows style path separator with linux style path separator for linux dev setup guide. It also adds chmod command for ./monkey_island/linux/run.sh in monkey_island/readme.md Closes https://github.com/guardicore/monkey/issues/561 --- monkey/infection_monkey/readme.md | 4 ++-- monkey/monkey_island/readme.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/readme.md b/monkey/infection_monkey/readme.md index 8522767dd..da865c35f 100644 --- a/monkey/infection_monkey/readme.md +++ b/monkey/infection_monkey/readme.md @@ -55,11 +55,11 @@ Tested on Ubuntu 16.04. 3. Build Sambacry binaries - Build/Download according to sections at the end of this readme. - - Place the binaries under [code location]\infection_monkey\bin, under the names 'sc_monkey_runner32.so', 'sc_monkey_runner64.so' + - Place the binaries under [code location]/infection_monkey/bin, under the names 'sc_monkey_runner32.so', 'sc_monkey_runner64.so' 4. Build Traceroute binaries - Build/Download according to sections at the end of this readme. - - Place the binaries under [code location]\infection_monkey\bin, under the names 'traceroute32', 'traceroute64' + - Place the binaries under [code location]/infection_monkey/bin, under the names 'traceroute32', 'traceroute64' 5. To build, run in terminal: - `cd [code location]/infection_monkey` diff --git a/monkey/monkey_island/readme.md b/monkey/monkey_island/readme.md index e0c04e0bb..c16679b61 100644 --- a/monkey/monkey_island/readme.md +++ b/monkey/monkey_island/readme.md @@ -103,4 +103,4 @@ #### How to run -1. When your current working directory is monkey, run ./monkey_island/linux/run.sh (located under /linux) +1. When your current working directory is monkey, run `chmod 755 ./monkey_island/linux/run.sh` followed by `./monkey_island/linux/run.sh` (located under /linux) From d8487eed601f5b15208a70e1084bea74bc8e1e5c Mon Sep 17 00:00:00 2001 From: PrajwalM2212 Date: Sat, 7 Mar 2020 20:40:45 +0530 Subject: [PATCH 110/119] install_mongo.sh: Add entry for ubuntu 19.10 This PR adds entry for ubuntu 19.10. mongodb does not provide the download for 19.10 version yet. But the 18.04 version download works fine. The entry will have to be replaced if and when the mongodb download for 19.10 becomes available Closes https://github.com/guardicore/monkey/issues/563 --- monkey/monkey_island/linux/install_mongo.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/monkey/monkey_island/linux/install_mongo.sh b/monkey/monkey_island/linux/install_mongo.sh index 8fcef9633..36203b298 100755 --- a/monkey/monkey_island/linux/install_mongo.sh +++ b/monkey/monkey_island/linux/install_mongo.sh @@ -14,6 +14,9 @@ if [[ ${os_version_monkey} == "Ubuntu 16.04"* ]]; then elif [[ ${os_version_monkey} == "Ubuntu 18.04"* ]]; then echo Detected Ubuntu 18.04 export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.3.tgz" +elif [[ ${os_version_monkey} == "Ubuntu 19.10"* ]]; then + echo Detected Ubuntu 19.10 + export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.3.tgz" elif [[ ${os_version_monkey} == "Debian GNU/Linux 8"* ]]; then echo Detected Debian 8 export tgz_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian81-4.0.16.tgz" From f0f5ddfd604dc89f105aa9361dbd05c03eeebb20 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Wed, 11 Mar 2020 18:39:10 +0200 Subject: [PATCH 111/119] Unused dependency --- monkey/monkey_island/requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/monkey/monkey_island/requirements.txt b/monkey/monkey_island/requirements.txt index 77ff9a620..96ad1c47d 100644 --- a/monkey/monkey_island/requirements.txt +++ b/monkey/monkey_island/requirements.txt @@ -4,7 +4,6 @@ python-dateutil tornado werkzeug jinja2 -markupsafe itsdangerous click flask From a716204b0f4b754480175ff2493e765f39cc6b28 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 15 Mar 2020 11:20:49 +0200 Subject: [PATCH 112/119] Updated pytest config to ignore some directories dist and node_modules --- monkey/pytest.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/pytest.ini b/monkey/pytest.ini index 3d355a4ac..3596bf5f6 100644 --- a/monkey/pytest.ini +++ b/monkey/pytest.ini @@ -4,3 +4,4 @@ log_cli_level = DEBUG log_cli_format = %(asctime)s [%(levelname)s] %(module)s.%(funcName)s.%(lineno)d: %(message)s log_cli_date_format=%H:%M:%S addopts = -v --capture=sys +norecursedirs = node_modules dist From bff9cc36b1c9409615d3c8eab436902764a0c6b8 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 15 Mar 2020 11:20:58 +0200 Subject: [PATCH 113/119] Added codecov tests to travis yml and updated readme --- .travis.yml | 27 ++++++++++++++++++--------- README.md | 24 +++++++++++++++++------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6abeb59b1..2f9fb4764 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ install: # Python - pip install -r monkey/monkey_island/requirements.txt # for unit tests - pip install flake8 pytest dlint # for next stages +- pip install coverage # for code coverage - pip install -r monkey/infection_monkey/requirements.txt # for unit tests before_script: @@ -23,24 +24,28 @@ before_script: script: # Check Python code -# Check syntax errors and fail the build if any are found. +## Check syntax errors and fail the build if any are found. - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics -# Warn about linter issues. -# --exit-zero forces Flake8 to use the exit status code 0 even if there are errors, which means this will NOT fail the build. -# --count will print the total number of errors. -# --statistics Count the number of occurrences of each error/warning code and print a report. -# The output is redirected to a file. +## Warn about linter issues. +### --exit-zero forces Flake8 to use the exit status code 0 even if there are errors, which means this will NOT fail the build. +### --count will print the total number of errors. +### --statistics Count the number of occurrences of each error/warning code and print a report. +### The output is redirected to a file. - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics > flake8_warnings.txt -# Display the linter issues +## Display the linter issues - cat flake8_warnings.txt -# Make sure that we haven't increased the amount of warnings. +## Make sure that we haven't increased the amount of warnings. - PYTHON_WARNINGS_AMOUNT_UPPER_LIMIT=190 -- if [ $(tail -n 1 flake8_warnings.txt) -gt $PYTHON_WARNINGS_AMOUNT_UPPER_LIMIT ]; then echo "Too many warnings! Failing this build. Lower the amount of linter errors in this and try again. " && exit 1; fi +- if [ $(tail -n 1 flake8_warnings.txt) -gt $PYTHON_WARNINGS_AMOUNT_UPPER_LIMIT ]; then echo "Too many python linter warnings! Failing this build. Lower the amount of linter errors in this and try again. " && exit 1; fi +## Run unit tests - cd monkey # This is our source dir - python -m pytest # Have to use `python -m pytest` instead of `pytest` to add "{$builddir}/monkey/monkey" to sys.path. +## Calculate Code Coverage +- coverage run -m pytest discover + # Check JS code. The npm install must happen AFTER the flake8 because the node_modules folder will cause a lot of errors. - cd monkey_island/cc/ui - npm i @@ -51,6 +56,10 @@ script: - JS_WARNINGS_AMOUNT_UPPER_LIMIT=37 - eslint ./src --max-warnings $JS_WARNINGS_AMOUNT_UPPER_LIMIT +after_success: + # Upload code coverage results to codecov.io, see https://github.com/codecov/codecov-bash for more information + - bash <(curl -s https://codecov.io/bash) + notifications: slack: # Notify to slack rooms: diff --git a/README.md b/README.md index dd1d7982b..39cf1519d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # Infection Monkey -[![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/guardicore/monkey)](https://github.com/guardicore/monkey/releases) + +[![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) +[![codecov](https://codecov.io/gh/guardicore/monkey/branch/master/graph/badge.svg)](https://codecov.io/gh/guardicore/monkey) + ![GitHub stars](https://img.shields.io/github/stars/guardicore/monkey) ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/guardicore/monkey) @@ -14,14 +17,15 @@ The Infection Monkey is an open source security tool for testing a data center's - The Infection Monkey is comprised of two parts: -* Monkey - A tool which infects other machines and propagates to them -* Monkey Island - A dedicated server to control and visualize the Infection Monkey's progress inside the data center -To read more about the Monkey, visit http://infectionmonkey.com +* **Monkey** - A tool which infects other machines and propagates to them. +* **Monkey Island** - A dedicated server to control and visualize the Infection Monkey's progress inside the data center. + +To read more about the Monkey, visit [infectionmonkey.com](https://infectionmonkey.com). ## Main Features + The Infection Monkey uses the following techniques and exploits to propagate to other machines. * Multiple propagation techniques: @@ -42,13 +46,11 @@ Check out the [Setup](https://github.com/guardicore/monkey/wiki/setup) page in t The Infection Monkey supports a variety of platforms, documented [in the wiki](https://github.com/guardicore/monkey/wiki/OS-compatibility). - ## Building the Monkey from source To deploy development version of monkey you should refer to readme in the [deployment scripts](deployment_scripts) folder. If you only want to build the monkey from source, see [Setup](https://github.com/guardicore/monkey/wiki/Setup#compile-it-yourself) and follow the instructions at the readme files under [infection_monkey](infection_monkey) and [monkey_island](monkey_island). - ### Build status | Branch | Status | | ------ | :----: | @@ -56,13 +58,21 @@ and follow the instructions at the readme files under [infection_monkey](infecti | Master | [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=master)](https://travis-ci.com/guardicore/monkey) | ## Tests + ### Unit Tests + In order to run all of the Unit Tests, run the command `python -m pytest` in the `monkey` directory. +To get a coverage report, first make sure the `coverage` package is installed using `pip install coverage`. Run the command +`coverage run -m unittest discover` in the `monkey` directory and then `coverage html`. The coverage report can be found in +`htmlcov.index`. + ### Blackbox tests + In order to run the Blackbox tests, refer to `envs/monkey_zoo/blackbox/README.md`. # License + Copyright (c) Guardicore Ltd See the [LICENSE](LICENSE) file for license rights and limitations (GPLv3). From 215dc59f12a941cc98739fa5104d7b0a45d83575 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 15 Mar 2020 11:28:46 +0200 Subject: [PATCH 114/119] Removed "discover" from coverage cmd (it's for unittest, not pytest) --- .travis.yml | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2f9fb4764..4400f7e9e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,7 @@ script: - python -m pytest # Have to use `python -m pytest` instead of `pytest` to add "{$builddir}/monkey/monkey" to sys.path. ## Calculate Code Coverage -- coverage run -m pytest discover +- coverage run -m pytest # Check JS code. The npm install must happen AFTER the flake8 because the node_modules folder will cause a lot of errors. - cd monkey_island/cc/ui diff --git a/README.md b/README.md index 39cf1519d..9e6bf5622 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ The Infection Monkey supports a variety of platforms, documented [in the wiki](h ## Building the Monkey from source To deploy development version of monkey you should refer to readme in the [deployment scripts](deployment_scripts) folder. If you only want to build the monkey from source, see [Setup](https://github.com/guardicore/monkey/wiki/Setup#compile-it-yourself) -and follow the instructions at the readme files under [infection_monkey](infection_monkey) and [monkey_island](monkey_island). +and follow the instructions at the readme files under [infection_monkey](monkey/infection_monkey) and [monkey_island](monkey/monkey_island). ### Build status | Branch | Status | @@ -64,7 +64,7 @@ and follow the instructions at the readme files under [infection_monkey](infecti In order to run all of the Unit Tests, run the command `python -m pytest` in the `monkey` directory. To get a coverage report, first make sure the `coverage` package is installed using `pip install coverage`. Run the command -`coverage run -m unittest discover` in the `monkey` directory and then `coverage html`. The coverage report can be found in +`coverage run -m unittest` in the `monkey` directory and then `coverage html`. The coverage report can be found in `htmlcov.index`. ### Blackbox tests From 9c3c9d8fba025480e50d5d2744b5687a7152eafd Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 15 Mar 2020 11:40:21 +0200 Subject: [PATCH 115/119] Created default yaml for codecov with different ranges on green (55+ is good) --- monkey/codecov.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 monkey/codecov.yml diff --git a/monkey/codecov.yml b/monkey/codecov.yml new file mode 100644 index 000000000..26d2c2031 --- /dev/null +++ b/monkey/codecov.yml @@ -0,0 +1,20 @@ +codecov: + require_ci_to_pass: yes + +coverage: + precision: 2 + round: down + range: "55...100" + +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: no + macro: no + +comment: + layout: "reach,diff,flags,tree" + behavior: default + require_changes: no From 88fe581c2f5d38c1a0cf60dc956bd6815b81249d Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 15 Mar 2020 11:50:43 +0200 Subject: [PATCH 116/119] Updated codecov coloring. See https://docs.codecov.io/docs/coverage-configuration --- monkey/codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/codecov.yml b/monkey/codecov.yml index 26d2c2031..8d5127230 100644 --- a/monkey/codecov.yml +++ b/monkey/codecov.yml @@ -4,7 +4,7 @@ codecov: coverage: precision: 2 round: down - range: "55...100" + range: "50...90" parsers: gcov: From fe5f04e494cdc7af5eb944b6f082efd413449bc5 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 15 Mar 2020 14:48:09 +0200 Subject: [PATCH 117/119] Update codecov badge branch to develop --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e6bf5622..83fd878ad 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GitHub release (latest by date)](https://img.shields.io/github/v/release/guardicore/monkey)](https://github.com/guardicore/monkey/releases) [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) -[![codecov](https://codecov.io/gh/guardicore/monkey/branch/master/graph/badge.svg)](https://codecov.io/gh/guardicore/monkey) +[![codecov](https://codecov.io/gh/guardicore/monkey/branch/develop/graph/badge.svg)](https://codecov.io/gh/guardicore/monkey) ![GitHub stars](https://img.shields.io/github/stars/guardicore/monkey) ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/guardicore/monkey) From bcdeadf7b6354d0c6027f218ab4cdde4474e11be Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 15 Mar 2020 15:58:41 +0200 Subject: [PATCH 118/119] Remove unused dependencies --- monkey/monkey_island/requirements.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/monkey/monkey_island/requirements.txt b/monkey/monkey_island/requirements.txt index 96ad1c47d..3c59bcc47 100644 --- a/monkey/monkey_island/requirements.txt +++ b/monkey/monkey_island/requirements.txt @@ -3,9 +3,6 @@ bson python-dateutil tornado werkzeug -jinja2 -itsdangerous -click flask Flask-Pymongo Flask-Restful From f49c70772dfd6581adce02b727105e5a737938c9 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 15 Mar 2020 18:26:24 +0200 Subject: [PATCH 119/119] Create test_environment.py --- .../test_environment.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_environment.py diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_environment.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_environment.py new file mode 100644 index 000000000..f85b2b88c --- /dev/null +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/test_environment.py @@ -0,0 +1,31 @@ +import uuid + +from monkey_island.cc.models import Monkey +from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import \ + SystemInfoTelemetryDispatcher +from monkey_island.cc.testing.IslandTestCase import IslandTestCase + + +class TestEnvironmentTelemetryProcessing(IslandTestCase): + def test_process_environment_telemetry(self): + self.fail_if_not_testing_env() + self.clean_monkey_db() + + # Arrange + monkey_guid = str(uuid.uuid4()) + a_monkey = Monkey(guid=monkey_guid) + a_monkey.save() + dispatcher = SystemInfoTelemetryDispatcher() + + on_premise = "On Premise" + telem_json = { + "data": { + "collectors": { + "EnvironmentCollector": {"environment": on_premise}, + } + }, + "monkey_guid": monkey_guid + } + dispatcher.dispatch_collector_results_to_relevant_processors(telem_json) + + self.assertEqual(Monkey.get_single_monkey_by_guid(monkey_guid).environment, on_premise)