diff --git a/monkey/monkey_island/cc/resources/aws_exporter.py b/monkey/monkey_island/cc/resources/aws_exporter.py index 363114948..6295f28f3 100644 --- a/monkey/monkey_island/cc/resources/aws_exporter.py +++ b/monkey/monkey_island/cc/resources/aws_exporter.py @@ -4,9 +4,13 @@ from datetime import datetime import boto3 from cc.resources.exporter import Exporter +from cc.services.config import ConfigService logger = logging.getLogger(__name__) +AWS_CRED_CONFIG_KEYS = [['cnc', 'aws_config', 'aws_access_key_id'], + ['cnc', 'aws_config', 'aws_secret_access_key']] + class AWSExporter(Exporter): @@ -19,12 +23,20 @@ class AWSExporter(Exporter): for issue in issues_list[machine]: findings_list.append(AWSExporter._prepare_finding(issue)) - if not AWSExporter._send_findings(findings_list): + if not AWSExporter._send_findings(findings_list, AWSExporter._get_aws_keys()): logger.error('Exporting findings to aws failed') return False return True + @staticmethod + def _get_aws_keys(): + creds_dict = {} + for key in AWS_CRED_CONFIG_KEYS: + creds_dict[key[2]] = ConfigService.get_config_value(key) + + return creds_dict + @staticmethod def merge_two_dicts(x, y): z = x.copy() # start with x's keys and values @@ -60,9 +72,11 @@ class AWSExporter(Exporter): return AWSExporter.merge_two_dicts(finding, findings_dict[issue['type']](issue)) @staticmethod - def _send_findings(findings_list): + def _send_findings(findings_list, creds_dict): - securityhub = boto3.client('securityhub') + securityhub = boto3.client('securityhub', + aws_access_key_id=creds_dict.get('aws_access_key_id', ''), + aws_secret_access_key=creds_dict.get('aws_secret_access_key', '')) import_response = securityhub.batch_import_findings(Findings=findings_list) print import_response if import_response['ResponseMetadata']['HTTPStatusCode'] == 200: diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index 3c61a89a3..6255a0656 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -639,6 +639,28 @@ SCHEMA = { "description": "The current command server the monkey is communicating with" } } + }, + 'aws_config': { + 'title': 'AWS Configuration', + 'type': 'object', + 'description': 'These credentials will be used in order to export the monkey\'s findings to the AWS Security Hub.', + 'properties': { + 'iam_role_id': { + 'title': 'IAM role ID', + 'type': 'string', + 'description': '' + }, + 'aws_access_key_id': { + 'title': 'AWS access key ID', + 'type': 'string', + 'description': 'Your AWS public access key ID, can be found in the IAM user interface in the AWS console.' + }, + 'aws_secret_access_key': { + 'title': 'AWS secret access key', + 'type': 'string', + 'description': 'Your AWS secret access key id, you can get this after creating a public access key in the console.' + } + } } } }, @@ -863,36 +885,6 @@ SCHEMA = { } } }, - 'island_configuration': { - 'title': 'Island Configuration', - 'type': 'object', - 'properties': - { - 'aws_config': - { - 'title': 'AWS Configuration', - 'type': 'object', - 'properties': - { - 'iam_role_id': - { - 'title': 'IAM role ID', - 'type': 'string' - }, - 'aws_access_key': - { - 'title': 'AWS access key ID', - 'type': 'string' - }, - 'aws_secret_access_key': - { - 'title': 'AWS Secret Access Key', - 'type': 'string' - } - } - } - } - } }, "options": { "collapsed": True @@ -906,9 +898,9 @@ ENCRYPTED_CONFIG_ARRAYS = \ ['internal', 'exploits', 'exploit_lm_hash_list'], ['internal', 'exploits', 'exploit_ntlm_hash_list'], ['internal', 'exploits', 'exploit_ssh_keys'], - ['island_configuration', 'aws_config', 'iam_role_id'], - ['island_configuration', 'aws_config', 'aws_access_key'], - ['island_configuration', 'aws_config', 'aws_secret_access_key'], + # ['cnc', 'aws_config', 'iam_role_id'], + # ['cnc', 'aws_config', 'aws_access_key_id'], + # ['cnc', 'aws_config', 'aws_secret_access_key'], ] # This should be used for config values of string type @@ -925,11 +917,12 @@ class ConfigService: pass @staticmethod - def get_config(is_initial_config=False, should_decrypt=True): + def get_config(is_initial_config=False, should_decrypt=True, is_island=False): """ Gets the entire global config. :param is_initial_config: If True, the initial config will be returned instead of the current config. :param should_decrypt: If True, all config values which are set as encrypted will be decrypted. + :param is_island: If True, will include island specific configuration parameters. :return: The entire global config. """ config = mongo.db.config.find_one({'name': 'initial' if is_initial_config else 'newconfig'}) or {} @@ -937,6 +930,8 @@ class ConfigService: config.pop(field, None) if should_decrypt and len(config) > 0: ConfigService.decrypt_config(config) + if not is_island: + config['cnc'].pop('aws_config', None) return config @staticmethod diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index 7e08170e2..a97447df0 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -10,7 +10,7 @@ class ConfigurePageComponent extends AuthComponent { this.currentSection = 'basic'; this.currentFormData = {}; - this.sectionsOrder = ['basic', 'basic_network', 'monkey', 'cnc', 'network', 'exploits', 'internal', 'monkey_island']; + this.sectionsOrder = ['basic', 'basic_network', 'monkey', 'cnc', 'network', 'exploits', 'internal']; // set schema from server this.state = {