forked from p34709852/monkey
Finished "no password" environment option
This commit is contained in:
parent
a5b1ac22f9
commit
ce5e415788
|
@ -7,9 +7,10 @@ from werkzeug.exceptions import NotFound
|
|||
|
||||
from monkey_island.cc.resources.auth.auth import init_jwt
|
||||
from monkey_island.cc.database import mongo, database
|
||||
from monkey_island.cc.environment.environment_singleton import env
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
from monkey_island.cc.resources.client_run import ClientRun
|
||||
from monkey_island.cc.resources.edge import Edge
|
||||
from monkey_island.cc.resources.environment import Environment
|
||||
from monkey_island.cc.resources.local_run import LocalRun
|
||||
from monkey_island.cc.resources.log import Log
|
||||
from monkey_island.cc.resources.island_logs import IslandLog
|
||||
|
@ -70,7 +71,7 @@ def init_app_config(app, mongo_url):
|
|||
app.config['MONGO_URI'] = mongo_url
|
||||
app.config['SECRET_KEY'] = str(uuid.getnode())
|
||||
app.config['JWT_AUTH_URL_RULE'] = '/api/auth'
|
||||
app.config['JWT_EXPIRATION_DELTA'] = env.get_auth_expiration_time()
|
||||
app.config['JWT_EXPIRATION_DELTA'] = env_singleton.env.get_auth_expiration_time()
|
||||
|
||||
|
||||
def init_app_services(app):
|
||||
|
@ -93,6 +94,7 @@ def init_app_url_rules(app):
|
|||
def init_api_resources(api):
|
||||
api.add_resource(Root, '/api')
|
||||
api.add_resource(Registration, '/api/registration')
|
||||
api.add_resource(Environment, '/api/environment')
|
||||
api.add_resource(Monkey, '/api/monkey', '/api/monkey/', '/api/monkey/<string:guid>')
|
||||
api.add_resource(Bootloader, '/api/bootloader/<string:os>')
|
||||
api.add_resource(LocalRun, '/api/local-monkey', '/api/local-monkey/')
|
||||
|
|
|
@ -23,8 +23,8 @@ class Environment(object, metaclass=ABCMeta):
|
|||
|
||||
_testing = False
|
||||
|
||||
def __init__(self):
|
||||
self._config = EnvironmentConfig("", "", UserCreds())
|
||||
def __init__(self, config: EnvironmentConfig):
|
||||
self._config = config
|
||||
self._testing = False # Assume env is not for unit testing.
|
||||
|
||||
@property
|
||||
|
@ -72,8 +72,11 @@ class Environment(object, metaclass=ABCMeta):
|
|||
def testing(self, value):
|
||||
self._testing = value
|
||||
|
||||
def set_config(self, config: EnvironmentConfig):
|
||||
self._config = config
|
||||
def save_config(self):
|
||||
self._config.save_to_file()
|
||||
|
||||
def get_config(self) -> EnvironmentConfig:
|
||||
return self._config
|
||||
|
||||
def get_island_port(self):
|
||||
return self._ISLAND_PORT
|
||||
|
@ -93,12 +96,15 @@ class Environment(object, metaclass=ABCMeta):
|
|||
hash_obj.update(secret.encode('utf-8'))
|
||||
return hash_obj.hexdigest()
|
||||
|
||||
def get_deployment(self):
|
||||
def get_deployment(self) -> str:
|
||||
deployment = 'unknown'
|
||||
if self._config and self._config.deployment:
|
||||
deployment = self._config.deployment
|
||||
return deployment
|
||||
|
||||
def set_deployment(self, deployment: str):
|
||||
self._config.deployment = deployment
|
||||
|
||||
@property
|
||||
def mongo_db_name(self):
|
||||
return self._MONGO_DB_NAME
|
||||
|
|
|
@ -9,8 +9,8 @@ class AwsEnvironment(Environment):
|
|||
|
||||
_credentials_required = True
|
||||
|
||||
def __init__(self):
|
||||
super(AwsEnvironment, self).__init__()
|
||||
def __init__(self, config):
|
||||
super(AwsEnvironment, self).__init__(config)
|
||||
# Not suppressing error here on purpose. This is critical if we're on AWS env.
|
||||
self.aws_info = AwsInstance()
|
||||
self._instance_id = self._get_instance_id()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import json
|
||||
import logging
|
||||
|
||||
env = None
|
||||
|
||||
import monkey_island.cc.resources.auth.user_store as user_store
|
||||
from monkey_island.cc.environment import standard, EnvironmentConfig
|
||||
from monkey_island.cc.environment import testing
|
||||
from monkey_island.cc.environment import aws
|
||||
|
@ -24,11 +24,28 @@ ENV_DICT = {
|
|||
TESTING: testing.TestingEnvironment
|
||||
}
|
||||
|
||||
|
||||
def set_env(env_type: str, env_config: EnvironmentConfig):
|
||||
global env
|
||||
if env_type in ENV_DICT:
|
||||
env = ENV_DICT[env_type](env_config)
|
||||
|
||||
|
||||
def set_to_standard():
|
||||
global env
|
||||
if env:
|
||||
env_config = env.get_config()
|
||||
env_config.server_config = 'standard'
|
||||
set_env('standard', env_config)
|
||||
env.save_config()
|
||||
user_store.UserStore.set_users(env.get_auth_users())
|
||||
|
||||
|
||||
try:
|
||||
config = EnvironmentConfig.get_from_file()
|
||||
__env_type = config.server_config
|
||||
env = ENV_DICT[__env_type]()
|
||||
env.set_config(config)
|
||||
set_env(__env_type, config)
|
||||
# noinspection PyUnresolvedReferences
|
||||
logger.info('Monkey\'s env is: {0}'.format(env.__class__.__name__))
|
||||
except Exception:
|
||||
logger.error('Failed initializing environment', exc_info=True)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from monkey_island.cc.environment import EnvironmentConfig, UserCreds
|
||||
from monkey_island.cc.resources.auth.auth_user import User
|
||||
from monkey_island.cc.testing.IslandTestCase import IslandTestCase
|
||||
from monkey_island.cc.environment.aws import AwsEnvironment
|
||||
|
@ -7,7 +8,7 @@ import hashlib
|
|||
|
||||
class TestAwsEnvironment(IslandTestCase):
|
||||
def test_get_auth_users(self):
|
||||
env = AwsEnvironment()
|
||||
env = AwsEnvironment(EnvironmentConfig("", "", UserCreds()))
|
||||
# This is "injecting" the instance id to the env. This is the UTs aren't always executed on the same AWS machine
|
||||
# (might not be an AWS machine at all).
|
||||
# Perhaps it would have been more elegant to create a Mock, but not worth it for
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from monkey_island.cc.environment import Environment
|
||||
from monkey_island.cc.environment import Environment, EnvironmentConfig
|
||||
|
||||
|
||||
class TestingEnvironment(Environment):
|
||||
|
@ -9,8 +9,8 @@ class TestingEnvironment(Environment):
|
|||
|
||||
_credentials_required = True
|
||||
|
||||
def __init__(self):
|
||||
super(TestingEnvironment, self).__init__()
|
||||
def __init__(self, config: EnvironmentConfig):
|
||||
super(TestingEnvironment, self).__init__(config)
|
||||
self.testing = True
|
||||
|
||||
def get_auth_users(self):
|
||||
|
|
|
@ -23,7 +23,7 @@ logger = logging.getLogger(__name__)
|
|||
from monkey_island.cc.app import init_app
|
||||
from monkey_island.cc.services.reporting.exporter_init import populate_exporter_list
|
||||
from monkey_island.cc.network_utils import local_ip_addresses
|
||||
from monkey_island.cc.environment.environment_singleton import env
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
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
|
||||
|
@ -33,7 +33,7 @@ from monkey_island.cc.setup import setup
|
|||
|
||||
def main(should_setup_only=False):
|
||||
logger.info("Starting bootloader server")
|
||||
mongo_url = os.environ.get('MONGO_URL', env.get_mongo_url())
|
||||
mongo_url = os.environ.get('MONGO_URL', env_singleton.env.get_mongo_url())
|
||||
bootloader_server_thread = Thread(target=BootloaderHttpServer(mongo_url).serve_forever, daemon=True)
|
||||
|
||||
bootloader_server_thread.start()
|
||||
|
@ -46,7 +46,7 @@ def start_island_server(should_setup_only):
|
|||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
|
||||
mongo_url = os.environ.get('MONGO_URL', env.get_mongo_url())
|
||||
mongo_url = os.environ.get('MONGO_URL', env_singleton.env.get_mongo_url())
|
||||
wait_for_mongo_db_server(mongo_url)
|
||||
assert_mongo_db_version(mongo_url)
|
||||
|
||||
|
@ -62,13 +62,13 @@ def start_island_server(should_setup_only):
|
|||
logger.warning("Setup only flag passed. Exiting.")
|
||||
return
|
||||
|
||||
if env.is_debug():
|
||||
if env_singleton.env.is_debug():
|
||||
app.run(host='0.0.0.0', debug=True, ssl_context=(crt_path, key_path))
|
||||
else:
|
||||
http_server = HTTPServer(WSGIContainer(app),
|
||||
ssl_options={'certfile': os.environ.get('SERVER_CRT', crt_path),
|
||||
'keyfile': os.environ.get('SERVER_KEY', key_path)})
|
||||
http_server.listen(env.get_island_port())
|
||||
http_server.listen(env_singleton.env.get_island_port())
|
||||
log_init_info()
|
||||
IOLoop.instance().start()
|
||||
|
||||
|
@ -77,7 +77,7 @@ def log_init_info():
|
|||
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()])
|
||||
", ".join(["https://{}:{}".format(x, env_singleton.env.get_island_port()) for x in local_ip_addresses()])
|
||||
)
|
||||
)
|
||||
MonkeyDownload.log_executable_hashes()
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
from mongoengine import connect
|
||||
|
||||
from monkey_island.cc.environment.environment_singleton import env
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
|
||||
# This section sets up the DB connection according to the environment.
|
||||
# If testing, use mongomock which only emulates mongo. for more information, see
|
||||
# http://docs.mongoengine.org/guide/mongomock.html .
|
||||
# Otherwise, use an actual mongod instance with connection parameters supplied by env.
|
||||
if env.testing: # See monkey_island.cc.environment.testing
|
||||
if env_singleton.env.testing: # See monkey_island.cc.environment.testing
|
||||
connect('mongoenginetest', host='mongomock://localhost')
|
||||
else:
|
||||
connect(db=env.mongo_db_name, host=env.mongo_db_host, port=env.mongo_db_port)
|
||||
connect(db=env_singleton.env.mongo_db_name, host=env_singleton.env.mongo_db_host, port=env_singleton.env.mongo_db_port)
|
||||
|
||||
# Order of importing matters here, for registering the embedded and referenced documents before using them.
|
||||
from .config import Config # noqa: F401
|
||||
|
|
|
@ -4,23 +4,23 @@ from flask import current_app, abort
|
|||
from flask_jwt import JWT, _jwt_required, JWTError
|
||||
from werkzeug.security import safe_str_cmp
|
||||
|
||||
from monkey_island.cc.environment.environment_singleton import env
|
||||
from monkey_island.cc.resources.auth.user_store import UserStore
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
import monkey_island.cc.resources.auth.user_store as user_store
|
||||
|
||||
__author__ = 'itay.mizeretz'
|
||||
|
||||
|
||||
def init_jwt(app):
|
||||
UserStore.set_users(env.get_auth_users())
|
||||
user_store.UserStore.set_users(env_singleton.env.get_auth_users())
|
||||
|
||||
def authenticate(username, secret):
|
||||
user = UserStore.username_table.get(username, None)
|
||||
user = user_store.UserStore.username_table.get(username, None)
|
||||
if user and safe_str_cmp(user.secret.encode('utf-8'), secret.encode('utf-8')):
|
||||
return user
|
||||
|
||||
def identity(payload):
|
||||
user_id = payload['identity']
|
||||
return UserStore.userid_table.get(user_id, None)
|
||||
return user_store.UserStore.userid_table.get(user_id, None)
|
||||
|
||||
JWT(app, authenticate, identity)
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import json
|
||||
|
||||
from flask import request
|
||||
import flask_restful
|
||||
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
|
||||
|
||||
class Environment(flask_restful.Resource):
|
||||
|
||||
def patch(self):
|
||||
env_data = json.loads(request.data)
|
||||
if env_data['server_config'] == "standard":
|
||||
if env_singleton.env.needs_registration():
|
||||
env_singleton.set_to_standard()
|
||||
return {}
|
|
@ -6,7 +6,7 @@ import sys
|
|||
from flask import request, jsonify, make_response
|
||||
import flask_restful
|
||||
|
||||
from monkey_island.cc.environment.environment_singleton import env
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
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
|
||||
|
@ -43,7 +43,7 @@ def run_local_monkey():
|
|||
|
||||
# run the monkey
|
||||
try:
|
||||
args = ['"%s" m0nk3y -s %s:%s' % (target_path, local_ip_addresses()[0], env.get_island_port())]
|
||||
args = ['"%s" m0nk3y -s %s:%s' % (target_path, local_ip_addresses()[0], env_singleton.env.get_island_port())]
|
||||
if sys.platform == "win32":
|
||||
args = "".join(args)
|
||||
pid = subprocess.Popen(args, shell=True).pid
|
||||
|
|
|
@ -2,18 +2,18 @@ import flask_restful
|
|||
from flask import request, make_response
|
||||
|
||||
from common.utils.exceptions import InvalidRegistrationCredentials
|
||||
from monkey_island.cc.environment.environment_singleton import env
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
from monkey_island.cc.environment.user_creds import UserCreds
|
||||
|
||||
|
||||
class Registration(flask_restful.Resource):
|
||||
def get(self):
|
||||
return {'needs_registration': env.needs_registration()}
|
||||
return {'needs_registration': env_singleton.env.needs_registration()}
|
||||
|
||||
def post(self):
|
||||
credentials = UserCreds.get_from_json(request.data)
|
||||
try:
|
||||
env.try_add_user(credentials)
|
||||
env_singleton.env.try_add_user(credentials)
|
||||
return make_response({"error": ""}, 200)
|
||||
except InvalidRegistrationCredentials as e:
|
||||
return make_response({"error": str(e)}, 400)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"server_config": "standard",
|
||||
"deployment": "develop"
|
||||
}
|
|
@ -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_singleton import env
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
from monkey_island.cc.network_utils import local_ip_addresses
|
||||
from .config_schema import SCHEMA
|
||||
from monkey_island.cc.encryptor import encryptor
|
||||
|
@ -216,8 +216,8 @@ class ConfigService:
|
|||
@staticmethod
|
||||
def set_server_ips_in_config(config):
|
||||
ips = local_ip_addresses()
|
||||
config["cnc"]["servers"]["command_servers"] = ["%s:%d" % (ip, env.get_island_port()) for ip in ips]
|
||||
config["cnc"]["servers"]["current_server"] = "%s:%d" % (ips[0], env.get_island_port())
|
||||
config["cnc"]["servers"]["command_servers"] = ["%s:%d" % (ip, env_singleton.env.get_island_port()) for ip in ips]
|
||||
config["cnc"]["servers"]["current_server"] = "%s:%d" % (ips[0], env_singleton.env.get_island_port())
|
||||
|
||||
@staticmethod
|
||||
def save_initial_config_if_needed():
|
||||
|
|
|
@ -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_singleton import env
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -21,7 +21,7 @@ def try_add_aws_exporter_to_manager(manager):
|
|||
# noinspection PyBroadException
|
||||
try:
|
||||
RemoteRunAwsService.init()
|
||||
if RemoteRunAwsService.is_running_on_aws() and ('aws' == env.get_deployment()):
|
||||
if RemoteRunAwsService.is_running_on_aws() and ('aws' == env_singleton.env.get_deployment()):
|
||||
manager.add_exporter_to_list(AWSExporter)
|
||||
except Exception:
|
||||
logger.error("Failed adding aws exporter to manager. Exception info:", exc_info=True)
|
||||
|
|
|
@ -3,7 +3,7 @@ import logging
|
|||
import requests
|
||||
|
||||
from common.version import get_version
|
||||
from monkey_island.cc.environment.environment_singleton import env
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
|
||||
__author__ = "itay.mizeretz"
|
||||
|
||||
|
@ -40,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(), get_version())
|
||||
url = VersionUpdateService.VERSION_SERVER_CHECK_NEW_URL % (env_singleton.env.get_deployment(), get_version())
|
||||
|
||||
reply = requests.get(url, timeout=15)
|
||||
|
||||
|
@ -54,4 +54,4 @@ class VersionUpdateService:
|
|||
|
||||
@staticmethod
|
||||
def get_download_link():
|
||||
return VersionUpdateService.VERSION_SERVER_DOWNLOAD_URL % (env.get_deployment(), get_version())
|
||||
return VersionUpdateService.VERSION_SERVER_DOWNLOAD_URL % (env_singleton.env.get_deployment(), get_version())
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import unittest
|
||||
from monkey_island.cc.environment.environment_singleton import env
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
from monkey_island.cc.models import Monkey
|
||||
from monkey_island.cc.models.zero_trust.finding import Finding
|
||||
|
||||
|
||||
class IslandTestCase(unittest.TestCase):
|
||||
def fail_if_not_testing_env(self):
|
||||
self.assertFalse(not env.testing, "Change server_config.json to testing environment.")
|
||||
self.assertFalse(not env_singleton.env.testing, "Change server_config.json to testing environment.")
|
||||
|
||||
@staticmethod
|
||||
def clean_monkey_db():
|
||||
|
|
|
@ -9,6 +9,8 @@ import monkeyDetective from '../../images/detective-monkey.svg';
|
|||
|
||||
class RegisterPageComponent extends React.Component {
|
||||
|
||||
NO_AUTH_API_ENDPOINT = '/api/environment';
|
||||
|
||||
register = () => {
|
||||
this.auth.register(this.username, this.password).then(res => {
|
||||
this.setState({failed: false, error: ''});
|
||||
|
@ -23,6 +25,29 @@ class RegisterPageComponent extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
setNoAuth = () => {
|
||||
let options = {}
|
||||
options['headers'] = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
options['method'] = 'PATCH'
|
||||
options['body'] = JSON.stringify({'server_config': 'standard'})
|
||||
|
||||
return fetch(this.NO_AUTH_API_ENDPOINT, options)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
this.auth.attemptNoAuthLogin().then(() => {
|
||||
this.redirectToHome();
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
failed: true,
|
||||
error: res['error']
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
updateUsername = (evt) => {
|
||||
this.username = evt.target.value;
|
||||
};
|
||||
|
@ -72,6 +97,9 @@ class RegisterPageComponent extends React.Component {
|
|||
}}>
|
||||
Lets Go!
|
||||
</Button>
|
||||
<a href='#' onClick={this.setNoAuth} className={'no-auth-link'}>
|
||||
I want anyone to access the island
|
||||
</a>
|
||||
{
|
||||
this.state.failed ?
|
||||
<div className='alert alert-danger' role='alert'>{this.state.error}</div>
|
||||
|
|
|
@ -60,3 +60,13 @@
|
|||
.registration-block h3 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.no-auth-link {
|
||||
float: right;
|
||||
color: #6a5b00;
|
||||
}
|
||||
|
||||
.no-auth-link:hover {
|
||||
float: right;
|
||||
color: #796900;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue