Password setup: Backed environment changes and unit tests

This commit is contained in:
VakarisZ 2020-06-10 11:52:55 +03:00
parent d430b91eac
commit 18dec0c652
19 changed files with 224 additions and 32 deletions

View File

@ -0,0 +1,10 @@
class ExploitingVulnerableMachineError(Exception):
""" Raise when exploiter failed, but machine is vulnerable """
class FailedExploitationError(Exception):
""" Raise when exploiter fails instead of returning False """
class ServerConfigFileChanged(Exception):
""" Raise when server config file changed and island needs to restart """

View File

@ -11,7 +11,7 @@ from infection_monkey.exploit.tools.http_tools import MonkeyHTTPServer
from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, build_monkey_commandline, get_monkey_depth from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, build_monkey_commandline, get_monkey_depth
from infection_monkey.model import DROPPER_ARG from infection_monkey.model import DROPPER_ARG
from infection_monkey.exploit.tools.payload_parsing import LimitedSizePayload from infection_monkey.exploit.tools.payload_parsing import LimitedSizePayload
from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError, FailedExploitationError from common.utils.exceptions import ExploitingVulnerableMachineError, FailedExploitationError
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)

View File

@ -9,7 +9,7 @@ from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline
from infection_monkey.model import MONKEY_ARG from infection_monkey.model import MONKEY_ARG
from infection_monkey.network.tools import check_tcp_port, get_interface_to_target from infection_monkey.network.tools import check_tcp_port, get_interface_to_target
from infection_monkey.exploit.tools.exceptions import FailedExploitationError from common.utils.exceptions import FailedExploitationError
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from common.utils.attack_utils import ScanStatus from common.utils.attack_utils import ScanStatus
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem from infection_monkey.telemetry.attack.t1105_telem import T1105Telem

View File

@ -1,6 +0,0 @@
class ExploitingVulnerableMachineError(Exception):
""" Raise when exploiter failed, but machine is vulnerable"""
class FailedExploitationError(Exception):
""" Raise when exploiter fails instead of returning False"""

View File

@ -28,7 +28,7 @@ from infection_monkey.telemetry.tunnel_telem import TunnelTelem
from infection_monkey.windows_upgrader import WindowsUpgrader from infection_monkey.windows_upgrader import WindowsUpgrader
from infection_monkey.post_breach.post_breach_handler import PostBreach from infection_monkey.post_breach.post_breach_handler import PostBreach
from infection_monkey.network.tools import get_interface_to_target, is_running_on_server from infection_monkey.network.tools import get_interface_to_target, is_running_on_server
from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError, FailedExploitationError from common.utils.exceptions import ExploitingVulnerableMachineError, FailedExploitationError
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
from common.utils.attack_utils import ScanStatus, UsageEnum from common.utils.attack_utils import ScanStatus, UsageEnum
from common.version import get_version from common.version import get_version

View File

@ -1,8 +1,14 @@
import json
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from datetime import timedelta from datetime import timedelta
import os import os
import hashlib import hashlib
from typing import Dict
from common.utils.exceptions import ServerConfigFileChanged
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
__author__ = 'itay.mizeretz' __author__ = 'itay.mizeretz'
@ -18,6 +24,45 @@ class Environment(object, metaclass=ABCMeta):
_testing = False _testing = False
@property
@abstractmethod
def _credentials_required(self) -> bool:
pass
@abstractmethod
def get_auth_users(self):
return
@staticmethod
def set_server_config(config: Dict):
Environment.upload_server_configuration_to_file(config)
raise ServerConfigFileChanged
@staticmethod
def upload_server_configuration_to_file(config: Dict):
file_path = Environment.get_server_config_file_path()
with open(file_path, 'w') as f:
f.write(json.dumps(config, indent=2))
@staticmethod
def get_server_config_file_path():
return os.path.join(MONKEY_ISLAND_ABS_PATH, 'cc/server_config.json')
def needs_registration(self) -> bool:
if not self._credentials_required:
return False
else:
return not self._is_registered()
def _is_registered(self) -> bool:
return self._credentials_required and self._is_credentials_set_up()
def _is_credentials_set_up(self) -> bool:
if 'user' in self.config and 'hash' in self.config:
return True
else:
return False
@property @property
def testing(self): def testing(self):
return self._testing return self._testing
@ -63,10 +108,6 @@ class Environment(object, metaclass=ABCMeta):
val = self.config.get(key, val) val = self.config.get(key, val)
return val return val
@abstractmethod
def get_auth_users(self):
return
@property @property
def mongo_db_name(self): def mongo_db_name(self):
return self._MONGO_DB_NAME return self._MONGO_DB_NAME

