diff --git a/monkey/monkey_island/cc/services/attack/attack_config.py b/monkey/monkey_island/cc/services/attack/attack_config.py index d03a7cc21..713eeab36 100644 --- a/monkey/monkey_island/cc/services/attack/attack_config.py +++ b/monkey/monkey_island/cc/services/attack/attack_config.py @@ -1,4 +1,5 @@ import logging +from dpath import util from cc.database import mongo from attack_schema import SCHEMA from cc.services.config import ConfigService @@ -28,56 +29,96 @@ def update_config(config_json): def apply_to_monkey_config(): """ - Applies ATT&CK matrix in the database to the monkey configuration + Applies ATT&CK matrix to the monkey configuration :return: """ attack_techniques = get_techniques() monkey_config = ConfigService.get_config(False, True, True) monkey_schema = ConfigService.get_config_schema() - set_exploiters(attack_techniques, monkey_config, monkey_schema) + set_arrays(attack_techniques, monkey_config, monkey_schema) + set_booleans(attack_techniques, monkey_config, monkey_schema) ConfigService.update_config(monkey_config, True) -def set_exploiters(attack_techniques, monkey_config, monkey_schema): +def set_arrays(attack_techniques, monkey_config, monkey_schema): """ - Sets exploiters according to ATT&CK matrix + Sets exploiters/scanners/PBAs and other array type fields according to ATT&CK matrix :param attack_techniques: ATT&CK techniques dict. Format: {'T1110': True, ...} :param monkey_config: Monkey island's configuration :param monkey_schema: Monkey configuration schema """ - for exploiter in monkey_schema['definitions']['exploiter_classes']['anyOf']: - # Go trough each attack technique used by exploiter - for attack_technique in exploiter['attack_techniques']: - # If exploiter's attack technique is disabled, disable the exploiter - if not attack_techniques[attack_technique]: - remove_exploiter(exploiter['enum'][0], monkey_config) - break - # If exploiter's attack technique is enabled, enable the exploiter - else: - add_exploiter(exploiter['enum'][0], monkey_config) + for key, definition in monkey_schema['definitions'].items(): + for array_field in definition['anyOf']: + # Go trough each attack technique used by exploiter/scanner/PBA + if 'attack_techniques' not in array_field: + continue + for attack_technique in array_field['attack_techniques']: + # Skip if exploiter is marked with not yet implemented technique + if attack_technique not in attack_techniques: + continue + # If exploiter's attack technique is disabled, disable the exploiter/scanner/PBA + if not attack_techniques[attack_technique]: + r_alter_array(monkey_config, key, array_field['enum'][0], remove=True) + break + # If exploiter's attack technique is enabled, enable the exploiter/scanner/PBA + else: + r_alter_array(monkey_config, key, array_field['enum'][0], remove=False) -def remove_exploiter(exploiter, monkey_config): +def set_booleans(attack_techniques, monkey_config, monkey_schema): """ - Removes exploiter from monkey's configuration - :param exploiter: Exploiter class name found in SCHEMA->definitions->exploiter_classes -> anyOf -> enum - :param monkey_config: Monkey's configuration + Sets exploiters/scanners/PBAs and other array type fields according to ATT&CK matrix + :param attack_techniques: ATT&CK techniques dict. Format: {'T1110': True, ...} + :param monkey_config: Monkey island's configuration + :param monkey_schema: Monkey configuration schema """ - if exploiter in monkey_config['exploits']['general']['exploiter_classes']: - monkey_config['exploits']['general']['exploiter_classes'].remove(exploiter) + for key, value in monkey_schema['properties'].items(): + r_set_booleans([key], value, attack_techniques, monkey_config) -def add_exploiter(exploiter, monkey_config): - """ - Adds exploiter to monkey's configuration - :param exploiter: Exploiter class name found in SCHEMA->definitions->exploiter_classes -> anyOf -> enum - :param monkey_config: Monkey's configuration - """ - if not exploiter in monkey_config['exploits']['general']['exploiter_classes']: - monkey_config['exploits']['general']['exploiter_classes'].append(exploiter) +def r_set_booleans(path, value, attack_techniques, monkey_config): + if isinstance(value, dict): + dictionary = {} + if 'type' in value and value['type'] == 'boolean' and 'attack_techniques' in value: + set_bool_conf_val(path, should_enable_field(value['attack_techniques'], attack_techniques), monkey_config) + elif 'properties' in value: + dictionary = value['properties'] + else: + dictionary = value + for key, item in dictionary.items(): + path.append(key) + r_set_booleans(path, item, attack_techniques, monkey_config) + del path[-1] + + +def set_bool_conf_val(path, val, monkey_config): + util.set(monkey_config, '/'.join(path), val) + + +def should_enable_field(field_techniques, users_techniques): + for technique in field_techniques: + if not users_techniques[technique]: + return False + return True + + +def r_alter_array(config_value, array_name, field, remove=True): + if isinstance(config_value, dict): + if array_name in config_value and isinstance(config_value[array_name], list): + if remove and field in config_value[array_name]: + config_value[array_name].remove(field) + elif not remove and field not in config_value[array_name]: + config_value[array_name].append(field) + else: + for prop in config_value.items(): + r_alter_array(prop[1], array_name, field, remove) def get_techniques(): + """ + Parses ATT&CK config into a dic of techniques. + :return: Dictionary of techniques. Format: {"T1110": True, "T1075": False, ...} + """ attack_config = get_config() techniques = {} for key, attack_type in attack_config['properties'].items(): diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py index 582eeb876..87f7f7274 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -14,7 +14,7 @@ SCHEMA = { "description": "Adversaries may steal the credentials of a specific user or service account using " "Credential Access techniques or capture credentials earlier in their " "reconnaissance process.", - "mapped_to": ["T1003"] + "depends_on": ["T1003"] } } }, @@ -61,7 +61,7 @@ SCHEMA = { "description": "Credential dumping is the process of obtaining account login and password " "information, normally in the form of a hash or a clear text password, " "from the operating system and software.", - "mapped_to": ["T1078"] + "depends_on": ["T1078"] } } }, diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index c5611e4e1..7d7d0d440 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -116,6 +116,7 @@ SCHEMA = { "BackdoorUser" ], "title": "Back door user", + "attack_techniques": ["T1110"] }, ], }, @@ -135,7 +136,8 @@ SCHEMA = { "enum": [ "SSHFinger" ], - "title": "SSHFinger" + "title": "SSHFinger", + "attack_techniques": ["T1110"] }, { "type": "string", @@ -393,6 +395,7 @@ SCHEMA = { "title": "Harvest Azure Credentials", "type": "boolean", "default": True, + "attack_techniques": ["T1110", "T1078"], "description": "Determine if the Monkey should try to harvest password credentials from Azure VMs" }, @@ -406,6 +409,7 @@ SCHEMA = { "title": "Should use Mimikatz", "type": "boolean", "default": True, + "attack_techniques": ["T1110", "T1078"], "description": "Determines whether to use Mimikatz" }, } diff --git a/monkey/monkey_island/cc/ui/src/components/attack/MatrixComponent.js b/monkey/monkey_island/cc/ui/src/components/attack/MatrixComponent.js index 8267449d0..ae0d5b92c 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/MatrixComponent.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/MatrixComponent.js @@ -138,9 +138,9 @@ class MatrixComponent extends AuthComponent { let tempMatrix = this.state.configData; tempMatrix[techType[0]].properties[technique].value = value; // Toggle all mapped techniques - if (! mapped && tempMatrix[techType[0]].properties[technique].hasOwnProperty('mapped_to')){ + if (! mapped && tempMatrix[techType[0]].properties[technique].hasOwnProperty('depends_on')){ console.log("Triggered"); - tempMatrix[techType[0]].properties[technique].mapped_to.forEach(mappedTechnique => { + tempMatrix[techType[0]].properties[technique].depends_on.forEach(mappedTechnique => { console.log(mappedTechnique) this.handleTechniqueChange(mappedTechnique, value, true) }) diff --git a/monkey/monkey_island/requirements.txt b/monkey/monkey_island/requirements.txt index b8df0f5a9..41441e5b9 100644 --- a/monkey/monkey_island/requirements.txt +++ b/monkey/monkey_island/requirements.txt @@ -15,4 +15,5 @@ ipaddress enum34 pycryptodome boto3 -awscli \ No newline at end of file +awscli +dpath