diff --git a/monkey_island/cc/resources/monkey_configuration.py b/monkey_island/cc/resources/monkey_configuration.py index 6d622b1cd..c3c9f51cb 100644 --- a/monkey_island/cc/resources/monkey_configuration.py +++ b/monkey_island/cc/resources/monkey_configuration.py @@ -18,6 +18,6 @@ class MonkeyConfiguration(flask_restful.Resource): if config_json.has_key('reset'): ConfigService.reset_config() else: - ConfigService.update_config(config_json) + ConfigService.update_config(config_json, should_encrypt=True) return self.get() diff --git a/monkey_island/cc/resources/telemetry.py b/monkey_island/cc/resources/telemetry.py index 94c4046b5..6f69ecc2f 100644 --- a/monkey_island/cc/resources/telemetry.py +++ b/monkey_island/cc/resources/telemetry.py @@ -11,6 +11,7 @@ from cc.database import mongo from cc.services.config import ConfigService from cc.services.edge import EdgeService from cc.services.node import NodeService +from cc.encryptor import encryptor __author__ = 'Barak' @@ -121,6 +122,8 @@ class Telemetry(flask_restful.Resource): if new_exploit['result']: EdgeService.set_edge_exploited(edge) + Telemetry.encrypt_exploit_creds(telemetry_json) + for attempt in telemetry_json['data']['attempts']: if attempt['result']: found_creds = {'user': attempt['user']} @@ -163,25 +166,49 @@ class Telemetry(flask_restful.Resource): def process_system_info_telemetry(telemetry_json): if 'credentials' in telemetry_json['data']: creds = telemetry_json['data']['credentials'] - for user in creds: - ConfigService.creds_add_username(user) - if 'password' in creds[user]: - ConfigService.creds_add_password(creds[user]['password']) - if 'lm_hash' in creds[user]: - ConfigService.creds_add_lm_hash(creds[user]['lm_hash']) - if 'ntlm_hash' in creds[user]: - ConfigService.creds_add_ntlm_hash(creds[user]['ntlm_hash']) - - for user in creds: - if -1 != user.find('.'): - new_user = user.replace('.', ',') - creds[new_user] = creds.pop(user) + Telemetry.encrypt_system_info_creds(creds) + Telemetry.add_system_info_creds_to_config(creds) + Telemetry.replace_user_dot_with_comma(creds) @staticmethod def process_trace_telemetry(telemetry_json): # Nothing to do return + @staticmethod + def replace_user_dot_with_comma(creds): + for user in creds: + if -1 != user.find('.'): + new_user = user.replace('.', ',') + creds[new_user] = creds.pop(user) + + @staticmethod + def encrypt_system_info_creds(creds): + for user in creds: + for field in ['password', 'lm_hash', 'ntlm_hash']: + if field in creds[user]: + creds[user][field] = encryptor.enc(creds[user][field]) + + @staticmethod + def add_system_info_creds_to_config(creds): + for user in creds: + ConfigService.creds_add_username(user) + if 'password' in creds[user]: + ConfigService.creds_add_password(creds[user]['password']) + if 'lm_hash' in creds[user]: + ConfigService.creds_add_lm_hash(creds[user]['lm_hash']) + if 'ntlm_hash' in creds[user]: + ConfigService.creds_add_ntlm_hash(creds[user]['ntlm_hash']) + + @staticmethod + def encrypt_exploit_creds(telemetry_json): + attempts = telemetry_json['data']['attempts'] + for i in range(len(attempts)): + for field in ['password', 'lm_hash', 'ntlm_hash']: + credential = attempts[i][field] + if len(credential) > 0: + attempts[i][field] = encryptor.enc(credential) + TELEM_PROCESS_DICT = \ { diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index ea755312f..878520217 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -1,6 +1,9 @@ -from cc.database import mongo +import copy + from jsonschema import Draft4Validator, validators +from cc.database import mongo +from cc.encryptor import encryptor from cc.island_config import ISLAND_PORT from cc.utils import local_ip_addresses @@ -17,60 +20,60 @@ SCHEMA = { "type": "string", "anyOf": [ { - "type": "string", - "enum": [ - "SmbExploiter" - ], - "title": "SMB Exploiter" + "type": "string", + "enum": [ + "SmbExploiter" + ], + "title": "SMB Exploiter" }, { - "type": "string", - "enum": [ - "WmiExploiter" - ], - "title": "WMI Exploiter" + "type": "string", + "enum": [ + "WmiExploiter" + ], + "title": "WMI Exploiter" }, { - "type": "string", - "enum": [ - "RdpExploiter" - ], - "title": "RDP Exploiter (UNSAFE)" + "type": "string", + "enum": [ + "RdpExploiter" + ], + "title": "RDP Exploiter (UNSAFE)" }, { - "type": "string", - "enum": [ - "Ms08_067_Exploiter" - ], - "title": "MS08-067 Exploiter (UNSAFE)" + "type": "string", + "enum": [ + "Ms08_067_Exploiter" + ], + "title": "MS08-067 Exploiter (UNSAFE)" }, { - "type": "string", - "enum": [ - "SSHExploiter" - ], - "title": "SSH Exploiter" + "type": "string", + "enum": [ + "SSHExploiter" + ], + "title": "SSH Exploiter" }, { - "type": "string", - "enum": [ - "ShellShockExploiter" - ], - "title": "ShellShock Exploiter" + "type": "string", + "enum": [ + "ShellShockExploiter" + ], + "title": "ShellShock Exploiter" }, { - "type": "string", - "enum": [ - "SambaCryExploiter" - ], - "title": "SambaCry Exploiter" + "type": "string", + "enum": [ + "SambaCryExploiter" + ], + "title": "SambaCry Exploiter" }, { - "type": "string", - "enum": [ - "ElasticGroovyExploiter" - ], - "title": "ElasticGroovy Exploiter" + "type": "string", + "enum": [ + "ElasticGroovyExploiter" + ], + "title": "ElasticGroovy Exploiter" }, ] }, @@ -79,46 +82,46 @@ SCHEMA = { "type": "string", "anyOf": [ { - "type": "string", - "enum": [ - "SMBFinger" - ], - "title": "SMBFinger" + "type": "string", + "enum": [ + "SMBFinger" + ], + "title": "SMBFinger" }, { - "type": "string", - "enum": [ - "SSHFinger" - ], - "title": "SSHFinger" + "type": "string", + "enum": [ + "SSHFinger" + ], + "title": "SSHFinger" }, { - "type": "string", - "enum": [ - "PingScanner" - ], - "title": "PingScanner" + "type": "string", + "enum": [ + "PingScanner" + ], + "title": "PingScanner" }, { - "type": "string", - "enum": [ - "HTTPFinger" - ], - "title": "HTTPFinger" + "type": "string", + "enum": [ + "HTTPFinger" + ], + "title": "HTTPFinger" }, { - "type": "string", - "enum": [ - "MySQLFinger" - ], - "title": "MySQLFinger" + "type": "string", + "enum": [ + "MySQLFinger" + ], + "title": "MySQLFinger" }, { - "type": "string", - "enum": [ - "ElasticFinger" - ], - "title": "ElasticFinger" + "type": "string", + "enum": [ + "ElasticFinger" + ], + "title": "ElasticFinger" } ] } @@ -794,29 +797,42 @@ SCHEMA = { } } +ENCRYPTED_CONFIG_ARRAYS = \ + [ + ['basic', 'credentials', 'exploit_password_list'], + ['internal', 'exploits', 'exploit_lm_hash_list'], + ['internal', 'exploits', 'exploit_ntlm_hash_list'] + ] + class ConfigService: + default_config = None + def __init__(self): pass @staticmethod - def get_config(is_initial_config=False): + def get_config(is_initial_config=False, should_decrypt=True): config = mongo.db.config.find_one({'name': 'initial' if is_initial_config else 'newconfig'}) or {} for field in ('name', '_id'): config.pop(field, None) + if should_decrypt and len(config) > 0: + ConfigService.decrypt_config(config) return config @staticmethod - def get_config_value(config_key_as_arr, is_initial_config=False): - config_key = reduce(lambda x, y: x+'.'+y, config_key_as_arr) + def get_config_value(config_key_as_arr, is_initial_config=False, should_decrypt=True): + config_key = reduce(lambda x, y: x + '.' + y, config_key_as_arr) config = mongo.db.config.find_one({'name': 'initial' if is_initial_config else 'newconfig'}, {config_key: 1}) for config_key_part in config_key_as_arr: config = config[config_key_part] + if should_decrypt and (config_key_as_arr in ENCRYPTED_CONFIG_ARRAYS): + config = [encryptor.dec(x) for x in config] return config @staticmethod - def get_flat_config(is_initial_config=False): - config_json = ConfigService.get_config(is_initial_config) + def get_flat_config(is_initial_config=False, should_decrypt=True): + config_json = ConfigService.get_config(is_initial_config, should_decrypt) flat_config_json = {} for i in config_json: for j in config_json[i]: @@ -860,27 +876,38 @@ class ConfigService: ConfigService.add_item_to_config_set('internal.exploits.exploit_ntlm_hash_list', ntlm_hash) @staticmethod - def update_config(config_json): + def update_config(config_json, should_encrypt): + if should_encrypt: + ConfigService.encrypt_config(config_json) mongo.db.config.update({'name': 'newconfig'}, {"$set": config_json}, upsert=True) @staticmethod - def get_default_config(): - defaultValidatingDraft4Validator = ConfigService._extend_config_with_default(Draft4Validator) - config = {} - defaultValidatingDraft4Validator(SCHEMA).validate(config) + def init_default_config(): + if ConfigService.default_config is None: + defaultValidatingDraft4Validator = ConfigService._extend_config_with_default(Draft4Validator) + config = {} + defaultValidatingDraft4Validator(SCHEMA).validate(config) + ConfigService.default_config = config + + @staticmethod + def get_default_config(should_decrypt=True): + ConfigService.init_default_config() + config = copy.deepcopy(ConfigService.default_config) + if not should_decrypt: + ConfigService.encrypt_config(config) return config @staticmethod def init_config(): - if ConfigService.get_config() != {}: + if ConfigService.get_config(should_decrypt=False) != {}: return ConfigService.reset_config() @staticmethod def reset_config(): - config = ConfigService.get_default_config() + config = ConfigService.get_default_config(should_decrypt=False) ConfigService.set_server_ips_in_config(config) - ConfigService.update_config(config) + ConfigService.update_config(config, should_encrypt=False) @staticmethod def set_server_ips_in_config(config): @@ -922,3 +949,21 @@ class ConfigService: return validators.extend( validator_class, {"properties": set_defaults}, ) + + @staticmethod + def decrypt_config(config): + ConfigService._encrypt_config(config, True) + + @staticmethod + def encrypt_config(config): + ConfigService._encrypt_config(config, False) + + @staticmethod + def _encrypt_config(config, is_decrypt=False): + for config_arr_as_array in ENCRYPTED_CONFIG_ARRAYS: + config_arr = config + for config_key_part in config_arr_as_array: + config_arr = config_arr[config_key_part] + + for i in range(len(config_arr)): + config_arr[i] = encryptor.dec(config_arr[i]) if is_decrypt else encryptor.enc(config_arr[i])