View File

@ -6,6 +6,9 @@ __author__ = 'itay.mizeretz'
class AwsEnvironment(Environment): class AwsEnvironment(Environment):
_credentials_required = True
def __init__(self): def __init__(self):
super(AwsEnvironment, self).__init__() super(AwsEnvironment, self).__init__()
# Not suppressing error here on purpose. This is critical if we're on AWS env. # Not suppressing error here on purpose. This is critical if we're on AWS env.

View File

@ -1,14 +1,12 @@
import json import json
import logging import logging
import os
env = None env = None
from monkey_island.cc.environment import standard from monkey_island.cc.environment import standard, Environment
from monkey_island.cc.environment import testing from monkey_island.cc.environment import testing
from monkey_island.cc.environment import aws from monkey_island.cc.environment import aws
from monkey_island.cc.environment import password from monkey_island.cc.environment import password
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
__author__ = 'itay.mizeretz' __author__ = 'itay.mizeretz'
@ -27,17 +25,18 @@ ENV_DICT = {
} }
def load_server_configuration_from_file():
with open(os.path.join(MONKEY_ISLAND_ABS_PATH, 'cc/server_config.json'), 'r') as f:
config_content = f.read()
return json.loads(config_content)
def load_env_from_file(): def load_env_from_file():
loaded_config_json = load_server_configuration_from_file() loaded_config_json = load_server_configuration_from_file()
return loaded_config_json['server_config'] return loaded_config_json['server_config']
def load_server_configuration_from_file():
file_path = Environment.get_server_config_file_path()
with open(file_path, 'r') as f:
config_content = f.read()
return json.loads(config_content)
try: try:
config_json = load_server_configuration_from_file() config_json = load_server_configuration_from_file()
__env_type = config_json['server_config'] __env_type = config_json['server_config']

View File

@ -6,7 +6,10 @@ __author__ = 'itay.mizeretz'
class PasswordEnvironment(Environment): class PasswordEnvironment(Environment):
_credentials_required = True
def get_auth_users(self): def get_auth_users(self):
return [ if 'user' in self.config and 'hash' in self.config:
monkey_island.cc.auth.User(1, self.config['user'], self.config['hash']) return [monkey_island.cc.auth.User(1, self.config['user'], self.config['hash'])]
] else:
return []

View File

@ -5,6 +5,9 @@ __author__ = 'itay.mizeretz'
class StandardEnvironment(Environment): class StandardEnvironment(Environment):
_credentials_required = False
# SHA3-512 of '1234567890!@#$%^&*()_nothing_up_my_sleeve_1234567890!@#$%^&*()' # SHA3-512 of '1234567890!@#$%^&*()_nothing_up_my_sleeve_1234567890!@#$%^&*()'
NO_AUTH_CREDS = '55e97c9dcfd22b8079189ddaeea9bce8125887e3237b800c6176c9afa80d2062' \ NO_AUTH_CREDS = '55e97c9dcfd22b8079189ddaeea9bce8125887e3237b800c6176c9afa80d2062' \
'8d2c8d0b1538d2208c1444ac66535b764a3d902b35e751df3faec1e477ed3557' '8d2c8d0b1538d2208c1444ac66535b764a3d902b35e751df3faec1e477ed3557'

View File

@ -0,0 +1,137 @@
import json
import os
from unittest import TestCase
from unittest.mock import MagicMock, patch
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
from common.utils.exceptions import ServerConfigFileChanged
from monkey_island.cc.environment import Environment
def get_server_config_file_path_test_version():
return os.path.join(os.getcwd(), 'test_config.json')
class TestEnvironment(TestCase):
class EnvironmentNoCredentials(Environment):
_credentials_required = False
def get_auth_users(self):
return []
class EnvironmentWithCredentials(Environment):
_credentials_required = True
def get_auth_users(self):
return []
# Username:test Password:test
CONFIG_JSON_WITH_CREDENTIALS = {
"server_config": "password",
"deployment": "develop",
"user": "test",
"hash": "9ece086e9bac491fac5c1d1046ca11d737b92a2b2ebd93f005d7b710110c0a678288166e7fbe796883a"
"4f2e9b3ca9f484f521d0ce464345cc1aec96779149c14"
}
CONFIG_JSON_NO_CREDENTIALS = {
"server_config": "password",
"deployment": "develop"
}
CONFIG_JSON_PARTIAL_CREDENTIALS = {
"server_config": "password",
"deployment": "develop",
"user": "test"
}
CONFIG_JSON_STANDARD_ENV = {
"server_config": "standard",
"deployment": "develop"
}
CONFIG_JSON_STANDARD_WITH_CREDENTIALS = {
"server_config": "standard",
"deployment": "develop",
"user": "test",
"hash": "9ece086e9bac491fac5c1d1046ca11d737b92a2b2ebd93f005d7b710110c0a678288166e7fbe796883a"
"4f2e9b3ca9f484f521d0ce464345cc1aec96779149c14"
}
@patch.object(target=Environment, attribute="get_server_config_file_path",
new=MagicMock(return_value=get_server_config_file_path_test_version()))
def test_upload_server_configuration_to_file(self):
Environment.upload_server_configuration_to_file(TestEnvironment.CONFIG_JSON_WITH_CREDENTIALS)
file_path = get_server_config_file_path_test_version()
with open(file_path, 'r') as f:
content_from_file = f.read()
os.remove(file_path)
self.assertDictEqual(TestEnvironment.CONFIG_JSON_WITH_CREDENTIALS, json.loads(content_from_file))
def test_get_server_config_file_path(self):
server_file_path = MONKEY_ISLAND_ABS_PATH + "\cc/server_config.json"
self.assertEqual(Environment.get_server_config_file_path(), server_file_path)
@patch.object(Environment, "upload_server_configuration_to_file", MagicMock())
def test_set_server_config(self):
with self.assertRaises(ServerConfigFileChanged):
Environment.set_server_config(TestEnvironment.CONFIG_JSON_WITH_CREDENTIALS)
def test_needs_registration(self):
env = TestEnvironment.EnvironmentWithCredentials()
env.config = TestEnvironment.CONFIG_JSON_WITH_CREDENTIALS
self.assertFalse(env.needs_registration())
env.config = TestEnvironment.CONFIG_JSON_NO_CREDENTIALS
self.assertTrue(env.needs_registration())
env.config = TestEnvironment.CONFIG_JSON_PARTIAL_CREDENTIALS
self.assertTrue(env.needs_registration())
env = TestEnvironment.EnvironmentNoCredentials()
env.config = TestEnvironment.CONFIG_JSON_STANDARD_ENV
self.assertFalse(env.needs_registration())
env.config = TestEnvironment.CONFIG_JSON_STANDARD_WITH_CREDENTIALS
self.assertFalse(env.needs_registration())
def test_is_registered(self):
env = TestEnvironment.EnvironmentWithCredentials()
env.config = TestEnvironment.CONFIG_JSON_WITH_CREDENTIALS
self.assertTrue(env._is_registered())
env.config = TestEnvironment.CONFIG_JSON_NO_CREDENTIALS
self.assertFalse(env._is_registered())
env.config = TestEnvironment.CONFIG_JSON_PARTIAL_CREDENTIALS
self.assertFalse(env._is_registered())
env = TestEnvironment.EnvironmentNoCredentials()
env.config = TestEnvironment.CONFIG_JSON_STANDARD_ENV
self.assertFalse(env._is_registered())
env.config = TestEnvironment.CONFIG_JSON_STANDARD_WITH_CREDENTIALS
self.assertFalse(env._is_registered())
def test_is_credentials_set_up(self):
env = TestEnvironment.EnvironmentWithCredentials()
env.config = TestEnvironment.CONFIG_JSON_NO_CREDENTIALS
self.assertFalse(env._is_credentials_set_up())
env.config = TestEnvironment.CONFIG_JSON_WITH_CREDENTIALS
self.assertTrue(env._is_credentials_set_up())
env.config = TestEnvironment.CONFIG_JSON_PARTIAL_CREDENTIALS
self.assertFalse(env._is_credentials_set_up())
env = TestEnvironment.EnvironmentNoCredentials()
env.config = TestEnvironment.CONFIG_JSON_STANDARD_ENV
self.assertFalse(env._is_credentials_set_up())

