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.model import DROPPER_ARG
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__)

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.model import MONKEY_ARG
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.attack_utils import ScanStatus
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.post_breach.post_breach_handler import PostBreach
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 common.utils.attack_utils import ScanStatus, UsageEnum
from common.version import get_version

View File

@ -1,8 +1,14 @@
import json
from abc import ABCMeta, abstractmethod
from datetime import timedelta
import os
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'
@ -18,6 +24,45 @@ class Environment(object, metaclass=ABCMeta):
_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
def testing(self):
return self._testing
@ -63,10 +108,6 @@ class Environment(object, metaclass=ABCMeta):
val = self.config.get(key, val)
return val
@abstractmethod
def get_auth_users(self):
return
@property
def mongo_db_name(self):
return self._MONGO_DB_NAME

View File

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

View File

@ -1,14 +1,12 @@
import json
import logging
import os
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 aws
from monkey_island.cc.environment import password
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
__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():
loaded_config_json = load_server_configuration_from_file()
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:
config_json = load_server_configuration_from_file()
__env_type = config_json['server_config']

View File

@ -6,7 +6,10 @@ __author__ = 'itay.mizeretz'
class PasswordEnvironment(Environment):
_credentials_required = True
def get_auth_users(self):
return [
monkey_island.cc.auth.User(1, self.config['user'], self.config['hash'])
]
if 'user' in self.config and 'hash' in self.config:
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):
_credentials_required = False
# SHA3-512 of '1234567890!@#$%^&*()_nothing_up_my_sleeve_1234567890!@#$%^&*()'
NO_AUTH_CREDS = '55e97c9dcfd22b8079189ddaeea9bce8125887e3237b800c6176c9afa80d2062' \
'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.
"""
_credentials_required = True
def __init__(self):
super(TestingEnvironment, self).__init__()
self.testing = True

View File

@ -1,6 +1,6 @@
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.
# 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
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.resources.monkey_download import get_monkey_executable
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
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 .config_schema import SCHEMA
from monkey_island.cc.encryptor import encryptor

View File

@ -6,7 +6,7 @@ import boto3
from botocore.exceptions import UnknownServiceError
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
__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.aws_exporter import AWSExporter
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__)

View File

@ -3,7 +3,7 @@ import logging
import requests
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"

View File

@ -1,5 +1,5 @@
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.zero_trust.finding import Finding