View File

@ -7,6 +7,8 @@ class TestingEnvironment(Environment):
This will cause all mongo connections to happen via `mongomock` instead of using an actual mongodb instance. This will cause all mongo connections to happen via `mongomock` instead of using an actual mongodb instance.
""" """
_credentials_required = True
def __init__(self): def __init__(self):
super(TestingEnvironment, self).__init__() super(TestingEnvironment, self).__init__()
self.testing = True self.testing = True

View File

@ -1,6 +1,6 @@
from mongoengine import connect from mongoengine import connect
from monkey_island.cc.environment.environment import env from monkey_island.cc.environment.environment_singleton import env
# This section sets up the DB connection according to the environment. # This section sets up the DB connection according to the environment.
# If testing, use mongomock which only emulates mongo. for more information, see # If testing, use mongomock which only emulates mongo. for more information, see

View File

@ -6,7 +6,7 @@ import sys
from flask import request, jsonify, make_response from flask import request, jsonify, make_response
import flask_restful import flask_restful
from monkey_island.cc.environment.environment import env from monkey_island.cc.environment.environment_singleton import env
from monkey_island.cc.models import Monkey from monkey_island.cc.models import Monkey
from monkey_island.cc.resources.monkey_download import get_monkey_executable from monkey_island.cc.resources.monkey_download import get_monkey_executable
from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.node import NodeService

View File

@ -6,7 +6,7 @@ from jsonschema import Draft4Validator, validators
import monkey_island.cc.services.post_breach_files import monkey_island.cc.services.post_breach_files
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
from monkey_island.cc.environment.environment import env from monkey_island.cc.environment.environment_singleton import env
from monkey_island.cc.network_utils import local_ip_addresses from monkey_island.cc.network_utils import local_ip_addresses
from .config_schema import SCHEMA from .config_schema import SCHEMA
from monkey_island.cc.encryptor import encryptor from monkey_island.cc.encryptor import encryptor

View File

@ -6,7 +6,7 @@ import boto3
from botocore.exceptions import UnknownServiceError from botocore.exceptions import UnknownServiceError
from common.cloud.aws.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.environment.environment_singleton import load_server_configuration_from_file
from monkey_island.cc.services.reporting.exporter import Exporter from monkey_island.cc.services.reporting.exporter import Exporter
__authors__ = ['maor.rayzin', 'shay.nehmad'] __authors__ = ['maor.rayzin', 'shay.nehmad']

View File

@ -3,7 +3,7 @@ import logging
from monkey_island.cc.services.reporting.report_exporter_manager import ReportExporterManager from monkey_island.cc.services.reporting.report_exporter_manager import ReportExporterManager
from monkey_island.cc.services.reporting.aws_exporter import AWSExporter from monkey_island.cc.services.reporting.aws_exporter import AWSExporter
from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService
from monkey_island.cc.environment.environment import env from monkey_island.cc.environment.environment_singleton import env
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -3,7 +3,7 @@ import logging
import requests import requests
from common.version import get_version from common.version import get_version
from monkey_island.cc.environment.environment import env from monkey_island.cc.environment.environment_singleton import env
__author__ = "itay.mizeretz" __author__ = "itay.mizeretz"

View File

@ -1,5 +1,5 @@
import unittest import unittest
from monkey_island.cc.environment.environment import env from monkey_island.cc.environment.environment_singleton import env
from monkey_island.cc.models import Monkey from monkey_island.cc.models import Monkey
from monkey_island.cc.models.zero_trust.finding import Finding from monkey_island.cc.models.zero_trust.finding import Finding