From 09c6abcc83f46d59463eebdaa4dc7ad46614795f Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Tue, 28 Jan 2020 13:05:06 -0600 Subject: [PATCH 001/312] feat: add EC2 instance tags --- ScoutSuite/providers/aws/facade/ec2.py | 5 +++++ ScoutSuite/providers/aws/resources/ec2/instances.py | 3 ++- ScoutSuite/providers/aws/services.py | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/ec2.py b/ScoutSuite/providers/aws/facade/ec2.py index f37cdb400..1fe39a56a 100644 --- a/ScoutSuite/providers/aws/facade/ec2.py +++ b/ScoutSuite/providers/aws/facade/ec2.py @@ -180,6 +180,11 @@ async def _get_and_set_subnet_flow_logs(self, subnet: {}, region: str): [flow_log for flow_log in self.flow_logs_cache[region] if flow_log['ResourceId'] == subnet['SubnetId'] or flow_log['ResourceId'] == subnet['VpcId']] + async def get_and_set_ec2_instance_tags(self, raw_instance): + instance = {} + instance['tags'] = {x['Key']: x['Value'] for x in raw_instance['TagSet']} + return instance + async def get_peering_connections(self, region): try: peering_connections = await AWSFacadeUtils.get_all_pages('ec2', region, self.session, 'describe_vpc_peering_connections', 'VpcPeeringConnections') diff --git a/ScoutSuite/providers/aws/resources/ec2/instances.py b/ScoutSuite/providers/aws/resources/ec2/instances.py index 3ab09aec5..6662d4900 100644 --- a/ScoutSuite/providers/aws/resources/ec2/instances.py +++ b/ScoutSuite/providers/aws/resources/ec2/instances.py @@ -28,7 +28,7 @@ async def _parse_instance(self, raw_instance): get_name(raw_instance, instance, 'InstanceId') get_keys(raw_instance, instance, - ['KeyName', 'LaunchTime', 'InstanceType', 'State', 'IamInstanceProfile', 'SubnetId']) + ['KeyName', 'LaunchTime', 'InstanceType', 'State', 'IamInstanceProfile', 'SubnetId', 'TagSet']) instance['network_interfaces'] = {} for eni in raw_instance['NetworkInterfaces']: @@ -36,6 +36,7 @@ async def _parse_instance(self, raw_instance): get_keys(eni, nic, ['Association', 'Groups', 'PrivateIpAddresses', 'SubnetId', 'Ipv6Addresses']) instance['network_interfaces'][eni['NetworkInterfaceId']] = nic + instance['tags'] = self.facade.ec2.get_and_set_ec2_instance_tags(raw_instance) return id, instance @staticmethod diff --git a/ScoutSuite/providers/aws/services.py b/ScoutSuite/providers/aws/services.py index eba29977b..2629f976a 100644 --- a/ScoutSuite/providers/aws/services.py +++ b/ScoutSuite/providers/aws/services.py @@ -48,8 +48,8 @@ class AWSServicesConfig(BaseServicesConfig): :ivar rds: RDS configuration :ivar redshift: Redshift configuration :ivar s3: S3 configuration - :ivar ses: SES configuration: - "ivar sns: SNS configuration + :ivar ses: SES configuration + :ivar sns: SNS configuration :ivar sqs: SQS configuration """ From 1959876581dd904c30723af0ed7ac92f3bd2714d Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Tue, 28 Jan 2020 15:33:45 -0600 Subject: [PATCH 002/312] fix: handle concurrently running ec2 tags --- ScoutSuite/providers/aws/facade/ec2.py | 8 +++++--- ScoutSuite/providers/aws/resources/ec2/instances.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/ec2.py b/ScoutSuite/providers/aws/facade/ec2.py index 1fe39a56a..174111e04 100644 --- a/ScoutSuite/providers/aws/facade/ec2.py +++ b/ScoutSuite/providers/aws/facade/ec2.py @@ -180,9 +180,11 @@ async def _get_and_set_subnet_flow_logs(self, subnet: {}, region: str): [flow_log for flow_log in self.flow_logs_cache[region] if flow_log['ResourceId'] == subnet['SubnetId'] or flow_log['ResourceId'] == subnet['VpcId']] - async def get_and_set_ec2_instance_tags(self, raw_instance): - instance = {} - instance['tags'] = {x['Key']: x['Value'] for x in raw_instance['TagSet']} + async def get_and_set_ec2_instance_tags(self, raw_instance: {}): + if 'TagSet' in raw_instance: + instance = {'tags': {x['Key']: x['Value'] for x in raw_instance['TagSet']}} + else: + instance = {'tags': {}} return instance async def get_peering_connections(self, region): diff --git a/ScoutSuite/providers/aws/resources/ec2/instances.py b/ScoutSuite/providers/aws/resources/ec2/instances.py index 6662d4900..42c6a0ae3 100644 --- a/ScoutSuite/providers/aws/resources/ec2/instances.py +++ b/ScoutSuite/providers/aws/resources/ec2/instances.py @@ -36,7 +36,7 @@ async def _parse_instance(self, raw_instance): get_keys(eni, nic, ['Association', 'Groups', 'PrivateIpAddresses', 'SubnetId', 'Ipv6Addresses']) instance['network_interfaces'][eni['NetworkInterfaceId']] = nic - instance['tags'] = self.facade.ec2.get_and_set_ec2_instance_tags(raw_instance) + instance['tags'] = await self.facade.ec2.get_and_set_ec2_instance_tags(raw_instance) return id, instance @staticmethod From 7b9a9fe91a993fbad5da4b9333dc130dd5730b73 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Wed, 29 Jan 2020 06:21:58 -0600 Subject: [PATCH 003/312] fix: add other EC2 stuff for tagging --- ScoutSuite/providers/aws/facade/ec2.py | 9 ++++++++- ScoutSuite/providers/aws/resources/ec2/ami.py | 2 ++ ScoutSuite/providers/aws/resources/ec2/snapshots.py | 2 ++ ScoutSuite/providers/aws/resources/ec2/volumes.py | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ScoutSuite/providers/aws/facade/ec2.py b/ScoutSuite/providers/aws/facade/ec2.py index 174111e04..d296a9cc2 100644 --- a/ScoutSuite/providers/aws/facade/ec2.py +++ b/ScoutSuite/providers/aws/facade/ec2.py @@ -94,12 +94,19 @@ async def get_network_interfaces(self, region: str, vpc: str): async def get_volumes(self, region: str): try: volumes = await AWSFacadeUtils.get_all_pages('ec2', region, self.session, 'describe_volumes', 'Volumes') - await get_and_set_concurrently([self._get_and_set_key_manager], volumes, region=region) + await get_and_set_concurrently([self._get_and_set_key_manager, self._get_and_set_volume_tags], volumes, region=region) return volumes except Exception as e: print_exception('Failed to get EC2 volumes: {}'.format(e)) return [] + async def _get_and_set_volume_tags(self, volume: {}, region: str): + if "Tags" in volume: + volume["tags"] = {x["Key"]: x["Value"] for x in volume["Tags"]} + else: + volume["tags"] = {} + return volume + async def _get_and_set_key_manager(self, volume: {}, region: str): kms_client = AWSFacadeUtils.get_client('kms', self.session, region) if 'KmsKeyId' in volume: diff --git a/ScoutSuite/providers/aws/resources/ec2/ami.py b/ScoutSuite/providers/aws/resources/ec2/ami.py index 2e8993643..2e0538846 100644 --- a/ScoutSuite/providers/aws/resources/ec2/ami.py +++ b/ScoutSuite/providers/aws/resources/ec2/ami.py @@ -16,5 +16,7 @@ async def fetch_all(self): def _parse_image(self, raw_image): raw_image['id'] = raw_image['ImageId'] raw_image['name'] = raw_image['Name'] + if 'Tags' in raw_image: + raw_image['tags'] = {x["Key"]: x["Value"] for x in raw_image["Tags"]} return raw_image['id'], raw_image diff --git a/ScoutSuite/providers/aws/resources/ec2/snapshots.py b/ScoutSuite/providers/aws/resources/ec2/snapshots.py index d48b5f9e6..d3304dd56 100644 --- a/ScoutSuite/providers/aws/resources/ec2/snapshots.py +++ b/ScoutSuite/providers/aws/resources/ec2/snapshots.py @@ -18,6 +18,8 @@ def _parse_snapshot(self, raw_snapshot): raw_snapshot['id'] = raw_snapshot.pop('SnapshotId') raw_snapshot['name'] = get_name(raw_snapshot, raw_snapshot, 'id') raw_snapshot['public'] = self._is_public(raw_snapshot) + if "Tags" in raw_snapshot: + raw_snapshot['tags'] = {x["Key"]: x["Value"] for x in raw_snapshot["Tags"]} return raw_snapshot['id'], raw_snapshot @staticmethod diff --git a/ScoutSuite/providers/aws/resources/ec2/volumes.py b/ScoutSuite/providers/aws/resources/ec2/volumes.py index 6dec86616..9dc79b2da 100644 --- a/ScoutSuite/providers/aws/resources/ec2/volumes.py +++ b/ScoutSuite/providers/aws/resources/ec2/volumes.py @@ -17,4 +17,6 @@ async def fetch_all(self): def _parse_volume(self, raw_volume): raw_volume['id'] = raw_volume.pop('VolumeId') raw_volume['name'] = get_name(raw_volume, raw_volume, 'id') + if "Tags" in raw_volume: + raw_volume['tags'] = {x["Key"]: x["Value"] for x in raw_volume["Tags"]} return raw_volume['id'], raw_volume From 9464c4afe2279592faaaf6a8bc17cd4193aca707 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Mon, 3 Feb 2020 13:03:31 -0600 Subject: [PATCH 004/312] fix: ec2 instances return Tags instead of TagSet --- ScoutSuite/providers/aws/facade/ec2.py | 4 ++-- ScoutSuite/providers/aws/resources/ec2/instances.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/ec2.py b/ScoutSuite/providers/aws/facade/ec2.py index d296a9cc2..2a4b1030a 100644 --- a/ScoutSuite/providers/aws/facade/ec2.py +++ b/ScoutSuite/providers/aws/facade/ec2.py @@ -188,8 +188,8 @@ async def _get_and_set_subnet_flow_logs(self, subnet: {}, region: str): if flow_log['ResourceId'] == subnet['SubnetId'] or flow_log['ResourceId'] == subnet['VpcId']] async def get_and_set_ec2_instance_tags(self, raw_instance: {}): - if 'TagSet' in raw_instance: - instance = {'tags': {x['Key']: x['Value'] for x in raw_instance['TagSet']}} + if 'Tags' in raw_instance: + instance = {'tags': {x['Key']: x['Value'] for x in raw_instance['Tags']}} else: instance = {'tags': {}} return instance diff --git a/ScoutSuite/providers/aws/resources/ec2/instances.py b/ScoutSuite/providers/aws/resources/ec2/instances.py index 42c6a0ae3..439c05050 100644 --- a/ScoutSuite/providers/aws/resources/ec2/instances.py +++ b/ScoutSuite/providers/aws/resources/ec2/instances.py @@ -28,7 +28,7 @@ async def _parse_instance(self, raw_instance): get_name(raw_instance, instance, 'InstanceId') get_keys(raw_instance, instance, - ['KeyName', 'LaunchTime', 'InstanceType', 'State', 'IamInstanceProfile', 'SubnetId', 'TagSet']) + ['KeyName', 'LaunchTime', 'InstanceType', 'State', 'IamInstanceProfile', 'SubnetId', 'Tags']) instance['network_interfaces'] = {} for eni in raw_instance['NetworkInterfaces']: From b728ae1f16e3af297fc50a942c164644e36d76b6 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Tue, 4 Feb 2020 12:08:13 -0600 Subject: [PATCH 005/312] fix: remove double-nesting of 'tags' --- ScoutSuite/providers/aws/facade/ec2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/ec2.py b/ScoutSuite/providers/aws/facade/ec2.py index 2a4b1030a..edc20d8c0 100644 --- a/ScoutSuite/providers/aws/facade/ec2.py +++ b/ScoutSuite/providers/aws/facade/ec2.py @@ -189,9 +189,9 @@ async def _get_and_set_subnet_flow_logs(self, subnet: {}, region: str): async def get_and_set_ec2_instance_tags(self, raw_instance: {}): if 'Tags' in raw_instance: - instance = {'tags': {x['Key']: x['Value'] for x in raw_instance['Tags']}} + instance = {x['Key']: x['Value'] for x in raw_instance['Tags']} else: - instance = {'tags': {}} + instance = {} return instance async def get_peering_connections(self, region): From 8f97dd978a22410062a44b562d3990719e4be495 Mon Sep 17 00:00:00 2001 From: Juan Jose Date: Tue, 17 Mar 2020 11:05:55 +0100 Subject: [PATCH 006/312] Fixed unused import --- ScoutSuite/providers/aws/resources/secretsmanager/secrets.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ScoutSuite/providers/aws/resources/secretsmanager/secrets.py b/ScoutSuite/providers/aws/resources/secretsmanager/secrets.py index 6a7a377bc..836d2f612 100755 --- a/ScoutSuite/providers/aws/resources/secretsmanager/secrets.py +++ b/ScoutSuite/providers/aws/resources/secretsmanager/secrets.py @@ -1,5 +1,3 @@ -import json - from ScoutSuite.providers.aws.facade.base import AWSFacade from ScoutSuite.providers.aws.resources.base import AWSResources From 52fd162defc5b6bd42b6ecafc50a4f69924e1383 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Thu, 19 Mar 2020 05:43:28 +0100 Subject: [PATCH 007/312] Added 2 rules for AWS CIS 1.2.0 and updated rules format --- .../iam-root-account-used-recently.json | 10 +- .../rules/findings/iam-user-without-mfa.json | 10 +- .../aws/rules/rulesets/cis-1.2.0.json | 164 ++++++++++++++++++ 3 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json index c199bd86f..4357a151e 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json @@ -1,7 +1,15 @@ { "description": "Root account used recently", - "path": "iam.credential_reports.id", + "rationale": "Description:

The use of the root account should be avoided.", + "remediation": "Follow the remediation instructions of the Ensure IAM policies are attached only to groups or roles recommendation", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.1"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users"], "dashboard_name": "Root account", + "path": "iam.credential_reports.id", "conditions": [ "and", [ "iam.credential_reports.id.password_last_used", "notNull", "" ], [ "iam.credential_reports.id.password_last_used", "newerThan", ["90", "days"] ], diff --git a/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json b/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json index 4e4cfb76b..1933d8e8a 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json @@ -1,7 +1,15 @@ { "description": "User without MFA", - "path": "iam.users.id", + "rationale": "Description:

All IAM users should have Multi Factor Authentication (MFA) enabled.", + "remediation": "Enable MFA for all users in the AWS account", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.2"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.2"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.2"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#enable-mfa-for-privileged-users"], "dashboard_name": "Users", + "path": "iam.users.id", "conditions": [ "and", [ "iam.users.id.", "withKey", "LoginProfile" ], [ "iam.users.id.MFADevices", "empty", "" ] diff --git a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json new file mode 100644 index 000000000..65808daba --- /dev/null +++ b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json @@ -0,0 +1,164 @@ +{ + "about": "This ruleset attempts to cover as many recommendations from the CIS Amazon Web Services Foundation v1.0.0.", + "rules": { + "iam-root-account-used-recently.json": [ + { + "comment": "Recommendation 1.1", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "iam-user-without-mfa.json": [ + { + "comment": "Recommendation 1.2", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "cloudtrail-no-logging.json": [ + { + "comment": "Recommendation2,1 (part 2/2)", + "enabled": true, + "level": "danger" + } + ], + "cloudtrail-not-configured.json": [ + { + "comment": "Recommendation2.1 (part 1/2)", + "enabled": true, + "level": "danger" + } + ], + "ec2-default-security-group-with-rules.json": [ + { + "comment": "Recommendation4.4", + "enabled": true, + "level": "warning" + } + ], + "ec2-security-group-opens-known-port-to-all.json": [ + { + "args": [ + "SSH", + "TCP", + "22" + ], + "comment": "Recommendation4.1", + "enabled": true, + "level": "danger" + }, + { + "args": [ + "RDP", + "TCP", + "3389" + ], + "comment": "Recommendation4.2", + "enabled": true, + "level": "danger" + } + ], + "iam-password-policy-expiration-threshold.json": [ + { + "args": [ + "90" + ], + "comment": "recommendation1.11", + "enabled": true, + "level": "danger" + } + ], + "iam-password-policy-minimum-length.json": [ + { + "args": [ + "14" + ], + "comment": "recommendation1.9", + "enabled": true, + "level": "danger" + } + ], + "iam-password-policy-no-lowercase-required.json": [ + { + "comment": "recommendation1.6", + "enabled": true, + "level": "danger" + } + ], + "iam-password-policy-no-number-required.json": [ + { + "comment": "recommendation1.8", + "enabled": true, + "level": "danger" + } + ], + "iam-password-policy-no-symbol-required.json": [ + { + "comment": "recommendation1.7", + "enabled": true, + "level": "danger" + } + ], + "iam-password-policy-no-uppercase-required.json": [ + { + "comment": "recommendation1.5", + "enabled": true, + "level": "danger" + } + ], + "iam-password-policy-reuse-enabled.json": [ + { + "comment": "recommendation1.10", + "enabled": true, + "level": "danger" + } + ], + "iam-root-account-no-mfa.json": [ + { + "comment": "recommendation1.13 (partial: no check for hardware vs software)", + "enabled": true, + "level": "danger" + } + ], + "iam-root-account-with-active-keys.json": [ + { + "comment": "recommendation1.12", + "enabled": true, + "level": "danger" + } + ], + "iam-user-no-key-rotation.json": [ + { + "args": [ + "Active", + "90" + ], + "comment": "recommendation1.4", + "enabled": true, + "level": "danger" + } + ], + "iam-user-with-policies.json": [ + { + "args": [ + "inline", + "inline_policies" + ], + "comment": "Recommendation1.15 (part 1/2)", + "enabled": true, + "level": "danger" + }, + { + "args": [ + "managed", + "policies" + ], + "comment": "Recommendation1.15 (part 2/2)", + "enabled": true, + "level": "danger" + } + ] + } +} From 99afa13625337f63313c243a6af6532bc6425bec Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Fri, 20 Mar 2020 13:37:56 +0100 Subject: [PATCH 008/312] Added multiple IAM rules for AWS CIS Bencjmark 1.2.0 --- .../aws/services.iam.credential_reports.html | 14 +- .../aws/resources/iam/credentialreports.py | 9 + ...-password-policy-expiration-threshold.json | 14 +- .../iam-password-policy-minimum-length.json | 12 +- ...password-policy-no-lowercase-required.json | 10 +- ...am-password-policy-no-number-required.json | 10 +- ...am-password-policy-no-symbol-required.json | 10 +- ...password-policy-no-uppercase-required.json | 10 +- .../iam-password-policy-reuse-enabled.json | 12 +- .../findings/iam-root-account-no-mfa.json | 14 +- ...am-root-account-no-security-questions.json | 15 ++ .../iam-root-account-used-recently.json | 2 +- .../iam-root-account-with-active-keys.json | 11 +- .../iam-unused-credentials-not-disabled.json | 43 +++++ .../findings/iam-user-no-key-rotation.json | 13 +- .../findings/iam-user-with-policies.json | 11 +- .../rules/findings/iam-user-without-mfa.json | 2 +- .../aws/rules/rulesets/cis-1.2.0.json | 165 +++++++++++------- 18 files changed, 283 insertions(+), 94 deletions(-) create mode 100644 ScoutSuite/providers/aws/rules/findings/iam-root-account-no-security-questions.json create mode 100644 ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json diff --git a/ScoutSuite/output/data/html/partials/aws/services.iam.credential_reports.html b/ScoutSuite/output/data/html/partials/aws/services.iam.credential_reports.html index 7751382dc..d9fee4ebf 100644 --- a/ScoutSuite/output/data/html/partials/aws/services.iam.credential_reports.html +++ b/ScoutSuite/output/data/html/partials/aws/services.iam.credential_reports.html @@ -8,12 +8,16 @@

{{name}}

Credentials Report

Creation Date: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'user_creation_time')}}
Last Used Date: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'last_used')}}
-
Password Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'password_last_used')}}
+
Password Enabled: {{getValueAt 'services' 'iam' 'credential_reports' @key 'password_enabled'}}
+
Password Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'password_last_used')}}
+
Password Last Changed: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'password_last_changed')}}
MFA Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'mfa_active'}}
-
Access Key 1 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_active'}}
-
Access Key 2 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_active'}}
-
Access Key 1 Last Used: {{format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_last_used_date')}}
-
Access Key 2 Last Used: {{format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_last_used_date')}}
+
Access Key 1 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_active'}}
+
Access Key 1 Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_last_used_date')}}
+
Access Key 1 Last Rotated: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_last_rotated')}}
+
Access Key 2 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_active'}}
+
Access Key 2 Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_last_used_date')}}
+
Access Key 2 Last Rotated: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_last_rotated')}}
Signing Cert 1 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'cert_1_active'}}
Signing Cert 2 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'cert_2_active'}}
diff --git a/ScoutSuite/providers/aws/resources/iam/credentialreports.py b/ScoutSuite/providers/aws/resources/iam/credentialreports.py index c122234e3..79d640cac 100644 --- a/ScoutSuite/providers/aws/resources/iam/credentialreports.py +++ b/ScoutSuite/providers/aws/resources/iam/credentialreports.py @@ -13,11 +13,20 @@ def _parse_credential_reports(self, raw_credential_report): user_id = raw_credential_report['user'] raw_credential_report['name'] = user_id raw_credential_report['id'] = user_id + raw_credential_report['password_enabled'] = raw_credential_report['password_enabled'] raw_credential_report['password_last_used'] = self._sanitize_date(raw_credential_report['password_last_used']) + raw_credential_report['password_last_changed'] =\ + self._sanitize_date(raw_credential_report['password_last_changed']) + raw_credential_report['access_key_1_active'] = raw_credential_report['access_key_1_active'] raw_credential_report['access_key_1_last_used_date'] =\ self._sanitize_date(raw_credential_report['access_key_1_last_used_date']) + raw_credential_report['access_key_1_last_rotated'] = \ + self._sanitize_date(raw_credential_report['access_key_1_last_rotated']) + raw_credential_report['access_key_2_active'] = raw_credential_report['access_key_2_active'] raw_credential_report['access_key_2_last_used_date'] =\ self._sanitize_date(raw_credential_report['access_key_2_last_used_date']) + raw_credential_report['access_key_2_last_rotated'] = \ + self._sanitize_date(raw_credential_report['access_key_2_last_rotated']) raw_credential_report['last_used'] = self._compute_last_used(raw_credential_report) return get_non_provider_id(user_id), raw_credential_report diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-expiration-threshold.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-expiration-threshold.json index d97e11078..e770ab252 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-expiration-threshold.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-expiration-threshold.json @@ -1,12 +1,20 @@ { "arg_names": [ "Maximum password age" ], "description": "Passwords expire after _ARG_0_ days", + "rationale": "Reducing passwords lifetime increases account resiliency against brute force login attempts.", + "remediation": "Enable password expiration and set the expiration period to 90 days or less", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.11"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.11"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.11"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials"], + "dashboard_name": "Password policy", "path": "iam.password_policy", "display_path": "iam.password_policy.MaxPasswordAge", - "id_suffix": "MaxPasswordAge", - "dashboard_name": "Password policy", "conditions": [ "or", [ "iam.password_policy.ExpirePasswords", "false", "" ], [ "iam.password_policy.MaxPasswordAge", "moreThan", "_ARG_0_" ] - ] + ], + "id_suffix": "MaxPasswordAge" } diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-minimum-length.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-minimum-length.json index 8271a86cf..a0f39adcb 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-minimum-length.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-minimum-length.json @@ -1,8 +1,16 @@ { "arg_names": [ "Minimum password length" ], - "description": "Minimum password length too short", - "path": "iam.password_policy.MinimumPasswordLength", + "description": "Password policy lacks minimum length requirement of _ARG_0_", + "rationale": "Requiring passwords to require a minimum length increases account resiliency against brute force login attempts.", + "remediation": "Ensure the password policy is configured to require a minimum length", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.9"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.9"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.9"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", + "path": "iam.password_policy.MinimumPasswordLength", "conditions": [ "or", [ "this", "lessThan", "_ARG_0_" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-lowercase-required.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-lowercase-required.json index 64a1ea4db..53b840591 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-lowercase-required.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-lowercase-required.json @@ -1,7 +1,15 @@ { "description": "Password policy lacks lowercase requirement", - "path": "iam.password_policy.RequireLowercaseCharacters", + "rationale": "Requiring passwords to include at least a lowercase letter increases account resiliency against brute force login attempts.", + "remediation": "Ensure the password policy is configured to require at least one lowercase letter", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.6"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.6"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.6"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", + "path": "iam.password_policy.RequireLowercaseCharacters", "conditions": [ "or", [ "this", "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-number-required.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-number-required.json index 63abb9def..f73c106d8 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-number-required.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-number-required.json @@ -1,7 +1,15 @@ { "description": "Password policy lacks number requirement", - "path": "iam.password_policy.RequireNumbers", + "rationale": "Requiring passwords to include at least one number increases account resiliency against brute force login attempts.", + "remediation": "Ensure the password policy is configured to require at least one number", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.8"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.8"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.8"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", + "path": "iam.password_policy.RequireNumbers", "conditions": [ "or", [ "this", "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-symbol-required.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-symbol-required.json index 54c25be2e..a5e0980ab 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-symbol-required.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-symbol-required.json @@ -1,7 +1,15 @@ { "description": "Password policy lacks symbol requirement", - "path": "iam.password_policy.RequireSymbols", + "rationale": "Requiring passwords to include at least one symbol increases account resiliency against brute force login attempts.", + "remediation": "Ensure the password policy is configured to require at least one symbol", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.7"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.7"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.7"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", + "path": "iam.password_policy.RequireSymbols", "conditions": [ "or", [ "this", "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-uppercase-required.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-uppercase-required.json index 92aae8dc7..d48ca6c22 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-uppercase-required.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-uppercase-required.json @@ -1,7 +1,15 @@ { "description": "Password policy lacks uppercase requirement", - "path": "iam.password_policy.RequireUppercaseCharacters", + "rationale": "Requiring passwords to include at least an uppercase letter increases account resiliency against brute force login attempts.", + "remediation": "Ensure the password policy is configured to require at least one uppercase letter", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.5"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.5"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.5"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", + "path": "iam.password_policy.RequireUppercaseCharacters", "conditions": [ "or", [ "this", "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-reuse-enabled.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-reuse-enabled.json index f521d09ad..cc25f1563 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-reuse-enabled.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-reuse-enabled.json @@ -1,7 +1,15 @@ { - "description": "Password reuse enabled", - "path": "iam.password_policy.PasswordReusePrevention", + "description": "Password policy allows the reuse of passwords", + "rationale": "Preventing password reuse increases account resiliency against brute force login attempts.", + "remediation": "Ensure the password policy is configured to prevent password reuse", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.10"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.10"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.10"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", + "path": "iam.password_policy.PasswordReusePrevention", "conditions": [ "or", [ "this", "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json index 999d13697..19982d1cc 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json @@ -1,7 +1,17 @@ { - "description": "Lack of MFA (root account)", - "path": "iam.credential_reports.id", + "description": "Root account without MFA", + "rationale": "The root account should have Multi Factor Authentication (MFA) enabled.", + "remediation": "Enable MFA for the root account", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.13"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.13"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.14"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.13"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.14"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials"], "dashboard_name": "Root account", + "path": "iam.credential_reports.id", "conditions": [ "and", [ "iam.credential_reports.id.mfa_active", "notTrue", "" ], [ "iam.credential_reports.id.name", "equal", "" ] diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-security-questions.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-security-questions.json new file mode 100644 index 000000000..54eb91fe0 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-security-questions.json @@ -0,0 +1,15 @@ +{ + "description": "Root account has no security questions configured", + "rationale": "In the event that root account access is not possible, account recovery can be performed through authentication using secret questions and associated answers.", + "remediation": "Ensure the root account has the security questions and answers section configured", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.14"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.15"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.15"} + ], + "dashboard_name": "Users", + "path": "iam.credential_reports.id", + "conditions": [ "and", + [ "iam.credential_reports.id.name", "equal", "" ] + ] +} diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json index 4357a151e..88326ec5b 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json @@ -1,6 +1,6 @@ { "description": "Root account used recently", - "rationale": "Description:

The use of the root account should be avoided.", + "rationale": "The use of the root account should be avoided.", "remediation": "Follow the remediation instructions of the Ensure IAM policies are attached only to groups or roles recommendation", "compliance": [ {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.1"}, diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-with-active-keys.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-with-active-keys.json index ac967d88e..8341c9790 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-root-account-with-active-keys.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-with-active-keys.json @@ -1,8 +1,15 @@ { "description": "Root account has active keys", - "rationale": "Description:

AWS root account access keys should be deleted as they provide unrestricted access to the AWS Account.", - "path": "iam.credential_reports.id", + "rationale": "AWS root account access keys should be deleted as they provide unrestricted access to the AWS Account.", + "remediation": "Delete or disable active root account access keys", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.12"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.12"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.12"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials"], "dashboard_name": "Root account", + "path": "iam.credential_reports.id", "conditions": [ "and", [ "iam.credential_reports.id.name", "equal", "" ], [ diff --git a/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json b/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json new file mode 100644 index 000000000..7c8e635c0 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json @@ -0,0 +1,43 @@ +{ + "arg_names": [ "Period" ], + "description": "Credentials unused for _ARG_0_ days or greater are not disabled", + "rationale": "Disabling or removing unnecessary credentials will reduce the window of opportunity for compromised accounts to be used.", + "remediation": "Ensure that all credentials (including passwords and access keys) have been used and changed in the last _ARG_0_ days", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.3"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.3"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.3"} + ], + "dashboard_name": "Users", + "path": "iam.credential_reports.id", + "conditions": [ "or", + [ "iam.credential_reports.id.password_enabled", "true", "" ], + [ + "and", + [ "iam.credential_reports.id.password_last_used", "moreThan", "_ARG_0_" ], + [ + "or", + [ "iam.credential_reports.id.password_last_changed", "moreThan", "_ARG_0_" ] + ] + ], + [ "iam.credential_reports.id.access_key_1_active", "true", "" ], + [ + "and", + [ "iam.credential_reports.id.access_key_1_last_used_date", "moreThan", "_ARG_0_" ], + [ + "or", + [ "iam.credential_reports.id.access_key_1_last_rotated", "moreThan", "_ARG_0_" ] + ] + ], + [ "iam.credential_reports.id.access_key_2_active", "true", "" ], + [ + "and", + [ "iam.credential_reports.id.access_key_2_last_used_date", "moreThan", "_ARG_0_" ], + [ + "or", + [ "iam.credential_reports.id.access_key_2_last_rotated", "moreThan", "_ARG_0_" ] + ] + ] + ], + "id_suffix": "unused_credentials" +} diff --git a/ScoutSuite/providers/aws/rules/findings/iam-user-no-key-rotation.json b/ScoutSuite/providers/aws/rules/findings/iam-user-no-key-rotation.json index d19d94fc2..1247ce7cf 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-user-no-key-rotation.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-user-no-key-rotation.json @@ -1,10 +1,17 @@ { "arg_names": [ "Key status", "Rotation period" ], - "description": "Lack of key rotation (_ARG_0_)", - "rationale": "Description:

In case of access key compromise, the lack of credential rotation increases the period during which an attacker has access to the AWS account", + "description": "Lack of key rotation for (_ARG_0_) days", + "rationale": "In case of access key compromise, the lack of credential rotation increases the period during which an attacker has access to the AWS account.", + "remediation": "Rotate access keys that have not been changed recently", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.4"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.4"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.4"} + ], + "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials"], "key": "iam-user-no-_ARG_0_-key-rotation.json", - "path": "iam.users.id.AccessKeys.id", "dashboard_name": "Access keys", + "path": "iam.users.id.AccessKeys.id", "display_path": "iam.users.id", "conditions": [ "and", [ "iam.users.id.AccessKeys.id.Status", "equal", "_ARG_0_" ], diff --git a/ScoutSuite/providers/aws/rules/findings/iam-user-with-policies.json b/ScoutSuite/providers/aws/rules/findings/iam-user-with-policies.json index 469f0160a..d11a388d4 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-user-with-policies.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-user-with-policies.json @@ -2,11 +2,18 @@ "arg_names": [ "Type of policy", "Path to policies" ], "key": "iam-user-with-_ARG_0_-policies", "description": "User with _ARG_0_ policies", - "path": "iam.users.id", + "rationale": "Assigning privileges at the user level increases the complexity of access management and the opportunity for a user to receive or retain excessive privileges.", + "remediation": "Ensure IAM policies are only attached to groups or roles", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.15"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.16"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.16"} + ], "dashboard_name": "Users", + "path": "iam.users.id", "conditions": [ "and", [ "iam.users.id.", "withKey", "_ARG_1_" ], [ "iam.users.id._ARG_1_", "notEmpty", "" ] ], "id_suffix": "_ARG_1_" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json b/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json index 1933d8e8a..40358d7c1 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json @@ -1,6 +1,6 @@ { "description": "User without MFA", - "rationale": "Description:

All IAM users should have Multi Factor Authentication (MFA) enabled.", + "rationale": "All IAM users should have Multi Factor Authentication (MFA) enabled.", "remediation": "Enable MFA for all users in the AWS account", "compliance": [ {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.2"}, diff --git a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json index 65808daba..b62ef9be7 100644 --- a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json +++ b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json @@ -1,5 +1,5 @@ { - "about": "This ruleset attempts to cover as many recommendations from the CIS Amazon Web Services Foundation v1.0.0.", + "about": "This ruleset attempts to cover as many recommendations from the CIS Amazon Web Services Foundation v1.2.0.", "rules": { "iam-root-account-used-recently.json": [ { @@ -17,57 +17,59 @@ "scored": true } ], - "cloudtrail-no-logging.json": [ + "iam-unused-credentials-not-disabled.json": [ { - "comment": "Recommendation2,1 (part 2/2)", + "args": [ + "90" + ], + "comment": "Recommendation 1.3", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], - "cloudtrail-not-configured.json": [ + "iam-user-no-key-rotation.json": [ { - "comment": "Recommendation2.1 (part 1/2)", + "args": [ + "Active", + "90" + ], + "comment": "Recommendation 1.4", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], - "ec2-default-security-group-with-rules.json": [ + "iam-password-policy-no-uppercase-required.json": [ { - "comment": "Recommendation4.4", + "comment": "Recommendation 1.5", "enabled": true, - "level": "warning" + "level": "danger", + "scored": true } ], - "ec2-security-group-opens-known-port-to-all.json": [ + "iam-password-policy-no-lowercase-required.json": [ { - "args": [ - "SSH", - "TCP", - "22" - ], - "comment": "Recommendation4.1", + "comment": "Recommendation 1.6", "enabled": true, - "level": "danger" - }, + "level": "danger", + "scored": true + } + ], + "iam-password-policy-no-symbol-required.json": [ { - "args": [ - "RDP", - "TCP", - "3389" - ], - "comment": "Recommendation4.2", + "comment": "Recommendation 1.7", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], - "iam-password-policy-expiration-threshold.json": [ + "iam-password-policy-no-number-required.json": [ { - "args": [ - "90" - ], - "comment": "recommendation1.11", + "comment": "Recommendation 1.8", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], "iam-password-policy-minimum-length.json": [ @@ -75,87 +77,116 @@ "args": [ "14" ], - "comment": "recommendation1.9", + "comment": "Recommendation 1.9", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], - "iam-password-policy-no-lowercase-required.json": [ + "iam-password-policy-reuse-enabled.json": [ { - "comment": "recommendation1.6", + "comment": "Recommendation 1.10", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], - "iam-password-policy-no-number-required.json": [ + "iam-password-policy-expiration-threshold.json": [ { - "comment": "recommendation1.8", + "args": [ + "90" + ], + "comment": "Recommendation 1.11", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], - "iam-password-policy-no-symbol-required.json": [ + "iam-root-account-with-active-keys.json": [ { - "comment": "recommendation1.7", + "comment": "Recommendation 1.12", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], - "iam-password-policy-no-uppercase-required.json": [ + "iam-root-account-no-mfa.json": [ { - "comment": "recommendation1.5", + "comment": "Recommendation 1.13 and 1.14 (it is not possible to check if MFA is hardware or software)", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], - "iam-password-policy-reuse-enabled.json": [ + "iam-root-account-no-security-questions.json": [ { - "comment": "recommendation1.10", + "comment": "Recommendation 1.15 (no API call to know if root account has security questions set)", + "enabled": false, + "level": "danger", + "scored": false + } + ], + "iam-user-with-policies.json": [ + { + "args": [ + "inline", + "inline_policies" + ], + "comment": "Recommendation 1.16 (Part 1/2)", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true + }, + { + "args": [ + "managed", + "policies" + ], + "comment": "Recommendation 1.16 (Part 2/2)", + "enabled": true, + "level": "danger", + "scored": true } ], - "iam-root-account-no-mfa.json": [ + "cloudtrail-no-logging.json": [ { - "comment": "recommendation1.13 (partial: no check for hardware vs software)", + "comment": "Recommendation2,1 (part 2/2)", "enabled": true, "level": "danger" } ], - "iam-root-account-with-active-keys.json": [ + "cloudtrail-not-configured.json": [ { - "comment": "recommendation1.12", + "comment": "Recommendation2.1 (part 1/2)", "enabled": true, "level": "danger" } ], - "iam-user-no-key-rotation.json": [ + "ec2-default-security-group-with-rules.json": [ { - "args": [ - "Active", - "90" - ], - "comment": "recommendation1.4", + "comment": "Recommendation4.4", "enabled": true, - "level": "danger" + "level": "warning" } ], - "iam-user-with-policies.json": [ + "ec2-security-group-opens-known-port-to-all.json": [ { "args": [ - "inline", - "inline_policies" + "SSH", + "TCP", + "22" ], - "comment": "Recommendation1.15 (part 1/2)", + "comment": "Recommendation4.1", "enabled": true, "level": "danger" }, { "args": [ - "managed", - "policies" + "RDP", + "TCP", + "3389" ], - "comment": "Recommendation1.15 (part 2/2)", + "comment": "Recommendation4.2", "enabled": true, "level": "danger" } From 0852793281a5924ae9d985809a7cb3b403280f69 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Fri, 20 Mar 2020 18:22:21 +0100 Subject: [PATCH 009/312] Completed all IAM rules for CIS Benchmark 1.2.0 --- .../aws/services.iam.credential_reports.html | 18 +++---- .../aws/resources/iam/credentialreports.py | 2 + ...managed-policy-allows-full-privileges.json | 16 ++++++ .../rules/findings/iam-no-support-role.json | 14 +++++ ...am-root-account-no-security-questions.json | 15 ------ .../iam-unused-credentials-not-disabled.json | 22 ++++---- ...-user-unused-access-key-initial-setup.json | 24 +++++++++ .../aws/rules/rulesets/cis-1.2.0.json | 52 ++++++++++++++++++- .../providers/aws/rules/rulesets/default.json | 15 ++++++ 9 files changed, 141 insertions(+), 37 deletions(-) create mode 100644 ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json create mode 100644 ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json delete mode 100644 ScoutSuite/providers/aws/rules/findings/iam-root-account-no-security-questions.json create mode 100644 ScoutSuite/providers/aws/rules/findings/iam-user-unused-access-key-initial-setup.json diff --git a/ScoutSuite/output/data/html/partials/aws/services.iam.credential_reports.html b/ScoutSuite/output/data/html/partials/aws/services.iam.credential_reports.html index d9fee4ebf..e4135e003 100644 --- a/ScoutSuite/output/data/html/partials/aws/services.iam.credential_reports.html +++ b/ScoutSuite/output/data/html/partials/aws/services.iam.credential_reports.html @@ -8,16 +8,16 @@

{{name}}

Credentials Report

Creation Date: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'user_creation_time')}}
Last Used Date: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'last_used')}}
-
Password Enabled: {{getValueAt 'services' 'iam' 'credential_reports' @key 'password_enabled'}}
-
Password Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'password_last_used')}}
-
Password Last Changed: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'password_last_changed')}}
+
Password Enabled: {{getValueAt 'services' 'iam' 'credential_reports' @key 'password_enabled'}}
+
Password Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'password_last_used')}}
+
Password Last Changed: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'password_last_changed')}}
MFA Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'mfa_active'}}
-
Access Key 1 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_active'}}
-
Access Key 1 Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_last_used_date')}}
-
Access Key 1 Last Rotated: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_last_rotated')}}
-
Access Key 2 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_active'}}
-
Access Key 2 Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_last_used_date')}}
-
Access Key 2 Last Rotated: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_last_rotated')}}
+
Access Key 1 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_active'}}
+
Access Key 1 Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_last_used_date')}}
+
Access Key 1 Last Rotated: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_1_last_rotated')}}
+
Access Key 2 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_active'}}
+
Access Key 2 Last Used: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_last_used_date')}}
+
Access Key 2 Last Rotated: {{ format_date (getValueAt 'services' 'iam' 'credential_reports' @key 'access_key_2_last_rotated')}}
Signing Cert 1 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'cert_1_active'}}
Signing Cert 2 Active: {{getValueAt 'services' 'iam' 'credential_reports' @key 'cert_2_active'}}
diff --git a/ScoutSuite/providers/aws/resources/iam/credentialreports.py b/ScoutSuite/providers/aws/resources/iam/credentialreports.py index 79d640cac..bea8a84ad 100644 --- a/ScoutSuite/providers/aws/resources/iam/credentialreports.py +++ b/ScoutSuite/providers/aws/resources/iam/credentialreports.py @@ -28,6 +28,8 @@ def _parse_credential_reports(self, raw_credential_report): raw_credential_report['access_key_2_last_rotated'] = \ self._sanitize_date(raw_credential_report['access_key_2_last_rotated']) raw_credential_report['last_used'] = self._compute_last_used(raw_credential_report) + raw_credential_report['cert_1_active'] = raw_credential_report['cert_1_active'] + raw_credential_report['cert_2_active'] = raw_credential_report['cert_2_active'] return get_non_provider_id(user_id), raw_credential_report @staticmethod diff --git a/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json new file mode 100644 index 000000000..983ea84ed --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json @@ -0,0 +1,16 @@ +{ + "description": "Managed policy allows full administrative privileges", + "rationale": "Providing full administrative privileges instead of restricting to the minimum set of permissions that the user is required to do exposes the resources to potentially unwanted actions.", + "remediation": "Ensure no managed policies are configured with Effect:Allow, Action:* and Resource:*", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.24"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.22"} + ], + "dashboard_name": "Policies", + "path": "iam.policies.id", + "conditions": [ "and", + [ "iam.policies.id.PolicyDocument.Statement.id.Effect", "equal", "Allow" ], + [ "iam.policies.id.PolicyDocument.Statement.id.Action", "containAction", "*" ], + [ "iam.policies.id.PolicyDocument.Statement.id.Resource", "containAtLeastOneOf", [ "*" ] ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json b/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json new file mode 100644 index 000000000..34ebda2d7 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json @@ -0,0 +1,14 @@ +{ + "description": "No authorized user to manage incidents with AWS Support", + "rationale": "There should be at least one user authorized to manage incidents with AWS Support.", + "remediation": "Attach the AWSSupportAccess to a role or group", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.22"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.20"} + ], + "dashboard_name": "Policies", + "path": "iam.policies.AWSSupportAccess", + "conditions": [ "and", + [ "iam.policies.AWSSupportAccess.attached_to", "notEmpty", "" ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-security-questions.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-security-questions.json deleted file mode 100644 index 54eb91fe0..000000000 --- a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-security-questions.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "description": "Root account has no security questions configured", - "rationale": "In the event that root account access is not possible, account recovery can be performed through authentication using secret questions and associated answers.", - "remediation": "Ensure the root account has the security questions and answers section configured", - "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.14"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.15"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.15"} - ], - "dashboard_name": "Users", - "path": "iam.credential_reports.id", - "conditions": [ "and", - [ "iam.credential_reports.id.name", "equal", "" ] - ] -} diff --git a/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json b/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json index 7c8e635c0..27e58b5e1 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json @@ -1,5 +1,5 @@ { - "arg_names": [ "Period" ], + "arg_names": [ "Period in days" ], "description": "Credentials unused for _ARG_0_ days or greater are not disabled", "rationale": "Disabling or removing unnecessary credentials will reduce the window of opportunity for compromised accounts to be used.", "remediation": "Ensure that all credentials (including passwords and access keys) have been used and changed in the last _ARG_0_ days", @@ -11,33 +11,33 @@ "dashboard_name": "Users", "path": "iam.credential_reports.id", "conditions": [ "or", - [ "iam.credential_reports.id.password_enabled", "true", "" ], [ "and", - [ "iam.credential_reports.id.password_last_used", "moreThan", "_ARG_0_" ], + [ "iam.credential_reports.id.password_enabled", "true", "" ], [ "or", - [ "iam.credential_reports.id.password_last_changed", "moreThan", "_ARG_0_" ] + [ "iam.credential_reports.id.password_last_used", "olderThan", ["_ARG_0_", "days"] ], + [ "iam.credential_reports.id.password_last_changed", "olderThan", ["_ARG_0_", "days"] ] ] ], - [ "iam.credential_reports.id.access_key_1_active", "true", "" ], [ "and", - [ "iam.credential_reports.id.access_key_1_last_used_date", "moreThan", "_ARG_0_" ], + [ "iam.credential_reports.id.access_key_1_active", "true", "" ], [ "or", - [ "iam.credential_reports.id.access_key_1_last_rotated", "moreThan", "_ARG_0_" ] + [ "iam.credential_reports.id.access_key_1_last_used_date", "olderThan", ["_ARG_0_", "days"] ], + [ "iam.credential_reports.id.access_key_1_last_rotated", "olderThan", ["_ARG_0_", "days"] ] ] ], - [ "iam.credential_reports.id.access_key_2_active", "true", "" ], [ "and", - [ "iam.credential_reports.id.access_key_2_last_used_date", "moreThan", "_ARG_0_" ], + [ "iam.credential_reports.id.access_key_2_active", "true", "" ], [ "or", - [ "iam.credential_reports.id.access_key_2_last_rotated", "moreThan", "_ARG_0_" ] + [ "iam.credential_reports.id.access_key_2_last_used_date", "olderThan", ["_ARG_0_", "days"] ], + [ "iam.credential_reports.id.access_key_2_last_rotated", "olderThan", ["_ARG_0_", "days"] ] ] ] ], - "id_suffix": "unused_credentials" + "class_suffix": "unused_credentials" } diff --git a/ScoutSuite/providers/aws/rules/findings/iam-user-unused-access-key-initial-setup.json b/ScoutSuite/providers/aws/rules/findings/iam-user-unused-access-key-initial-setup.json new file mode 100644 index 000000000..8d1af4841 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/iam-user-unused-access-key-initial-setup.json @@ -0,0 +1,24 @@ +{ + "description": "Users with access keys created during initial setup and not used", + "rationale": "Not creating access keys during initial user setup will avoid unnecessary management work and give more control over keys used somewhere in the organization.", + "remediation": "Do not setup access keys during initial user setup. Instead, require users to create the keys themselves or put in a support ticket to have them created", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.23"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.21"} + ], + "dashboard_name": "Users", + "path": "iam.credential_reports.id", + "conditions": [ "or", + [ + "and", + [ "iam.credential_reports.id.access_key_1_active", "true", "" ], + [ "iam.credential_reports.id.access_key_1_last_used_date", "equal", "None" ] + ], + [ + "and", + [ "iam.credential_reports.id.access_key_2_active", "true", "" ], + [ "iam.credential_reports.id.access_key_2_last_used_date", "equal", "None" ] + ] + ], + "class_suffix": "unused_access_keys" +} diff --git a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json index b62ef9be7..0760f7456 100644 --- a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json +++ b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json @@ -118,11 +118,11 @@ "scored": true } ], - "iam-root-account-no-security-questions.json": [ + "todo-recommendation-1-15.json": [ { "comment": "Recommendation 1.15 (no API call to know if root account has security questions set)", "enabled": false, - "level": "danger", + "level": "warning", "scored": false } ], @@ -148,6 +148,54 @@ "scored": true } ], + "todo-recommendation-1-17.json": [ + { + "comment": "Recommendation 1.17 (no API call to check contact details)", + "enabled": false, + "level": "warning", + "scored": false + } + ], + "todo-recommendation-1-18.json": [ + { + "comment": "Recommendation 1.18 (no API call to check security contact information)", + "enabled": false, + "level": "warning", + "scored": false + } + ], + "TODO.json": [ + { + "comment": "Recommendation 1.19 (TODO)", + "enabled": false, + "level": "warning", + "scored": false + } + ], + "iam-no-support-role.json": [ + { + "comment": "Recommendation 1.20", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "iam-user-unused-access-key-initial-setup.json": [ + { + "comment": "Recommendation 1.21", + "enabled": true, + "level": "warning", + "scored": false + } + ], + "iam-managed-policy-allows-full-privileges.json": [ + { + "comment": "Recommendation 1.22", + "enabled": true, + "level": "danger", + "scored": true + } + ], "cloudtrail-no-logging.json": [ { "comment": "Recommendation2,1 (part 2/2)", diff --git a/ScoutSuite/providers/aws/rules/rulesets/default.json b/ScoutSuite/providers/aws/rules/rulesets/default.json index 196c06b2b..375cdf039 100644 --- a/ScoutSuite/providers/aws/rules/rulesets/default.json +++ b/ScoutSuite/providers/aws/rules/rulesets/default.json @@ -513,6 +513,12 @@ "level": "danger" } ], + "iam-managed-policy-allows-full-privileges.json": [ + { + "enabled": true, + "level": "danger" + } + ], "iam-managed-policy-allows-NotActions.json": [ { "enabled": true, @@ -648,6 +654,15 @@ "level": "warning" } ], + "iam-unused-credentials-not-disabled.json": [ + { + "args": [ + "90" + ], + "enabled": true, + "level": "danger" + } + ], "iam-user-no-key-rotation.json": [ { "args": [ From 93eb9b8292b8104f1a7cb96b533d3d159f63e7d7 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Mon, 23 Mar 2020 18:12:23 +0100 Subject: [PATCH 010/312] Completed all Logging rules for CIS Benchmark 1.2.0 --- ...services.cloudtrail.regions.id.trails.html | 7 +- .../partials/aws/services.config.regions.html | 2 +- .../aws/services.kms.regions.id.keys.html | 2 +- .../cloudtrail-no-cloudwatch-integration.json | 22 ++++++ .../cloudtrail-no-encryption-with-kms.json | 19 +++++ .../cloudtrail-no-log-file-validation.json | 13 +++- .../rules/findings/cloudtrail-no-logging.json | 19 ++++- .../cloudtrail-s3-bucket-no-logging.json | 19 +++++ .../config-recorder-not-configured.json | 12 ++- .../findings/kms-key-rotation-disabled.json | 16 ++++ .../rules/findings/s3-bucket-no-logging.json | 4 +- .../findings/vpc-subnet-without-flow-log.json | 13 +++- .../aws/rules/rulesets/cis-1.2.0.json | 74 ++++++++++++++++++- 13 files changed, 198 insertions(+), 24 deletions(-) create mode 100644 ScoutSuite/providers/aws/rules/findings/cloudtrail-no-cloudwatch-integration.json create mode 100644 ScoutSuite/providers/aws/rules/findings/cloudtrail-no-encryption-with-kms.json create mode 100644 ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json create mode 100644 ScoutSuite/providers/aws/rules/findings/kms-key-rotation-disabled.json diff --git a/ScoutSuite/output/data/html/partials/aws/services.cloudtrail.regions.id.trails.html b/ScoutSuite/output/data/html/partials/aws/services.cloudtrail.regions.id.trails.html index 98f112db2..ff27cd061 100644 --- a/ScoutSuite/output/data/html/partials/aws/services.cloudtrail.regions.id.trails.html +++ b/ScoutSuite/output/data/html/partials/aws/services.cloudtrail.regions.id.trails.html @@ -13,10 +13,10 @@

Information

{{/if}} {{#unless scout_link}} -
  • Logging: {{convert_bool_to_enabled IsLogging}}
  • +
  • Logging: {{convert_bool_to_enabled IsLogging}}
  • Start Logging Time: {{format_date StartLoggingTime}}
  • Stop Logging Time: {{format_date StopLoggingTime}}
  • -
  • Multi Region: {{convert_bool_to_enabled IsMultiRegionTrail}}
  • +
  • Multi Region: {{convert_bool_to_enabled IsMultiRegionTrail}}
  • Management Events: {{convert_bool_to_enabled ManagementEventsEnabled}}
  • Data Events: {{convert_bool_to_enabled DataEventsEnabled}}
  • Include Global Services: @@ -28,7 +28,8 @@

    Information

  • Destination S3 Bucket Name: {{getValueAt 'services.s3.buckets' bucket_id 'name'}}/{{S3KeyPrefix}}
  • Log File Validation Enabled: {{convert_bool_to_enabled LogFileValidationEnabled}}
  • -
  • KMS Key: {{#if KmsKeyId}} true {{else}} false {{/if}}
  • +
  • KMS Key: {{#if KmsKeyId}} true {{else}} false {{/if}}
  • +
  • Latest CloudWatch Logs Delivery Time: {{format_date LatestCloudWatchLogsDeliveryTime}}
  • {{/unless}} diff --git a/ScoutSuite/output/data/html/partials/aws/services.config.regions.html b/ScoutSuite/output/data/html/partials/aws/services.config.regions.html index 9c59be20b..bc2d48891 100644 --- a/ScoutSuite/output/data/html/partials/aws/services.config.regions.html +++ b/ScoutSuite/output/data/html/partials/aws/services.config.regions.html @@ -7,7 +7,7 @@

    {{name}}

    Information

      -
    • Configured: +
    • AWS Config Recorder enabled: {{#ifPositive recorders_count}}true{{else}}false{{/ifPositive}} diff --git a/ScoutSuite/output/data/html/partials/aws/services.kms.regions.id.keys.html b/ScoutSuite/output/data/html/partials/aws/services.kms.regions.id.keys.html index c06c5b44b..e69ae6c66 100644 --- a/ScoutSuite/output/data/html/partials/aws/services.kms.regions.id.keys.html +++ b/ScoutSuite/output/data/html/partials/aws/services.kms.regions.id.keys.html @@ -13,7 +13,7 @@

      Information

    • Description: {{value_or_none description}}
    • Creation Date: {{format_date creation_date}}
    • Status: {{convert_bool_to_enabled key_enabled}}
    • -
    • Rotation: {{convert_bool_to_enabled rotation_enabled}}
    • +
    • Rotation: {{convert_bool_to_enabled rotation_enabled}}
    • Origin: {{value_or_none origin}}
    • Key Manager: {{value_or_none key_manager}}
    diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-cloudwatch-integration.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-cloudwatch-integration.json new file mode 100644 index 000000000..7571fff78 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-cloudwatch-integration.json @@ -0,0 +1,22 @@ +{ + "description": "Trail is not integrated with CloudWatch", + "rationale": "The lack of integration with CloudWatch hinders ral-time and historic activity logging as well as not allowing the configuration of alarms and notifications for anomalous account activity.", + "remediation": "Configure each Trail to have a CloudWatch Logs group attached", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.4"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.4"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.4"} + ], + "dashboard_name": "Trails", + "path": "cloudtrail.regions.id.trails.id", + "display_path": "cloudtrail.regions.id.trails.id", + "conditions": [ "and", + [ "cloudtrail.regions.id.trails.id.", "withKey", "LatestCloudWatchLogsDeliveryTime" ], + [ + "or", + [ "cloudtrail.regions.id.trails.id.LatestCloudWatchLogsDeliveryTime", "null", "" ], + [ "cloudtrail.regions.id.trails.id.LatestCloudWatchLogsDeliveryTime", "olderThan", ["1", "days"] ] + ] + ], + "id_suffix": "TrailCloudwatchNoIntegration" +} diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-encryption-with-kms.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-encryption-with-kms.json new file mode 100644 index 000000000..ccf6ac041 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-encryption-with-kms.json @@ -0,0 +1,19 @@ +{ + "description": "CloudTrail logs not encrypted with KMS CMKs", + "rationale": "Not encrypting CloudTrail logs with SSE-KMS affects the confidentiality of the log data.", + "remediation": "Ensure each Trail is encrypted with a KMS key", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.7"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.7"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.7"} + ], + "references": ["https://docs.aws.amazon.com/awscloudtrail/latest/userguide/encrypting-cloudtrail-log-files-with-aws-kms.html"], + "dashboard_name": "Trails", + "path": "cloudtrail.regions.id.trails.id", + "display_path": "cloudtrail.regions.id.trails.id", + "conditions": [ "and", + [ "cloudtrail.regions.id.trails.id.", "withKey", "KMSKeyId" ], + [ "cloudtrail.regions.id.trails.id.KMSKeyId", "null", "" ] + ], + "id_suffix": "NoKMSEncryption" +} diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-log-file-validation.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-log-file-validation.json index 087080fcd..b77e64dd4 100644 --- a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-log-file-validation.json +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-log-file-validation.json @@ -1,8 +1,15 @@ { - "description": "Log file validation disabled", - "rationale": "Description:

    The lack of log file validation prevents from verifying the integrity of the log files.", - "path": "cloudtrail.regions.id.trails.id", + "description": "Log file validation is disabled", + "rationale": "The lack of log file validation prevents from verifying the integrity of CloudTrail log files.", + "remediation": "Ensure that each Trail has Enable log file validation set to Yes", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.2"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.2"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.2"} + ], + "references": ["https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-intro.html"], "dashboard_name": "Trails", + "path": "cloudtrail.regions.id.trails.id", "display_path": "cloudtrail.regions.id.trails.id", "conditions": [ "and", [ "cloudtrail.regions.id.trails.id.", "withKey", "LogFileValidationEnabled" ], diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json index f2ac77f76..14659ec16 100644 --- a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json @@ -1,11 +1,22 @@ { "description": "Logging disabled", - "rationale": "Description:

    Logging is disabled for a given Trail. Depending on the configuration, logs for important API activity may be missing.", - "path": "cloudtrail.regions.id.trails.id", + "rationale": "Logging is disabled for a given Trail. Depending on the configuration, logs for important API activity may be missing.", + "remediation": "Configure all Trails to enable Logging, set Apply trail to all regions and ensure that Read/Write Events are set to ALL", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.1"} + ], + "references": ["https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html"], "dashboard_name": "Trails", + "path": "cloudtrail.regions.id.trails.id", "conditions": [ "and", [ "cloudtrail.regions.id.trails.id.", "withKey", "IsLogging" ], - [ "cloudtrail.regions.id.trails.id.IsLogging", "false", "" ] + [ + "or", + [ "cloudtrail.regions.id.trails.id.IsLogging", "false", "" ], + [ "cloudtrail.regions.id.trails.id.IsMultiRegionTrail", "false", "" ] + ] ], - "id_suffix": "IsLogging" + "class_suffix": "IsLogging" } diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json new file mode 100644 index 000000000..d02387330 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json @@ -0,0 +1,19 @@ +{ + "description": "CloudTrail S3 bucket access logging is disabled", + "rationale": "The lack of S3 bucket logging prevents log information to be accessed in security and incident response workflows.", + "remediation": "Ensure that critical S3 buckets have Logging enabled", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.6"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.6"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.6"} + ], + "dashboard_name": "Buckets", + "path": "s3.buckets.id", + "conditions": [ "and", + [ "s3.buckets.id.policy.id.", "withKey", "Statement" ], + [ "s3.buckets.id.policy.id.Statement.id.", "withKey", "Principal" ], + [ "s3.buckets.id.policy.id.Statement.id.Principal.Service", "containString", "cloudtrail.amazonaws.com" ], + [ "s3.buckets.id.logging", "equal", "Disabled" ] + ], + "id_suffix": "logging" +} diff --git a/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json b/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json index 88a4f48f0..daa9ad228 100644 --- a/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json +++ b/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json @@ -1,8 +1,14 @@ { - "description": "Not configured", - "rationale": "Description:

    No Config recorders are configured, which means that changes in AWS resource configuration are not logged.", - "path": "config.regions.id", + "description": "AWS Config not enabled", + "rationale": "No AWS Config recorders are configured, which means that changes in AWS resource configuration are not logged. This hinders security analysis, resource change tracking and compliance auditing.", + "remediation": "Enable AWS Config in all regions, define the resources you want to record in each region and include global resources (IAM resources)", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.5"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.5"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.5"} + ], "dashboard_name": "Regions", + "path": "config.regions.id", "conditions": [ "and", [ "recorders_count", "equal", "0" ] ], diff --git a/ScoutSuite/providers/aws/rules/findings/kms-key-rotation-disabled.json b/ScoutSuite/providers/aws/rules/findings/kms-key-rotation-disabled.json new file mode 100644 index 000000000..f6d73483f --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/kms-key-rotation-disabled.json @@ -0,0 +1,16 @@ +{ + "description": "CMK rotation is disabled", + "rationale": "Rotating encryption keys helps reduce the potential impact of a compromised key.", + "remediation": "For every Customer-created Master Key (CMK) ensure that Rotate this key every year is enabled", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.8"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.8"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.8"} + ], + "dashboard_name": "KMS", + "path": "kms.regions.id.keys.id", + "conditions": [ "and", + [ "kms.regions.id.keys.id.rotation_enabled", "false", "" ] + ], + "id_suffix": "CMKRotationDisabled" +} diff --git a/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json b/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json index 723886bf4..35ee1e281 100644 --- a/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json +++ b/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json @@ -1,6 +1,8 @@ { + "description": "S3 bucket access logging is disabled", + "rationale": "The lack of S3 bucket logging prevents log information to be accessed in security and incident response workflows.", + "remediation": "Ensure that S3 buckets have Logging enabled", "dashboard_name": "Buckets", - "description": "Bucket access logging disabled", "path": "s3.buckets.id", "conditions": [ "and", [ "s3.buckets.id.logging", "equal", "Disabled" ] diff --git a/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json b/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json index d3b239dba..a54a95cdc 100644 --- a/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json +++ b/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json @@ -1,11 +1,16 @@ { "description": "Subnet without a flow log", - "rationale": "Description:

    Flow logs enable the investigatation of incidents involving unauthorized network traffic, such as an attacker exfiltrating data or pivoting to other hosts.

    References:
    • CIS Amazon Web Services Foundations v1.2.0 2.9
    ", - "path": "vpc.regions.id.vpcs.id.subnets.id", + "rationale": "Flow logs enable the investigation of incidents involving unauthorized network traffic, such as an attacker exfiltrating data or pivoting to other hosts.", + "remediation": "Create a flow log for each subnet.", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.9"} + ], + "references": ["https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html"], "dashboard_name": "Subnets", - "id_suffix": "NoFlowLog", + "path": "vpc.regions.id.vpcs.id.subnets.id", "conditions": [ "or", [ "this", "withoutKey", "flow_logs"], [ "flow_logs", "empty", "" ] - ] + ], + "id_suffix": "NoFlowLog" } diff --git a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json index 0760f7456..88f9b97f0 100644 --- a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json +++ b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json @@ -198,16 +198,82 @@ ], "cloudtrail-no-logging.json": [ { - "comment": "Recommendation2,1 (part 2/2)", + "comment": "Recommendation 2.1 (Part 1/2)", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true } ], "cloudtrail-not-configured.json": [ { - "comment": "Recommendation2.1 (part 1/2)", + "comment": "Recommendation 2.1 (part 2/2)", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true + } + ], + "cloudtrail-no-log-file-validation.json": [ + { + "comment": "Recommendation 2.2", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "TODO_2.json": [ + { + "comment": "Recommendation 2.3", + "enabled": false, + "level": "danger", + "scored": true + } + ], + "cloudtrail-no-cloudwatch-integration.json": [ + { + "comment": "Recommendation 2.4", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "config-recorder-not-configured.json": [ + { + "comment": "Recommendation 2.5", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "s3-bucket-no-logging.json": [ + { + "comment": "Recommendation 2.6", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "cloudtrail-no-encryption-with-kms.json": [ + { + "comment": "Recommendation 2.7", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "kms-key-rotation-disabled.json": [ + { + "comment": "Recommendation 2.8", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "vpc-subnet-without-flow-log.json": [ + { + "comment": "Recommendation 2.9", + "enabled": true, + "level": "danger", + "scored": true } ], "ec2-default-security-group-with-rules.json": [ From fc02a86171b88c157f6fc68b9f92d9f0d0963741 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Tue, 24 Mar 2020 17:44:36 +0100 Subject: [PATCH 011/312] Completed all Networking rules for CIS Benchmark 1.2.0 --- ScoutSuite/providers/aws/facade/ec2.py | 8 ++++ .../providers/aws/resources/vpc/base.py | 4 +- .../aws/resources/vpc/route_tables.py | 19 +++++++++ .../ec2-default-security-group-in-use.json | 10 ++++- ...ec2-default-security-group-with-rules.json | 14 +++++-- .../ec2-route-tables-full-peering.json | 16 ++++++++ .../ec2-security-group-opens-port-to-all.json | 16 ++++++-- .../findings/vpc-subnet-without-flow-log.json | 2 + .../aws/rules/rulesets/cis-1.2.0.json | 41 ++++++++++++++----- 9 files changed, 109 insertions(+), 21 deletions(-) create mode 100644 ScoutSuite/providers/aws/resources/vpc/route_tables.py create mode 100644 ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json diff --git a/ScoutSuite/providers/aws/facade/ec2.py b/ScoutSuite/providers/aws/facade/ec2.py index 7eb73e60c..124ba4a9f 100644 --- a/ScoutSuite/providers/aws/facade/ec2.py +++ b/ScoutSuite/providers/aws/facade/ec2.py @@ -195,3 +195,11 @@ async def get_peering_connections(self, region): except Exception as e: print_exception('Failed to get peering connections: {}'.format(e)) return [] + + async def get_route_tables(self, region): + try: + route_tables = await AWSFacadeUtils.get_all_pages('ec2', region, self.session, 'describe_route_tables', 'RouteTables') + return route_tables + except Exception as e: + print_exception('Failed to get route tables: {}'.format(e)) + return [] \ No newline at end of file diff --git a/ScoutSuite/providers/aws/resources/vpc/base.py b/ScoutSuite/providers/aws/resources/vpc/base.py index a35c3cc9d..f3eff169c 100644 --- a/ScoutSuite/providers/aws/resources/vpc/base.py +++ b/ScoutSuite/providers/aws/resources/vpc/base.py @@ -7,6 +7,7 @@ from .flow_logs import FlowLogs from .vpcs import RegionalVpcs from .peering_connections import PeeringConnections +from .route_tables import RouteTables known_cidrs = {'0.0.0.0/0': 'All'} aws_ip_ranges = {} @@ -16,7 +17,8 @@ class VPC(Regions): _children = [ (RegionalVpcs, 'vpcs'), (FlowLogs, 'flow_logs'), - (PeeringConnections, 'peering_connections'), + (PeeringConnections, 'peering_connections') + # (RouteTables, 'route_tables') ] def __init__(self, facade: AWSFacade): diff --git a/ScoutSuite/providers/aws/resources/vpc/route_tables.py b/ScoutSuite/providers/aws/resources/vpc/route_tables.py new file mode 100644 index 000000000..5699e4bb4 --- /dev/null +++ b/ScoutSuite/providers/aws/resources/vpc/route_tables.py @@ -0,0 +1,19 @@ +from ScoutSuite.providers.aws.facade.base import AWSFacade +from ScoutSuite.providers.aws.resources.base import AWSResources + + +class RouteTables(AWSResources): + def __init__(self, facade: AWSFacade, region: str): + super().__init__(facade) + self.facade = facade + self.region = region + + async def fetch_all(self): + raw_route_tables = await self.facade.ec2.get_route_tables(self.region) + for raw_route_table in raw_route_tables: + id, route_table = self._parse_route_tables(raw_route_table) + self[id] = route_table + + def _parse_route_tables(self, raw_route_table): + pass + # return route_table_id, raw_route_tables diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json index 70218aaf8..028b84bda 100644 --- a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json @@ -1,11 +1,17 @@ { "description": "Default security groups in use", - "path": "ec2.regions.id.vpcs.id.security_groups.id", + "rationale": "Resources in default security groups may be configured to allow all traffic.", + "remediation": "Ensure resources are not within default security groups. Instead, create a custom security group tailored to each resource needs.", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.4"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.4"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.3"} + ], "dashboard_name": "Security groups", + "path": "ec2.regions.id.vpcs.id.security_groups.id", "conditions": [ "and", [ "ec2.regions.id.vpcs.id.security_groups.id.name", "equal", "default" ], [ "ec2.regions.id.vpcs.id.security_groups.id.", "withKey", "used_by" ] - ], "id_suffix": "default_in_use" } diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json index afa6c1a7a..8161af833 100644 --- a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json @@ -1,12 +1,18 @@ { "description": "Non-empty rulesets for default security groups", - "path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id", + "rationale": "Configuring all VPC default security groups to restrict all traffic will encourage least privilege principle.", + "remediation": "Ensure the default security group of every VPC restricts all traffic", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.4"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.4"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.3"} + ], "dashboard_name": "Rulesets", + "path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id", + "display_path": "ec2.regions.id.vpcs.id.security_groups.id", "conditions": [ "and", [ "ec2.regions.id.vpcs.id.security_groups.id.name", "equal", "default" ], [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols", "notEmpty", "" ] - ], - "id_suffix": "default_with_rules", - "display_path": "ec2.regions.id.vpcs.id.security_groups.id" + "id_suffix": "default_with_rules" } diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json b/ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json new file mode 100644 index 000000000..ffb1516db --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json @@ -0,0 +1,16 @@ +{ + "description": "Routing table with VPC peering", + "rationale": "Being highly selective in peering routing tables minimizes the impact of breach as resources outside of these routes are inaccessible to the peered VPC.", + "remediation": "Ensure route tables contain the least number of subnets or hosts as is required to accomplish the purpose for peering", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.5"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.4"} + ], + "dashboard_name": "Rulesets", + "path": "vpc.regions.id.peering_connections.id", + "display_path": "vpc.regions.id.peering_connections.peering_connections.id", + "conditions": [ "and", + [ "vpc.regions.id.peering_connections.peering_connection_id", "notNull", "" ] + ], + "id_suffix": "default_with_rules" +} diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-port-to-all.json b/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-port-to-all.json index 247682c5a..fa41cad27 100644 --- a/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-port-to-all.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-port-to-all.json @@ -1,14 +1,24 @@ { "arg_names": [ "Network transport protocol" ], "key": "ec2-security-group-opens-_ARG_0_-port-to-all", - "description": "_ARG_0_ port open to all", + "description": "Port _ARG_0_ open to all", + "rationale": "Open ports increase the server's exposure to risk.", + "remediation": "Remove the inbound rules that expose open ports", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.2"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.2"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.2"} + ], "dashboard_name": "Rules", "path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id.cidrs.id.CIDR", "display_path": "ec2.regions.id.vpcs.id.security_groups.id", "conditions": [ "and", [ "_INCLUDE_(conditions/cidr-is-all.json)", "", ""], [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id", "equal", "ingress" ], - [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id", "equal", "_ARG_0_" ], - [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id", "containNoneOf", [ "22", "80", "443", "1433", "1521", "3306", "3389", "5432", "27017" ] ] + [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id", "equal", "_ARG_1_" ], + [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id", "equal", "_ARG_2_" ] ] } diff --git a/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json b/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json index a54a95cdc..b7dbb6e55 100644 --- a/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json +++ b/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json @@ -3,6 +3,8 @@ "rationale": "Flow logs enable the investigation of incidents involving unauthorized network traffic, such as an attacker exfiltrating data or pivoting to other hosts.", "remediation": "Create a flow log for each subnet.", "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.3"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.3"}, {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.9"} ], "references": ["https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html"], diff --git a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json index 88f9b97f0..3577423f2 100644 --- a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json +++ b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json @@ -276,13 +276,6 @@ "scored": true } ], - "ec2-default-security-group-with-rules.json": [ - { - "comment": "Recommendation4.4", - "enabled": true, - "level": "warning" - } - ], "ec2-security-group-opens-known-port-to-all.json": [ { "args": [ @@ -290,9 +283,10 @@ "TCP", "22" ], - "comment": "Recommendation4.1", + "comment": "Recommendation 4.1", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true }, { "args": [ @@ -300,9 +294,34 @@ "TCP", "3389" ], - "comment": "Recommendation4.2", + "comment": "Recommendation 4.2", "enabled": true, - "level": "danger" + "level": "danger", + "scored": true + } + ], + "ec2-default-security-group-with-rules.json": [ + { + "comment": "Recommendation 4.3 (Part 1/2)", + "enabled": true, + "level": "danger", + "scored": "true" + } + ], + "ec2-default-security-group-in-use.json": [ + { + "comment": "Recommendation 4.3 (Part 2/2)", + "enabled": true, + "level": "danger", + "scored": "true" + } + ], + "ec2-route-tables-full-peering.json": [ + { + "comment": "Recommendation 4.4 TODO", + "enabled": false, + "level": "warning", + "scored": "false" } ] } From a708f37e660003b531fbc411f3bcdd2b4ab46714 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Tue, 24 Mar 2020 17:56:31 +0100 Subject: [PATCH 012/312] Restored EC2 finding edited by error and updated the format of the correct one --- ...2-security-group-opens-known-port-to-all.json | 12 +++++++++++- .../ec2-security-group-opens-port-to-all.json | 16 +++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-known-port-to-all.json b/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-known-port-to-all.json index 18d6b4ed0..5314c16f0 100644 --- a/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-known-port-to-all.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-known-port-to-all.json @@ -1,7 +1,17 @@ { "arg_names": [ "Network protocol name", "Transport protocol name", "Port number" ], "key": "ec2-security-group-opens-_ARG_0_-port-to-all", - "description": "_ARG_0_ port open to all", + "description": "Port _ARG_0_ open to all", + "rationale": "Open ports increase the server's exposure to risk.", + "remediation": "Remove the inbound rules that expose open ports", + "compliance": [ + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.2"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.2"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.1"}, + {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.2"} + ], "dashboard_name": "Rules", "path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id.cidrs.id.CIDR", "display_path": "ec2.regions.id.vpcs.id.security_groups.id", diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-port-to-all.json b/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-port-to-all.json index fa41cad27..247682c5a 100644 --- a/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-port-to-all.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-port-to-all.json @@ -1,24 +1,14 @@ { "arg_names": [ "Network transport protocol" ], "key": "ec2-security-group-opens-_ARG_0_-port-to-all", - "description": "Port _ARG_0_ open to all", - "rationale": "Open ports increase the server's exposure to risk.", - "remediation": "Remove the inbound rules that expose open ports", - "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.2"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.2"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.2"} - ], + "description": "_ARG_0_ port open to all", "dashboard_name": "Rules", "path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id.cidrs.id.CIDR", "display_path": "ec2.regions.id.vpcs.id.security_groups.id", "conditions": [ "and", [ "_INCLUDE_(conditions/cidr-is-all.json)", "", ""], [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id", "equal", "ingress" ], - [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id", "equal", "_ARG_1_" ], - [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id", "equal", "_ARG_2_" ] + [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id", "equal", "_ARG_0_" ], + [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id", "containNoneOf", [ "22", "80", "443", "1433", "1521", "3306", "3389", "5432", "27017" ] ] ] } From 5b1f148bf8f758561a5cb0b5cede54b97c04afa4 Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 8 Apr 2020 11:44:31 +0200 Subject: [PATCH 013/312] Restore fix --- .../providers/aws/resources/iam/credentialreports.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ScoutSuite/providers/aws/resources/iam/credentialreports.py b/ScoutSuite/providers/aws/resources/iam/credentialreports.py index bea8a84ad..3331d6122 100755 --- a/ScoutSuite/providers/aws/resources/iam/credentialreports.py +++ b/ScoutSuite/providers/aws/resources/iam/credentialreports.py @@ -10,9 +10,8 @@ async def fetch_all(self): self[name] = resource def _parse_credential_reports(self, raw_credential_report): - user_id = raw_credential_report['user'] - raw_credential_report['name'] = user_id - raw_credential_report['id'] = user_id + raw_credential_report['id'] = get_non_provider_id(raw_credential_report['user']) + raw_credential_report['name'] = raw_credential_report['user'] raw_credential_report['password_enabled'] = raw_credential_report['password_enabled'] raw_credential_report['password_last_used'] = self._sanitize_date(raw_credential_report['password_last_used']) raw_credential_report['password_last_changed'] =\ @@ -30,7 +29,7 @@ def _parse_credential_reports(self, raw_credential_report): raw_credential_report['last_used'] = self._compute_last_used(raw_credential_report) raw_credential_report['cert_1_active'] = raw_credential_report['cert_1_active'] raw_credential_report['cert_2_active'] = raw_credential_report['cert_2_active'] - return get_non_provider_id(user_id), raw_credential_report + return raw_credential_report['id'], raw_credential_report @staticmethod def _sanitize_date(date): From c2ab2612a69e866fdb123fa6c4e7de3e65a6117f Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 8 Apr 2020 11:45:45 +0200 Subject: [PATCH 014/312] Format findings --- .../cloudtrail-no-cloudwatch-integration.json | 48 +++++++-- .../cloudtrail-no-encryption-with-kms.json | 43 ++++++-- .../cloudtrail-no-log-file-validation.json | 43 ++++++-- .../rules/findings/cloudtrail-no-logging.json | 47 ++++++-- .../cloudtrail-s3-bucket-no-logging.json | 49 +++++++-- .../config-recorder-not-configured.json | 31 ++++-- .../ec2-default-security-group-in-use.json | 37 +++++-- ...ec2-default-security-group-with-rules.json | 39 +++++-- .../ec2-route-tables-full-peering.json | 27 +++-- ...ecurity-group-opens-known-port-to-all.json | 77 ++++++++++--- ...managed-policy-allows-full-privileges.json | 37 +++++-- .../rules/findings/iam-no-support-role.json | 23 +++- ...-password-policy-expiration-threshold.json | 47 ++++++-- .../iam-password-policy-minimum-length.json | 39 +++++-- ...password-policy-no-lowercase-required.json | 35 ++++-- ...am-password-policy-no-number-required.json | 35 ++++-- ...am-password-policy-no-symbol-required.json | 35 ++++-- ...password-policy-no-uppercase-required.json | 35 ++++-- .../iam-password-policy-reuse-enabled.json | 35 ++++-- .../findings/iam-root-account-no-mfa.json | 59 +++++++--- .../iam-root-account-used-recently.json | 50 +++++++-- .../iam-root-account-with-active-keys.json | 47 ++++++-- .../iam-unused-credentials-not-disabled.json | 101 +++++++++++++++--- .../findings/iam-user-no-key-rotation.json | 53 ++++++--- ...-user-unused-access-key-initial-setup.json | 43 ++++++-- .../findings/iam-user-with-policies.json | 42 ++++++-- .../rules/findings/iam-user-without-mfa.json | 43 ++++++-- .../findings/kms-key-rotation-disabled.json | 31 ++++-- .../rules/findings/s3-bucket-no-logging.json | 13 ++- .../findings/vpc-subnet-without-flow-log.json | 41 +++++-- 30 files changed, 1007 insertions(+), 278 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-cloudwatch-integration.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-cloudwatch-integration.json index 7571fff78..4c309de02 100644 --- a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-cloudwatch-integration.json +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-cloudwatch-integration.json @@ -1,22 +1,50 @@ { - "description": "Trail is not integrated with CloudWatch", + "description": "Trail Is Not Integrated with CloudWatch", "rationale": "The lack of integration with CloudWatch hinders ral-time and historic activity logging as well as not allowing the configuration of alarms and notifications for anomalous account activity.", "remediation": "Configure each Trail to have a CloudWatch Logs group attached", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.4"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.4"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.4"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "2.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "2.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.4" + } ], "dashboard_name": "Trails", - "path": "cloudtrail.regions.id.trails.id", "display_path": "cloudtrail.regions.id.trails.id", - "conditions": [ "and", - [ "cloudtrail.regions.id.trails.id.", "withKey", "LatestCloudWatchLogsDeliveryTime" ], + "path": "cloudtrail.regions.id.trails.id", + "conditions": [ + "and", + [ + "cloudtrail.regions.id.trails.id.", + "withKey", + "LatestCloudWatchLogsDeliveryTime" + ], [ "or", - [ "cloudtrail.regions.id.trails.id.LatestCloudWatchLogsDeliveryTime", "null", "" ], - [ "cloudtrail.regions.id.trails.id.LatestCloudWatchLogsDeliveryTime", "olderThan", ["1", "days"] ] + [ + "cloudtrail.regions.id.trails.id.LatestCloudWatchLogsDeliveryTime", + "null", + "" + ], + [ + "cloudtrail.regions.id.trails.id.LatestCloudWatchLogsDeliveryTime", + "olderThan", + [ + "1", + "days" + ] + ] ] ], "id_suffix": "TrailCloudwatchNoIntegration" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-encryption-with-kms.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-encryption-with-kms.json index ccf6ac041..c78cca5f7 100644 --- a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-encryption-with-kms.json +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-encryption-with-kms.json @@ -1,19 +1,42 @@ { - "description": "CloudTrail logs not encrypted with KMS CMKs", + "description": "CloudTrail Logs Not Encrypted with KMS CMKs", "rationale": "Not encrypting CloudTrail logs with SSE-KMS affects the confidentiality of the log data.", "remediation": "Ensure each Trail is encrypted with a KMS key", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.7"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.7"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.7"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "2.7" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "2.7" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.7" + } + ], + "references": [ + "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/encrypting-cloudtrail-log-files-with-aws-kms.html" ], - "references": ["https://docs.aws.amazon.com/awscloudtrail/latest/userguide/encrypting-cloudtrail-log-files-with-aws-kms.html"], "dashboard_name": "Trails", - "path": "cloudtrail.regions.id.trails.id", "display_path": "cloudtrail.regions.id.trails.id", - "conditions": [ "and", - [ "cloudtrail.regions.id.trails.id.", "withKey", "KMSKeyId" ], - [ "cloudtrail.regions.id.trails.id.KMSKeyId", "null", "" ] + "path": "cloudtrail.regions.id.trails.id", + "conditions": [ + "and", + [ + "cloudtrail.regions.id.trails.id.", + "withKey", + "KMSKeyId" + ], + [ + "cloudtrail.regions.id.trails.id.KMSKeyId", + "null", + "" + ] ], "id_suffix": "NoKMSEncryption" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-log-file-validation.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-log-file-validation.json index b77e64dd4..b46f3f22a 100755 --- a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-log-file-validation.json +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-log-file-validation.json @@ -1,19 +1,42 @@ { - "description": "Log file validation is disabled", + "description": "Log File Validation Is Disabled", "rationale": "The lack of log file validation prevents from verifying the integrity of CloudTrail log files.", "remediation": "Ensure that each Trail has Enable log file validation set to Yes", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.2"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.2"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.2"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "2.2" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "2.2" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.2" + } + ], + "references": [ + "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-intro.html" ], - "references": ["https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-intro.html"], "dashboard_name": "Trails", - "path": "cloudtrail.regions.id.trails.id", "display_path": "cloudtrail.regions.id.trails.id", - "conditions": [ "and", - [ "cloudtrail.regions.id.trails.id.", "withKey", "LogFileValidationEnabled" ], - [ "cloudtrail.regions.id.trails.id.LogFileValidationEnabled", "false", "" ] + "path": "cloudtrail.regions.id.trails.id", + "conditions": [ + "and", + [ + "cloudtrail.regions.id.trails.id.", + "withKey", + "LogFileValidationEnabled" + ], + [ + "cloudtrail.regions.id.trails.id.LogFileValidationEnabled", + "false", + "" + ] ], "id_suffix": "LogFileValidationDisabled" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json index 14659ec16..db884bbce 100755 --- a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json @@ -1,22 +1,49 @@ { - "description": "Logging disabled", + "description": "Logging Disabled", "rationale": "Logging is disabled for a given Trail. Depending on the configuration, logs for important API activity may be missing.", "remediation": "Configure all Trails to enable Logging, set Apply trail to all regions and ensure that Read/Write Events are set to ALL", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.1"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "2.1" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "2.1" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.1" + } + ], + "references": [ + "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html" ], - "references": ["https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html"], "dashboard_name": "Trails", "path": "cloudtrail.regions.id.trails.id", - "conditions": [ "and", - [ "cloudtrail.regions.id.trails.id.", "withKey", "IsLogging" ], + "conditions": [ + "and", + [ + "cloudtrail.regions.id.trails.id.", + "withKey", + "IsLogging" + ], [ "or", - [ "cloudtrail.regions.id.trails.id.IsLogging", "false", "" ], - [ "cloudtrail.regions.id.trails.id.IsMultiRegionTrail", "false", "" ] + [ + "cloudtrail.regions.id.trails.id.IsLogging", + "false", + "" + ], + [ + "cloudtrail.regions.id.trails.id.IsMultiRegionTrail", + "false", + "" + ] ] ], "class_suffix": "IsLogging" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json index d02387330..74f121ccf 100644 --- a/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json @@ -1,19 +1,48 @@ { - "description": "CloudTrail S3 bucket access logging is disabled", + "description": "CloudTrail S3 Bucket Access Logging Is Disabled", "rationale": "The lack of S3 bucket logging prevents log information to be accessed in security and incident response workflows.", "remediation": "Ensure that critical S3 buckets have Logging enabled", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.6"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.6"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.6"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "2.6" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "2.6" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.6" + } ], "dashboard_name": "Buckets", "path": "s3.buckets.id", - "conditions": [ "and", - [ "s3.buckets.id.policy.id.", "withKey", "Statement" ], - [ "s3.buckets.id.policy.id.Statement.id.", "withKey", "Principal" ], - [ "s3.buckets.id.policy.id.Statement.id.Principal.Service", "containString", "cloudtrail.amazonaws.com" ], - [ "s3.buckets.id.logging", "equal", "Disabled" ] + "conditions": [ + "and", + [ + "s3.buckets.id.policy.id.", + "withKey", + "Statement" + ], + [ + "s3.buckets.id.policy.id.Statement.id.", + "withKey", + "Principal" + ], + [ + "s3.buckets.id.policy.id.Statement.id.Principal.Service", + "containString", + "cloudtrail.amazonaws.com" + ], + [ + "s3.buckets.id.logging", + "equal", + "Disabled" + ] ], "id_suffix": "logging" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json b/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json index daa9ad228..3a1298db3 100755 --- a/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json +++ b/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json @@ -1,16 +1,33 @@ { - "description": "AWS Config not enabled", + "description": "AWS Config Not Enabled", "rationale": "No AWS Config recorders are configured, which means that changes in AWS resource configuration are not logged. This hinders security analysis, resource change tracking and compliance auditing.", "remediation": "Enable AWS Config in all regions, define the resources you want to record in each region and include global resources (IAM resources)", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.5"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.5"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.5"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "2.5" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "2.5" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.5" + } ], "dashboard_name": "Regions", "path": "config.regions.id", - "conditions": [ "and", - [ "recorders_count", "equal", "0" ] + "conditions": [ + "and", + [ + "recorders_count", + "equal", + "0" + ] ], "id_suffix": "NotConfigured" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json index 028b84bda..4bbc3eaa6 100755 --- a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json @@ -1,17 +1,38 @@ { - "description": "Default security groups in use", + "description": "Default Security Groups in Use", "rationale": "Resources in default security groups may be configured to allow all traffic.", "remediation": "Ensure resources are not within default security groups. Instead, create a custom security group tailored to each resource needs.", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.4"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.4"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.3"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "4.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "4.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "4.3" + } ], "dashboard_name": "Security groups", "path": "ec2.regions.id.vpcs.id.security_groups.id", - "conditions": [ "and", - [ "ec2.regions.id.vpcs.id.security_groups.id.name", "equal", "default" ], - [ "ec2.regions.id.vpcs.id.security_groups.id.", "withKey", "used_by" ] + "conditions": [ + "and", + [ + "ec2.regions.id.vpcs.id.security_groups.id.name", + "equal", + "default" + ], + [ + "ec2.regions.id.vpcs.id.security_groups.id.", + "withKey", + "used_by" + ] ], "id_suffix": "default_in_use" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json index 8161af833..8061c412c 100755 --- a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json @@ -1,18 +1,39 @@ { - "description": "Non-empty rulesets for default security groups", + "description": "Non-empty Rulesets for Default Security Groups", "rationale": "Configuring all VPC default security groups to restrict all traffic will encourage least privilege principle.", "remediation": "Ensure the default security group of every VPC restricts all traffic", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.4"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.4"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.3"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "4.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "4.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "4.3" + } ], "dashboard_name": "Rulesets", - "path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id", "display_path": "ec2.regions.id.vpcs.id.security_groups.id", - "conditions": [ "and", - [ "ec2.regions.id.vpcs.id.security_groups.id.name", "equal", "default" ], - [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols", "notEmpty", "" ] + "path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id", + "conditions": [ + "and", + [ + "ec2.regions.id.vpcs.id.security_groups.id.name", + "equal", + "default" + ], + [ + "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols", + "notEmpty", + "" + ] ], "id_suffix": "default_with_rules" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json b/ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json index ffb1516db..5352a6b7d 100644 --- a/ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json @@ -1,16 +1,29 @@ { - "description": "Routing table with VPC peering", + "description": "Routing Table with VPC Peering", "rationale": "Being highly selective in peering routing tables minimizes the impact of breach as resources outside of these routes are inaccessible to the peered VPC.", "remediation": "Ensure route tables contain the least number of subnets or hosts as is required to accomplish the purpose for peering", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.5"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.4"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "4.5" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "4.4" + } ], "dashboard_name": "Rulesets", - "path": "vpc.regions.id.peering_connections.id", "display_path": "vpc.regions.id.peering_connections.peering_connections.id", - "conditions": [ "and", - [ "vpc.regions.id.peering_connections.peering_connection_id", "notNull", "" ] + "path": "vpc.regions.id.peering_connections.id", + "conditions": [ + "and", + [ + "vpc.regions.id.peering_connections.peering_connection_id", + "notNull", + "" + ] ], "id_suffix": "default_with_rules" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-known-port-to-all.json b/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-known-port-to-all.json index 5314c16f0..26b5239bb 100755 --- a/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-known-port-to-all.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-known-port-to-all.json @@ -1,24 +1,69 @@ { - "arg_names": [ "Network protocol name", "Transport protocol name", "Port number" ], - "key": "ec2-security-group-opens-_ARG_0_-port-to-all", - "description": "Port _ARG_0_ open to all", + "description": "Port _ARG_0_ Open to All", "rationale": "Open ports increase the server's exposure to risk.", "remediation": "Remove the inbound rules that expose open ports", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.2"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.2"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "4.2"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "4.1" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "4.2" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "4.1" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "4.2" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "4.1" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "4.2" + } ], "dashboard_name": "Rules", - "path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id.cidrs.id.CIDR", "display_path": "ec2.regions.id.vpcs.id.security_groups.id", - "conditions": [ "and", - [ "_INCLUDE_(conditions/cidr-is-all.json)", "", ""], - [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id", "equal", "ingress" ], - [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id", "equal", "_ARG_1_" ], - [ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id", "equal", "_ARG_2_" ] + "path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id.cidrs.id.CIDR", + "conditions": [ + "and", + [ + "_INCLUDE_(conditions/cidr-is-all.json)", + "", + "" + ], + [ + "ec2.regions.id.vpcs.id.security_groups.id.rules.id", + "equal", + "ingress" + ], + [ + "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id", + "equal", + "_ARG_1_" + ], + [ + "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id", + "equal", + "_ARG_2_" + ] + ], + "key": "ec2-security-group-opens-_ARG_0_-port-to-all", + "arg_names": [ + "Network protocol name", + "Transport protocol name", + "Port number" ] -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json index 983ea84ed..599b8e121 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json @@ -1,16 +1,39 @@ { - "description": "Managed policy allows full administrative privileges", + "description": "Managed Policy Allows Full Administrative Privileges", "rationale": "Providing full administrative privileges instead of restricting to the minimum set of permissions that the user is required to do exposes the resources to potentially unwanted actions.", "remediation": "Ensure no managed policies are configured with Effect:Allow, Action:* and Resource:*", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.24"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.22"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.24" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.22" + } ], "dashboard_name": "Policies", "path": "iam.policies.id", - "conditions": [ "and", - [ "iam.policies.id.PolicyDocument.Statement.id.Effect", "equal", "Allow" ], - [ "iam.policies.id.PolicyDocument.Statement.id.Action", "containAction", "*" ], - [ "iam.policies.id.PolicyDocument.Statement.id.Resource", "containAtLeastOneOf", [ "*" ] ] + "conditions": [ + "and", + [ + "iam.policies.id.PolicyDocument.Statement.id.Effect", + "equal", + "Allow" + ], + [ + "iam.policies.id.PolicyDocument.Statement.id.Action", + "containAction", + "*" + ], + [ + "iam.policies.id.PolicyDocument.Statement.id.Resource", + "containAtLeastOneOf", + [ + "*" + ] + ] ] } \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json b/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json index 34ebda2d7..d0b5fdfe1 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json @@ -1,14 +1,27 @@ { - "description": "No authorized user to manage incidents with AWS Support", + "description": "No Authorized User to Manage Incidents with AWS Support", "rationale": "There should be at least one user authorized to manage incidents with AWS Support.", "remediation": "Attach the AWSSupportAccess to a role or group", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.22"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.20"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.22" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.20" + } ], "dashboard_name": "Policies", "path": "iam.policies.AWSSupportAccess", - "conditions": [ "and", - [ "iam.policies.AWSSupportAccess.attached_to", "notEmpty", "" ] + "conditions": [ + "and", + [ + "iam.policies.AWSSupportAccess.attached_to", + "notEmpty", + "" + ] ] } \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-expiration-threshold.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-expiration-threshold.json index e770ab252..573c932aa 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-expiration-threshold.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-expiration-threshold.json @@ -1,20 +1,45 @@ { - "arg_names": [ "Maximum password age" ], - "description": "Passwords expire after _ARG_0_ days", + "description": "Passwords Expire after _ARG_0_ Days", "rationale": "Reducing passwords lifetime increases account resiliency against brute force login attempts.", "remediation": "Enable password expiration and set the expiration period to 90 days or less", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.11"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.11"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.11"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.11" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.11" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.11" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials"], "dashboard_name": "Password policy", - "path": "iam.password_policy", "display_path": "iam.password_policy.MaxPasswordAge", - "conditions": [ "or", - [ "iam.password_policy.ExpirePasswords", "false", "" ], - [ "iam.password_policy.MaxPasswordAge", "moreThan", "_ARG_0_" ] + "path": "iam.password_policy", + "conditions": [ + "or", + [ + "iam.password_policy.ExpirePasswords", + "false", + "" + ], + [ + "iam.password_policy.MaxPasswordAge", + "moreThan", + "_ARG_0_" + ] + ], + "arg_names": [ + "Maximum password age" ], "id_suffix": "MaxPasswordAge" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-minimum-length.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-minimum-length.json index a0f39adcb..a8344f22f 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-minimum-length.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-minimum-length.json @@ -1,17 +1,38 @@ { - "arg_names": [ "Minimum password length" ], - "description": "Password policy lacks minimum length requirement of _ARG_0_", + "description": "Password Policy Lacks Minimum Length Requirement of _ARG_0_", "rationale": "Requiring passwords to require a minimum length increases account resiliency against brute force login attempts.", "remediation": "Ensure the password policy is configured to require a minimum length", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.9"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.9"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.9"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.9" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.9" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.9" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", "path": "iam.password_policy.MinimumPasswordLength", - "conditions": [ "or", - [ "this", "lessThan", "_ARG_0_" ] + "conditions": [ + "or", + [ + "this", + "lessThan", + "_ARG_0_" + ] + ], + "arg_names": [ + "Minimum password length" ] -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-lowercase-required.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-lowercase-required.json index 53b840591..a191eea3b 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-lowercase-required.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-lowercase-required.json @@ -1,16 +1,35 @@ { - "description": "Password policy lacks lowercase requirement", + "description": "Password Policy Lacks Lowercase Requirement", "rationale": "Requiring passwords to include at least a lowercase letter increases account resiliency against brute force login attempts.", "remediation": "Ensure the password policy is configured to require at least one lowercase letter", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.6"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.6"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.6"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.6" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.6" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.6" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", "path": "iam.password_policy.RequireLowercaseCharacters", - "conditions": [ "or", - [ "this", "false", "" ] + "conditions": [ + "or", + [ + "this", + "false", + "" + ] ] -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-number-required.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-number-required.json index f73c106d8..5e2b6d55e 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-number-required.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-number-required.json @@ -1,16 +1,35 @@ { - "description": "Password policy lacks number requirement", + "description": "Password Policy Lacks Number Requirement", "rationale": "Requiring passwords to include at least one number increases account resiliency against brute force login attempts.", "remediation": "Ensure the password policy is configured to require at least one number", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.8"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.8"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.8"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.8" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.8" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.8" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", "path": "iam.password_policy.RequireNumbers", - "conditions": [ "or", - [ "this", "false", "" ] + "conditions": [ + "or", + [ + "this", + "false", + "" + ] ] -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-symbol-required.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-symbol-required.json index a5e0980ab..f89555856 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-symbol-required.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-symbol-required.json @@ -1,16 +1,35 @@ { - "description": "Password policy lacks symbol requirement", + "description": "Password Policy Lacks Symbol Requirement", "rationale": "Requiring passwords to include at least one symbol increases account resiliency against brute force login attempts.", "remediation": "Ensure the password policy is configured to require at least one symbol", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.7"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.7"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.7"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.7" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.7" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.7" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", "path": "iam.password_policy.RequireSymbols", - "conditions": [ "or", - [ "this", "false", "" ] + "conditions": [ + "or", + [ + "this", + "false", + "" + ] ] -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-uppercase-required.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-uppercase-required.json index d48ca6c22..b1c250410 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-uppercase-required.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-no-uppercase-required.json @@ -1,16 +1,35 @@ { - "description": "Password policy lacks uppercase requirement", + "description": "Password Policy Lacks Uppercase Requirement", "rationale": "Requiring passwords to include at least an uppercase letter increases account resiliency against brute force login attempts.", "remediation": "Ensure the password policy is configured to require at least one uppercase letter", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.5"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.5"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.5"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.5" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.5" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.5" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", "path": "iam.password_policy.RequireUppercaseCharacters", - "conditions": [ "or", - [ "this", "false", "" ] + "conditions": [ + "or", + [ + "this", + "false", + "" + ] ] -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-reuse-enabled.json b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-reuse-enabled.json index cc25f1563..4ecbdcce9 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-password-policy-reuse-enabled.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-password-policy-reuse-enabled.json @@ -1,16 +1,35 @@ { - "description": "Password policy allows the reuse of passwords", + "description": "Password Policy Allows the Reuse of Passwords", "rationale": "Preventing password reuse increases account resiliency against brute force login attempts.", "remediation": "Ensure the password policy is configured to prevent password reuse", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.10"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.10"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.10"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.10" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.10" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.10" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy"], "dashboard_name": "Password policy", "path": "iam.password_policy.PasswordReusePrevention", - "conditions": [ "or", - [ "this", "false", "" ] + "conditions": [ + "or", + [ + "this", + "false", + "" + ] ] -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json index 19982d1cc..76ecd5730 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json @@ -1,21 +1,54 @@ { - "description": "Root account without MFA", + "description": "Root Account without MFA", "rationale": "The root account should have Multi Factor Authentication (MFA) enabled.", "remediation": "Enable MFA for the root account", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.13"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.13"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.14"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.13"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.14"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.13" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.13" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.14" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.13" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.14" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials"], "dashboard_name": "Root account", "path": "iam.credential_reports.id", - "conditions": [ "and", - [ "iam.credential_reports.id.mfa_active", "notTrue", "" ], - [ "iam.credential_reports.id.name", "equal", "" ] + "conditions": [ + "and", + [ + "iam.credential_reports.id.mfa_active", + "notTrue", + "" + ], + [ + "iam.credential_reports.id.name", + "equal", + "" + ] + ], + "keys": [ + "this" ], - "id_suffix": "mfa_active", - "keys": [ "this" ] -} + "id_suffix": "mfa_active" +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json index 88326ec5b..67a028cac 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-used-recently.json @@ -1,19 +1,49 @@ { - "description": "Root account used recently", + "description": "Root Account Used Recently", "rationale": "The use of the root account should be avoided.", "remediation": "Follow the remediation instructions of the Ensure IAM policies are attached only to groups or roles recommendation", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.1"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.1"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.1" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.1" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.1" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users"], "dashboard_name": "Root account", "path": "iam.credential_reports.id", - "conditions": [ "and", - [ "iam.credential_reports.id.password_last_used", "notNull", "" ], - [ "iam.credential_reports.id.password_last_used", "newerThan", ["90", "days"] ], - [ "iam.credential_reports.id.name", "equal", "" ] + "conditions": [ + "and", + [ + "iam.credential_reports.id.password_last_used", + "notNull", + "" + ], + [ + "iam.credential_reports.id.password_last_used", + "newerThan", + [ + "90", + "days" + ] + ], + [ + "iam.credential_reports.id.name", + "equal", + "" + ] ], "id_suffix": "password_last_used" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-with-active-keys.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-with-active-keys.json index 8341c9790..67a909bb1 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-root-account-with-active-keys.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-with-active-keys.json @@ -1,21 +1,48 @@ { - "description": "Root account has active keys", + "description": "Root Account Has Active Keys", "rationale": "AWS root account access keys should be deleted as they provide unrestricted access to the AWS Account.", "remediation": "Delete or disable active root account access keys", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.12"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.12"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.12"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.12" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.12" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.12" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials"], "dashboard_name": "Root account", "path": "iam.credential_reports.id", - "conditions": [ "and", - [ "iam.credential_reports.id.name", "equal", "" ], + "conditions": [ + "and", + [ + "iam.credential_reports.id.name", + "equal", + "" + ], [ "or", - [ "iam.credential_reports.id.access_key_1_active", "true", "" ], - [ "iam.credential_reports.id.access_key_2_active", "true", "" ] + [ + "iam.credential_reports.id.access_key_1_active", + "true", + "" + ], + [ + "iam.credential_reports.id.access_key_2_active", + "true", + "" + ] ] ] -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json b/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json index 27e58b5e1..f53ae41dc 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json @@ -1,43 +1,112 @@ { - "arg_names": [ "Period in days" ], - "description": "Credentials unused for _ARG_0_ days or greater are not disabled", + "description": "Credentials Unused for _ARG_0_ Days or Greater Are Not Disabled", "rationale": "Disabling or removing unnecessary credentials will reduce the window of opportunity for compromised accounts to be used.", "remediation": "Ensure that all credentials (including passwords and access keys) have been used and changed in the last _ARG_0_ days", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.3"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.3"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.3"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.3" + } ], "dashboard_name": "Users", "path": "iam.credential_reports.id", - "conditions": [ "or", + "conditions": [ + "or", [ "and", - [ "iam.credential_reports.id.password_enabled", "true", "" ], + [ + "iam.credential_reports.id.password_enabled", + "true", + "" + ], [ "or", - [ "iam.credential_reports.id.password_last_used", "olderThan", ["_ARG_0_", "days"] ], - [ "iam.credential_reports.id.password_last_changed", "olderThan", ["_ARG_0_", "days"] ] + [ + "iam.credential_reports.id.password_last_used", + "olderThan", + [ + "_ARG_0_", + "days" + ] + ], + [ + "iam.credential_reports.id.password_last_changed", + "olderThan", + [ + "_ARG_0_", + "days" + ] + ] ] ], [ "and", - [ "iam.credential_reports.id.access_key_1_active", "true", "" ], + [ + "iam.credential_reports.id.access_key_1_active", + "true", + "" + ], [ "or", - [ "iam.credential_reports.id.access_key_1_last_used_date", "olderThan", ["_ARG_0_", "days"] ], - [ "iam.credential_reports.id.access_key_1_last_rotated", "olderThan", ["_ARG_0_", "days"] ] + [ + "iam.credential_reports.id.access_key_1_last_used_date", + "olderThan", + [ + "_ARG_0_", + "days" + ] + ], + [ + "iam.credential_reports.id.access_key_1_last_rotated", + "olderThan", + [ + "_ARG_0_", + "days" + ] + ] ] ], [ "and", - [ "iam.credential_reports.id.access_key_2_active", "true", "" ], + [ + "iam.credential_reports.id.access_key_2_active", + "true", + "" + ], [ "or", - [ "iam.credential_reports.id.access_key_2_last_used_date", "olderThan", ["_ARG_0_", "days"] ], - [ "iam.credential_reports.id.access_key_2_last_rotated", "olderThan", ["_ARG_0_", "days"] ] + [ + "iam.credential_reports.id.access_key_2_last_used_date", + "olderThan", + [ + "_ARG_0_", + "days" + ] + ], + [ + "iam.credential_reports.id.access_key_2_last_rotated", + "olderThan", + [ + "_ARG_0_", + "days" + ] + ] ] ] ], + "arg_names": [ + "Period in days" + ], "class_suffix": "unused_credentials" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-user-no-key-rotation.json b/ScoutSuite/providers/aws/rules/findings/iam-user-no-key-rotation.json index 1247ce7cf..9f453c540 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-user-no-key-rotation.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-user-no-key-rotation.json @@ -1,20 +1,49 @@ { - "arg_names": [ "Key status", "Rotation period" ], - "description": "Lack of key rotation for (_ARG_0_) days", + "description": "Lack of Key Rotation for (_ARG_0_) Days", "rationale": "In case of access key compromise, the lack of credential rotation increases the period during which an attacker has access to the AWS account.", "remediation": "Rotate access keys that have not been changed recently", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.4"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.4"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.4"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.4" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials"], - "key": "iam-user-no-_ARG_0_-key-rotation.json", "dashboard_name": "Access keys", - "path": "iam.users.id.AccessKeys.id", "display_path": "iam.users.id", - "conditions": [ "and", - [ "iam.users.id.AccessKeys.id.Status", "equal", "_ARG_0_" ], - [ "iam.users.id.AccessKeys.id.CreateDate", "olderThan", ["_ARG_1_", "days"] ] + "path": "iam.users.id.AccessKeys.id", + "conditions": [ + "and", + [ + "iam.users.id.AccessKeys.id.Status", + "equal", + "_ARG_0_" + ], + [ + "iam.users.id.AccessKeys.id.CreateDate", + "olderThan", + [ + "_ARG_1_", + "days" + ] + ] + ], + "key": "iam-user-no-_ARG_0_-key-rotation.json", + "arg_names": [ + "Key status", + "Rotation period" ] -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-user-unused-access-key-initial-setup.json b/ScoutSuite/providers/aws/rules/findings/iam-user-unused-access-key-initial-setup.json index 8d1af4841..93a403720 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-user-unused-access-key-initial-setup.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-user-unused-access-key-initial-setup.json @@ -1,24 +1,49 @@ { - "description": "Users with access keys created during initial setup and not used", + "description": "Users with Access Keys Created during Initial Setup and Not Used", "rationale": "Not creating access keys during initial user setup will avoid unnecessary management work and give more control over keys used somewhere in the organization.", "remediation": "Do not setup access keys during initial user setup. Instead, require users to create the keys themselves or put in a support ticket to have them created", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.23"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.21"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.23" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.21" + } ], "dashboard_name": "Users", "path": "iam.credential_reports.id", - "conditions": [ "or", + "conditions": [ + "or", [ "and", - [ "iam.credential_reports.id.access_key_1_active", "true", "" ], - [ "iam.credential_reports.id.access_key_1_last_used_date", "equal", "None" ] + [ + "iam.credential_reports.id.access_key_1_active", + "true", + "" + ], + [ + "iam.credential_reports.id.access_key_1_last_used_date", + "equal", + "None" + ] ], [ "and", - [ "iam.credential_reports.id.access_key_2_active", "true", "" ], - [ "iam.credential_reports.id.access_key_2_last_used_date", "equal", "None" ] + [ + "iam.credential_reports.id.access_key_2_active", + "true", + "" + ], + [ + "iam.credential_reports.id.access_key_2_last_used_date", + "equal", + "None" + ] ] ], "class_suffix": "unused_access_keys" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-user-with-policies.json b/ScoutSuite/providers/aws/rules/findings/iam-user-with-policies.json index d11a388d4..c0a665d68 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-user-with-policies.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-user-with-policies.json @@ -1,19 +1,43 @@ { - "arg_names": [ "Type of policy", "Path to policies" ], - "key": "iam-user-with-_ARG_0_-policies", - "description": "User with _ARG_0_ policies", + "description": "User with _ARG_0_ Policies", "rationale": "Assigning privileges at the user level increases the complexity of access management and the opportunity for a user to receive or retain excessive privileges.", "remediation": "Ensure IAM policies are only attached to groups or roles", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.15"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.16"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.16"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.15" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.16" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.16" + } ], "dashboard_name": "Users", "path": "iam.users.id", - "conditions": [ "and", - [ "iam.users.id.", "withKey", "_ARG_1_" ], - [ "iam.users.id._ARG_1_", "notEmpty", "" ] + "conditions": [ + "and", + [ + "iam.users.id.", + "withKey", + "_ARG_1_" + ], + [ + "iam.users.id._ARG_1_", + "notEmpty", + "" + ] + ], + "key": "iam-user-with-_ARG_0_-policies", + "arg_names": [ + "Type of policy", + "Path to policies" ], "id_suffix": "_ARG_1_" } \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json b/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json index 40358d7c1..a3b370b0a 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-user-without-mfa.json @@ -3,19 +3,42 @@ "rationale": "All IAM users should have Multi Factor Authentication (MFA) enabled.", "remediation": "Enable MFA for all users in the AWS account", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "1.2"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.2"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.2"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.2" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.2" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.2" + } + ], + "references": [ + "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#enable-mfa-for-privileged-users" ], - "references": ["https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#enable-mfa-for-privileged-users"], "dashboard_name": "Users", "path": "iam.users.id", - "conditions": [ "and", - [ "iam.users.id.", "withKey", "LoginProfile" ], - [ "iam.users.id.MFADevices", "empty", "" ] + "conditions": [ + "and", + [ + "iam.users.id.", + "withKey", + "LoginProfile" + ], + [ + "iam.users.id.MFADevices", + "empty", + "" + ] ], - "id_suffix": "mfa_enabled", "keys": [ "iam.users.id.name" - ] -} + ], + "id_suffix": "mfa_enabled" +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/kms-key-rotation-disabled.json b/ScoutSuite/providers/aws/rules/findings/kms-key-rotation-disabled.json index f6d73483f..a98b17b14 100644 --- a/ScoutSuite/providers/aws/rules/findings/kms-key-rotation-disabled.json +++ b/ScoutSuite/providers/aws/rules/findings/kms-key-rotation-disabled.json @@ -1,16 +1,33 @@ { - "description": "CMK rotation is disabled", + "description": "CMK Rotation Is Disabled", "rationale": "Rotating encryption keys helps reduce the potential impact of a compromised key.", "remediation": "For every Customer-created Master Key (CMK) ensure that Rotate this key every year is enabled", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "2.8"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "2.8"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.8"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "2.8" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "2.8" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.8" + } ], "dashboard_name": "KMS", "path": "kms.regions.id.keys.id", - "conditions": [ "and", - [ "kms.regions.id.keys.id.rotation_enabled", "false", "" ] + "conditions": [ + "and", + [ + "kms.regions.id.keys.id.rotation_enabled", + "false", + "" + ] ], "id_suffix": "CMKRotationDisabled" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json b/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json index 35ee1e281..fbf11865d 100755 --- a/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json +++ b/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json @@ -1,11 +1,16 @@ { - "description": "S3 bucket access logging is disabled", + "description": "S3 Bucket Access Logging Is Disabled", "rationale": "The lack of S3 bucket logging prevents log information to be accessed in security and incident response workflows.", "remediation": "Ensure that S3 buckets have Logging enabled", "dashboard_name": "Buckets", "path": "s3.buckets.id", - "conditions": [ "and", - [ "s3.buckets.id.logging", "equal", "Disabled" ] + "conditions": [ + "and", + [ + "s3.buckets.id.logging", + "equal", + "Disabled" + ] ], "id_suffix": "logging" -} +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json b/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json index b7dbb6e55..003925b81 100755 --- a/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json +++ b/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json @@ -1,18 +1,41 @@ { - "description": "Subnet without a flow log", + "description": "Subnet without a Flow Log", "rationale": "Flow logs enable the investigation of incidents involving unauthorized network traffic, such as an attacker exfiltrating data or pivoting to other hosts.", "remediation": "Create a flow log for each subnet.", "compliance": [ - {"name": "CIS Amazon Web Services Foundations", "version": "1.0.0", "reference": "4.3"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "4.3"}, - {"name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "2.9"} + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "4.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "4.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.9" + } + ], + "references": [ + "https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html" ], - "references": ["https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html"], "dashboard_name": "Subnets", "path": "vpc.regions.id.vpcs.id.subnets.id", - "conditions": [ "or", - [ "this", "withoutKey", "flow_logs"], - [ "flow_logs", "empty", "" ] + "conditions": [ + "or", + [ + "this", + "withoutKey", + "flow_logs" + ], + [ + "flow_logs", + "empty", + "" + ] ], "id_suffix": "NoFlowLog" -} +} \ No newline at end of file From b362c4d4b64a1c883c4540af8b86c2f66178e3d2 Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 8 Apr 2020 11:53:20 +0200 Subject: [PATCH 015/312] Should be fixed --- .../findings/iam-managed-policy-allows-full-privileges.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json index 599b8e121..8b103b536 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-full-privileges.json @@ -15,7 +15,8 @@ } ], "dashboard_name": "Policies", - "path": "iam.policies.id", + "display_path": "iam.policies.id", + "path": "iam.policies.id.PolicyDocument.Statement.id", "conditions": [ "and", [ @@ -24,7 +25,7 @@ "Allow" ], [ - "iam.policies.id.PolicyDocument.Statement.id.Action", + "iam.policies.id.PolicyDocument.Statement.id.", "containAction", "*" ], From 224edd819262a33d399ce47f508ac3fdf0cf7979 Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 8 Apr 2020 12:02:47 +0200 Subject: [PATCH 016/312] Fix finding --- .../iam-unused-credentials-not-disabled.json | 64 ++++++++++++++----- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json b/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json index f53ae41dc..60c63ee90 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-unused-credentials-not-disabled.json @@ -33,19 +33,35 @@ [ "or", [ - "iam.credential_reports.id.password_last_used", - "olderThan", + "and", [ - "_ARG_0_", - "days" + "iam.credential_reports.id.password_last_used", + "notNull", + "" + ], + [ + "iam.credential_reports.id.password_last_used", + "olderThan", + [ + "_ARG_0_", + "days" + ] ] ], [ - "iam.credential_reports.id.password_last_changed", - "olderThan", + "and", [ - "_ARG_0_", - "days" + "iam.credential_reports.id.password_last_changed", + "notNull", + "" + ], + [ + "iam.credential_reports.id.password_last_changed", + "olderThan", + [ + "_ARG_0_", + "days" + ] ] ] ] @@ -60,11 +76,19 @@ [ "or", [ - "iam.credential_reports.id.access_key_1_last_used_date", - "olderThan", + "and", [ - "_ARG_0_", - "days" + "iam.credential_reports.id.access_key_1_last_used_date", + "notNull", + "" + ], + [ + "iam.credential_reports.id.access_key_1_last_used_date", + "olderThan", + [ + "_ARG_0_", + "days" + ] ] ], [ @@ -87,11 +111,19 @@ [ "or", [ - "iam.credential_reports.id.access_key_2_last_used_date", - "olderThan", + "and", [ - "_ARG_0_", - "days" + "iam.credential_reports.id.access_key_2_last_used_date", + "notNull", + "" + ], + [ + "iam.credential_reports.id.access_key_2_last_used_date", + "olderThan", + [ + "_ARG_0_", + "days" + ] ] ], [ From 159c8dc61e6add27337e92decc96b2e7c155aeb8 Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 8 Apr 2020 12:19:20 +0200 Subject: [PATCH 017/312] Fix finding --- .../aws/rules/findings/iam-no-support-role.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json b/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json index d0b5fdfe1..c10bf04ea 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json @@ -1,6 +1,6 @@ { "description": "No Authorized User to Manage Incidents with AWS Support", - "rationale": "There should be at least one user authorized to manage incidents with AWS Support.", + "rationale": "The arn:aws:iam::aws:policy/AWSSupportAccess AWS Managed Policy was not found to be attached to any principal. There should be at least one user authorized to manage incidents with AWS Support.", "remediation": "Attach the AWSSupportAccess to a role or group", "compliance": [ { @@ -15,13 +15,14 @@ } ], "dashboard_name": "Policies", - "path": "iam.policies.AWSSupportAccess", + "display_path": "iam.policies.id", + "path": "iam.policies.id.arn", "conditions": [ "and", [ - "iam.policies.AWSSupportAccess.attached_to", - "notEmpty", - "" + "this", + "notEqual", + "arn:aws:iam::aws:policy/AWSSupportAccess" ] ] } \ No newline at end of file From 1c182cfcd0a0cf87a74346c334f95486f794cd25 Mon Sep 17 00:00:00 2001 From: Juan Jose Date: Tue, 5 May 2020 17:07:29 +0200 Subject: [PATCH 018/312] ARN added to resources --- ScoutSuite/providers/aws/resources/cloudformation/stacks.py | 1 + ScoutSuite/providers/aws/resources/ec2/networkinterfaces.py | 3 +++ ScoutSuite/providers/aws/resources/ec2/securitygroups.py | 3 +++ ScoutSuite/providers/aws/resources/ec2/snapshots.py | 3 +++ ScoutSuite/providers/aws/resources/ec2/volumes.py | 3 +++ ScoutSuite/providers/aws/resources/elasticache/cluster.py | 3 +++ ScoutSuite/providers/aws/resources/elb/load_balancers.py | 3 +++ ScoutSuite/providers/aws/resources/rds/instances.py | 3 +++ ScoutSuite/providers/aws/resources/route53/domains.py | 3 +++ 9 files changed, 25 insertions(+) diff --git a/ScoutSuite/providers/aws/resources/cloudformation/stacks.py b/ScoutSuite/providers/aws/resources/cloudformation/stacks.py index dc81df735..0338e8308 100755 --- a/ScoutSuite/providers/aws/resources/cloudformation/stacks.py +++ b/ScoutSuite/providers/aws/resources/cloudformation/stacks.py @@ -21,6 +21,7 @@ def _parse_stack(self, raw_stack): raw_stack['drifted'] = raw_stack.pop('DriftInformation')[ 'StackDriftStatus'] == 'DRIFTED' raw_stack['termination_protection'] = raw_stack['EnableTerminationProtection'] + raw_stack['arn'] = raw_stack['id'] template = raw_stack.pop('template') raw_stack['deletion_policy'] = self.has_deletion_policy(template) diff --git a/ScoutSuite/providers/aws/resources/ec2/networkinterfaces.py b/ScoutSuite/providers/aws/resources/ec2/networkinterfaces.py index a76930b2d..4e2691b18 100755 --- a/ScoutSuite/providers/aws/resources/ec2/networkinterfaces.py +++ b/ScoutSuite/providers/aws/resources/ec2/networkinterfaces.py @@ -16,4 +16,7 @@ async def fetch_all(self): def _parse_network_interface(self, raw_network_interface): raw_network_interface['name'] = raw_network_interface['NetworkInterfaceId'] + raw_network_interface['arn'] = 'arn:aws:ec2:{}:{}:network-interface/{}'.format(self.region, + raw_network_interface.get('OwnerId'), + raw_network_interface.get('NetworkInterfaceId')) return raw_network_interface['NetworkInterfaceId'], raw_network_interface diff --git a/ScoutSuite/providers/aws/resources/ec2/securitygroups.py b/ScoutSuite/providers/aws/resources/ec2/securitygroups.py index c6da28c3f..91c7311ae 100755 --- a/ScoutSuite/providers/aws/resources/ec2/securitygroups.py +++ b/ScoutSuite/providers/aws/resources/ec2/securitygroups.py @@ -22,6 +22,9 @@ def _parse_security_group(self, raw_security_group): security_group = {} security_group['name'] = raw_security_group['GroupName'] security_group['id'] = raw_security_group['GroupId'] + security_group['arn'] = 'arn:aws:ec2:{}:{}:security-group/{}'.format(self.region, + raw_security_group.get('OwnerId'), + raw_security_group.get('GroupId')) security_group['description'] = raw_security_group['Description'] security_group['owner_id'] = raw_security_group['OwnerId'] diff --git a/ScoutSuite/providers/aws/resources/ec2/snapshots.py b/ScoutSuite/providers/aws/resources/ec2/snapshots.py index d48b5f9e6..02a9b858a 100755 --- a/ScoutSuite/providers/aws/resources/ec2/snapshots.py +++ b/ScoutSuite/providers/aws/resources/ec2/snapshots.py @@ -18,6 +18,9 @@ def _parse_snapshot(self, raw_snapshot): raw_snapshot['id'] = raw_snapshot.pop('SnapshotId') raw_snapshot['name'] = get_name(raw_snapshot, raw_snapshot, 'id') raw_snapshot['public'] = self._is_public(raw_snapshot) + raw_snapshot['arn'] = 'arn:aws:ec2:{}:{}:snapshot/{}'.format(self.get('region'), + raw_snapshot.get('OwnerId'), + raw_snapshot.get('GroupId')) return raw_snapshot['id'], raw_snapshot @staticmethod diff --git a/ScoutSuite/providers/aws/resources/ec2/volumes.py b/ScoutSuite/providers/aws/resources/ec2/volumes.py index 6dec86616..e83156684 100755 --- a/ScoutSuite/providers/aws/resources/ec2/volumes.py +++ b/ScoutSuite/providers/aws/resources/ec2/volumes.py @@ -17,4 +17,7 @@ async def fetch_all(self): def _parse_volume(self, raw_volume): raw_volume['id'] = raw_volume.pop('VolumeId') raw_volume['name'] = get_name(raw_volume, raw_volume, 'id') + raw_volume['arn'] = 'arn:aws:ec2:{}:{}:volume/{}'.format(self.region, + raw_volume.get('id'), + raw_volume.get('name')) return raw_volume['id'], raw_volume diff --git a/ScoutSuite/providers/aws/resources/elasticache/cluster.py b/ScoutSuite/providers/aws/resources/elasticache/cluster.py index ecf4d9d70..c0d10307f 100755 --- a/ScoutSuite/providers/aws/resources/elasticache/cluster.py +++ b/ScoutSuite/providers/aws/resources/elasticache/cluster.py @@ -16,4 +16,7 @@ async def fetch_all(self): def _parse_cluster(self, raw_cluster): raw_cluster['name'] = raw_cluster.pop('CacheClusterId') + raw_cluster['arn'] = 'arn:aws:elasticache:{}:{}:cluster/{}'.format(self.region, + raw_cluster.get('OwnerId'), + raw_cluster.get('GroupId')) return raw_cluster['name'], raw_cluster diff --git a/ScoutSuite/providers/aws/resources/elb/load_balancers.py b/ScoutSuite/providers/aws/resources/elb/load_balancers.py index 5e4ffff78..bd4c4dada 100755 --- a/ScoutSuite/providers/aws/resources/elb/load_balancers.py +++ b/ScoutSuite/providers/aws/resources/elb/load_balancers.py @@ -22,6 +22,9 @@ def _parse_load_balancer(self, raw_load_balancer): ['DNSName', 'CreatedTime', 'AvailabilityZones', 'Subnets', 'Scheme', 'attributes']) load_balancer['security_groups'] = [] + load_balancer['arn'] = 'arn:aws:elb:{}:{}:load-balancer/{}'.format(self.region, + raw_load_balancer.get('OwnerId'), + raw_load_balancer.get('GroupId')) for sg in raw_load_balancer['SecurityGroups']: load_balancer['security_groups'].append({'GroupId': sg}) diff --git a/ScoutSuite/providers/aws/resources/rds/instances.py b/ScoutSuite/providers/aws/resources/rds/instances.py index c2e8abb85..01ceadac0 100755 --- a/ScoutSuite/providers/aws/resources/rds/instances.py +++ b/ScoutSuite/providers/aws/resources/rds/instances.py @@ -24,6 +24,9 @@ def _parse_instance(self, raw_instance): instance[key] = raw_instance[key] if key in raw_instance else None instance['is_read_replica'] = self._is_read_replica(raw_instance) + instance['arn'] = 'arn:aws:rds:{}:{}:instance/{}'.format(self.region, + raw_instance.get('OwnerId'), + raw_instance.get('GroupId')) return instance['name'], instance @staticmethod diff --git a/ScoutSuite/providers/aws/resources/route53/domains.py b/ScoutSuite/providers/aws/resources/route53/domains.py index ee86434f5..664116703 100755 --- a/ScoutSuite/providers/aws/resources/route53/domains.py +++ b/ScoutSuite/providers/aws/resources/route53/domains.py @@ -21,4 +21,7 @@ def _parse_domain(self, raw_domain): domain_dict['auto_renew'] = raw_domain.get('AutoRenew') domain_dict['transfer_lock'] = raw_domain.get('TransferLock') domain_dict['expiry'] = raw_domain.get('Expiry') + domain_dict['arn'] = 'arn:aws:route53:{}:{}:domain/{}'.format(self.region, + raw_domain.get('OwnerId'), + domain_dict.get('id')) return domain_dict['id'], domain_dict From 4c4e8bb8f0bff8aed66154472745c6d38f29ccc9 Mon Sep 17 00:00:00 2001 From: Juan Jose Date: Wed, 6 May 2020 17:37:29 +0200 Subject: [PATCH 019/312] Fixed some account id and bugs --- ScoutSuite/providers/aws/resources/ec2/snapshots.py | 4 ++-- ScoutSuite/providers/aws/resources/ec2/volumes.py | 2 +- ScoutSuite/providers/aws/resources/elasticache/cluster.py | 4 ++-- ScoutSuite/providers/aws/resources/elb/load_balancers.py | 4 ++-- ScoutSuite/providers/aws/resources/rds/instances.py | 4 ++-- ScoutSuite/providers/aws/resources/route53/domains.py | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ScoutSuite/providers/aws/resources/ec2/snapshots.py b/ScoutSuite/providers/aws/resources/ec2/snapshots.py index 02a9b858a..591f00daa 100755 --- a/ScoutSuite/providers/aws/resources/ec2/snapshots.py +++ b/ScoutSuite/providers/aws/resources/ec2/snapshots.py @@ -19,8 +19,8 @@ def _parse_snapshot(self, raw_snapshot): raw_snapshot['name'] = get_name(raw_snapshot, raw_snapshot, 'id') raw_snapshot['public'] = self._is_public(raw_snapshot) raw_snapshot['arn'] = 'arn:aws:ec2:{}:{}:snapshot/{}'.format(self.get('region'), - raw_snapshot.get('OwnerId'), - raw_snapshot.get('GroupId')) + self.facade.owner_id, + raw_snapshot.get('name')) return raw_snapshot['id'], raw_snapshot @staticmethod diff --git a/ScoutSuite/providers/aws/resources/ec2/volumes.py b/ScoutSuite/providers/aws/resources/ec2/volumes.py index e83156684..5f82d34bb 100755 --- a/ScoutSuite/providers/aws/resources/ec2/volumes.py +++ b/ScoutSuite/providers/aws/resources/ec2/volumes.py @@ -18,6 +18,6 @@ def _parse_volume(self, raw_volume): raw_volume['id'] = raw_volume.pop('VolumeId') raw_volume['name'] = get_name(raw_volume, raw_volume, 'id') raw_volume['arn'] = 'arn:aws:ec2:{}:{}:volume/{}'.format(self.region, - raw_volume.get('id'), + self.facade.owner_id, raw_volume.get('name')) return raw_volume['id'], raw_volume diff --git a/ScoutSuite/providers/aws/resources/elasticache/cluster.py b/ScoutSuite/providers/aws/resources/elasticache/cluster.py index c0d10307f..6b2661bd0 100755 --- a/ScoutSuite/providers/aws/resources/elasticache/cluster.py +++ b/ScoutSuite/providers/aws/resources/elasticache/cluster.py @@ -17,6 +17,6 @@ async def fetch_all(self): def _parse_cluster(self, raw_cluster): raw_cluster['name'] = raw_cluster.pop('CacheClusterId') raw_cluster['arn'] = 'arn:aws:elasticache:{}:{}:cluster/{}'.format(self.region, - raw_cluster.get('OwnerId'), - raw_cluster.get('GroupId')) + self.facade.owner_id, + raw_cluster.get('name')) return raw_cluster['name'], raw_cluster diff --git a/ScoutSuite/providers/aws/resources/elb/load_balancers.py b/ScoutSuite/providers/aws/resources/elb/load_balancers.py index bd4c4dada..de3abf5f3 100755 --- a/ScoutSuite/providers/aws/resources/elb/load_balancers.py +++ b/ScoutSuite/providers/aws/resources/elb/load_balancers.py @@ -23,8 +23,8 @@ def _parse_load_balancer(self, raw_load_balancer): load_balancer['security_groups'] = [] load_balancer['arn'] = 'arn:aws:elb:{}:{}:load-balancer/{}'.format(self.region, - raw_load_balancer.get('OwnerId'), - raw_load_balancer.get('GroupId')) + self.facade.owner_id, + raw_load_balancer.get('LoadBalancerName')) for sg in raw_load_balancer['SecurityGroups']: load_balancer['security_groups'].append({'GroupId': sg}) diff --git a/ScoutSuite/providers/aws/resources/rds/instances.py b/ScoutSuite/providers/aws/resources/rds/instances.py index 01ceadac0..b68419280 100755 --- a/ScoutSuite/providers/aws/resources/rds/instances.py +++ b/ScoutSuite/providers/aws/resources/rds/instances.py @@ -25,8 +25,8 @@ def _parse_instance(self, raw_instance): instance['is_read_replica'] = self._is_read_replica(raw_instance) instance['arn'] = 'arn:aws:rds:{}:{}:instance/{}'.format(self.region, - raw_instance.get('OwnerId'), - raw_instance.get('GroupId')) + self.facade.owner_id, + raw_instance.get('DbiResourceId')) return instance['name'], instance @staticmethod diff --git a/ScoutSuite/providers/aws/resources/route53/domains.py b/ScoutSuite/providers/aws/resources/route53/domains.py index 664116703..943b14ee9 100755 --- a/ScoutSuite/providers/aws/resources/route53/domains.py +++ b/ScoutSuite/providers/aws/resources/route53/domains.py @@ -22,6 +22,6 @@ def _parse_domain(self, raw_domain): domain_dict['transfer_lock'] = raw_domain.get('TransferLock') domain_dict['expiry'] = raw_domain.get('Expiry') domain_dict['arn'] = 'arn:aws:route53:{}:{}:domain/{}'.format(self.region, - raw_domain.get('OwnerId'), + self.facade.owner_id, domain_dict.get('id')) return domain_dict['id'], domain_dict From 236fb25136dc25918afce3fc2e846f92102313d9 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Thu, 7 May 2020 16:58:18 +0200 Subject: [PATCH 020/312] Added template for CIS 1.2.0 Monitoring rules. --- .../logs-no-alarm-IAM-policy-changes.json | 32 +++++ ...gs-no-alarm-aws-configuration-changes.json | 32 +++++ ...larm-cloudtrail-configuration-changes.json | 32 +++++ .../findings/logs-no-alarm-cmk-deletion.json | 32 +++++ ...alarm-console-authentication-failures.json | 32 +++++ .../findings/logs-no-alarm-nacl-changes.json | 32 +++++ ...ogs-no-alarm-network-gateways-changes.json | 32 +++++ .../findings/logs-no-alarm-root-usage.json | 32 +++++ .../logs-no-alarm-route-table-changes.json | 32 +++++ .../logs-no-alarm-s3-policy-changes.json | 32 +++++ .../logs-no-alarm-security-group-changes.json | 32 +++++ .../logs-no-alarm-signin-without-mfa.json | 32 +++++ .../logs-no-alarm-unauthorized-api-calls.json | 32 +++++ .../findings/logs-no-alarm-vpc-changes.json | 32 +++++ .../aws/rules/rulesets/cis-1.2.0.json | 112 ++++++++++++++++++ 15 files changed, 560 insertions(+) create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-IAM-policy-changes.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-aws-configuration-changes.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cloudtrail-configuration-changes.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cmk-deletion.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-console-authentication-failures.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-nacl-changes.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-network-gateways-changes.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-root-usage.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-route-table-changes.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-s3-policy-changes.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-security-group-changes.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-unauthorized-api-calls.json create mode 100644 ScoutSuite/providers/aws/rules/findings/logs-no-alarm-vpc-changes.json diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-IAM-policy-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-IAM-policy-changes.json new file mode 100644 index 000000000..df7fa442c --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-IAM-policy-changes.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for IAM policy changes", + "rationale": "There was no CloudWatch alarm to monitor IAM policy changes. Monitoring for IAM policy changes will help ensure authentication and authorization control remain intact.", + "remediation": "Enable a CloudWatch alarm to monitor the usage of the root account.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.4" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.4" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-aws-configuration-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-aws-configuration-changes.json new file mode 100644 index 000000000..78800b96e --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-aws-configuration-changes.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for AWS configuration changes", + "rationale": "There was no CloudWatch alarm to monitor AWS configuration changes. Monitoring for AWS configuration changes will help ensure sustained visibility to changes performed in the AWS account.", + "remediation": "Enable a CloudWatch alarm to detect AWS configuration changes.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.9" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.9" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.9" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cloudtrail-configuration-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cloudtrail-configuration-changes.json new file mode 100644 index 000000000..a5cb35480 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cloudtrail-configuration-changes.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for CloudTrail configuration changes", + "rationale": "There was no CloudWatch alarm to monitor CloudTrail configuration changes. Monitoring for CloudTrail policy changes will help ensure sustained visibility to activities performed in the AWS account.", + "remediation": "Enable a CloudWatch alarm to monitor CloudTrail configuration changes.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.5" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.5" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.5" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cmk-deletion.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cmk-deletion.json new file mode 100644 index 000000000..cd06e1325 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cmk-deletion.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for disabled or deleted master keys", + "rationale": "There was no CloudWatch alarm to alert about disabled or deleted master keys. Monitoring for disabled or deleted master keys can prevent permanent loss of data encrypted with such keys.", + "remediation": "Enable a CloudWatch alarm to detect recently disabled or deleted master keys.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.7" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.7" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.7" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-console-authentication-failures.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-console-authentication-failures.json new file mode 100644 index 000000000..23ecfb861 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-console-authentication-failures.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for failed console authentications", + "rationale": "There was no CloudWatch alarm for failed console authentication requests. Monitoring for failed console authentications can decrease the lead time to detect brute force attacks.", + "remediation": "Enable a CloudWatch alarm to monitor failed authentication attempts.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.6" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.6" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.6" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-nacl-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-nacl-changes.json new file mode 100644 index 000000000..c2b02d43e --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-nacl-changes.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for Network Access Control Lists changes", + "rationale": "There was no CloudWatch alarm to detect changes to NACL. Monitoring for NACL changes will help ensure that no service or resource is unintentionally exposed.", + "remediation": "Enable a CloudWatch alarm to detect NACL changes.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.11" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.11" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.11" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-network-gateways-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-network-gateways-changes.json new file mode 100644 index 000000000..f17a876ca --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-network-gateways-changes.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for network gateways changes", + "rationale": "There was no CloudWatch alarm to monitor changes in network gateways. Monitoring for network gateways changes will help ensure that all traffic traverses the VPC border via a controlled path.", + "remediation": "Enable a CloudWatch alarm to detect network gateways changes.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.12" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.12" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.12" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-root-usage.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-root-usage.json new file mode 100644 index 000000000..5bf7e979a --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-root-usage.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for root account usage", + "rationale": "There was no CloudWatch alarm for the usage of the root account. Monitoring for root account log ins will provide visibility into the use of a fully privileged account.", + "remediation": "Enable a CloudWatch alarm to monitor the usage of the root account.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.3" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-route-table-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-route-table-changes.json new file mode 100644 index 000000000..9cc890405 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-route-table-changes.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for route table changes", + "rationale": "There was no CloudWatch alarm to monitor changes in route tables. Monitoring for route table changes will help ensure that all VPC traffic flows thorough an expected path.", + "remediation": "Enable a CloudWatch alarm to detect route table changes.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.13" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.13" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.13" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-s3-policy-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-s3-policy-changes.json new file mode 100644 index 000000000..d79fc807d --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-s3-policy-changes.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for S3 bucket policy changes", + "rationale": "There was no CloudWatch alarm to detect changes in S3 bucket policy changes. Monitoring for changes in S3 bucket policy changes may reduce the time to detect and fix permissive policies on sensitive S3 buckets.", + "remediation": "Enable a CloudWatch alarm to detect policy changes in S3 buckets.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.8" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.8" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.8" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-security-group-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-security-group-changes.json new file mode 100644 index 000000000..c85c457f0 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-security-group-changes.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for security group changes", + "rationale": "There was no CloudWatch alarm to monitor changes to security groups. Monitoring for security group changes will help ensure that no service or resource is unintentionally exposed.", + "remediation": "Enable a CloudWatch alarm to monitor security group changes.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.10" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.10" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.10" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json new file mode 100644 index 000000000..1d4508738 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for console log ins without MFA", + "rationale": "There was no CloudWatch alarm for console log ins without MFA. Monitoring for console log ins without MFA will provide visibility into the use of accounts not protected by Multi Factor Authentication (MFA).", + "remediation": "Enable a CloudWatch alarm to monitor console log ins without MFA.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.2" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.2" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.2" + } + ], + "dashboard_name": "Logs", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-unauthorized-api-calls.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-unauthorized-api-calls.json new file mode 100644 index 000000000..4a5b7dd6d --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-unauthorized-api-calls.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for unauthorized API calls", + "rationale": "There was no CloudWatch alarm for unauthorized API calls. Monitoring for unauthorized API calls helps reveal application errors and detect malicious activity.", + "remediation": "Enable a CloudWatch alarm to monitor unauthorized API calls.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.1" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.1" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.1" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-vpc-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-vpc-changes.json new file mode 100644 index 000000000..44632cdec --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-vpc-changes.json @@ -0,0 +1,32 @@ +{ + "description": "No CloudWatch alarm for VPC changes", + "rationale": "There was no CloudWatch alarm to monitor VPC changes. Monitoring for VPC changes will help ensure authentication and authorization controls remain intact.", + "remediation": "Enable a CloudWatch alarm to detect VPC changes.", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "3.14" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "3.14" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "3.14" + } + ], + "dashboard_name": "Cloudwatch", + "path": "cloudwatch.regions.id.alarms.id", + "conditions": [ + "and", + [ + "cloudwatch.regions.id.alarms.id.AlarmActions", + "empty", + "" + ] + ] +} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json index 3577423f2..27a0c6da7 100644 --- a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json +++ b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json @@ -276,6 +276,118 @@ "scored": true } ], + "logs-no-alarm-unauthorized-api-calls.json": [ + { + "comment": "Recommendation 3.1", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-signin-without-mfa.json": [ + { + "comment": "Recommendation 3.2", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-root-usage.json": [ + { + "comment": "Recommendation 3.3", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-IAM-policy-changes.json": [ + { + "comment": "Recommendation 3.4", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-cloudtrail-configuration-changes.json": [ + { + "comment": "Recommendation 3.5", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-console-authentication-failures.json": [ + { + "comment": "Recommendation 3.6", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-cmk-deletion.json": [ + { + "comment": "Recommendation 3.7", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-s3-policy-changes.json": [ + { + "comment": "Recommendation 3.8", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-aws-configuration-changes.json": [ + { + "comment": "Recommendation 3.9", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-security-group-changes.json": [ + { + "comment": "Recommendation 3.10", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-nacl-changes.json": [ + { + "comment": "Recommendation 3.11", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-network-gateways-changes.json": [ + { + "comment": "Recommendation 3.12", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-route-table-changes.json": [ + { + "comment": "Recommendation 3.13", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "logs-no-alarm-vpc-changes.json": [ + { + "comment": "Recommendation 3.14", + "enabled": true, + "level": "danger", + "scored": true + } + ], "ec2-security-group-opens-known-port-to-all.json": [ { "args": [ From 33ae2b0bcefed3f132bda3e219899117c34bfda6 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Fri, 8 May 2020 15:37:25 +0200 Subject: [PATCH 021/312] Fixed delimiters in rules --- .../aws/rules/findings/config-recorder-not-configured.json | 1 + .../aws/rules/findings/ec2-default-security-group-in-use.json | 1 + .../rules/findings/ec2-default-security-group-with-rules.json | 1 + .../providers/aws/rules/findings/s3-bucket-no-logging.json | 1 + 4 files changed, 4 insertions(+) diff --git a/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json b/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json index 9dd596341..b59fcb0c0 100755 --- a/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json +++ b/ScoutSuite/providers/aws/rules/findings/config-recorder-not-configured.json @@ -18,6 +18,7 @@ "version": "1.2.0", "reference": "2.5" } + ], "references": [ "https://aws.amazon.com/blogs/mt/aws-config-best-practices/" ], diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json index cf756262c..1d705cfbe 100755 --- a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json @@ -18,6 +18,7 @@ "version": "1.2.0", "reference": "4.3" } + ], "references": [ "https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-cis-controls.html#securityhub-cis-controls-4.3" ], diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json index 44769f903..172524721 100755 --- a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json @@ -18,6 +18,7 @@ "version": "1.2.0", "reference": "4.3" } + ], "references": [ "https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-cis-controls.html#securityhub-cis-controls-4.3" ], diff --git a/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json b/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json index b6a9bede5..37b838341 100755 --- a/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json +++ b/ScoutSuite/providers/aws/rules/findings/s3-bucket-no-logging.json @@ -21,6 +21,7 @@ ], "references": [ "https://docs.aws.amazon.com/AmazonS3/latest/dev/security-best-practices.html" + ], "dashboard_name": "Buckets", "path": "s3.buckets.id", "conditions": [ From a8e375b4793d394caecd0276f6fa6703b8c92368 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Fri, 8 May 2020 17:19:47 +0200 Subject: [PATCH 022/312] Fixed some bugs --- .../aws/rules/findings/cloudtrail-no-logging.json | 4 ++++ .../aws/rules/findings/iam-no-support-role.json | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json index 0c6b5026e..7d9abdeba 100755 --- a/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json +++ b/ScoutSuite/providers/aws/rules/findings/cloudtrail-no-logging.json @@ -43,6 +43,10 @@ "false", "" ] + ], + "and", + [ + "cloudtrail.regions.id.trails.id." ] ], "class_suffix": "IsLogging" diff --git a/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json b/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json index c10bf04ea..9bf87e6b2 100644 --- a/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-no-support-role.json @@ -16,13 +16,18 @@ ], "dashboard_name": "Policies", "display_path": "iam.policies.id", - "path": "iam.policies.id.arn", + "path": "iam.policies.id", "conditions": [ "and", [ - "this", - "notEqual", + "iam.policies.id.arn", + "equal", "arn:aws:iam::aws:policy/AWSSupportAccess" + ], + [ + "iam.policies.id.attached_to", + "empty", + "" ] ] } \ No newline at end of file From 442371b5185d804f07af9e9f195d26df5c051a50 Mon Sep 17 00:00:00 2001 From: xga Date: Sun, 17 May 2020 18:35:50 +0200 Subject: [PATCH 023/312] Add support for cloudwatch metric filters --- ....cloudwatch.regions.id.metric_filters.html | 25 +++++++++++++++++ ScoutSuite/providers/aws/facade/cloudwatch.py | 10 +++++++ ScoutSuite/providers/aws/metadata.json | 6 +++++ .../aws/resources/cloudwatch/base.py | 4 ++- .../resources/cloudwatch/metric_filters.py | 27 +++++++++++++++++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 ScoutSuite/output/data/html/partials/aws/services.cloudwatch.regions.id.metric_filters.html create mode 100644 ScoutSuite/providers/aws/resources/cloudwatch/metric_filters.py diff --git a/ScoutSuite/output/data/html/partials/aws/services.cloudwatch.regions.id.metric_filters.html b/ScoutSuite/output/data/html/partials/aws/services.cloudwatch.regions.id.metric_filters.html new file mode 100644 index 000000000..bf16cf265 --- /dev/null +++ b/ScoutSuite/output/data/html/partials/aws/services.cloudwatch.regions.id.metric_filters.html @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/ScoutSuite/providers/aws/facade/cloudwatch.py b/ScoutSuite/providers/aws/facade/cloudwatch.py index e56f4e3cd..67450a3f5 100755 --- a/ScoutSuite/providers/aws/facade/cloudwatch.py +++ b/ScoutSuite/providers/aws/facade/cloudwatch.py @@ -4,6 +4,7 @@ class CloudWatch(AWSBaseFacade): + async def get_alarms(self, region): try: return await AWSFacadeUtils.get_all_pages('cloudwatch', region, self.session, 'describe_alarms', @@ -11,3 +12,12 @@ async def get_alarms(self, region): except Exception as e: print_exception('Failed to get CloudWatch alarms: {}'.format(e)) return [] + + async def get_metric_filters(self, region): + try: + return await AWSFacadeUtils.get_all_pages('logs', region, self.session, 'describe_metric_filters', + 'metricFilters') + except Exception as e: + print_exception('Failed to get CloudWatch metric filters: {}'.format(e)) + return [] + diff --git a/ScoutSuite/providers/aws/metadata.json b/ScoutSuite/providers/aws/metadata.json index 55500f6a2..b2168b4da 100755 --- a/ScoutSuite/providers/aws/metadata.json +++ b/ScoutSuite/providers/aws/metadata.json @@ -44,6 +44,12 @@ "path": "services.cloudwatch.regions.id.alarms" } }, + "resources": { + "metric_filters": { + "cols": 2, + "path": "services.cloudwatch.regions.id.metric_filters" + } + }, "summaries": { "statistics": { "cols": 1, diff --git a/ScoutSuite/providers/aws/resources/cloudwatch/base.py b/ScoutSuite/providers/aws/resources/cloudwatch/base.py index 83fe0c8ab..3d18a4ca4 100755 --- a/ScoutSuite/providers/aws/resources/cloudwatch/base.py +++ b/ScoutSuite/providers/aws/resources/cloudwatch/base.py @@ -2,11 +2,13 @@ from ScoutSuite.providers.aws.resources.regions import Regions from .alarms import Alarms +from .metric_filters import MetricFilters class CloudWatch(Regions): _children = [ - (Alarms, 'alarms') + (Alarms, 'alarms'), + (MetricFilters, 'metric_filters') ] def __init__(self, facade: AWSFacade): diff --git a/ScoutSuite/providers/aws/resources/cloudwatch/metric_filters.py b/ScoutSuite/providers/aws/resources/cloudwatch/metric_filters.py new file mode 100644 index 000000000..e10b5396d --- /dev/null +++ b/ScoutSuite/providers/aws/resources/cloudwatch/metric_filters.py @@ -0,0 +1,27 @@ +from ScoutSuite.providers.aws.facade.base import AWSFacade +from ScoutSuite.providers.aws.resources.base import AWSResources +from ScoutSuite.providers.utils import get_non_provider_id + + +class MetricFilters(AWSResources): + def __init__(self, facade: AWSFacade, region: str): + super(MetricFilters, self).__init__(facade) + self.region = region + + async def fetch_all(self): + for raw_metric_filter in await self.facade.cloudwatch.get_metric_filters(self.region): + name, resource = self._parse_metric_filter(raw_metric_filter) + self[name] = resource + + def _parse_metric_filter(self, raw_metric_filter): + metric_filter_dict = {} + metric_filter_dict['id'] = get_non_provider_id('{}{}'.format(raw_metric_filter.get('filterName'), + raw_metric_filter.get('creationTime'))) + metric_filter_dict['name'] = raw_metric_filter.get('filterName') + metric_filter_dict['creation_time'] = raw_metric_filter.get('creationTime') + metric_filter_dict['pattern'] = raw_metric_filter.get('filterPattern') + metric_filter_dict['metric_transformations'] = raw_metric_filter.get('metricTransformations') + metric_filter_dict['log_group_name'] = raw_metric_filter.get('logGroupName') + return metric_filter_dict['id'], metric_filter_dict + + From 9e934ed85f503e5ba009eaaeb2196c9a415b2f65 Mon Sep 17 00:00:00 2001 From: xga Date: Sun, 17 May 2020 19:09:02 +0200 Subject: [PATCH 024/312] Fix bug --- ScoutSuite/providers/aws/metadata.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ScoutSuite/providers/aws/metadata.json b/ScoutSuite/providers/aws/metadata.json index 00ec0805f..825fddde3 100755 --- a/ScoutSuite/providers/aws/metadata.json +++ b/ScoutSuite/providers/aws/metadata.json @@ -42,9 +42,7 @@ "alarms": { "cols": 2, "path": "services.cloudwatch.regions.id.alarms" - } - }, - "resources": { + }, "metric_filters": { "cols": 2, "path": "services.cloudwatch.regions.id.metric_filters" From 59a3c28d017249a67d959356178eaab7dedce865 Mon Sep 17 00:00:00 2001 From: xga Date: Sun, 17 May 2020 19:18:09 +0200 Subject: [PATCH 025/312] Update partial --- .../aws/services.cloudwatch.regions.id.metric_filters.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.cloudwatch.regions.id.metric_filters.html b/ScoutSuite/output/data/html/partials/aws/services.cloudwatch.regions.id.metric_filters.html index bf16cf265..0ed5443e8 100644 --- a/ScoutSuite/output/data/html/partials/aws/services.cloudwatch.regions.id.metric_filters.html +++ b/ScoutSuite/output/data/html/partials/aws/services.cloudwatch.regions.id.metric_filters.html @@ -6,9 +6,9 @@

    {{name}}

    Information

    Name: {{value_or_none name}}
    -
    Pattern: {{value_or_none pattern}}
    Creation Time: {{format_date creation_time}}
    Log Group Name: {{value_or_none log_group_name}}
    +
    Pattern: {{value_or_none pattern}}
    From 3808336a928c739fff35a50b454f7338d3095d52 Mon Sep 17 00:00:00 2001 From: xga Date: Sun, 17 May 2020 19:51:37 +0200 Subject: [PATCH 026/312] Add finalize processing --- .../providers/aws/resources/cloudwatch/base.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ScoutSuite/providers/aws/resources/cloudwatch/base.py b/ScoutSuite/providers/aws/resources/cloudwatch/base.py index 3d18a4ca4..b27642e5b 100755 --- a/ScoutSuite/providers/aws/resources/cloudwatch/base.py +++ b/ScoutSuite/providers/aws/resources/cloudwatch/base.py @@ -13,3 +13,15 @@ class CloudWatch(Regions): def __init__(self, facade: AWSFacade): super(CloudWatch, self).__init__('cloudwatch', facade) + + async def finalize(self): + + # For each region, check if at least one metric filter covers the desired events + for region in self['regions']: + self['regions'][region]['metric_filters_pattern_checks'] = {} + # Initialize results at "False" + self['regions'][region]['metric_filters_pattern_checks']['console_login_mfa'] = False + for metric_filter_id, metric_filter in self['regions'][region]['metric_filters'].items(): + # Check events + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName = "ConsoleLogin") && ($.additionalEventData.MFAUsed != "Yes") }': + self['regions'][region]['metric_filters_pattern_checks']['console_login_mfa'] = True From 95f9710faa25ebb79320219419725869fc9c8b50 Mon Sep 17 00:00:00 2001 From: xga Date: Sun, 17 May 2020 19:51:48 +0200 Subject: [PATCH 027/312] Fix rule --- .../findings/logs-no-alarm-signin-without-mfa.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json index 1d4508738..74dc101a5 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for console log ins without MFA", + "description": "No CloudWatch Alarm for \"Console Logins without MFA\"", "rationale": "There was no CloudWatch alarm for console log ins without MFA. Monitoring for console log ins without MFA will provide visibility into the use of accounts not protected by Multi Factor Authentication (MFA).", "remediation": "Enable a CloudWatch alarm to monitor console log ins without MFA.", "compliance": [ @@ -19,13 +19,14 @@ "reference": "3.2" } ], - "dashboard_name": "Logs", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters_pattern_checks.console_login_mfa", + "display_path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ "and", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.console_login_mfa", + "false", "" ] ] From 0c75f6c3b2ee7d0c38de2a69c3dd4b1d5bfe67e8 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Mon, 25 May 2020 17:56:07 +0200 Subject: [PATCH 028/312] Implemented CIS 1.2.0 Monitoring findings --- .../aws/resources/cloudwatch/base.py | 39 +++++++++++++++++++ ...gs-no-alarm-aws-configuration-changes.json | 12 +++--- ...larm-cloudtrail-configuration-changes.json | 12 +++--- .../findings/logs-no-alarm-cmk-deletion.json | 12 +++--- ...alarm-console-authentication-failures.json | 12 +++--- ... => logs-no-alarm-iam-policy-changes.json} | 12 +++--- .../findings/logs-no-alarm-nacl-changes.json | 12 +++--- ...ogs-no-alarm-network-gateways-changes.json | 12 +++--- .../findings/logs-no-alarm-root-usage.json | 12 +++--- .../logs-no-alarm-route-table-changes.json | 12 +++--- .../logs-no-alarm-s3-policy-changes.json | 12 +++--- .../logs-no-alarm-security-group-changes.json | 12 +++--- .../logs-no-alarm-signin-without-mfa.json | 5 +-- .../logs-no-alarm-unauthorized-api-calls.json | 12 +++--- .../findings/logs-no-alarm-vpc-changes.json | 12 +++--- .../aws/rules/rulesets/cis-1.2.0.json | 2 +- 16 files changed, 120 insertions(+), 82 deletions(-) rename ScoutSuite/providers/aws/rules/findings/{logs-no-alarm-IAM-policy-changes.json => logs-no-alarm-iam-policy-changes.json} (74%) diff --git a/ScoutSuite/providers/aws/resources/cloudwatch/base.py b/ScoutSuite/providers/aws/resources/cloudwatch/base.py index b27642e5b..bdb7ed7be 100755 --- a/ScoutSuite/providers/aws/resources/cloudwatch/base.py +++ b/ScoutSuite/providers/aws/resources/cloudwatch/base.py @@ -20,8 +20,47 @@ async def finalize(self): for region in self['regions']: self['regions'][region]['metric_filters_pattern_checks'] = {} # Initialize results at "False" + self['regions'][region]['metric_filters_pattern_checks']['unauthorized_api_calls'] = False self['regions'][region]['metric_filters_pattern_checks']['console_login_mfa'] = False + self['regions'][region]['metric_filters_pattern_checks']['root_usage'] = False + self['regions'][region]['metric_filters_pattern_checks']['iam_policy_changes'] = False + self['regions'][region]['metric_filters_pattern_checks']['cloudtrail_configuration_changes'] = False + self['regions'][region]['metric_filters_pattern_checks']['console_authentication_failures'] = False + self['regions'][region]['metric_filters_pattern_checks']['cmk_deletion'] = False + self['regions'][region]['metric_filters_pattern_checks']['s3_policy_changes'] = False + self['regions'][region]['metric_filters_pattern_checks']['aws_configuration_changes'] = False + self['regions'][region]['metric_filters_pattern_checks']['security_group_changes'] = False + self['regions'][region]['metric_filters_pattern_checks']['nacl_changes'] = False + self['regions'][region]['metric_filters_pattern_checks']['network_gateways_changes'] = False + self['regions'][region]['metric_filters_pattern_checks']['route_table_changes'] = False + self['regions'][region]['metric_filters_pattern_checks']['vpc_changes'] = False for metric_filter_id, metric_filter in self['regions'][region]['metric_filters'].items(): # Check events + if metric_filter['pattern'] == 'filterPattern": "{ ($.errorCode = "*UnauthorizedOperation") || ($.errorCode = "AccessDenied*") }': + self['regions'][region]['metric_filters_pattern_checks']['unauthorized_api_calls'] = True if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName = "ConsoleLogin") && ($.additionalEventData.MFAUsed != "Yes") }': self['regions'][region]['metric_filters_pattern_checks']['console_login_mfa'] = True + if metric_filter['pattern'] == 'filterPattern": "{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }': + self['regions'][region]['metric_filters_pattern_checks']['root_usage'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName=DeleteGroupPolicy) || ($..eventName=DeleteRolePolicy) || ($.eventName=DeleteUserPolicy) || ($.eventName=PutGroupPolicy) || ($.eventName=PutRolePolicy) || ($.eventName=PutUserPolicy) || ($.eventName=CreatePolicy) || ($.eventName=DeletePolicy) || ($.eventName=CreatePolicyVersion) || ($.eventName=DeletePolicyVersion) || ($.eventName=AttachRolePolicy) || ($.eventName=DetachRolePolicy) || ($.eventName=AttachUserPolicy) || ($.eventName=DetachUserPolicy) || ($.eventName=AttachGroupPolicy) || ($.eventName=DetachGroupPolicy) }': + self['regions'][region]['metric_filters_pattern_checks']['iam_policy_changes'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }': + self['regions'][region]['metric_filters_pattern_checks']['cloudtrail_configuration_changes'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName = ConsoleLogin) && ($.errorMessage = "Failed authentication") }': + self['regions'][region]['metric_filters_pattern_checks']['console_authentication_failures'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventSource = kms.amazonaws.com) && (($.eventName = DisableKey) || ($.eventName = ScheduleKeyDeletion)) }': + self['regions'][region]['metric_filters_pattern_checks']['cmk_deletion'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventSource = s3.amazonaws.com) && (($.eventName = PutBucketAcl) || ($.eventName = PutBucketPolicy) || ($.eventName = PutBucketCors) || ($.eventName = PutBucketLifecycle) || ($.eventName = PutBucketReplication) || ($.eventName = DeleteBucketPolicy) || ($.eventName = DeleteBucketReplication)) }': + self['regions'][region]['metric_filters_pattern_checks']['s3_policy_changes'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventSource = config.amazonaws.com) && (($.eventName = StopConfigurationRecorder) || ($.eventName = DeleteDeliveryChannel) || ($.eventName = PutDeliveryChannel) || ($.eventName = PutConfigurationRecorder)) }': + self['regions'][region]['metric_filters_pattern_checks']['aws_configuration_changes'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup) }': + self['regions'][region]['metric_filters_pattern_checks']['security_group_changes'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry) || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry) || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation) }': + self['regions'][region]['metric_filters_pattern_checks']['nacl_changes'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway) || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway) || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway) }': + self['regions'][region]['metric_filters_pattern_checks']['network_gateways_changes'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }': + self['regions'][region]['metric_filters_pattern_checks']['route_table_changes'] = True + if metric_filter['pattern'] == 'filterPattern": "{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }': + self['regions'][region]['metric_filters_pattern_checks']['vpc_changes'] = True diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-aws-configuration-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-aws-configuration-changes.json index 78800b96e..17f0bbd8c 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-aws-configuration-changes.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-aws-configuration-changes.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for AWS configuration changes", + "description": "No CloudWatch alarm for \"AWS Configuration Changes\"", "rationale": "There was no CloudWatch alarm to monitor AWS configuration changes. Monitoring for AWS configuration changes will help ensure sustained visibility to changes performed in the AWS account.", "remediation": "Enable a CloudWatch alarm to detect AWS configuration changes.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.9" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.aws_configuration_changes", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cloudtrail-configuration-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cloudtrail-configuration-changes.json index a5cb35480..1008dbabd 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cloudtrail-configuration-changes.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cloudtrail-configuration-changes.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for CloudTrail configuration changes", + "description": "No CloudWatch alarm for \"CloudTrail Configuration Changes\"", "rationale": "There was no CloudWatch alarm to monitor CloudTrail configuration changes. Monitoring for CloudTrail policy changes will help ensure sustained visibility to activities performed in the AWS account.", "remediation": "Enable a CloudWatch alarm to monitor CloudTrail configuration changes.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.5" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.cloudtrail_configuration_changes", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cmk-deletion.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cmk-deletion.json index cd06e1325..894921641 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cmk-deletion.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-cmk-deletion.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for disabled or deleted master keys", + "description": "No CloudWatch alarm for \"Disabled or Deleted Master Keys\"", "rationale": "There was no CloudWatch alarm to alert about disabled or deleted master keys. Monitoring for disabled or deleted master keys can prevent permanent loss of data encrypted with such keys.", "remediation": "Enable a CloudWatch alarm to detect recently disabled or deleted master keys.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.7" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.cmk_deletion", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-console-authentication-failures.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-console-authentication-failures.json index 23ecfb861..162d209bc 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-console-authentication-failures.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-console-authentication-failures.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for failed console authentications", + "description": "No CloudWatch alarm for \"Failed Console Authentications\"", "rationale": "There was no CloudWatch alarm for failed console authentication requests. Monitoring for failed console authentications can decrease the lead time to detect brute force attacks.", "remediation": "Enable a CloudWatch alarm to monitor failed authentication attempts.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.6" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.console_authentication_failures", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-IAM-policy-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-iam-policy-changes.json similarity index 74% rename from ScoutSuite/providers/aws/rules/findings/logs-no-alarm-IAM-policy-changes.json rename to ScoutSuite/providers/aws/rules/findings/logs-no-alarm-iam-policy-changes.json index df7fa442c..b37961662 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-IAM-policy-changes.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-iam-policy-changes.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for IAM policy changes", + "description": "No CloudWatch alarm for \"IAM Policy Changes\"", "rationale": "There was no CloudWatch alarm to monitor IAM policy changes. Monitoring for IAM policy changes will help ensure authentication and authorization control remain intact.", "remediation": "Enable a CloudWatch alarm to monitor the usage of the root account.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.4" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.iam_policy_changes", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-nacl-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-nacl-changes.json index c2b02d43e..0ed4e495b 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-nacl-changes.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-nacl-changes.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for Network Access Control Lists changes", + "description": "No CloudWatch alarm for \"Network Access Control Lists Changes\"", "rationale": "There was no CloudWatch alarm to detect changes to NACL. Monitoring for NACL changes will help ensure that no service or resource is unintentionally exposed.", "remediation": "Enable a CloudWatch alarm to detect NACL changes.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.11" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.nacl_changes", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-network-gateways-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-network-gateways-changes.json index f17a876ca..06b483891 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-network-gateways-changes.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-network-gateways-changes.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for network gateways changes", + "description": "No CloudWatch alarm for \"Network Gateways Changes\"", "rationale": "There was no CloudWatch alarm to monitor changes in network gateways. Monitoring for network gateways changes will help ensure that all traffic traverses the VPC border via a controlled path.", "remediation": "Enable a CloudWatch alarm to detect network gateways changes.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.12" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.network_gateways_changes", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-root-usage.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-root-usage.json index 5bf7e979a..7d1bf248a 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-root-usage.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-root-usage.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for root account usage", + "description": "No CloudWatch alarm for \"Root Account Usage\"", "rationale": "There was no CloudWatch alarm for the usage of the root account. Monitoring for root account log ins will provide visibility into the use of a fully privileged account.", "remediation": "Enable a CloudWatch alarm to monitor the usage of the root account.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.3" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.root_usage", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-route-table-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-route-table-changes.json index 9cc890405..fed58aa40 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-route-table-changes.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-route-table-changes.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for route table changes", + "description": "No CloudWatch alarm for \"Route Table Changes\"", "rationale": "There was no CloudWatch alarm to monitor changes in route tables. Monitoring for route table changes will help ensure that all VPC traffic flows thorough an expected path.", "remediation": "Enable a CloudWatch alarm to detect route table changes.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.13" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.route_table_changes", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-s3-policy-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-s3-policy-changes.json index d79fc807d..172afbd82 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-s3-policy-changes.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-s3-policy-changes.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for S3 bucket policy changes", + "description": "No CloudWatch alarm for \"S3 Bucket Policy Changes\"", "rationale": "There was no CloudWatch alarm to detect changes in S3 bucket policy changes. Monitoring for changes in S3 bucket policy changes may reduce the time to detect and fix permissive policies on sensitive S3 buckets.", "remediation": "Enable a CloudWatch alarm to detect policy changes in S3 buckets.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.8" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.s3_policy_changes", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-security-group-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-security-group-changes.json index c85c457f0..d5f4e1894 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-security-group-changes.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-security-group-changes.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for security group changes", + "description": "No CloudWatch alarm for \"Security Group Changes\"", "rationale": "There was no CloudWatch alarm to monitor changes to security groups. Monitoring for security group changes will help ensure that no service or resource is unintentionally exposed.", "remediation": "Enable a CloudWatch alarm to monitor security group changes.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.10" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.security_group_changes", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json index 74dc101a5..7d9d475a5 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-signin-without-mfa.json @@ -20,10 +20,9 @@ } ], "dashboard_name": "Regions", - "path": "cloudwatch.regions.id.metric_filters_pattern_checks.console_login_mfa", - "display_path": "cloudwatch.regions.id.metric_filters.id", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ "cloudwatch.regions.id.metric_filters_pattern_checks.console_login_mfa", "false", diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-unauthorized-api-calls.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-unauthorized-api-calls.json index 4a5b7dd6d..d069e0e34 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-unauthorized-api-calls.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-unauthorized-api-calls.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for unauthorized API calls", + "description": "No CloudWatch Alarm for \"Unauthorized API Calls\"", "rationale": "There was no CloudWatch alarm for unauthorized API calls. Monitoring for unauthorized API calls helps reveal application errors and detect malicious activity.", "remediation": "Enable a CloudWatch alarm to monitor unauthorized API calls.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.1" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.unauthorized_api_calls", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-vpc-changes.json b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-vpc-changes.json index 44632cdec..48d35ee04 100644 --- a/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-vpc-changes.json +++ b/ScoutSuite/providers/aws/rules/findings/logs-no-alarm-vpc-changes.json @@ -1,5 +1,5 @@ { - "description": "No CloudWatch alarm for VPC changes", + "description": "No CloudWatch alarm for \"VPC Changes\"", "rationale": "There was no CloudWatch alarm to monitor VPC changes. Monitoring for VPC changes will help ensure authentication and authorization controls remain intact.", "remediation": "Enable a CloudWatch alarm to detect VPC changes.", "compliance": [ @@ -19,13 +19,13 @@ "reference": "3.14" } ], - "dashboard_name": "Cloudwatch", - "path": "cloudwatch.regions.id.alarms.id", + "dashboard_name": "Regions", + "path": "cloudwatch.regions.id.metric_filters.id", "conditions": [ - "and", + "or", [ - "cloudwatch.regions.id.alarms.id.AlarmActions", - "empty", + "cloudwatch.regions.id.metric_filters_pattern_checks.vpc_changes", + "false", "" ] ] diff --git a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json index 27a0c6da7..304de41cd 100644 --- a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json +++ b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json @@ -300,7 +300,7 @@ "scored": true } ], - "logs-no-alarm-IAM-policy-changes.json": [ + "logs-no-alarm-iam-policy-changes.json": [ { "comment": "Recommendation 3.4", "enabled": true, From 2941a2a8199e2457706694a6297b738d3450561c Mon Sep 17 00:00:00 2001 From: xga Date: Tue, 26 May 2020 18:52:31 +0200 Subject: [PATCH 029/312] Add ARN to partial --- .../html/partials/aws/services.ec2.regions.id.snapshots.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.snapshots.html b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.snapshots.html index bf03d8966..95d2dd648 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.snapshots.html +++ b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.snapshots.html @@ -7,7 +7,8 @@

    {{name}}

    Information

      -
    • Id: {{id}}
    • +
    • ID: {{id}}
    • +
    • ARN: {{arn}}
    • Date: {{StartTime}}
    • Description:{{Description}}
    • State: {{State}}
    • From 7d30321c7a90c087f327f5f66c38e7bfe2e6acb8 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Wed, 27 May 2020 16:51:48 +0200 Subject: [PATCH 030/312] Added Cloudtrail S3 bucket findings --- .../rules/findings/s3-bucket-world-acl.json | 19 +++ .../findings/s3-bucket-world-policy-star.json | 18 +++ .../aws/rules/rulesets/cis-1.2.0.json | 108 +++++++++++++++++- 3 files changed, 140 insertions(+), 5 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-acl.json b/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-acl.json index cee261d45..3b40295a6 100755 --- a/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-acl.json +++ b/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-acl.json @@ -1,5 +1,24 @@ { "description": "_ARG_2_", + "rationale": "Allowing public access to any S3 bucket may disclose sensitive information stored in them or allow unauthenticated users to upload any type of files.", + "remediation": "Remove any public access that has been granted to the affected buckets via an ACL", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "2.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "2.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.3" + } + ], "dashboard_name": "Bucket ACLs", "display_path": "s3.buckets.id", "path": "s3.buckets.id.grantees.id", diff --git a/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-star.json b/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-star.json index 87c103be7..3a276cacd 100755 --- a/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-star.json +++ b/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-star.json @@ -1,6 +1,24 @@ { "description": "All Actions Authorized to All Principals", "rationale": "Allowing IAM actions to all principals is contrary to the principle of least privilege and presents and opportunity for abuse. This policy should be reviewed to ensure it is secure and in line with the resource's intended use.", + "remediation": "Remove any Statement having an Effect set to Allow and a Principal set to \"*\" or {\"AWS\":\"*\"} in the affected bucket policy", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "2.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "2.3" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "2.3" + } + ], "dashboard_name": "Buckets", "display_path": "s3.buckets.id", "path": "s3.buckets.id.policy.Statement.id", diff --git a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json index 304de41cd..81f858f98 100644 --- a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json +++ b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json @@ -206,7 +206,7 @@ ], "cloudtrail-not-configured.json": [ { - "comment": "Recommendation 2.1 (part 2/2)", + "comment": "Recommendation 2.1 (Part 2/2)", "enabled": true, "level": "danger", "scored": true @@ -220,12 +220,110 @@ "scored": true } ], - "TODO_2.json": [ + "s3-bucket-world-acl.json": [ { - "comment": "Recommendation 2.3", - "enabled": false, + "args": [ + "AllUsers", + "read", + "Bucket world-listable (anonymous)", + "warning" + ], + "comment": "Recommendation 2.3 (Part 1/2)", + "enabled": true, "level": "danger", - "scored": true + "score": true + }, + { + "args": [ + "AllUsers", + "read_acp", + "Bucket's permissions world-readable (anonymous)", + "warning" + ], + "comment": "Recommendation 2.3 (Part 1/2)", + "enabled": true, + "level": "danger", + "score": true + }, + { + "args": [ + "AllUsers", + "write", + "Bucket world-writable (anonymous)", + "danger" + ], + "comment": "Recommendation 2.3 (Part 1/2)", + "enabled": true, + "level": "danger", + "score": true + }, + { + "args": [ + "AllUsers", + "write_acp", + "Bucket's permissions world-writable (anonymous)", + "danger" + ], + "comment": "Recommendation 2.3 (Part 1/2)", + "enabled": true, + "level": "danger", + "score": true + }, + { + "args": [ + "AuthenticatedUsers", + "read", + "Bucket world-listable", + "danger" + ], + "comment": "Recommendation 2.3 (Part 1/2)", + "enabled": true, + "level": "danger", + "score": true + }, + { + "args": [ + "AuthenticatedUsers", + "read_acp", + "Bucket's permissions world-readable", + "warning" + ], + "comment": "Recommendation 2.3 (Part 1/2)", + "enabled": true, + "level": "danger", + "score": true + }, + { + "args": [ + "AuthenticatedUsers", + "write", + "Bucket world-writable", + "danger" + ], + "comment": "Recommendation 2.3 (Part 1/2)", + "enabled": true, + "level": "danger", + "score": true + }, + { + "args": [ + "AuthenticatedUsers", + "write_acp", + "Bucket's permissions world-writable", + "danger" + ], + "comment": "Recommendation 2.3 (Part 1/2)", + "enabled": true, + "level": "danger", + "score": true + } + ], + "s3-bucket-world-policy-star.json": [ + { + "comment": "Recommendation 2.3 (Part 2/2)", + "enabled": true, + "level": "danger", + "score": true } ], "cloudtrail-no-cloudwatch-integration.json": [ From a03a75d2655877310cfe8cb9d1f1c99e73c3ff34 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Fri, 29 May 2020 14:08:10 -0500 Subject: [PATCH 031/312] feat: stubs for DynamoDB --- ScoutSuite/providers/aws/facade/dynamodb.py | 41 +++++++++++++++++++ .../aws/resources/dynamodb/__init__.py | 0 .../aws/resources/dynamodb/backups.py | 26 ++++++++++++ .../providers/aws/resources/dynamodb/base.py | 11 +++++ .../aws/resources/dynamodb/tables.py | 17 ++++++++ 5 files changed, 95 insertions(+) create mode 100644 ScoutSuite/providers/aws/facade/dynamodb.py create mode 100644 ScoutSuite/providers/aws/resources/dynamodb/__init__.py create mode 100644 ScoutSuite/providers/aws/resources/dynamodb/backups.py create mode 100644 ScoutSuite/providers/aws/resources/dynamodb/base.py create mode 100644 ScoutSuite/providers/aws/resources/dynamodb/tables.py diff --git a/ScoutSuite/providers/aws/facade/dynamodb.py b/ScoutSuite/providers/aws/facade/dynamodb.py new file mode 100644 index 000000000..adb6514e4 --- /dev/null +++ b/ScoutSuite/providers/aws/facade/dynamodb.py @@ -0,0 +1,41 @@ + + + +from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.core.console import print_exception +from ScoutSuite.providers.aws.facade.utils import AWSFacadeUtils +from ScoutSuite.providers.aws.facade.basefacade import AWSBaseFacade + + +class DynamoDBFacase(AWSBaseFacade): + async def get_backups(self, region, table_name): + try: + return await AWSFacadeUtils.get_all_pages('dynamodb', region, self.session, 'list_backups', 'BackupSummaries') + except Exception as e: + print_exception(f"Failed to get DynamoDB Backups for {table_name}") + return [] + + async def get_tables(self, region): + try: + return await AWSFacadeUtils.get_all_pages('dynamodb', region, self.session, 'list_tables', 'TableNames') + except Exception as e: + print_exception(f"Failed to get DynamoDB tables") + return [] + + async def get_tags_for_resource(self, region, resource_arn): + try: + return await AWSFacadeUtils.get_all_pages('dynamodb', region, self.session, 'list_tags_of_resource', 'Tags', ResourceArn=resource_arn) + except Exception as e: + print_exception(f"Failed to get DynamoDB tags for resource {resource_arn}") + return [] + + + async def get_table(self, table_name: str, region): + client = AWSFacadeUtils.get_client('dynamodb', self.session, region) + try: + table = await run_concurrently(lambda: client.describe_table(TableName=table_name)) + except Exception as e: + print_exception(f"Failed to get table {table_name}: {e}") + table = None + + if table: diff --git a/ScoutSuite/providers/aws/resources/dynamodb/__init__.py b/ScoutSuite/providers/aws/resources/dynamodb/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ScoutSuite/providers/aws/resources/dynamodb/backups.py b/ScoutSuite/providers/aws/resources/dynamodb/backups.py new file mode 100644 index 000000000..5951e40ad --- /dev/null +++ b/ScoutSuite/providers/aws/resources/dynamodb/backups.py @@ -0,0 +1,26 @@ + +from ScoutSuite.providers.aws.facade.base import AWSFacade +from ScoutSuite.providers.aws.resources.base import AWSResources + + +class Backups(AWSResources): + + def __init__(self, facade: AWSFacade, region: str) -> None: + super(Backups, self).__init__(facade) + self.region = region + + + async def fetch_all(self, **kwargs): + raw_backups = await self.facade.dynamodb.get_backups(self.region) + for raw_backup in raw_backups: + name, resource = await self._parse_backup(raw_backup) + self[name] = resource + + + async def _parse_backup(self, raw_backup): + backup = { + 'table_name': raw_backup.get('TableName'), + 'id': raw_backup.get('TableId'), + 'arn': raw_backup.get('TableArn'), + } + return backup['table_name'], backup diff --git a/ScoutSuite/providers/aws/resources/dynamodb/base.py b/ScoutSuite/providers/aws/resources/dynamodb/base.py new file mode 100644 index 000000000..1825a898c --- /dev/null +++ b/ScoutSuite/providers/aws/resources/dynamodb/base.py @@ -0,0 +1,11 @@ +from ScoutSuite.providers.aws.facade.base import AWSFacade +from ScoutSuite.providers.aws.resources.regions import Regions + +from .backups import Backups + + +class DynamoDB(Regions): + _children = [(Backups, "backups")] + + def __init__(self, facade: AWSFacade): + super(Backups, self).__init__("backups", facade) diff --git a/ScoutSuite/providers/aws/resources/dynamodb/tables.py b/ScoutSuite/providers/aws/resources/dynamodb/tables.py new file mode 100644 index 000000000..12205349d --- /dev/null +++ b/ScoutSuite/providers/aws/resources/dynamodb/tables.py @@ -0,0 +1,17 @@ +from ScoutSuite.providers.aws.facade.base import AWSFacade +from ScoutSuite.providers.aws.resources.base import AWSResources + + +class Tables(AWSResources): + def __init__(self, facade: AWSFacade, region: str) -> None: + super(Tables, self).__init__(facade) + self.region = region + + async def fetch_all(self, **kwargs): + raw_tables = await self.facade.dynamodb.get_tables(self.region) + for raw_table in raw_tables: + name, resource = await self._parse_table(raw_table) + + async def _parse_table(self, raw_table): + table = {} + table['name'] = raw_table From f24888a18b908a911ec4422c169518531e870696 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Fri, 29 May 2020 21:32:31 -0500 Subject: [PATCH 032/312] feat: initial grab of DynamoDB Data --- ScoutSuite/providers/aws/facade/base.py | 2 + ScoutSuite/providers/aws/facade/dynamodb.py | 54 +++++++++++++++---- .../aws/resources/dynamodb/backups.py | 2 +- .../providers/aws/resources/dynamodb/base.py | 5 +- .../aws/resources/dynamodb/tables.py | 7 ++- ScoutSuite/providers/aws/services.py | 6 ++- 6 files changed, 59 insertions(+), 17 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/base.py b/ScoutSuite/providers/aws/facade/base.py index a2e25f743..ae0d10fca 100755 --- a/ScoutSuite/providers/aws/facade/base.py +++ b/ScoutSuite/providers/aws/facade/base.py @@ -8,6 +8,7 @@ from ScoutSuite.providers.aws.facade.cloudwatch import CloudWatch from ScoutSuite.providers.aws.facade.config import ConfigFacade from ScoutSuite.providers.aws.facade.directconnect import DirectConnectFacade +from ScoutSuite.providers.aws.facade.dynamodb import DynamoDBFacade from ScoutSuite.providers.aws.facade.ec2 import EC2Facade from ScoutSuite.providers.aws.facade.efs import EFSFacade from ScoutSuite.providers.aws.facade.elasticache import ElastiCacheFacade @@ -246,6 +247,7 @@ def _instantiate_facades(self): self.cloudwatch = CloudWatch(self.session) self.config = ConfigFacade(self.session) self.directconnect = DirectConnectFacade(self.session) + self.dynamodb = DynamoDBFacade(self.session) self.efs = EFSFacade(self.session) self.elasticache = ElastiCacheFacade(self.session) self.emr = EMRFacade(self.session) diff --git a/ScoutSuite/providers/aws/facade/dynamodb.py b/ScoutSuite/providers/aws/facade/dynamodb.py index adb6514e4..168ba0263 100644 --- a/ScoutSuite/providers/aws/facade/dynamodb.py +++ b/ScoutSuite/providers/aws/facade/dynamodb.py @@ -1,4 +1,4 @@ - +# import debugpy from ScoutSuite.providers.utils import run_concurrently @@ -7,35 +7,69 @@ from ScoutSuite.providers.aws.facade.basefacade import AWSBaseFacade -class DynamoDBFacase(AWSBaseFacade): +class DynamoDBFacade(AWSBaseFacade): async def get_backups(self, region, table_name): try: - return await AWSFacadeUtils.get_all_pages('dynamodb', region, self.session, 'list_backups', 'BackupSummaries') + return await AWSFacadeUtils.get_all_pages( + "dynamodb", + region, + self.session, + "list_backups", + "BackupSummaries", + TableName=table_name, + ) except Exception as e: print_exception(f"Failed to get DynamoDB Backups for {table_name}") return [] async def get_tables(self, region): try: - return await AWSFacadeUtils.get_all_pages('dynamodb', region, self.session, 'list_tables', 'TableNames') + return await AWSFacadeUtils.get_all_pages( + "dynamodb", region, self.session, "list_tables", "TableNames" + ) except Exception as e: print_exception(f"Failed to get DynamoDB tables") return [] async def get_tags_for_resource(self, region, resource_arn): try: - return await AWSFacadeUtils.get_all_pages('dynamodb', region, self.session, 'list_tags_of_resource', 'Tags', ResourceArn=resource_arn) + return await AWSFacadeUtils.get_all_pages( + "dynamodb", + region, + self.session, + "list_tags_of_resource", + "Tags", + ResourceArn=resource_arn, + ) except Exception as e: print_exception(f"Failed to get DynamoDB tags for resource {resource_arn}") return [] + async def get_table(self, region, table_name): + # debugpy.listen(5678) + # print("Waiting for debugger attach") + # debugpy.wait_for_client() - async def get_table(self, table_name: str, region): - client = AWSFacadeUtils.get_client('dynamodb', self.session, region) + client = AWSFacadeUtils.get_client("dynamodb", self.session, region) try: - table = await run_concurrently(lambda: client.describe_table(TableName=table_name)) + raw_table = await run_concurrently( + lambda: client.describe_table(TableName=table_name) + ) except Exception as e: print_exception(f"Failed to get table {table_name}: {e}") - table = None + raw_table = None + + # debugpy.breakpoint() + if raw_table["Table"]: + table = {} + raw = raw_table["Table"] + if "SSEDescription" in raw: + table["sse_description"] = raw["SSEDescription"] + table["sse_enabled"] = True + else: + table["sse_enabled"] = False - if table: + if "ArchivalSummary" in raw: + table["archival_summary"] = raw["ArchivalSummary"] + return raw["TableName"], table + return "", [] diff --git a/ScoutSuite/providers/aws/resources/dynamodb/backups.py b/ScoutSuite/providers/aws/resources/dynamodb/backups.py index 5951e40ad..7e25b78ac 100644 --- a/ScoutSuite/providers/aws/resources/dynamodb/backups.py +++ b/ScoutSuite/providers/aws/resources/dynamodb/backups.py @@ -10,7 +10,7 @@ def __init__(self, facade: AWSFacade, region: str) -> None: self.region = region - async def fetch_all(self, **kwargs): + async def fetch_all(self): raw_backups = await self.facade.dynamodb.get_backups(self.region) for raw_backup in raw_backups: name, resource = await self._parse_backup(raw_backup) diff --git a/ScoutSuite/providers/aws/resources/dynamodb/base.py b/ScoutSuite/providers/aws/resources/dynamodb/base.py index 1825a898c..3691f52ec 100644 --- a/ScoutSuite/providers/aws/resources/dynamodb/base.py +++ b/ScoutSuite/providers/aws/resources/dynamodb/base.py @@ -2,10 +2,11 @@ from ScoutSuite.providers.aws.resources.regions import Regions from .backups import Backups +from .tables import Tables class DynamoDB(Regions): - _children = [(Backups, "backups")] + _children = [(Tables, "tables")] def __init__(self, facade: AWSFacade): - super(Backups, self).__init__("backups", facade) + super(DynamoDB, self).__init__("dynamodb", facade) diff --git a/ScoutSuite/providers/aws/resources/dynamodb/tables.py b/ScoutSuite/providers/aws/resources/dynamodb/tables.py index 12205349d..d372b6cd2 100644 --- a/ScoutSuite/providers/aws/resources/dynamodb/tables.py +++ b/ScoutSuite/providers/aws/resources/dynamodb/tables.py @@ -7,11 +7,14 @@ def __init__(self, facade: AWSFacade, region: str) -> None: super(Tables, self).__init__(facade) self.region = region - async def fetch_all(self, **kwargs): + async def fetch_all(self): raw_tables = await self.facade.dynamodb.get_tables(self.region) for raw_table in raw_tables: name, resource = await self._parse_table(raw_table) + self[name] = resource async def _parse_table(self, raw_table): table = {} - table['name'] = raw_table + t, resource = await self.facade.dynamodb.get_table(self.region, raw_table) + table = {**table, **resource} + return raw_table, table diff --git a/ScoutSuite/providers/aws/services.py b/ScoutSuite/providers/aws/services.py index ba0141ea6..a5b178117 100755 --- a/ScoutSuite/providers/aws/services.py +++ b/ScoutSuite/providers/aws/services.py @@ -6,6 +6,7 @@ from ScoutSuite.providers.aws.resources.cloudwatch.base import CloudWatch from ScoutSuite.providers.aws.resources.config.base import Config from ScoutSuite.providers.aws.resources.directconnect.base import DirectConnect +from ScoutSuite.providers.aws.resources.dynamodb.base import DynamoDB from ScoutSuite.providers.aws.resources.ec2.base import EC2 from ScoutSuite.providers.aws.resources.efs.base import EFS from ScoutSuite.providers.aws.resources.elasticache.base import ElastiCache @@ -59,7 +60,7 @@ class AWSServicesConfig(BaseServicesConfig): :ivar cloudtrail: CloudTrail configuration :ivar cloudwatch: CloudWatch configuration: :ivar config: Config configuration - :ivar dynamodb: DynomaDB configuration + :ivar dynamodb: DynamoDB configuration :ivar ec2: EC2 configuration :ivar ecs: ECS configuration :ivar ecr: ECR configuration @@ -70,7 +71,7 @@ class AWSServicesConfig(BaseServicesConfig): :ivar redshift: Redshift configuration :ivar s3: S3 configuration :ivar ses: SES configuration: - "ivar sns: SNS configuration + :ivar sns: SNS configuration :ivar sqs: SQS configuration """ @@ -87,6 +88,7 @@ def __init__(self, credentials=None, **kwargs): self.cloudwatch = CloudWatch(facade) self.config = Config(facade) self.directconnect = DirectConnect(facade) + self.dynamodb = DynamoDB(facade) self.ec2 = EC2(facade) self.efs = EFS(facade) self.elasticache = ElastiCache(facade) From daf40cbe1810a23a23a2792302fcf8152d6aa36f Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Fri, 29 May 2020 21:58:07 -0500 Subject: [PATCH 033/312] :building_construction: move parsing out of facade --- ScoutSuite/providers/aws/facade/dynamodb.py | 23 +------------------ .../aws/resources/dynamodb/tables.py | 23 +++++++++++++------ 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/dynamodb.py b/ScoutSuite/providers/aws/facade/dynamodb.py index 168ba0263..f4d370422 100644 --- a/ScoutSuite/providers/aws/facade/dynamodb.py +++ b/ScoutSuite/providers/aws/facade/dynamodb.py @@ -1,6 +1,3 @@ -# import debugpy - - from ScoutSuite.providers.utils import run_concurrently from ScoutSuite.core.console import print_exception from ScoutSuite.providers.aws.facade.utils import AWSFacadeUtils @@ -46,10 +43,6 @@ async def get_tags_for_resource(self, region, resource_arn): return [] async def get_table(self, region, table_name): - # debugpy.listen(5678) - # print("Waiting for debugger attach") - # debugpy.wait_for_client() - client = AWSFacadeUtils.get_client("dynamodb", self.session, region) try: raw_table = await run_concurrently( @@ -58,18 +51,4 @@ async def get_table(self, region, table_name): except Exception as e: print_exception(f"Failed to get table {table_name}: {e}") raw_table = None - - # debugpy.breakpoint() - if raw_table["Table"]: - table = {} - raw = raw_table["Table"] - if "SSEDescription" in raw: - table["sse_description"] = raw["SSEDescription"] - table["sse_enabled"] = True - else: - table["sse_enabled"] = False - - if "ArchivalSummary" in raw: - table["archival_summary"] = raw["ArchivalSummary"] - return raw["TableName"], table - return "", [] + return raw_table diff --git a/ScoutSuite/providers/aws/resources/dynamodb/tables.py b/ScoutSuite/providers/aws/resources/dynamodb/tables.py index d372b6cd2..2726529f7 100644 --- a/ScoutSuite/providers/aws/resources/dynamodb/tables.py +++ b/ScoutSuite/providers/aws/resources/dynamodb/tables.py @@ -1,3 +1,4 @@ +from debugpy.common.log import debug from ScoutSuite.providers.aws.facade.base import AWSFacade from ScoutSuite.providers.aws.resources.base import AWSResources @@ -8,13 +9,21 @@ def __init__(self, facade: AWSFacade, region: str) -> None: self.region = region async def fetch_all(self): - raw_tables = await self.facade.dynamodb.get_tables(self.region) - for raw_table in raw_tables: - name, resource = await self._parse_table(raw_table) - self[name] = resource + tables = await self.facade.dynamodb.get_tables(self.region) + for table_name in tables: + raw_table = await self.facade.dynamodb.get_table(self.region, table_name) + table = await self._parse_table(raw_table) + self[table_name] = table async def _parse_table(self, raw_table): table = {} - t, resource = await self.facade.dynamodb.get_table(self.region, raw_table) - table = {**table, **resource} - return raw_table, table + if raw_table["Table"]: + raw = raw_table["Table"] + if "SSEDescription" in raw: + table["sse_description"] = raw["SSEDescription"] + table["sse_enabled"] = True + else: + table["sse_enabled"] = False + if "ArchivalSummary" in raw: + table["archival_summary"] = raw["ArchivalSummary"] + return table From 5ea22ff0cba8039f79b41edcc531d817f23b4d14 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Fri, 29 May 2020 22:37:51 -0500 Subject: [PATCH 034/312] convert all of the response to snake case --- .../providers/aws/resources/dynamodb/tables.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ScoutSuite/providers/aws/resources/dynamodb/tables.py b/ScoutSuite/providers/aws/resources/dynamodb/tables.py index 2726529f7..b28d22197 100644 --- a/ScoutSuite/providers/aws/resources/dynamodb/tables.py +++ b/ScoutSuite/providers/aws/resources/dynamodb/tables.py @@ -1,6 +1,6 @@ -from debugpy.common.log import debug from ScoutSuite.providers.aws.facade.base import AWSFacade from ScoutSuite.providers.aws.resources.base import AWSResources +from ScoutSuite.providers.aws.utils import no_camel class Tables(AWSResources): @@ -20,10 +20,20 @@ async def _parse_table(self, raw_table): if raw_table["Table"]: raw = raw_table["Table"] if "SSEDescription" in raw: - table["sse_description"] = raw["SSEDescription"] table["sse_enabled"] = True else: table["sse_enabled"] = False - if "ArchivalSummary" in raw: - table["archival_summary"] = raw["ArchivalSummary"] + new_dict = await self.camel_keys(raw) + table.update(new_dict) + return table + + async def camel_keys(self, d: dict) -> dict: + new_table = {} + for k in d.keys(): + new_key = no_camel(k) + if type(d[k]) is dict: + new_table[new_key] = await self.camel_keys(d[k]) + else: + new_table[new_key] = d[k] + return new_table From 34dbc7f9c4fb9f38d4298d6565ec8dfa2d205805 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Fri, 29 May 2020 23:11:53 -0500 Subject: [PATCH 035/312] feat: create snake_keys utility function --- .../aws/resources/dynamodb/tables.py | 14 ++--------- ScoutSuite/providers/aws/utils.py | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/ScoutSuite/providers/aws/resources/dynamodb/tables.py b/ScoutSuite/providers/aws/resources/dynamodb/tables.py index b28d22197..e44530bd9 100644 --- a/ScoutSuite/providers/aws/resources/dynamodb/tables.py +++ b/ScoutSuite/providers/aws/resources/dynamodb/tables.py @@ -1,6 +1,6 @@ from ScoutSuite.providers.aws.facade.base import AWSFacade from ScoutSuite.providers.aws.resources.base import AWSResources -from ScoutSuite.providers.aws.utils import no_camel +from ScoutSuite.providers.aws.utils import snake_keys class Tables(AWSResources): @@ -23,17 +23,7 @@ async def _parse_table(self, raw_table): table["sse_enabled"] = True else: table["sse_enabled"] = False - new_dict = await self.camel_keys(raw) + new_dict = snake_keys(raw) table.update(new_dict) return table - - async def camel_keys(self, d: dict) -> dict: - new_table = {} - for k in d.keys(): - new_key = no_camel(k) - if type(d[k]) is dict: - new_table[new_key] = await self.camel_keys(d[k]) - else: - new_table[new_key] = d[k] - return new_table diff --git a/ScoutSuite/providers/aws/utils.py b/ScoutSuite/providers/aws/utils.py index 517f1bc9f..4fbcc6d4b 100755 --- a/ScoutSuite/providers/aws/utils.py +++ b/ScoutSuite/providers/aws/utils.py @@ -83,3 +83,26 @@ def no_camel(name): """ s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() + +def snake_keys(d: dict) -> dict: + """ + Converts a dictionary with CamelCase keys to camel_case + + :param name: d Dictionary to iterate over + :return: + """ + + new_table = {} + for k in d.keys(): + new_key = no_camel(k) + if type(d[k]) is dict: + new_table[new_key] = snake_keys(d[k]) + elif type(d[k]) is list: + if len(d[k]) > 0 and type(d[k][0]) is dict: + new_ary = [] + for val in d[k]: + new_ary.append(no_camel(val)) + new_table[new_key] = new_ary + else: + new_table[new_key] = d[k] + return new_table From 830ac868dd1b1f34e4e67d446998cba47b687f78 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Fri, 29 May 2020 23:22:55 -0500 Subject: [PATCH 036/312] cleanup --- ScoutSuite/providers/aws/utils.py | 50 ++++++++++++++----------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/ScoutSuite/providers/aws/utils.py b/ScoutSuite/providers/aws/utils.py index 4fbcc6d4b..6b59c02e7 100755 --- a/ScoutSuite/providers/aws/utils.py +++ b/ScoutSuite/providers/aws/utils.py @@ -1,24 +1,24 @@ import re from ScoutSuite.core.console import print_exception -ec2_classic = 'EC2-Classic' +ec2_classic = "EC2-Classic" def get_caller_identity(session): - sts_client = session.client('sts') + sts_client = session.client("sts") identity = sts_client.get_caller_identity() return identity def get_aws_account_id(session): caller_identity = get_caller_identity(session) - account_id = caller_identity['Arn'].split(':')[4] + account_id = caller_identity["Arn"].split(":")[4] return account_id def get_partition_name(session): caller_identity = get_caller_identity(session) - partition_name = caller_identity['Arn'].split(':')[1] + partition_name = caller_identity["Arn"].split(":")[1] return partition_name @@ -30,14 +30,15 @@ def is_throttled(e): :return: True if it's a throttling exception else False """ try: - return (hasattr(e, 'response') - and e.response - and 'Error' in e.response - and e.response['Error']['Code'] in ['Throttling', - 'RequestLimitExceeded', - 'ThrottlingException']) + return ( + hasattr(e, "response") + and e.response + and "Error" in e.response + and e.response["Error"]["Code"] + in ["Throttling", "RequestLimitExceeded", "ThrottlingException"] + ) except Exception as e: - print_exception('Unable to validate exception for throttling: {}'.format(e)) + print_exception("Unable to validate exception for throttling: {}".format(e)) return False @@ -64,14 +65,14 @@ def get_name(src, dst, default_attribute): :return: """ name_found = False - if 'Tags' in src: - for tag in src['Tags']: - if tag['Key'] == 'Name' and tag['Value'] != '': - dst['name'] = tag['Value'] + if "Tags" in src: + for tag in src["Tags"]: + if tag["Key"] == "Name" and tag["Value"] != "": + dst["name"] = tag["Value"] name_found = True if not name_found: - dst['name'] = src[default_attribute] - return dst['name'] + dst["name"] = src[default_attribute] + return dst["name"] def no_camel(name): @@ -81,10 +82,11 @@ def no_camel(name): :param name: Name string to convert :return: """ - s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) - return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() + s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name) + return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower() -def snake_keys(d: dict) -> dict: + +def snake_keys(d): """ Converts a dictionary with CamelCase keys to camel_case @@ -95,14 +97,8 @@ def snake_keys(d: dict) -> dict: new_table = {} for k in d.keys(): new_key = no_camel(k) - if type(d[k]) is dict: + if isinstance(d[k], dict): new_table[new_key] = snake_keys(d[k]) - elif type(d[k]) is list: - if len(d[k]) > 0 and type(d[k][0]) is dict: - new_ary = [] - for val in d[k]: - new_ary.append(no_camel(val)) - new_table[new_key] = new_ary else: new_table[new_key] = d[k] return new_table From 9cc9d43b115d0667554ed11f566acf71a26222dc Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 12:09:25 -0500 Subject: [PATCH 037/312] run pyupgrade --py3-only --- ScoutSuite/core/console.py | 1 - ScoutSuite/core/exceptions.py | 2 +- ScoutSuite/core/fs.py | 2 -- ScoutSuite/core/processingengine.py | 8 +++---- ScoutSuite/core/rule.py | 10 ++++----- ScoutSuite/core/rule_definition.py | 12 +++++----- ScoutSuite/core/ruleset.py | 6 ++--- ScoutSuite/core/server.py | 2 +- ScoutSuite/core/utils.py | 2 +- ScoutSuite/output/html.py | 14 +++++------- ScoutSuite/output/result_encoder.py | 6 ++--- ScoutSuite/output/utils.py | 3 --- ScoutSuite/providers/aliyun/provider.py | 4 ++-- .../providers/aliyun/resources/ecs/base.py | 2 +- .../aliyun/resources/ecs/instances.py | 2 +- .../providers/aliyun/resources/kms/base.py | 2 +- .../providers/aliyun/resources/kms/keys.py | 2 +- .../aliyun/resources/ram/api_keys.py | 2 +- .../providers/aliyun/resources/ram/base.py | 2 +- .../providers/aliyun/resources/ram/groups.py | 2 +- .../aliyun/resources/ram/password_policy.py | 2 +- .../aliyun/resources/ram/policies.py | 2 +- .../providers/aliyun/resources/ram/roles.py | 2 +- .../aliyun/resources/ram/security_policy.py | 2 +- .../providers/aliyun/resources/rds/base.py | 2 +- .../aliyun/resources/rds/instances.py | 2 +- .../providers/aliyun/resources/regions.py | 2 +- .../providers/aliyun/resources/vpc/base.py | 2 +- .../providers/aliyun/resources/vpc/vpcs.py | 2 +- ScoutSuite/providers/aliyun/services.py | 2 +- ScoutSuite/providers/aws/facade/base.py | 2 +- ScoutSuite/providers/aws/facade/basefacade.py | 2 +- ScoutSuite/providers/aws/facade/ec2.py | 2 +- ScoutSuite/providers/aws/facade/rds.py | 6 ++--- ScoutSuite/providers/aws/facade/s3.py | 22 +++++++++---------- ScoutSuite/providers/aws/provider.py | 4 ++-- .../providers/aws/resources/acm/base.py | 2 +- .../aws/resources/acm/certificates.py | 2 +- .../providers/aws/resources/awslambda/base.py | 2 +- .../aws/resources/awslambda/functions.py | 2 +- .../aws/resources/cloudformation/base.py | 2 +- .../aws/resources/cloudformation/stacks.py | 2 +- .../aws/resources/cloudtrail/base.py | 2 +- .../aws/resources/cloudtrail/trails.py | 8 +++---- .../aws/resources/cloudwatch/alarms.py | 2 +- .../aws/resources/cloudwatch/base.py | 2 +- .../providers/aws/resources/config/base.py | 2 +- .../aws/resources/config/recorders.py | 2 +- .../providers/aws/resources/config/rules.py | 2 +- .../aws/resources/directconnect/base.py | 2 +- .../resources/directconnect/connections.py | 2 +- ScoutSuite/providers/aws/resources/ec2/ami.py | 2 +- .../providers/aws/resources/ec2/base.py | 4 ++-- .../providers/aws/resources/ec2/instances.py | 2 +- .../aws/resources/ec2/networkinterfaces.py | 2 +- .../aws/resources/ec2/securitygroups.py | 4 ++-- .../providers/aws/resources/ec2/snapshots.py | 2 +- .../providers/aws/resources/ec2/volumes.py | 2 +- .../providers/aws/resources/efs/base.py | 2 +- .../aws/resources/efs/filesystems.py | 2 +- .../aws/resources/elasticache/base.py | 4 ++-- .../aws/resources/elasticache/cluster.py | 2 +- .../resources/elasticache/parametergroups.py | 2 +- .../resources/elasticache/securitygroups.py | 2 +- .../aws/resources/elasticache/subnetgroups.py | 2 +- .../providers/aws/resources/elb/base.py | 2 +- .../aws/resources/elb/load_balancers.py | 2 +- .../providers/aws/resources/elb/policies.py | 2 +- .../providers/aws/resources/elbv2/base.py | 2 +- .../aws/resources/elbv2/listeners.py | 2 +- .../aws/resources/elbv2/load_balancers.py | 2 +- .../providers/aws/resources/emr/base.py | 4 ++-- .../providers/aws/resources/emr/clusters.py | 2 +- .../providers/aws/resources/emr/vpcs.py | 2 +- .../providers/aws/resources/iam/base.py | 2 +- .../providers/aws/resources/kms/base.py | 2 +- .../providers/aws/resources/kms/grants.py | 2 +- .../providers/aws/resources/kms/keys.py | 2 +- .../providers/aws/resources/rds/base.py | 4 ++-- .../providers/aws/resources/rds/instances.py | 2 +- .../aws/resources/rds/parametergroups.py | 2 +- .../aws/resources/rds/securitygroups.py | 2 +- .../providers/aws/resources/rds/snapshots.py | 2 +- .../aws/resources/rds/subnetgroups.py | 2 +- .../providers/aws/resources/redshift/base.py | 2 +- .../redshift/cluster_parameter_groups.py | 2 +- .../resources/redshift/cluster_parameters.py | 2 +- .../redshift/cluster_security_groups.py | 2 +- .../aws/resources/redshift/clusters.py | 2 +- ScoutSuite/providers/aws/resources/regions.py | 2 +- .../providers/aws/resources/route53/base.py | 2 +- .../aws/resources/route53/domains.py | 2 +- .../aws/resources/route53/hosted_zones.py | 2 +- ScoutSuite/providers/aws/resources/s3/base.py | 2 +- .../aws/resources/secretsmanager/base.py | 2 +- .../aws/resources/secretsmanager/secrets.py | 2 +- .../providers/aws/resources/ses/base.py | 2 +- .../providers/aws/resources/ses/identities.py | 2 +- .../aws/resources/ses/identity_policies.py | 2 +- .../providers/aws/resources/sns/base.py | 2 +- .../aws/resources/sns/subscriptions.py | 2 +- .../providers/aws/resources/sns/topics.py | 2 +- .../providers/aws/resources/sqs/base.py | 2 +- .../providers/aws/resources/sqs/queues.py | 2 +- .../providers/aws/resources/vpc/base.py | 4 ++-- .../providers/aws/resources/vpc/flow_logs.py | 2 +- .../aws/resources/vpc/network_acls.py | 2 +- .../providers/aws/resources/vpc/subnets.py | 2 +- ScoutSuite/providers/aws/resources/vpcs.py | 2 +- ScoutSuite/providers/aws/services.py | 2 +- ScoutSuite/providers/azure/provider.py | 4 ++-- .../azure/resources/appservice/web_apps.py | 2 +- .../azure/resources/keyvault/vaults.py | 2 +- .../network/application_security_groups.py | 2 +- .../resources/network/network_interfaces.py | 2 +- .../resources/network/security_groups.py | 2 +- .../resources/network/virtual_networks.py | 2 +- .../azure/resources/network/watchers.py | 2 +- .../azure/resources/rbac/role_assignments.py | 2 +- .../providers/azure/resources/rbac/roles.py | 2 +- .../azure/resources/securitycenter/alerts.py | 2 +- .../auto_provisioning_settings.py | 2 +- .../securitycenter/compliance_results.py | 2 +- .../information_protection_policies.py | 2 +- .../resources/securitycenter/pricings.py | 2 +- .../regulatory_compliance_results.py | 2 +- .../securitycenter/security_contacts.py | 2 +- .../resources/securitycenter/settings.py | 2 +- .../database_blob_auditing_policies.py | 2 +- .../database_threat_detection_policies.py | 2 +- .../azure/resources/sqldatabase/databases.py | 2 +- .../sqldatabase/replication_links.py | 2 +- .../server_azure_ad_administrators.py | 2 +- .../server_blob_auditing_policies.py | 2 +- .../server_security_alert_policies.py | 2 +- .../azure/resources/sqldatabase/servers.py | 2 +- .../transparent_data_encryptions.py | 2 +- .../storageaccounts/blob_containers.py | 2 +- .../azure/resources/storageaccounts/queues.py | 2 +- .../storageaccounts/storage_accounts.py | 2 +- .../azure/resources/virtualmachines/disks.py | 2 +- .../azure/resources/virtualmachines/images.py | 2 +- .../resources/virtualmachines/instances.py | 2 +- .../resources/virtualmachines/snapshots.py | 2 +- ScoutSuite/providers/azure/services.py | 4 ++-- ScoutSuite/providers/base/provider.py | 7 ++---- ScoutSuite/providers/base/resources/base.py | 4 ++-- ScoutSuite/providers/base/services.py | 2 +- ScoutSuite/providers/gcp/facade/base.py | 6 ++--- .../gcp/facade/cloudresourcemanager.py | 2 +- ScoutSuite/providers/gcp/facade/cloudsql.py | 2 +- ScoutSuite/providers/gcp/facade/gce.py | 4 ++-- ScoutSuite/providers/gcp/facade/iam.py | 2 +- ScoutSuite/providers/gcp/facade/kms.py | 2 +- ScoutSuite/providers/gcp/provider.py | 4 ++-- .../gcp/resources/cloudsql/backups.py | 2 +- .../resources/cloudsql/database_instances.py | 2 +- .../providers/gcp/resources/cloudsql/users.py | 2 +- .../gcp/resources/cloudstorage/buckets.py | 2 +- .../providers/gcp/resources/gce/firewalls.py | 2 +- .../gcp/resources/gce/instance_disks.py | 2 +- .../providers/gcp/resources/gce/networks.py | 2 +- .../providers/gcp/resources/gce/snapshots.py | 2 +- .../gcp/resources/gce/subnetworks.py | 4 ++-- .../providers/gcp/resources/iam/groups.py | 2 +- .../providers/gcp/resources/iam/keys.py | 2 +- .../gcp/resources/iam/member_bindings.py | 2 +- .../resources/iam/service_account_bindings.py | 2 +- .../gcp/resources/iam/service_accounts.py | 4 ++-- .../providers/gcp/resources/iam/users.py | 2 +- .../providers/gcp/resources/kms/keyrings.py | 2 +- .../providers/gcp/resources/kms/keys.py | 2 +- ScoutSuite/providers/gcp/resources/regions.py | 2 +- .../resources/stackdriverlogging/metrics.py | 2 +- .../gcp/resources/stackdriverlogging/sinks.py | 2 +- .../stackdrivermonitoring/alert_policies.py | 2 +- .../stackdrivermonitoring/uptime_checks.py | 2 +- ScoutSuite/providers/gcp/resources/zones.py | 2 +- ScoutSuite/providers/gcp/services.py | 2 +- ScoutSuite/providers/oci/provider.py | 4 ++-- .../oci/resources/identity/api_keys.py | 2 +- .../identity/authentication_policy.py | 2 +- .../providers/oci/resources/identity/base.py | 2 +- .../oci/resources/identity/groups.py | 2 +- .../oci/resources/identity/policies.py | 2 +- .../providers/oci/resources/kms/base.py | 2 +- .../providers/oci/resources/kms/keys.py | 2 +- .../providers/oci/resources/kms/keyvaults.py | 2 +- .../oci/resources/objectstorage/base.py | 2 +- .../oci/resources/objectstorage/buckets.py | 2 +- ScoutSuite/providers/oci/services.py | 2 +- ScoutSuite/utils.py | 2 -- 192 files changed, 242 insertions(+), 257 deletions(-) diff --git a/ScoutSuite/core/console.py b/ScoutSuite/core/console.py index 9c05a1a1a..344948eba 100755 --- a/ScoutSuite/core/console.py +++ b/ScoutSuite/core/console.py @@ -4,7 +4,6 @@ import traceback import coloredlogs -from six.moves import input from ScoutSuite import ERRORS_LIST diff --git a/ScoutSuite/core/exceptions.py b/ScoutSuite/core/exceptions.py index 783974828..ee23d4400 100755 --- a/ScoutSuite/core/exceptions.py +++ b/ScoutSuite/core/exceptions.py @@ -3,7 +3,7 @@ from ScoutSuite.output.result_encoder import JavaScriptEncoder -class RuleExceptions(object): +class RuleExceptions: """ Exceptions handling """ diff --git a/ScoutSuite/core/fs.py b/ScoutSuite/core/fs.py index 3f46cd52e..0cd8451e5 100755 --- a/ScoutSuite/core/fs.py +++ b/ScoutSuite/core/fs.py @@ -1,5 +1,3 @@ -from __future__ import print_function - import datetime import json import os diff --git a/ScoutSuite/core/processingengine.py b/ScoutSuite/core/processingengine.py index 3c86389e3..d2f7bd4af 100755 --- a/ScoutSuite/core/processingengine.py +++ b/ScoutSuite/core/processingengine.py @@ -4,7 +4,7 @@ from ScoutSuite.core.utils import recurse -class ProcessingEngine(object): +class ProcessingEngine: """ """ @@ -21,7 +21,7 @@ def __init__(self, ruleset): manage_dictionary(self.rules, rule.path, []) self.rules[rule.path].append(rule) except Exception as e: - print_exception('Failed to create rule %s: %s' % (rule.filename, e)) + print_exception('Failed to create rule {}: {}'.format(rule.filename, e)) def run(self, cloud_provider, skip_dashboard=False): # Clean up existing findings @@ -35,7 +35,7 @@ def run(self, cloud_provider, skip_dashboard=False): if not rule.enabled: # or rule.service not in []: # TODO: handle this... continue - print_debug('Processing %s rule "%s" (%s)' % (rule.service, rule.description, rule.filename)) + print_debug('Processing {} rule "{}" ({})'.format(rule.service, rule.description, rule.filename)) finding_path = rule.path path = finding_path.split('.') service = path[0] @@ -68,7 +68,7 @@ def run(self, cloud_provider, skip_dashboard=False): cloud_provider.services[service][self.ruleset.rule_type][rule.key]['references'] = \ rule.references if hasattr(rule, 'references') else None except Exception as e: - print_exception('Failed to process rule defined in %s: %s' % (rule.filename, e)) + print_exception('Failed to process rule defined in {}: {}'.format(rule.filename, e)) # Fallback if process rule failed to ensure report creation and data dump still happen cloud_provider.services[service][self.ruleset.rule_type][rule.key]['checked_items'] = 0 cloud_provider.services[service][self.ruleset.rule_type][rule.key]['flagged_items'] = 0 diff --git a/ScoutSuite/core/rule.py b/ScoutSuite/core/rule.py index 1c9199cd0..0f2bec78d 100755 --- a/ScoutSuite/core/rule.py +++ b/ScoutSuite/core/rule.py @@ -29,7 +29,7 @@ ] -class Rule(object): +class Rule: def to_string(self): return str(vars(self)) @@ -71,8 +71,8 @@ def set_definition(self, rule_definitions, attributes=None, ip_ranges=None, para if condition[0].startswith('_INCLUDE_('): include = re.findall(r'_INCLUDE_\((.*?)\)', condition[0])[0] # new_conditions = load_data(include, key_name = 'conditions') - rules_path = '%s/%s' % (self.data_path, include) - with open(rules_path, 'rt') as f: + rules_path = '{}/{}'.format(self.data_path, include) + with open(rules_path) as f: new_conditions = f.read() for (i, value) in enumerate(condition[1]): new_conditions = re.sub(condition[1][i], condition[2][i], new_conditions) @@ -139,6 +139,6 @@ def set_definition(self, rule_definitions, attributes=None, ip_ranges=None, para setattr(self, 'key', self.filename) setattr(self, 'key', self.key.replace('.json', '')) if self.key_suffix: - setattr(self, 'key', '%s-%s' % (self.key, self.key_suffix)) + setattr(self, 'key', '{}-{}'.format(self.key, self.key_suffix)) except Exception as e: - print_exception('Failed to set definition %s: %s' % (self.filename, e)) + print_exception('Failed to set definition {}: {}'.format(self.filename, e)) diff --git a/ScoutSuite/core/rule_definition.py b/ScoutSuite/core/rule_definition.py index f4a19b2bc..2a849aca5 100755 --- a/ScoutSuite/core/rule_definition.py +++ b/ScoutSuite/core/rule_definition.py @@ -4,7 +4,7 @@ from ScoutSuite.core.console import print_error, print_exception -class RuleDefinition(object): +class RuleDefinition: def __init__(self, data_path, file_name=None, rule_dirs=None, string_definition=None): rule_dirs = [] if rule_dirs is None else rule_dirs @@ -28,7 +28,7 @@ def __str__(self): value = '-' * 80 + '\n' + ' ' * padding + ' %s' % getattr(self, 'description') + '\n' + '-' * 80 + '\n' quiet_list = ['descriptions', 'rule_dirs', 'rule_types', 'rules_data_path', 'string_definition'] value += '\n'.join( - '%s: %s' % (attr, str(getattr(self, attr))) for attr in vars(self) if attr not in quiet_list) + '{}: {}'.format(attr, str(getattr(self, attr))) for attr in vars(self) if attr not in quiet_list) value += '\n' return value @@ -46,7 +46,7 @@ def load(self): try: file_path = os.path.join(rule_dir, self.file_name) if rule_dir else self.file_name except Exception as e: - print_exception('Failed to load file %s: %s' % (self.file_name, str(e))) + print_exception('Failed to load file {}: {}'.format(self.file_name, str(e))) if os.path.isfile(file_path): self.file_path = file_path file_name_valid = True @@ -72,11 +72,11 @@ def load(self): print_error('Error: could not find %s' % self.file_name) else: try: - with open(self.file_path, 'rt') as f: + with open(self.file_path) as f: self.string_definition = f.read() self.load_from_string_definition() except Exception as e: - print_exception('Failed to load rule defined in %s: %s' % (self.file_name, str(e))) + print_exception('Failed to load rule defined in {}: {}'.format(self.file_name, str(e))) def load_from_string_definition(self): try: @@ -84,4 +84,4 @@ def load_from_string_definition(self): for attr in definition: setattr(self, attr, definition[attr]) except Exception as e: - print_exception('Failed to load string definition %s: %s' % (self.string_definition, str(e))) + print_exception('Failed to load string definition {}: {}'.format(self.string_definition, str(e))) diff --git a/ScoutSuite/core/ruleset.py b/ScoutSuite/core/ruleset.py index ef6ea7f80..1069e1d3a 100755 --- a/ScoutSuite/core/ruleset.py +++ b/ScoutSuite/core/ruleset.py @@ -73,7 +73,7 @@ def load(self, rule_type, quiet=False): """ if self.filename and os.path.exists(self.filename): try: - with open(self.filename, 'rt') as f: + with open(self.filename) as f: ruleset = json.load(f) self.about = ruleset['about'] if 'about' in ruleset else '' self.rules = {} @@ -82,7 +82,7 @@ def load(self, rule_type, quiet=False): for rule in ruleset['rules'][filename]: self.handle_rule_versions(filename, rule_type, rule) except Exception as e: - print_exception('Ruleset file %s contains malformed JSON: %s' % (self.filename, e)) + print_exception('Ruleset file {} contains malformed JSON: {}'.format(self.filename, e)) self.rules = [] self.about = '' else: @@ -193,7 +193,7 @@ def find_file(self, filename, filetype='rulesets'): if filename and not os.path.isfile(filename): # Not a valid relative / absolute path, check Scout's data under findings/ or filters/ if not filename.startswith('findings/') and not filename.startswith('filters/'): - filename = '%s/%s' % (filetype, filename) + filename = '{}/{}'.format(filetype, filename) if not os.path.isfile(filename): filename = os.path.join(self.rules_data_path, filename) if not os.path.isfile(filename) and not filename.endswith('.json'): diff --git a/ScoutSuite/core/server.py b/ScoutSuite/core/server.py index 13d342777..e127591e9 100755 --- a/ScoutSuite/core/server.py +++ b/ScoutSuite/core/server.py @@ -7,7 +7,7 @@ count_re = re.compile(r".*_count$") -class Server(object): +class Server: """ Boots a server that serves the result of the report for the user. This is still a proof of concept, but will eventually be used to serve data when it exceeds 400mb. diff --git a/ScoutSuite/core/utils.py b/ScoutSuite/core/utils.py index 83fb02465..f639d4edb 100755 --- a/ScoutSuite/core/utils.py +++ b/ScoutSuite/core/utils.py @@ -74,7 +74,7 @@ def recurse(all_info, current_info, target_path, current_path, config, add_suffi results = results + recurse(all_info, split_current_info, copy.deepcopy(target_path), split_current_path, config, add_suffix) # Python 2-3 compatible way to check for string type - elif isinstance(current_info, string_types): + elif isinstance(current_info, str): split_current_path = copy.deepcopy(current_path) results = results + recurse(all_info, current_info, [], split_current_path, config, add_suffix) diff --git a/ScoutSuite/output/html.py b/ScoutSuite/output/html.py index 8d312cd05..4650da35d 100755 --- a/ScoutSuite/output/html.py +++ b/ScoutSuite/output/html.py @@ -1,5 +1,3 @@ -from __future__ import print_function - import datetime import os import shutil @@ -15,7 +13,7 @@ from ScoutSuite.output.utils import get_filename, prompt_for_overwrite -class HTMLReport(object): +class HTMLReport: """ Base HTML report """ @@ -46,10 +44,10 @@ def get_content_from_folder(self, templates_type): os.path.isfile(os.path.join(template_dir, f))] for filename in template_files: try: - with open('%s' % filename, 'rt') as f: + with open('%s' % filename) as f: contents = contents + f.read() except Exception as e: - print_exception('Error reading filename %s: %s' % (filename, e)) + print_exception('Error reading filename {}: {}'.format(filename, e)) return contents def get_content_from_file(self, filename): @@ -57,10 +55,10 @@ def get_content_from_file(self, filename): template_dir = os.path.join(self.html_data_path, 'conditionals') filename = template_dir + filename try: - with open('%s' % filename, 'rt') as f: + with open('%s' % filename) as f: contents = contents + f.read() except Exception as e: - print_exception('Error reading filename %s: %s' % (filename, e)) + print_exception('Error reading filename {}: {}'.format(filename, e)) return contents def prepare_html_report_dir(self): @@ -93,7 +91,7 @@ def __init__(self, provider, report_name=None, report_dir=None, timestamp=False, self.provider = provider self.result_format = result_format - super(ScoutReport, self).__init__(report_name, report_dir, timestamp, exceptions, result_format) + super().__init__(report_name, report_dir, timestamp, exceptions, result_format) def save(self, config, exceptions, force_write=False, debug=False): self.prepare_html_report_dir() diff --git a/ScoutSuite/output/result_encoder.py b/ScoutSuite/output/result_encoder.py index dcf676a4a..15e6f309d 100755 --- a/ScoutSuite/output/result_encoder.py +++ b/ScoutSuite/output/result_encoder.py @@ -1,5 +1,3 @@ -from __future__ import print_function - import datetime import json import os @@ -36,7 +34,7 @@ def default(self, o): return str(o) -class ScoutResultEncoder(object): +class ScoutResultEncoder: def __init__(self, report_name=None, report_dir=None, timestamp=None): self.report_name = report_name if self.report_name: @@ -99,7 +97,7 @@ class JavaScriptEncoder(ScoutResultEncoder): def load_from_file(self, file_type, file_path=None, first_line=None): if not file_path: file_path, first_line = get_filename(file_type, self.report_name, self.report_dir) - with open(file_path, 'rt') as f: + with open(file_path) as f: json_payload = f.readlines() if first_line: json_payload.pop(0) diff --git a/ScoutSuite/output/utils.py b/ScoutSuite/output/utils.py index c139cc250..fead8ed57 100755 --- a/ScoutSuite/output/utils.py +++ b/ScoutSuite/output/utils.py @@ -1,9 +1,6 @@ -from __future__ import print_function - import os import sys -from six.moves import input from ScoutSuite import DEFAULT_REPORT_DIRECTORY, DEFAULT_REPORT_RESULTS_DIRECTORY from ScoutSuite.core.console import print_error diff --git a/ScoutSuite/providers/aliyun/provider.py b/ScoutSuite/providers/aliyun/provider.py index f95d3e147..29bdc9769 100755 --- a/ScoutSuite/providers/aliyun/provider.py +++ b/ScoutSuite/providers/aliyun/provider.py @@ -26,7 +26,7 @@ def __init__(self, self.credentials = kwargs['credentials'] self.account_id = self.credentials.caller_details['AccountId'] - super(AliyunProvider, self).__init__(report_dir, timestamp, services, skipped_services) + super().__init__(report_dir, timestamp, services, skipped_services) def get_report_name(self): """ @@ -39,5 +39,5 @@ def get_report_name(self): def preprocessing(self, ip_ranges=None, ip_ranges_name_key=None): - super(AliyunProvider, self).preprocessing() + super().preprocessing() diff --git a/ScoutSuite/providers/aliyun/resources/ecs/base.py b/ScoutSuite/providers/aliyun/resources/ecs/base.py index 4a3ac626c..e9c78639d 100755 --- a/ScoutSuite/providers/aliyun/resources/ecs/base.py +++ b/ScoutSuite/providers/aliyun/resources/ecs/base.py @@ -9,4 +9,4 @@ class ECS(Regions): ] def __init__(self, facade: AliyunFacade): - super(ECS, self).__init__('ecs', facade) + super().__init__('ecs', facade) diff --git a/ScoutSuite/providers/aliyun/resources/ecs/instances.py b/ScoutSuite/providers/aliyun/resources/ecs/instances.py index c82927932..a07048102 100755 --- a/ScoutSuite/providers/aliyun/resources/ecs/instances.py +++ b/ScoutSuite/providers/aliyun/resources/ecs/instances.py @@ -4,7 +4,7 @@ class Instances(AliyunResources): def __init__(self, facade: AliyunFacade, region: str): - super(Instances, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aliyun/resources/kms/base.py b/ScoutSuite/providers/aliyun/resources/kms/base.py index 38329b6e0..b1cf6292e 100755 --- a/ScoutSuite/providers/aliyun/resources/kms/base.py +++ b/ScoutSuite/providers/aliyun/resources/kms/base.py @@ -9,4 +9,4 @@ class KMS(Regions): ] def __init__(self, facade: AliyunFacade): - super(KMS, self).__init__('kms', facade) + super().__init__('kms', facade) diff --git a/ScoutSuite/providers/aliyun/resources/kms/keys.py b/ScoutSuite/providers/aliyun/resources/kms/keys.py index e430fe95f..4cdaf409b 100755 --- a/ScoutSuite/providers/aliyun/resources/kms/keys.py +++ b/ScoutSuite/providers/aliyun/resources/kms/keys.py @@ -4,7 +4,7 @@ class Keys(AliyunResources): def __init__(self, facade: AliyunFacade, region: str): - super(Keys, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aliyun/resources/ram/api_keys.py b/ScoutSuite/providers/aliyun/resources/ram/api_keys.py index 75336e743..7f0f70759 100755 --- a/ScoutSuite/providers/aliyun/resources/ram/api_keys.py +++ b/ScoutSuite/providers/aliyun/resources/ram/api_keys.py @@ -4,7 +4,7 @@ class ApiKeys(AliyunResources): def __init__(self, facade: AliyunFacade, user): - super(ApiKeys, self).__init__(facade) + super().__init__(facade) self.user = user async def fetch_all(self): diff --git a/ScoutSuite/providers/aliyun/resources/ram/base.py b/ScoutSuite/providers/aliyun/resources/ram/base.py index ac48b169e..d258f3a36 100755 --- a/ScoutSuite/providers/aliyun/resources/ram/base.py +++ b/ScoutSuite/providers/aliyun/resources/ram/base.py @@ -19,7 +19,7 @@ class RAM(AliyunCompositeResources): ] def __init__(self, facade: AliyunFacade): - super(RAM, self).__init__(facade) + super().__init__(facade) self.service = 'ram' async def fetch_all(self, **kwargs): diff --git a/ScoutSuite/providers/aliyun/resources/ram/groups.py b/ScoutSuite/providers/aliyun/resources/ram/groups.py index 00b2aed3a..c203ba870 100755 --- a/ScoutSuite/providers/aliyun/resources/ram/groups.py +++ b/ScoutSuite/providers/aliyun/resources/ram/groups.py @@ -4,7 +4,7 @@ class Groups(AliyunResources): def __init__(self, facade: AliyunFacade): - super(Groups, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): for raw_group in await self.facade.ram.get_groups(): diff --git a/ScoutSuite/providers/aliyun/resources/ram/password_policy.py b/ScoutSuite/providers/aliyun/resources/ram/password_policy.py index d36923c0e..cc2ee3f88 100755 --- a/ScoutSuite/providers/aliyun/resources/ram/password_policy.py +++ b/ScoutSuite/providers/aliyun/resources/ram/password_policy.py @@ -4,7 +4,7 @@ class PasswordPolicy(AliyunResources): def __init__(self, facade: AliyunFacade): - super(PasswordPolicy, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): raw_password_policy = await self.facade.ram.get_password_policy() diff --git a/ScoutSuite/providers/aliyun/resources/ram/policies.py b/ScoutSuite/providers/aliyun/resources/ram/policies.py index c6923210f..c92e510f0 100755 --- a/ScoutSuite/providers/aliyun/resources/ram/policies.py +++ b/ScoutSuite/providers/aliyun/resources/ram/policies.py @@ -5,7 +5,7 @@ class Policies(AliyunResources): def __init__(self, facade: AliyunFacade): - super(Policies, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): for raw_policy in await self.facade.ram.get_policies(): diff --git a/ScoutSuite/providers/aliyun/resources/ram/roles.py b/ScoutSuite/providers/aliyun/resources/ram/roles.py index cd718ee83..efc7c3d1f 100755 --- a/ScoutSuite/providers/aliyun/resources/ram/roles.py +++ b/ScoutSuite/providers/aliyun/resources/ram/roles.py @@ -4,7 +4,7 @@ class Roles(AliyunResources): def __init__(self, facade: AliyunFacade): - super(Roles, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): for raw_role in await self.facade.ram.get_roles(): diff --git a/ScoutSuite/providers/aliyun/resources/ram/security_policy.py b/ScoutSuite/providers/aliyun/resources/ram/security_policy.py index e839484d2..b4392864c 100755 --- a/ScoutSuite/providers/aliyun/resources/ram/security_policy.py +++ b/ScoutSuite/providers/aliyun/resources/ram/security_policy.py @@ -4,7 +4,7 @@ class SecurityPolicy(AliyunResources): def __init__(self, facade: AliyunFacade): - super(SecurityPolicy, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): raw_security_policy = await self.facade.ram.get_security_policy() diff --git a/ScoutSuite/providers/aliyun/resources/rds/base.py b/ScoutSuite/providers/aliyun/resources/rds/base.py index e815b562a..de201acb8 100755 --- a/ScoutSuite/providers/aliyun/resources/rds/base.py +++ b/ScoutSuite/providers/aliyun/resources/rds/base.py @@ -9,5 +9,5 @@ class RDS(Regions): ] def __init__(self, facade: AliyunFacade): - super(RDS, self).__init__('rds', facade) + super().__init__('rds', facade) diff --git a/ScoutSuite/providers/aliyun/resources/rds/instances.py b/ScoutSuite/providers/aliyun/resources/rds/instances.py index 03fce666a..9e0e905a0 100755 --- a/ScoutSuite/providers/aliyun/resources/rds/instances.py +++ b/ScoutSuite/providers/aliyun/resources/rds/instances.py @@ -4,7 +4,7 @@ class Instances(AliyunResources): def __init__(self, facade: AliyunFacade, region: str): - super(Instances, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aliyun/resources/regions.py b/ScoutSuite/providers/aliyun/resources/regions.py index 8d995d86c..f7fbd5e9b 100755 --- a/ScoutSuite/providers/aliyun/resources/regions.py +++ b/ScoutSuite/providers/aliyun/resources/regions.py @@ -6,7 +6,7 @@ class Regions(AliyunCompositeResources, metaclass=abc.ABCMeta): def __init__(self, service: str, facade: AliyunFacade): - super(Regions, self).__init__(facade) + super().__init__(facade) self.service = service async def fetch_all(self, regions=None): diff --git a/ScoutSuite/providers/aliyun/resources/vpc/base.py b/ScoutSuite/providers/aliyun/resources/vpc/base.py index 7f876d613..11cb86ca0 100755 --- a/ScoutSuite/providers/aliyun/resources/vpc/base.py +++ b/ScoutSuite/providers/aliyun/resources/vpc/base.py @@ -9,4 +9,4 @@ class VPC(Regions): ] def __init__(self, facade: AliyunFacade): - super(VPC, self).__init__('vpc', facade) + super().__init__('vpc', facade) diff --git a/ScoutSuite/providers/aliyun/resources/vpc/vpcs.py b/ScoutSuite/providers/aliyun/resources/vpc/vpcs.py index 9c4bb7139..14dd0e116 100755 --- a/ScoutSuite/providers/aliyun/resources/vpc/vpcs.py +++ b/ScoutSuite/providers/aliyun/resources/vpc/vpcs.py @@ -4,7 +4,7 @@ class VPCs(AliyunResources): def __init__(self, facade: AliyunFacade, region: str): - super(VPCs, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aliyun/services.py b/ScoutSuite/providers/aliyun/services.py index 6ee1cfdd7..633125505 100755 --- a/ScoutSuite/providers/aliyun/services.py +++ b/ScoutSuite/providers/aliyun/services.py @@ -12,7 +12,7 @@ class AliyunServicesConfig(BaseServicesConfig): def __init__(self, credentials, **kwargs): - super(AliyunServicesConfig, self).__init__(credentials) + super().__init__(credentials) facade = AliyunFacade(credentials) diff --git a/ScoutSuite/providers/aws/facade/base.py b/ScoutSuite/providers/aws/facade/base.py index a2e25f743..375f70b2e 100755 --- a/ScoutSuite/providers/aws/facade/base.py +++ b/ScoutSuite/providers/aws/facade/base.py @@ -58,7 +58,7 @@ class AWSFacade(AWSBaseFacade): def __init__(self, credentials=None): - super(AWSFacade, self).__init__() + super().__init__() self.owner_id = get_aws_account_id(credentials.session) self.session = credentials.session self._instantiate_facades() diff --git a/ScoutSuite/providers/aws/facade/basefacade.py b/ScoutSuite/providers/aws/facade/basefacade.py index e168ffef1..7429669b6 100755 --- a/ScoutSuite/providers/aws/facade/basefacade.py +++ b/ScoutSuite/providers/aws/facade/basefacade.py @@ -1,6 +1,6 @@ import boto3 -class AWSBaseFacade(object): +class AWSBaseFacade: def __init__(self, session: boto3.session.Session = None): self.session = session diff --git a/ScoutSuite/providers/aws/facade/ec2.py b/ScoutSuite/providers/aws/facade/ec2.py index 27af07f7e..c316c8d21 100755 --- a/ScoutSuite/providers/aws/facade/ec2.py +++ b/ScoutSuite/providers/aws/facade/ec2.py @@ -17,7 +17,7 @@ class EC2Facade(AWSBaseFacade): def __init__(self, session: boto3.session.Session, owner_id: str): self.owner_id = owner_id - super(EC2Facade, self).__init__(session) + super().__init__(session) async def get_instance_user_data(self, region: str, instance_id: str): ec2_client = AWSFacadeUtils.get_client('ec2', self.session, region) diff --git a/ScoutSuite/providers/aws/facade/rds.py b/ScoutSuite/providers/aws/facade/rds.py index bf98bf005..e6b1e4b56 100755 --- a/ScoutSuite/providers/aws/facade/rds.py +++ b/ScoutSuite/providers/aws/facade/rds.py @@ -53,9 +53,9 @@ async def _get_and_set_instance_tags(self, instance: {}, region: str): instance['Tags'] = {x['Key']: x['Value'] for x in instance_tagset['TagList']} except ClientError as e: if e.response['Error']['Code'] != 'NoSuchTagSet': - print_exception('Failed to get db instance tags for %s: %s' % (instance['DBInstanceIdentifier'], e)) + print_exception('Failed to get db instance tags for {}: {}'.format(instance['DBInstanceIdentifier'], e)) except Exception as e: - print_exception('Failed to get db instance tags for %s: %s' % (instance['DBInstanceIdentifier'], e)) + print_exception('Failed to get db instance tags for {}: {}'.format(instance['DBInstanceIdentifier'], e)) instance['Tags'] = {} async def _get_and_set_instance_clusters(self, instance: {}, region: str): @@ -170,7 +170,7 @@ async def _get_and_set_db_parameters(self, parameter_group: {}, region: str): parameter_name = parameter.pop('ParameterName') parameter_group['Parameters'][parameter_name] = parameter except Exception as e: - print_exception('Failed fetching DB parameters for %s: %s' % (name, e)) + print_exception('Failed fetching DB parameters for {}: {}'.format(name, e)) async def get_security_groups(self, region: str) : try: diff --git a/ScoutSuite/providers/aws/facade/s3.py b/ScoutSuite/providers/aws/facade/s3.py index 6af1e674e..8ae342427 100755 --- a/ScoutSuite/providers/aws/facade/s3.py +++ b/ScoutSuite/providers/aws/facade/s3.py @@ -81,7 +81,7 @@ async def _get_and_set_s3_bucket_logging(self, bucket: {}): try: logging = await run_concurrently(lambda: client.get_bucket_logging(Bucket=bucket['Name'])) except Exception as e: - print_exception('Failed to get logging configuration for %s: %s' % (bucket['Name'], e)) + print_exception('Failed to get logging configuration for {}: {}'.format(bucket['Name'], e)) bucket['logging'] = 'Unknown' else: if 'LoggingEnabled' in logging: @@ -97,7 +97,7 @@ async def _get_and_set_s3_bucket_versioning(self, bucket: {}): bucket['versioning_status_enabled'] = self._status_to_bool(versioning.get('Status')) bucket['version_mfa_delete_enabled'] = self._status_to_bool(versioning.get('MFADelete')) except Exception as e: - print_exception('Failed to get versioning configuration for %s: %s' % (bucket['Name'], e)) + print_exception('Failed to get versioning configuration for {}: {}'.format(bucket['Name'], e)) bucket['versioning_status_enabled'] = None bucket['version_mfa_delete_enabled'] = None @@ -110,7 +110,7 @@ async def _get_and_set_s3_bucket_webhosting(self, bucket: {}): if "NoSuchWebsiteConfiguration" in str(e): bucket['web_hosting_enabled'] = False else: - print_exception('Failed to get web hosting configuration for %s: %s' % (bucket['Name'], e)) + print_exception('Failed to get web hosting configuration for {}: {}'.format(bucket['Name'], e)) async def _get_and_set_s3_bucket_default_encryption(self, bucket: {}): bucket_name = bucket['Name'] @@ -123,9 +123,9 @@ async def _get_and_set_s3_bucket_default_encryption(self, bucket: {}): bucket['default_encryption_enabled'] = False else: bucket['default_encryption_enabled'] = None - print_exception('Failed to get encryption configuration for %s: %s' % (bucket_name, e)) + print_exception('Failed to get encryption configuration for {}: {}'.format(bucket_name, e)) except Exception as e: - print_exception('Failed to get encryption configuration for %s: %s' % (bucket_name, e)) + print_exception('Failed to get encryption configuration for {}: {}'.format(bucket_name, e)) bucket['default_encryption'] = 'Unknown' async def _get_and_set_s3_acls(self, bucket: {}, key_name=None): @@ -156,7 +156,7 @@ async def _get_and_set_s3_acls(self, bucket: {}, key_name=None): self._set_s3_permissions(grantees[grantee]['permissions'], permission) bucket['grantees'] = grantees except Exception as e: - print_exception('Failed to get ACL configuration for %s: %s' % (bucket_name, e)) + print_exception('Failed to get ACL configuration for {}: {}'.format(bucket_name, e)) bucket['grantees'] = {} async def _get_and_set_s3_bucket_policy(self, bucket: {}): @@ -166,9 +166,9 @@ async def _get_and_set_s3_bucket_policy(self, bucket: {}): bucket['policy'] = json.loads(bucket_policy['Policy']) except ClientError as e: if e.response['Error']['Code'] != 'NoSuchBucketPolicy': - print_exception('Failed to get bucket policy for %s: %s' % (bucket['Name'], e)) + print_exception('Failed to get bucket policy for {}: {}'.format(bucket['Name'], e)) except Exception as e: - print_exception('Failed to get bucket policy for %s: %s' % (bucket['Name'], e)) + print_exception('Failed to get bucket policy for {}: {}'.format(bucket['Name'], e)) bucket['grantees'] = {} async def _get_and_set_s3_bucket_tags(self, bucket: {}): @@ -178,9 +178,9 @@ async def _get_and_set_s3_bucket_tags(self, bucket: {}): bucket['tags'] = {x['Key']: x['Value'] for x in bucket_tagset['TagSet']} except ClientError as e: if e.response['Error']['Code'] != 'NoSuchTagSet': - print_exception('Failed to get bucket tags for %s: %s' % (bucket['Name'], e)) + print_exception('Failed to get bucket tags for {}: {}'.format(bucket['Name'], e)) except Exception as e: - print_exception('Failed to get bucket tags for %s: %s' % (bucket['Name'], e)) + print_exception('Failed to get bucket tags for {}: {}'.format(bucket['Name'], e)) bucket['tags'] = {} def _set_s3_bucket_secure_transport(self, bucket: {}): @@ -201,7 +201,7 @@ def _set_s3_bucket_secure_transport(self, bucket: {}): else: bucket['secure_transport_enabled'] = False except Exception as e: - print_exception('Failed to evaluate bucket policy for %s: %s' % (bucket['Name'], e)) + print_exception('Failed to evaluate bucket policy for {}: {}'.format(bucket['Name'], e)) bucket['secure_transport'] = None @staticmethod diff --git a/ScoutSuite/providers/aws/provider.py b/ScoutSuite/providers/aws/provider.py index 7a6b1780c..24904b223 100755 --- a/ScoutSuite/providers/aws/provider.py +++ b/ScoutSuite/providers/aws/provider.py @@ -40,7 +40,7 @@ def __init__(self, profile='default', report_dir=None, timestamp=None, services= self.account_id = get_aws_account_id(self.credentials.session) - super(AWSProvider, self).__init__(report_dir, timestamp, + super().__init__(report_dir, timestamp, services, skipped_services, result_format) def get_report_name(self): @@ -95,7 +95,7 @@ def preprocessing(self, ip_ranges=None, ip_ranges_name_key=None): self._add_cidr_display_name(ip_ranges, ip_ranges_name_key) - super(AWSProvider, self).preprocessing() + super().preprocessing() def _add_cidr_display_name(self, ip_ranges, ip_ranges_name_key): if len(ip_ranges): diff --git a/ScoutSuite/providers/aws/resources/acm/base.py b/ScoutSuite/providers/aws/resources/acm/base.py index bfbe91e3b..9033ff731 100755 --- a/ScoutSuite/providers/aws/resources/acm/base.py +++ b/ScoutSuite/providers/aws/resources/acm/base.py @@ -10,4 +10,4 @@ class Certificates(Regions): ] def __init__(self, facade: AWSFacade): - super(Certificates, self).__init__('acm', facade) + super().__init__('acm', facade) diff --git a/ScoutSuite/providers/aws/resources/acm/certificates.py b/ScoutSuite/providers/aws/resources/acm/certificates.py index 920b076d6..77532c1a2 100755 --- a/ScoutSuite/providers/aws/resources/acm/certificates.py +++ b/ScoutSuite/providers/aws/resources/acm/certificates.py @@ -6,7 +6,7 @@ class Certificates(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Certificates, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/awslambda/base.py b/ScoutSuite/providers/aws/resources/awslambda/base.py index 9516f5772..8883439c1 100755 --- a/ScoutSuite/providers/aws/resources/awslambda/base.py +++ b/ScoutSuite/providers/aws/resources/awslambda/base.py @@ -10,4 +10,4 @@ class Lambdas(Regions): ] def __init__(self, facade: AWSFacade): - super(Lambdas, self).__init__('lambda', facade) + super().__init__('lambda', facade) diff --git a/ScoutSuite/providers/aws/resources/awslambda/functions.py b/ScoutSuite/providers/aws/resources/awslambda/functions.py index 04a0ee7a6..6d5404480 100755 --- a/ScoutSuite/providers/aws/resources/awslambda/functions.py +++ b/ScoutSuite/providers/aws/resources/awslambda/functions.py @@ -4,7 +4,7 @@ class Functions(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Functions, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/cloudformation/base.py b/ScoutSuite/providers/aws/resources/cloudformation/base.py index 621af14fb..1cdc7027a 100755 --- a/ScoutSuite/providers/aws/resources/cloudformation/base.py +++ b/ScoutSuite/providers/aws/resources/cloudformation/base.py @@ -9,4 +9,4 @@ class CloudFormation(Regions): ] def __init__(self, facade: AWSFacade): - super(CloudFormation, self).__init__('cloudformation', facade) + super().__init__('cloudformation', facade) diff --git a/ScoutSuite/providers/aws/resources/cloudformation/stacks.py b/ScoutSuite/providers/aws/resources/cloudformation/stacks.py index dc81df735..6fa5b9a20 100755 --- a/ScoutSuite/providers/aws/resources/cloudformation/stacks.py +++ b/ScoutSuite/providers/aws/resources/cloudformation/stacks.py @@ -6,7 +6,7 @@ class Stacks(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Stacks, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/cloudtrail/base.py b/ScoutSuite/providers/aws/resources/cloudtrail/base.py index 766a83223..bcd1fc881 100755 --- a/ScoutSuite/providers/aws/resources/cloudtrail/base.py +++ b/ScoutSuite/providers/aws/resources/cloudtrail/base.py @@ -10,7 +10,7 @@ class CloudTrail(Regions): ] def __init__(self, facade: AWSFacade): - super(CloudTrail, self).__init__('cloudtrail', facade) + super().__init__('cloudtrail', facade) async def finalize(self): global_events_logging = [] diff --git a/ScoutSuite/providers/aws/resources/cloudtrail/trails.py b/ScoutSuite/providers/aws/resources/cloudtrail/trails.py index 84e7872a3..1cc863f35 100755 --- a/ScoutSuite/providers/aws/resources/cloudtrail/trails.py +++ b/ScoutSuite/providers/aws/resources/cloudtrail/trails.py @@ -7,7 +7,7 @@ class Trails(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Trails, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): @@ -25,7 +25,7 @@ def _parse_trail(self, raw_trail): raw_trail['HomeRegion'] != self.region: for key in ['HomeRegion', 'TrailARN']: trail[key] = raw_trail[key] - trail['scout_link'] = 'services.cloudtrail.regions.%s.trails.%s' % (raw_trail['HomeRegion'], trail_id) + trail['scout_link'] = 'services.cloudtrail.regions.{}.trails.{}'.format(raw_trail['HomeRegion'], trail_id) return trail_id, trail for key in raw_trail: @@ -52,8 +52,8 @@ def _parse_trail(self, raw_trail): def data_logging_status(self, trail): for event_selector in trail['EventSelectors']: has_wildcard = \ - {u'Values': ['arn:aws:s3'], 'Type': 'AWS::S3::Object'} in event_selector['DataResources'] or \ - {u'Values': ['arn:aws:lambda'], 'Type': 'AWS::Lambda::Function'} in event_selector['DataResources'] + {'Values': ['arn:aws:s3'], 'Type': 'AWS::S3::Object'} in event_selector['DataResources'] or \ + {'Values': ['arn:aws:lambda'], 'Type': 'AWS::Lambda::Function'} in event_selector['DataResources'] is_logging = trail['IsLogging'] if has_wildcard and is_logging and self.is_fresh(trail): return True diff --git a/ScoutSuite/providers/aws/resources/cloudwatch/alarms.py b/ScoutSuite/providers/aws/resources/cloudwatch/alarms.py index 45a5f8f00..369255610 100755 --- a/ScoutSuite/providers/aws/resources/cloudwatch/alarms.py +++ b/ScoutSuite/providers/aws/resources/cloudwatch/alarms.py @@ -5,7 +5,7 @@ class Alarms(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Alarms, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/cloudwatch/base.py b/ScoutSuite/providers/aws/resources/cloudwatch/base.py index 83fe0c8ab..3b17555f1 100755 --- a/ScoutSuite/providers/aws/resources/cloudwatch/base.py +++ b/ScoutSuite/providers/aws/resources/cloudwatch/base.py @@ -10,4 +10,4 @@ class CloudWatch(Regions): ] def __init__(self, facade: AWSFacade): - super(CloudWatch, self).__init__('cloudwatch', facade) + super().__init__('cloudwatch', facade) diff --git a/ScoutSuite/providers/aws/resources/config/base.py b/ScoutSuite/providers/aws/resources/config/base.py index 7f4f09679..e2959c3b8 100755 --- a/ScoutSuite/providers/aws/resources/config/base.py +++ b/ScoutSuite/providers/aws/resources/config/base.py @@ -11,4 +11,4 @@ class Config(Regions): ] def __init__(self, facade: AWSFacade): - super(Config, self).__init__('config', facade) + super().__init__('config', facade) diff --git a/ScoutSuite/providers/aws/resources/config/recorders.py b/ScoutSuite/providers/aws/resources/config/recorders.py index 9352d6684..81a7d2982 100755 --- a/ScoutSuite/providers/aws/resources/config/recorders.py +++ b/ScoutSuite/providers/aws/resources/config/recorders.py @@ -4,7 +4,7 @@ class Recorders(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Recorders, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/config/rules.py b/ScoutSuite/providers/aws/resources/config/rules.py index e23eb3162..484e083b0 100755 --- a/ScoutSuite/providers/aws/resources/config/rules.py +++ b/ScoutSuite/providers/aws/resources/config/rules.py @@ -4,7 +4,7 @@ class Rules(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Rules, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/directconnect/base.py b/ScoutSuite/providers/aws/resources/directconnect/base.py index a76ff05dc..bd597a54c 100755 --- a/ScoutSuite/providers/aws/resources/directconnect/base.py +++ b/ScoutSuite/providers/aws/resources/directconnect/base.py @@ -10,4 +10,4 @@ class DirectConnect(Regions): ] def __init__(self, facade: AWSFacade): - super(DirectConnect, self).__init__('directconnect', facade) + super().__init__('directconnect', facade) diff --git a/ScoutSuite/providers/aws/resources/directconnect/connections.py b/ScoutSuite/providers/aws/resources/directconnect/connections.py index 0596710a2..82de5af90 100755 --- a/ScoutSuite/providers/aws/resources/directconnect/connections.py +++ b/ScoutSuite/providers/aws/resources/directconnect/connections.py @@ -4,7 +4,7 @@ class Connections(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Connections, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/ec2/ami.py b/ScoutSuite/providers/aws/resources/ec2/ami.py index 2e0538846..ca30e6a83 100755 --- a/ScoutSuite/providers/aws/resources/ec2/ami.py +++ b/ScoutSuite/providers/aws/resources/ec2/ami.py @@ -4,7 +4,7 @@ class AmazonMachineImages(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(AmazonMachineImages, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/ec2/base.py b/ScoutSuite/providers/aws/resources/ec2/base.py index 759ec5065..0a82deac7 100755 --- a/ScoutSuite/providers/aws/resources/ec2/base.py +++ b/ScoutSuite/providers/aws/resources/ec2/base.py @@ -14,10 +14,10 @@ class EC2(Regions): ] def __init__(self, facade): - super(EC2, self).__init__('ec2', facade) + super().__init__('ec2', facade) async def fetch_all(self, regions=None, excluded_regions=None, partition_name='aws', **kwargs): - await super(EC2, self).fetch_all(regions, excluded_regions, partition_name) + await super().fetch_all(regions, excluded_regions, partition_name) for region in self['regions']: self['regions'][region]['instances_count'] =\ diff --git a/ScoutSuite/providers/aws/resources/ec2/instances.py b/ScoutSuite/providers/aws/resources/ec2/instances.py index ab59acbe5..ca3ebf30e 100755 --- a/ScoutSuite/providers/aws/resources/ec2/instances.py +++ b/ScoutSuite/providers/aws/resources/ec2/instances.py @@ -7,7 +7,7 @@ class EC2Instances(AWSResources): def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(EC2Instances, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/ec2/networkinterfaces.py b/ScoutSuite/providers/aws/resources/ec2/networkinterfaces.py index a76930b2d..cb0bfd599 100755 --- a/ScoutSuite/providers/aws/resources/ec2/networkinterfaces.py +++ b/ScoutSuite/providers/aws/resources/ec2/networkinterfaces.py @@ -4,7 +4,7 @@ class NetworkInterfaces(AWSResources): def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(NetworkInterfaces, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/ec2/securitygroups.py b/ScoutSuite/providers/aws/resources/ec2/securitygroups.py index c6da28c3f..9a61edd2c 100755 --- a/ScoutSuite/providers/aws/resources/ec2/securitygroups.py +++ b/ScoutSuite/providers/aws/resources/ec2/securitygroups.py @@ -8,7 +8,7 @@ class SecurityGroups(AWSResources): icmp_message_types_dict = load_data('icmp_message_types.json', 'icmp_message_types') def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(SecurityGroups, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc @@ -61,7 +61,7 @@ def _parse_security_group_rules(self, rules): elif rule['FromPort'] == rule['ToPort']: port_value = str(rule['FromPort']) else: - port_value = '%s-%s' % (rule['FromPort'], rule['ToPort']) + port_value = '{}-{}'.format(rule['FromPort'], rule['ToPort']) manage_dictionary(protocols[ip_protocol]['ports'], port_value, {}) # Save grants, values are either a CIDR or an EC2 security group diff --git a/ScoutSuite/providers/aws/resources/ec2/snapshots.py b/ScoutSuite/providers/aws/resources/ec2/snapshots.py index d3304dd56..3ee74219d 100755 --- a/ScoutSuite/providers/aws/resources/ec2/snapshots.py +++ b/ScoutSuite/providers/aws/resources/ec2/snapshots.py @@ -5,7 +5,7 @@ class Snapshots(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Snapshots, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/ec2/volumes.py b/ScoutSuite/providers/aws/resources/ec2/volumes.py index 9dc79b2da..5809cb502 100755 --- a/ScoutSuite/providers/aws/resources/ec2/volumes.py +++ b/ScoutSuite/providers/aws/resources/ec2/volumes.py @@ -5,7 +5,7 @@ class Volumes(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Volumes, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/efs/base.py b/ScoutSuite/providers/aws/resources/efs/base.py index 5c7461bf1..5f8db459d 100755 --- a/ScoutSuite/providers/aws/resources/efs/base.py +++ b/ScoutSuite/providers/aws/resources/efs/base.py @@ -10,4 +10,4 @@ class EFS(Regions): ] def __init__(self, facade: AWSFacade): - super(EFS, self).__init__('efs', facade) + super().__init__('efs', facade) diff --git a/ScoutSuite/providers/aws/resources/efs/filesystems.py b/ScoutSuite/providers/aws/resources/efs/filesystems.py index e0b1af0fd..8c1b157b8 100755 --- a/ScoutSuite/providers/aws/resources/efs/filesystems.py +++ b/ScoutSuite/providers/aws/resources/efs/filesystems.py @@ -4,7 +4,7 @@ class FileSystems(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(FileSystems, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/elasticache/base.py b/ScoutSuite/providers/aws/resources/elasticache/base.py index 89ddf3747..afcf8cc12 100755 --- a/ScoutSuite/providers/aws/resources/elasticache/base.py +++ b/ScoutSuite/providers/aws/resources/elasticache/base.py @@ -13,10 +13,10 @@ class ElastiCache(Regions): ] def __init__(self, facade: AWSFacade): - super(ElastiCache, self).__init__('elasticache', facade) + super().__init__('elasticache', facade) async def fetch_all(self, regions=None, excluded_regions=None, partition_name='aws', **kwargs): - await super(ElastiCache, self).fetch_all(regions, excluded_regions, partition_name) + await super().fetch_all(regions, excluded_regions, partition_name) for region in self['regions']: self['regions'][region]['clusters_count'] = \ diff --git a/ScoutSuite/providers/aws/resources/elasticache/cluster.py b/ScoutSuite/providers/aws/resources/elasticache/cluster.py index ecf4d9d70..30e657718 100755 --- a/ScoutSuite/providers/aws/resources/elasticache/cluster.py +++ b/ScoutSuite/providers/aws/resources/elasticache/cluster.py @@ -4,7 +4,7 @@ class Clusters(AWSResources): def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(Clusters, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/elasticache/parametergroups.py b/ScoutSuite/providers/aws/resources/elasticache/parametergroups.py index a624ae77f..7aa776d00 100755 --- a/ScoutSuite/providers/aws/resources/elasticache/parametergroups.py +++ b/ScoutSuite/providers/aws/resources/elasticache/parametergroups.py @@ -5,7 +5,7 @@ class ParameterGroups(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(ParameterGroups, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/elasticache/securitygroups.py b/ScoutSuite/providers/aws/resources/elasticache/securitygroups.py index b30792a35..d16234411 100755 --- a/ScoutSuite/providers/aws/resources/elasticache/securitygroups.py +++ b/ScoutSuite/providers/aws/resources/elasticache/securitygroups.py @@ -4,7 +4,7 @@ class SecurityGroups(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(SecurityGroups, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/elasticache/subnetgroups.py b/ScoutSuite/providers/aws/resources/elasticache/subnetgroups.py index 573b77724..1e99e6bf0 100755 --- a/ScoutSuite/providers/aws/resources/elasticache/subnetgroups.py +++ b/ScoutSuite/providers/aws/resources/elasticache/subnetgroups.py @@ -4,7 +4,7 @@ class SubnetGroups(AWSResources): def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(SubnetGroups, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/elb/base.py b/ScoutSuite/providers/aws/resources/elb/base.py index 0f463bd7b..95f244968 100755 --- a/ScoutSuite/providers/aws/resources/elb/base.py +++ b/ScoutSuite/providers/aws/resources/elb/base.py @@ -12,4 +12,4 @@ class ELB(Regions): ] def __init__(self, facade: AWSFacade): - super(ELB, self).__init__('elb', facade) + super().__init__('elb', facade) diff --git a/ScoutSuite/providers/aws/resources/elb/load_balancers.py b/ScoutSuite/providers/aws/resources/elb/load_balancers.py index 5e4ffff78..74660b7dd 100755 --- a/ScoutSuite/providers/aws/resources/elb/load_balancers.py +++ b/ScoutSuite/providers/aws/resources/elb/load_balancers.py @@ -6,7 +6,7 @@ class LoadBalancers(AWSResources): def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(LoadBalancers, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/elb/policies.py b/ScoutSuite/providers/aws/resources/elb/policies.py index 513a9bfa2..3f808166b 100755 --- a/ScoutSuite/providers/aws/resources/elb/policies.py +++ b/ScoutSuite/providers/aws/resources/elb/policies.py @@ -5,7 +5,7 @@ class Policies(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Policies, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/elbv2/base.py b/ScoutSuite/providers/aws/resources/elbv2/base.py index 48540c798..25c23a1de 100755 --- a/ScoutSuite/providers/aws/resources/elbv2/base.py +++ b/ScoutSuite/providers/aws/resources/elbv2/base.py @@ -10,4 +10,4 @@ class ELBv2(Regions): ] def __init__(self, facade: AWSFacade): - super(ELBv2, self).__init__('elbv2', facade) + super().__init__('elbv2', facade) diff --git a/ScoutSuite/providers/aws/resources/elbv2/listeners.py b/ScoutSuite/providers/aws/resources/elbv2/listeners.py index e2b38cc7b..5ab5e32eb 100755 --- a/ScoutSuite/providers/aws/resources/elbv2/listeners.py +++ b/ScoutSuite/providers/aws/resources/elbv2/listeners.py @@ -4,7 +4,7 @@ class Listeners(AWSResources): def __init__(self, facade: AWSFacade, region: str, load_balancer_arn: str): - super(Listeners, self).__init__(facade) + super().__init__(facade) self.region = region self.load_balancer_arn = load_balancer_arn diff --git a/ScoutSuite/providers/aws/resources/elbv2/load_balancers.py b/ScoutSuite/providers/aws/resources/elbv2/load_balancers.py index f8cd80da7..0b7c54fa1 100755 --- a/ScoutSuite/providers/aws/resources/elbv2/load_balancers.py +++ b/ScoutSuite/providers/aws/resources/elbv2/load_balancers.py @@ -10,7 +10,7 @@ class LoadBalancers(AWSCompositeResources): ] def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(LoadBalancers, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/emr/base.py b/ScoutSuite/providers/aws/resources/emr/base.py index d0c69b3ff..57c2855aa 100755 --- a/ScoutSuite/providers/aws/resources/emr/base.py +++ b/ScoutSuite/providers/aws/resources/emr/base.py @@ -10,10 +10,10 @@ class EMR(Regions): ] def __init__(self, facade: AWSFacade): - super(EMR, self).__init__('emr', facade) + super().__init__('emr', facade) async def fetch_all(self, regions=None, excluded_regions=None, partition_name='aws', **kwargs): - await super(EMR, self).fetch_all(regions, excluded_regions, partition_name) + await super().fetch_all(regions, excluded_regions, partition_name) for region in self['regions']: self['regions'][region]['clusters_count'] = sum( diff --git a/ScoutSuite/providers/aws/resources/emr/clusters.py b/ScoutSuite/providers/aws/resources/emr/clusters.py index 3f1ebaee3..9708bc415 100755 --- a/ScoutSuite/providers/aws/resources/emr/clusters.py +++ b/ScoutSuite/providers/aws/resources/emr/clusters.py @@ -4,7 +4,7 @@ class EMRClusters(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(EMRClusters, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/emr/vpcs.py b/ScoutSuite/providers/aws/resources/emr/vpcs.py index 7b20ab21c..83eb19fd8 100755 --- a/ScoutSuite/providers/aws/resources/emr/vpcs.py +++ b/ScoutSuite/providers/aws/resources/emr/vpcs.py @@ -12,7 +12,7 @@ class EMRVpcs(AWSCompositeResources): def __init__(self, facade: AWSFacade, region: str): self.region = region - super(EMRVpcs, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): # EMR won't disclose its VPC, so we put everything in a VPC named "EMR-UNKNOWN-VPC", and we diff --git a/ScoutSuite/providers/aws/resources/iam/base.py b/ScoutSuite/providers/aws/resources/iam/base.py index 03bbef6a0..b70d687b1 100755 --- a/ScoutSuite/providers/aws/resources/iam/base.py +++ b/ScoutSuite/providers/aws/resources/iam/base.py @@ -19,7 +19,7 @@ class IAM(AWSCompositeResources): ] def __init__(self, facade: AWSFacade): - super(IAM, self).__init__(facade) + super().__init__(facade) self.service = 'iam' async def fetch_all(self, partition_name='aws', **kwargs): diff --git a/ScoutSuite/providers/aws/resources/kms/base.py b/ScoutSuite/providers/aws/resources/kms/base.py index bc318763d..688be56bd 100755 --- a/ScoutSuite/providers/aws/resources/kms/base.py +++ b/ScoutSuite/providers/aws/resources/kms/base.py @@ -10,4 +10,4 @@ class KMS(Regions): ] def __init__(self, facade: AWSFacade): - super(KMS, self).__init__('kms', facade) + super().__init__('kms', facade) diff --git a/ScoutSuite/providers/aws/resources/kms/grants.py b/ScoutSuite/providers/aws/resources/kms/grants.py index 072900891..4684979f1 100755 --- a/ScoutSuite/providers/aws/resources/kms/grants.py +++ b/ScoutSuite/providers/aws/resources/kms/grants.py @@ -4,7 +4,7 @@ class Grants(AWSResources): def __init__(self, facade: AWSFacade, region: str, key_id: str): - super(Grants, self).__init__(facade) + super().__init__(facade) self.region = region self.key_id = key_id diff --git a/ScoutSuite/providers/aws/resources/kms/keys.py b/ScoutSuite/providers/aws/resources/kms/keys.py index b1fbb9be3..0a31bc65e 100755 --- a/ScoutSuite/providers/aws/resources/kms/keys.py +++ b/ScoutSuite/providers/aws/resources/kms/keys.py @@ -10,7 +10,7 @@ class Keys(AWSCompositeResources): ] def __init__(self, facade: AWSFacade, region: str): - super(Keys, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/rds/base.py b/ScoutSuite/providers/aws/resources/rds/base.py index 60271f04b..4e0132eac 100755 --- a/ScoutSuite/providers/aws/resources/rds/base.py +++ b/ScoutSuite/providers/aws/resources/rds/base.py @@ -13,10 +13,10 @@ class RDS(Regions): ] def __init__(self, facade: AWSFacade): - super(RDS, self).__init__('rds', facade) + super().__init__('rds', facade) async def fetch_all(self, regions=None, excluded_regions=None, partition_name='aws', **kwargs): - await super(RDS, self).fetch_all(regions, excluded_regions, partition_name) + await super().fetch_all(regions, excluded_regions, partition_name) for region in self['regions']: self['regions'][region]['instances_count'] =\ diff --git a/ScoutSuite/providers/aws/resources/rds/instances.py b/ScoutSuite/providers/aws/resources/rds/instances.py index c2e8abb85..6e3504cf2 100755 --- a/ScoutSuite/providers/aws/resources/rds/instances.py +++ b/ScoutSuite/providers/aws/resources/rds/instances.py @@ -4,7 +4,7 @@ class RDSInstances(AWSResources): def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(RDSInstances, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/rds/parametergroups.py b/ScoutSuite/providers/aws/resources/rds/parametergroups.py index c7bc244f5..bf248dde3 100755 --- a/ScoutSuite/providers/aws/resources/rds/parametergroups.py +++ b/ScoutSuite/providers/aws/resources/rds/parametergroups.py @@ -5,7 +5,7 @@ class ParameterGroups(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(ParameterGroups, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/rds/securitygroups.py b/ScoutSuite/providers/aws/resources/rds/securitygroups.py index 3e936955f..fcc7dff38 100755 --- a/ScoutSuite/providers/aws/resources/rds/securitygroups.py +++ b/ScoutSuite/providers/aws/resources/rds/securitygroups.py @@ -4,7 +4,7 @@ class SecurityGroups(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(SecurityGroups, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/rds/snapshots.py b/ScoutSuite/providers/aws/resources/rds/snapshots.py index 1bdaf0734..fb90dd8a0 100755 --- a/ScoutSuite/providers/aws/resources/rds/snapshots.py +++ b/ScoutSuite/providers/aws/resources/rds/snapshots.py @@ -4,7 +4,7 @@ class Snapshots(AWSResources): def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(Snapshots, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/rds/subnetgroups.py b/ScoutSuite/providers/aws/resources/rds/subnetgroups.py index ff96b5d8c..9719429c0 100755 --- a/ScoutSuite/providers/aws/resources/rds/subnetgroups.py +++ b/ScoutSuite/providers/aws/resources/rds/subnetgroups.py @@ -4,7 +4,7 @@ class SubnetGroups(AWSResources): def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(SubnetGroups, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/redshift/base.py b/ScoutSuite/providers/aws/resources/redshift/base.py index 50b2ba7a3..d58b3a2dc 100755 --- a/ScoutSuite/providers/aws/resources/redshift/base.py +++ b/ScoutSuite/providers/aws/resources/redshift/base.py @@ -14,4 +14,4 @@ class Redshift(Regions): ] def __init__(self, facade: AWSFacade): - super(Redshift, self).__init__('redshift', facade) + super().__init__('redshift', facade) diff --git a/ScoutSuite/providers/aws/resources/redshift/cluster_parameter_groups.py b/ScoutSuite/providers/aws/resources/redshift/cluster_parameter_groups.py index 987dd2c08..ca8fb5b03 100755 --- a/ScoutSuite/providers/aws/resources/redshift/cluster_parameter_groups.py +++ b/ScoutSuite/providers/aws/resources/redshift/cluster_parameter_groups.py @@ -11,7 +11,7 @@ class ClusterParameterGroups(AWSCompositeResources): ] def __init__(self, facade: AWSFacade, region: str): - super(ClusterParameterGroups, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/redshift/cluster_parameters.py b/ScoutSuite/providers/aws/resources/redshift/cluster_parameters.py index e12c8732f..c5ed6ece3 100755 --- a/ScoutSuite/providers/aws/resources/redshift/cluster_parameters.py +++ b/ScoutSuite/providers/aws/resources/redshift/cluster_parameters.py @@ -4,7 +4,7 @@ class ClusterParameters(AWSResources): def __init__(self, facade: AWSFacade, region: str, parameter_group_name: str): - super(ClusterParameters, self).__init__(facade) + super().__init__(facade) self.region = region self.parameter_group_name = parameter_group_name diff --git a/ScoutSuite/providers/aws/resources/redshift/cluster_security_groups.py b/ScoutSuite/providers/aws/resources/redshift/cluster_security_groups.py index bce999212..195834883 100755 --- a/ScoutSuite/providers/aws/resources/redshift/cluster_security_groups.py +++ b/ScoutSuite/providers/aws/resources/redshift/cluster_security_groups.py @@ -4,7 +4,7 @@ class ClusterSecurityGroups(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(ClusterSecurityGroups, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/redshift/clusters.py b/ScoutSuite/providers/aws/resources/redshift/clusters.py index 4cd885cec..aca61e0fa 100755 --- a/ScoutSuite/providers/aws/resources/redshift/clusters.py +++ b/ScoutSuite/providers/aws/resources/redshift/clusters.py @@ -4,7 +4,7 @@ class Clusters(AWSResources): def __init__(self, facade: AWSFacade, region: str, vpc: str): - super(Clusters, self).__init__(facade) + super().__init__(facade) self.region = region self.vpc = vpc diff --git a/ScoutSuite/providers/aws/resources/regions.py b/ScoutSuite/providers/aws/resources/regions.py index 1581a1be7..54c72037e 100755 --- a/ScoutSuite/providers/aws/resources/regions.py +++ b/ScoutSuite/providers/aws/resources/regions.py @@ -6,7 +6,7 @@ class Regions(AWSCompositeResources, metaclass=abc.ABCMeta): def __init__(self, service: str, facade: AWSFacade): - super(Regions, self).__init__(facade) + super().__init__(facade) self.service = service async def fetch_all(self, regions=None, excluded_regions=None, partition_name='aws', **kwargs): diff --git a/ScoutSuite/providers/aws/resources/route53/base.py b/ScoutSuite/providers/aws/resources/route53/base.py index 23da39370..5f6b9e678 100755 --- a/ScoutSuite/providers/aws/resources/route53/base.py +++ b/ScoutSuite/providers/aws/resources/route53/base.py @@ -12,4 +12,4 @@ class Route53(Regions): ] def __init__(self, facade: AWSFacade): - super(Route53, self).__init__('route53domains', facade) + super().__init__('route53domains', facade) diff --git a/ScoutSuite/providers/aws/resources/route53/domains.py b/ScoutSuite/providers/aws/resources/route53/domains.py index ee86434f5..d0b9cd6b7 100755 --- a/ScoutSuite/providers/aws/resources/route53/domains.py +++ b/ScoutSuite/providers/aws/resources/route53/domains.py @@ -5,7 +5,7 @@ class Domains(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Domains, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/route53/hosted_zones.py b/ScoutSuite/providers/aws/resources/route53/hosted_zones.py index daabdc349..be1049849 100755 --- a/ScoutSuite/providers/aws/resources/route53/hosted_zones.py +++ b/ScoutSuite/providers/aws/resources/route53/hosted_zones.py @@ -4,7 +4,7 @@ class HostedZones(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(HostedZones, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/s3/base.py b/ScoutSuite/providers/aws/resources/s3/base.py index 6a0dad387..2828169a7 100755 --- a/ScoutSuite/providers/aws/resources/s3/base.py +++ b/ScoutSuite/providers/aws/resources/s3/base.py @@ -9,7 +9,7 @@ class S3(AWSCompositeResources): ] def __init__(self, facade: AWSFacade): - super(S3, self).__init__(facade) + super().__init__(facade) self.service = 's3' async def fetch_all(self, partition_name='aws', **kwargs): diff --git a/ScoutSuite/providers/aws/resources/secretsmanager/base.py b/ScoutSuite/providers/aws/resources/secretsmanager/base.py index f0ca00fdc..6517f405f 100755 --- a/ScoutSuite/providers/aws/resources/secretsmanager/base.py +++ b/ScoutSuite/providers/aws/resources/secretsmanager/base.py @@ -10,4 +10,4 @@ class SecretsManager(Regions): ] def __init__(self, facade: AWSFacade): - super(SecretsManager, self).__init__('sqs', facade) + super().__init__('sqs', facade) diff --git a/ScoutSuite/providers/aws/resources/secretsmanager/secrets.py b/ScoutSuite/providers/aws/resources/secretsmanager/secrets.py index 6587ad6a3..157a7bd66 100755 --- a/ScoutSuite/providers/aws/resources/secretsmanager/secrets.py +++ b/ScoutSuite/providers/aws/resources/secretsmanager/secrets.py @@ -4,7 +4,7 @@ class Secrets(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Secrets, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/ses/base.py b/ScoutSuite/providers/aws/resources/ses/base.py index 20173df5e..de0c00681 100755 --- a/ScoutSuite/providers/aws/resources/ses/base.py +++ b/ScoutSuite/providers/aws/resources/ses/base.py @@ -10,4 +10,4 @@ class SES(Regions): ] def __init__(self, facade: AWSFacade): - super(SES, self).__init__('ses', facade) + super().__init__('ses', facade) diff --git a/ScoutSuite/providers/aws/resources/ses/identities.py b/ScoutSuite/providers/aws/resources/ses/identities.py index 364b57cf3..742d4fa66 100755 --- a/ScoutSuite/providers/aws/resources/ses/identities.py +++ b/ScoutSuite/providers/aws/resources/ses/identities.py @@ -11,7 +11,7 @@ class Identities(AWSCompositeResources): ] def __init__(self, facade: AWSFacade, region: str): - super(Identities, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/ses/identity_policies.py b/ScoutSuite/providers/aws/resources/ses/identity_policies.py index 17958a7cd..6fcae5746 100755 --- a/ScoutSuite/providers/aws/resources/ses/identity_policies.py +++ b/ScoutSuite/providers/aws/resources/ses/identity_policies.py @@ -7,7 +7,7 @@ class IdentityPolicies(AWSResources): def __init__(self, facade: AWSFacade, region: str, identity_name: str): - super(IdentityPolicies, self).__init__(facade) + super().__init__(facade) self.region = region self.identity_name = identity_name diff --git a/ScoutSuite/providers/aws/resources/sns/base.py b/ScoutSuite/providers/aws/resources/sns/base.py index 49256f9cb..9efe2856c 100755 --- a/ScoutSuite/providers/aws/resources/sns/base.py +++ b/ScoutSuite/providers/aws/resources/sns/base.py @@ -10,4 +10,4 @@ class SNS(Regions): ] def __init__(self, facade: AWSFacade): - super(SNS, self).__init__('sns', facade) + super().__init__('sns', facade) diff --git a/ScoutSuite/providers/aws/resources/sns/subscriptions.py b/ScoutSuite/providers/aws/resources/sns/subscriptions.py index b39219575..e28d74e7e 100755 --- a/ScoutSuite/providers/aws/resources/sns/subscriptions.py +++ b/ScoutSuite/providers/aws/resources/sns/subscriptions.py @@ -4,7 +4,7 @@ class Subscriptions(AWSResources): def __init__(self, facade: AWSFacade, region: str, topic_name: str): - super(Subscriptions, self).__init__(facade) + super().__init__(facade) self.region = region self.topic_name = topic_name diff --git a/ScoutSuite/providers/aws/resources/sns/topics.py b/ScoutSuite/providers/aws/resources/sns/topics.py index 8b33f513c..b98fd3b10 100755 --- a/ScoutSuite/providers/aws/resources/sns/topics.py +++ b/ScoutSuite/providers/aws/resources/sns/topics.py @@ -12,7 +12,7 @@ class Topics(AWSCompositeResources): ] def __init__(self, facade: AWSFacade, region: str): - super(Topics, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/sqs/base.py b/ScoutSuite/providers/aws/resources/sqs/base.py index d50b2f244..a7ca846d8 100755 --- a/ScoutSuite/providers/aws/resources/sqs/base.py +++ b/ScoutSuite/providers/aws/resources/sqs/base.py @@ -10,4 +10,4 @@ class SQS(Regions): ] def __init__(self, facade: AWSFacade): - super(SQS, self).__init__('sqs', facade) + super().__init__('sqs', facade) diff --git a/ScoutSuite/providers/aws/resources/sqs/queues.py b/ScoutSuite/providers/aws/resources/sqs/queues.py index 8d23b8af2..cee4fe757 100755 --- a/ScoutSuite/providers/aws/resources/sqs/queues.py +++ b/ScoutSuite/providers/aws/resources/sqs/queues.py @@ -6,7 +6,7 @@ class Queues(AWSResources): def __init__(self, facade: AWSFacade, region: str): - super(Queues, self).__init__(facade) + super().__init__(facade) self.region = region async def fetch_all(self): diff --git a/ScoutSuite/providers/aws/resources/vpc/base.py b/ScoutSuite/providers/aws/resources/vpc/base.py index a35c3cc9d..7d95b0234 100755 --- a/ScoutSuite/providers/aws/resources/vpc/base.py +++ b/ScoutSuite/providers/aws/resources/vpc/base.py @@ -21,7 +21,7 @@ class VPC(Regions): def __init__(self, facade: AWSFacade): # VPC is not a real service but a subset of ec2: - super(VPC, self).__init__('ec2', facade) + super().__init__('ec2', facade) # TODO: move these helpers elsewhere: @@ -59,5 +59,5 @@ def get_cidr_name(cidr, ip_ranges_files, ip_ranges_name_key): ip_prefix = netaddr.IPNetwork(ip_range['ip_prefix']) cidr = netaddr.IPNetwork(cidr) if cidr in ip_prefix: - return 'Unknown CIDR in %s %s' % (ip_range['service'], ip_range['region']) + return 'Unknown CIDR in {} {}'.format(ip_range['service'], ip_range['region']) return 'Unknown CIDR' diff --git a/ScoutSuite/providers/aws/resources/vpc/flow_logs.py b/ScoutSuite/providers/aws/resources/vpc/flow_logs.py index 979b48640..a6a137565 100755 --- a/ScoutSuite/providers/aws/resources/vpc/flow_logs.py +++ b/ScoutSuite/providers/aws/resources/vpc/flow_logs.py @@ -7,7 +7,7 @@ class FlowLogs(AWSResources): def __init__(self, facade: AWSFacade, region: str): self.region = region - super(FlowLogs, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): raw_logs = await self.facade.ec2.get_flow_logs(self.region) diff --git a/ScoutSuite/providers/aws/resources/vpc/network_acls.py b/ScoutSuite/providers/aws/resources/vpc/network_acls.py index 7acd2f327..19543e70c 100755 --- a/ScoutSuite/providers/aws/resources/vpc/network_acls.py +++ b/ScoutSuite/providers/aws/resources/vpc/network_acls.py @@ -11,7 +11,7 @@ def __init__(self, facade: AWSFacade, region: str, vpc: str): self.region = region self.vpc = vpc - super(NetworkACLs, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): raw_network_acls = await self.facade.ec2.get_network_acls(self.region, self.vpc) diff --git a/ScoutSuite/providers/aws/resources/vpc/subnets.py b/ScoutSuite/providers/aws/resources/vpc/subnets.py index c0c5e6c20..caa63ceb7 100755 --- a/ScoutSuite/providers/aws/resources/vpc/subnets.py +++ b/ScoutSuite/providers/aws/resources/vpc/subnets.py @@ -8,7 +8,7 @@ def __init__(self, facade: AWSFacade, region: str, vpc: str): self.region = region self.vpc = vpc - super(Subnets, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): raw_subnets = await self.facade.ec2.get_subnets(self.region, self.vpc) diff --git a/ScoutSuite/providers/aws/resources/vpcs.py b/ScoutSuite/providers/aws/resources/vpcs.py index 50a31c44f..18a6ac83e 100755 --- a/ScoutSuite/providers/aws/resources/vpcs.py +++ b/ScoutSuite/providers/aws/resources/vpcs.py @@ -8,7 +8,7 @@ class Vpcs(AWSCompositeResources): """ def __init__(self, facade, region: str, add_ec2_classic=False): - super(Vpcs, self).__init__(facade) + super().__init__(facade) self.region = region self.add_ec2_classic = add_ec2_classic diff --git a/ScoutSuite/providers/aws/services.py b/ScoutSuite/providers/aws/services.py index fd0ed4e10..2d1233215 100755 --- a/ScoutSuite/providers/aws/services.py +++ b/ScoutSuite/providers/aws/services.py @@ -76,7 +76,7 @@ class AWSServicesConfig(BaseServicesConfig): def __init__(self, credentials=None, **kwargs): - super(AWSServicesConfig, self).__init__(credentials) + super().__init__(credentials) facade = AWSFacade(credentials) diff --git a/ScoutSuite/providers/azure/provider.py b/ScoutSuite/providers/azure/provider.py index e234a0f1f..af6863a81 100755 --- a/ScoutSuite/providers/azure/provider.py +++ b/ScoutSuite/providers/azure/provider.py @@ -48,7 +48,7 @@ def __init__(self, self.result_format = result_format - super(AzureProvider, self).__init__(report_dir, timestamp, + super().__init__(report_dir, timestamp, services, skipped_services, result_format) def get_report_name(self): @@ -75,7 +75,7 @@ def preprocessing(self, ip_ranges=None, ip_ranges_name_key=None): if not self.last_run: self._match_rbac_roles_and_principals() - super(AzureProvider, self).preprocessing() + super().preprocessing() def _match_rbac_roles_and_principals(self): """ diff --git a/ScoutSuite/providers/azure/resources/appservice/web_apps.py b/ScoutSuite/providers/azure/resources/appservice/web_apps.py index b1ee7691d..36f15522b 100755 --- a/ScoutSuite/providers/azure/resources/appservice/web_apps.py +++ b/ScoutSuite/providers/azure/resources/appservice/web_apps.py @@ -6,7 +6,7 @@ class WebApplication(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(WebApplication, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/keyvault/vaults.py b/ScoutSuite/providers/azure/resources/keyvault/vaults.py index 1db639b54..c09c9b4eb 100755 --- a/ScoutSuite/providers/azure/resources/keyvault/vaults.py +++ b/ScoutSuite/providers/azure/resources/keyvault/vaults.py @@ -6,7 +6,7 @@ class Vaults(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Vaults, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/network/application_security_groups.py b/ScoutSuite/providers/azure/resources/network/application_security_groups.py index e5d325d75..ddda8af54 100755 --- a/ScoutSuite/providers/azure/resources/network/application_security_groups.py +++ b/ScoutSuite/providers/azure/resources/network/application_security_groups.py @@ -6,7 +6,7 @@ class ApplicationSecurityGroups(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(ApplicationSecurityGroups, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/network/network_interfaces.py b/ScoutSuite/providers/azure/resources/network/network_interfaces.py index 4858161dc..64e6c36fc 100755 --- a/ScoutSuite/providers/azure/resources/network/network_interfaces.py +++ b/ScoutSuite/providers/azure/resources/network/network_interfaces.py @@ -6,7 +6,7 @@ class NetworkInterfaces(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(NetworkInterfaces, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/network/security_groups.py b/ScoutSuite/providers/azure/resources/network/security_groups.py index dc543cf1f..1c3e234c8 100755 --- a/ScoutSuite/providers/azure/resources/network/security_groups.py +++ b/ScoutSuite/providers/azure/resources/network/security_groups.py @@ -6,7 +6,7 @@ class SecurityGroups(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(SecurityGroups, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/network/virtual_networks.py b/ScoutSuite/providers/azure/resources/network/virtual_networks.py index ede523786..e57103ffc 100755 --- a/ScoutSuite/providers/azure/resources/network/virtual_networks.py +++ b/ScoutSuite/providers/azure/resources/network/virtual_networks.py @@ -6,7 +6,7 @@ class VirtualNetworks(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(VirtualNetworks, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/network/watchers.py b/ScoutSuite/providers/azure/resources/network/watchers.py index 3a0c88dcb..418e6c94d 100755 --- a/ScoutSuite/providers/azure/resources/network/watchers.py +++ b/ScoutSuite/providers/azure/resources/network/watchers.py @@ -6,7 +6,7 @@ class Watchers(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Watchers, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/rbac/role_assignments.py b/ScoutSuite/providers/azure/resources/rbac/role_assignments.py index 9385b65e0..f5eafbd52 100755 --- a/ScoutSuite/providers/azure/resources/rbac/role_assignments.py +++ b/ScoutSuite/providers/azure/resources/rbac/role_assignments.py @@ -5,7 +5,7 @@ class RoleAssignments(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(RoleAssignments, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/rbac/roles.py b/ScoutSuite/providers/azure/resources/rbac/roles.py index cf1f92e6b..2db66a5a7 100755 --- a/ScoutSuite/providers/azure/resources/rbac/roles.py +++ b/ScoutSuite/providers/azure/resources/rbac/roles.py @@ -5,7 +5,7 @@ class Roles(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Roles, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/securitycenter/alerts.py b/ScoutSuite/providers/azure/resources/securitycenter/alerts.py index f4f859215..a80762b40 100644 --- a/ScoutSuite/providers/azure/resources/securitycenter/alerts.py +++ b/ScoutSuite/providers/azure/resources/securitycenter/alerts.py @@ -5,7 +5,7 @@ class Alerts(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Alerts, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/securitycenter/auto_provisioning_settings.py b/ScoutSuite/providers/azure/resources/securitycenter/auto_provisioning_settings.py index 9533e7196..629c0743c 100755 --- a/ScoutSuite/providers/azure/resources/securitycenter/auto_provisioning_settings.py +++ b/ScoutSuite/providers/azure/resources/securitycenter/auto_provisioning_settings.py @@ -5,7 +5,7 @@ class AutoProvisioningSettings(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(AutoProvisioningSettings, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/securitycenter/compliance_results.py b/ScoutSuite/providers/azure/resources/securitycenter/compliance_results.py index ae4cee04a..d0c7ea611 100644 --- a/ScoutSuite/providers/azure/resources/securitycenter/compliance_results.py +++ b/ScoutSuite/providers/azure/resources/securitycenter/compliance_results.py @@ -6,7 +6,7 @@ class ComplianceResults(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(ComplianceResults, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/securitycenter/information_protection_policies.py b/ScoutSuite/providers/azure/resources/securitycenter/information_protection_policies.py index be32880a8..cfb83928f 100755 --- a/ScoutSuite/providers/azure/resources/securitycenter/information_protection_policies.py +++ b/ScoutSuite/providers/azure/resources/securitycenter/information_protection_policies.py @@ -5,7 +5,7 @@ class InformationProtectionPolicies(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(InformationProtectionPolicies, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/securitycenter/pricings.py b/ScoutSuite/providers/azure/resources/securitycenter/pricings.py index d9d535baf..b0ff19c8c 100755 --- a/ScoutSuite/providers/azure/resources/securitycenter/pricings.py +++ b/ScoutSuite/providers/azure/resources/securitycenter/pricings.py @@ -5,7 +5,7 @@ class Pricings(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Pricings, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/securitycenter/regulatory_compliance_results.py b/ScoutSuite/providers/azure/resources/securitycenter/regulatory_compliance_results.py index 5a2d06abc..0d19bcdec 100644 --- a/ScoutSuite/providers/azure/resources/securitycenter/regulatory_compliance_results.py +++ b/ScoutSuite/providers/azure/resources/securitycenter/regulatory_compliance_results.py @@ -6,7 +6,7 @@ class RegulatoryComplianceResults(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(RegulatoryComplianceResults, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/securitycenter/security_contacts.py b/ScoutSuite/providers/azure/resources/securitycenter/security_contacts.py index 5c969e2d3..2e02ba043 100755 --- a/ScoutSuite/providers/azure/resources/securitycenter/security_contacts.py +++ b/ScoutSuite/providers/azure/resources/securitycenter/security_contacts.py @@ -5,7 +5,7 @@ class SecurityContacts(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(SecurityContacts, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/securitycenter/settings.py b/ScoutSuite/providers/azure/resources/securitycenter/settings.py index 551b66505..b4d87f03f 100755 --- a/ScoutSuite/providers/azure/resources/securitycenter/settings.py +++ b/ScoutSuite/providers/azure/resources/securitycenter/settings.py @@ -5,7 +5,7 @@ class Settings(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Settings, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/database_blob_auditing_policies.py b/ScoutSuite/providers/azure/resources/sqldatabase/database_blob_auditing_policies.py index 47e152b0d..ed51c7610 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/database_blob_auditing_policies.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/database_blob_auditing_policies.py @@ -6,7 +6,7 @@ class DatabaseBlobAuditingPolicies(AzureResources): def __init__(self, facade: AzureFacade, resource_group_name: str, server_name: str, database_name: str, subscription_id: str): - super(DatabaseBlobAuditingPolicies, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.server_name = server_name self.database_name = database_name diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/database_threat_detection_policies.py b/ScoutSuite/providers/azure/resources/sqldatabase/database_threat_detection_policies.py index d4a441aa0..05719898d 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/database_threat_detection_policies.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/database_threat_detection_policies.py @@ -6,7 +6,7 @@ class DatabaseThreatDetectionPolicies(AzureResources): def __init__(self, facade: AzureFacade, resource_group_name: str, server_name: str, database_name: str, subscription_id: str): - super(DatabaseThreatDetectionPolicies, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.server_name = server_name self.database_name = database_name diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/databases.py b/ScoutSuite/providers/azure/resources/sqldatabase/databases.py index e3d5bd826..0232b5629 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/databases.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/databases.py @@ -16,7 +16,7 @@ class Databases(AzureCompositeResources): ] def __init__(self, facade: AzureFacade, resource_group_name: str, server_name: str, subscription_id: str): - super(Databases, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.server_name = server_name self.subscription_id = subscription_id diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/replication_links.py b/ScoutSuite/providers/azure/resources/sqldatabase/replication_links.py index fa6a45526..d081a8e94 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/replication_links.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/replication_links.py @@ -6,7 +6,7 @@ class ReplicationLinks(AzureResources): def __init__(self, facade: AzureFacade, resource_group_name: str, server_name: str, database_name: str, subscription_id: str): - super(ReplicationLinks, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.server_name = server_name self.database_name = database_name diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/server_azure_ad_administrators.py b/ScoutSuite/providers/azure/resources/sqldatabase/server_azure_ad_administrators.py index 4bcd79da0..6d79a7c38 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/server_azure_ad_administrators.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/server_azure_ad_administrators.py @@ -5,7 +5,7 @@ class ServerAzureAdAdministrators(AzureResources): def __init__(self, facade: AzureFacade, resource_group_name: str, server_name: str, subscription_id: str): - super(ServerAzureAdAdministrators, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.server_name = server_name self.subscription_id = subscription_id diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/server_blob_auditing_policies.py b/ScoutSuite/providers/azure/resources/sqldatabase/server_blob_auditing_policies.py index 7708c47f3..97836ae78 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/server_blob_auditing_policies.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/server_blob_auditing_policies.py @@ -5,7 +5,7 @@ class ServerBlobAuditingPolicies(AzureResources): def __init__(self, facade: AzureFacade, resource_group_name: str, server_name: str, subscription_id: str): - super(ServerBlobAuditingPolicies, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.server_name = server_name self.subscription_id = subscription_id diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/server_security_alert_policies.py b/ScoutSuite/providers/azure/resources/sqldatabase/server_security_alert_policies.py index cff1d02e7..4afee5d5b 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/server_security_alert_policies.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/server_security_alert_policies.py @@ -5,7 +5,7 @@ class ServerSecurityAlertPolicies(AzureResources): def __init__(self, facade: AzureFacade, resource_group_name: str, server_name: str, subscription_id: str): - super(ServerSecurityAlertPolicies, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.server_name = server_name self.subscription_id = subscription_id diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/servers.py b/ScoutSuite/providers/azure/resources/sqldatabase/servers.py index b6259d979..52327193e 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/servers.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/servers.py @@ -18,7 +18,7 @@ class Servers(AzureCompositeResources): ] def __init__(self, facade: AzureFacade, subscription_id: str): - super(Servers, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/transparent_data_encryptions.py b/ScoutSuite/providers/azure/resources/sqldatabase/transparent_data_encryptions.py index 29a517f4f..ddf9bfb14 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/transparent_data_encryptions.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/transparent_data_encryptions.py @@ -6,7 +6,7 @@ class TransparentDataEncryptions(AzureResources): def __init__(self, facade: AzureFacade, resource_group_name: str, server_name: str, database_name: str, subscription_id: str): - super(TransparentDataEncryptions, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.server_name = server_name self.database_name = database_name diff --git a/ScoutSuite/providers/azure/resources/storageaccounts/blob_containers.py b/ScoutSuite/providers/azure/resources/storageaccounts/blob_containers.py index 7a36b7e34..70be49746 100755 --- a/ScoutSuite/providers/azure/resources/storageaccounts/blob_containers.py +++ b/ScoutSuite/providers/azure/resources/storageaccounts/blob_containers.py @@ -5,7 +5,7 @@ class BlobContainers(AzureResources): def __init__(self, facade: AzureFacade, resource_group_name: str, storage_account_name: str, subscription_id: str): - super(BlobContainers, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.storage_account_name = storage_account_name self.subscription_id = subscription_id diff --git a/ScoutSuite/providers/azure/resources/storageaccounts/queues.py b/ScoutSuite/providers/azure/resources/storageaccounts/queues.py index 3dcba5414..37c2a4635 100644 --- a/ScoutSuite/providers/azure/resources/storageaccounts/queues.py +++ b/ScoutSuite/providers/azure/resources/storageaccounts/queues.py @@ -5,7 +5,7 @@ class Queues(AzureResources): def __init__(self, facade: AzureFacade, resource_group_name: str, storage_account_name: str, subscription_id: str): - super(Queues, self).__init__(facade) + super().__init__(facade) self.resource_group_name = resource_group_name self.storage_account_name = storage_account_name self.subscription_id = subscription_id diff --git a/ScoutSuite/providers/azure/resources/storageaccounts/storage_accounts.py b/ScoutSuite/providers/azure/resources/storageaccounts/storage_accounts.py index 16ab6d840..5f015a2a9 100755 --- a/ScoutSuite/providers/azure/resources/storageaccounts/storage_accounts.py +++ b/ScoutSuite/providers/azure/resources/storageaccounts/storage_accounts.py @@ -14,7 +14,7 @@ class StorageAccounts(AzureCompositeResources): ] def __init__(self, facade: AzureFacade, subscription_id: str): - super(StorageAccounts, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/virtualmachines/disks.py b/ScoutSuite/providers/azure/resources/virtualmachines/disks.py index 40c91ef0d..05d3c5302 100644 --- a/ScoutSuite/providers/azure/resources/virtualmachines/disks.py +++ b/ScoutSuite/providers/azure/resources/virtualmachines/disks.py @@ -6,7 +6,7 @@ class Disks(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Disks, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/virtualmachines/images.py b/ScoutSuite/providers/azure/resources/virtualmachines/images.py index afb36b8b7..3f99b9ee5 100644 --- a/ScoutSuite/providers/azure/resources/virtualmachines/images.py +++ b/ScoutSuite/providers/azure/resources/virtualmachines/images.py @@ -6,7 +6,7 @@ class Images(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Images, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/virtualmachines/instances.py b/ScoutSuite/providers/azure/resources/virtualmachines/instances.py index b2878a0d9..dfe756cdb 100755 --- a/ScoutSuite/providers/azure/resources/virtualmachines/instances.py +++ b/ScoutSuite/providers/azure/resources/virtualmachines/instances.py @@ -7,7 +7,7 @@ class Instances(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Instances, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/resources/virtualmachines/snapshots.py b/ScoutSuite/providers/azure/resources/virtualmachines/snapshots.py index b7c9541b0..2ff5219ad 100644 --- a/ScoutSuite/providers/azure/resources/virtualmachines/snapshots.py +++ b/ScoutSuite/providers/azure/resources/virtualmachines/snapshots.py @@ -6,7 +6,7 @@ class Snapshots(AzureResources): def __init__(self, facade: AzureFacade, subscription_id: str): - super(Snapshots, self).__init__(facade) + super().__init__(facade) self.subscription_id = subscription_id async def fetch_all(self): diff --git a/ScoutSuite/providers/azure/services.py b/ScoutSuite/providers/azure/services.py index b4db87635..ca1504ffe 100755 --- a/ScoutSuite/providers/azure/services.py +++ b/ScoutSuite/providers/azure/services.py @@ -34,7 +34,7 @@ def __init__(self, programmatic_execution=None, **kwargs): - super(AzureServicesConfig, self).__init__(credentials) + super().__init__(credentials) facade = AzureFacade(credentials, subscription_ids, all_subscriptions, @@ -68,7 +68,7 @@ def _is_provider(self, provider_name): return provider_name == 'azure' async def fetch(self, services: list, regions: list, excluded_regions: list): - await super(AzureServicesConfig, self).fetch(services, regions, excluded_regions) + await super().fetch(services, regions, excluded_regions) # This is a unique case where we'll want to fetch additional resources (in the AAD service) in the # event the RBAC service was included. There's no existing cross-service fetching logic (only cross-service diff --git a/ScoutSuite/providers/base/provider.py b/ScoutSuite/providers/base/provider.py index b034d7469..5bee80827 100755 --- a/ScoutSuite/providers/base/provider.py +++ b/ScoutSuite/providers/base/provider.py @@ -1,6 +1,3 @@ -from __future__ import print_function -from __future__ import unicode_literals - import copy import json @@ -10,7 +7,7 @@ from ScoutSuite.providers.base.configs.browser import get_object_at -class BaseProvider(object): +class BaseProvider: """ Base class for the different providers. @@ -95,7 +92,7 @@ def _load_metadata(self): :return: None """ # Load metadata - with open(self.metadata_path, 'rt') as f: + with open(self.metadata_path) as f: self.metadata = json.load(f) @staticmethod diff --git a/ScoutSuite/providers/base/resources/base.py b/ScoutSuite/providers/base/resources/base.py index 656155a7d..b1ef3ff0e 100755 --- a/ScoutSuite/providers/base/resources/base.py +++ b/ScoutSuite/providers/base/resources/base.py @@ -19,7 +19,7 @@ class Resources(dict, metaclass=abc.ABCMeta): def __init__(self, service_facade): self.facade = service_facade - super(Resources, self).__init__() + super().__init__() @abc.abstractmethod async def fetch_all(self, **kwargs): @@ -34,7 +34,7 @@ async def fetch_all(self, **kwargs): class CompositeResources(Resources, metaclass=abc.ABCMeta): """This class represents a node in the hierarchical structure. As inherited from `Resources`, it still \ - stores instances of a given type of resources internally but also stores some kind of nested resources \ + stores instances of a given type of resources internally but also stores some kind of nested resources \\ referred to as its 'children'. """ diff --git a/ScoutSuite/providers/base/services.py b/ScoutSuite/providers/base/services.py index 96db93b4b..f1c3768d2 100755 --- a/ScoutSuite/providers/base/services.py +++ b/ScoutSuite/providers/base/services.py @@ -5,7 +5,7 @@ from ScoutSuite.utils import format_service_name -class BaseServicesConfig(object): +class BaseServicesConfig: def __init__(self, credentials): self.credentials = credentials diff --git a/ScoutSuite/providers/gcp/facade/base.py b/ScoutSuite/providers/gcp/facade/base.py index 57c80f572..ef4bc3b7e 100755 --- a/ScoutSuite/providers/gcp/facade/base.py +++ b/ScoutSuite/providers/gcp/facade/base.py @@ -21,7 +21,7 @@ class GCPFacade(GCPBaseFacade): def __init__(self, default_project_id=None, project_id=None, folder_id=None, organization_id=None, all_projects=None): - super(GCPFacade, self).__init__('cloudresourcemanager', 'v1') + super().__init__('cloudresourcemanager', 'v1') self.default_project_id = default_project_id self.all_projects = all_projects @@ -110,10 +110,10 @@ async def _get_projects_recursively(self, parent_type, parent_id): request = resourcemanager_client.projects().list(filter='parent.id:"%s"' % parent_id) # get parent children projects in children folders recursively - folder_request = resourcemanager_client_v2.folders().list(parent='%ss/%s' % (parent_type, parent_id)) + folder_request = resourcemanager_client_v2.folders().list(parent='{}s/{}'.format(parent_type, parent_id)) folder_response = await GCPFacadeUtils.get_all('folders', folder_request, projects_group) for folder in folder_response: - projects.extend(await self._get_projects_recursively("folder", folder['name'].strip(u'folders/'))) + projects.extend(await self._get_projects_recursively("folder", folder['name'].strip('folders/'))) project_response = await GCPFacadeUtils.get_all('projects', request, projects_group) if project_response: diff --git a/ScoutSuite/providers/gcp/facade/cloudresourcemanager.py b/ScoutSuite/providers/gcp/facade/cloudresourcemanager.py index 3ce7fa3d8..1070644a2 100755 --- a/ScoutSuite/providers/gcp/facade/cloudresourcemanager.py +++ b/ScoutSuite/providers/gcp/facade/cloudresourcemanager.py @@ -4,7 +4,7 @@ class CloudResourceManagerFacade(GCPBaseFacade): def __init__(self): - super(CloudResourceManagerFacade, self).__init__('cloudresourcemanager', 'v1') + super().__init__('cloudresourcemanager', 'v1') async def get_member_bindings(self, project_id: str): try: diff --git a/ScoutSuite/providers/gcp/facade/cloudsql.py b/ScoutSuite/providers/gcp/facade/cloudsql.py index d8901f8c7..5f0e3eed5 100755 --- a/ScoutSuite/providers/gcp/facade/cloudsql.py +++ b/ScoutSuite/providers/gcp/facade/cloudsql.py @@ -5,7 +5,7 @@ class CloudSQLFacade(GCPBaseFacade): def __init__(self): - super(CloudSQLFacade, self).__init__('sqladmin', 'v1beta4') + super().__init__('sqladmin', 'v1beta4') async def get_backups(self, project_id: str, instance_name: str): try: diff --git a/ScoutSuite/providers/gcp/facade/gce.py b/ScoutSuite/providers/gcp/facade/gce.py index fc769d2b7..0c1f6fd9d 100755 --- a/ScoutSuite/providers/gcp/facade/gce.py +++ b/ScoutSuite/providers/gcp/facade/gce.py @@ -6,7 +6,7 @@ class GCEFacade(GCPBaseFacade): def __init__(self): - super(GCEFacade, self).__init__('compute', 'v1') + super().__init__('compute', 'v1') async def get_disks(self, project_id, zone): try: @@ -48,7 +48,7 @@ async def _add_metadata(self, project_id, instances): instance['commonInstanceMetadata'] = common_instance_metadata def metadata_to_dict(self, metadata): - return dict((item['key'], item['value']) for item in metadata['items']) if 'items' in metadata else {} + return {item['key']: item['value'] for item in metadata['items']} if 'items' in metadata else {} async def get_networks(self, project_id): try: diff --git a/ScoutSuite/providers/gcp/facade/iam.py b/ScoutSuite/providers/gcp/facade/iam.py index c9a5269a3..bf2604015 100755 --- a/ScoutSuite/providers/gcp/facade/iam.py +++ b/ScoutSuite/providers/gcp/facade/iam.py @@ -5,7 +5,7 @@ class IAMFacade(GCPBaseFacade): def __init__(self): - super(IAMFacade, self).__init__('iam', 'v1') + super().__init__('iam', 'v1') async def get_service_accounts(self, project_id: str): try: diff --git a/ScoutSuite/providers/gcp/facade/kms.py b/ScoutSuite/providers/gcp/facade/kms.py index 427b5867e..3e8321cbf 100755 --- a/ScoutSuite/providers/gcp/facade/kms.py +++ b/ScoutSuite/providers/gcp/facade/kms.py @@ -10,7 +10,7 @@ class KMSFacade(GCPBaseFacade): def __init__(self): # This facade is currently using both libraries as the Cloud Client library doesn't support locations self.cloud_client = kms.KeyManagementServiceClient() # Cloud Client - super(KMSFacade, self).__init__('cloudkms', 'v1') # API Client + super().__init__('cloudkms', 'v1') # API Client async def get_locations(self, project_id: str): diff --git a/ScoutSuite/providers/gcp/provider.py b/ScoutSuite/providers/gcp/provider.py index 34f19d610..947822e05 100755 --- a/ScoutSuite/providers/gcp/provider.py +++ b/ScoutSuite/providers/gcp/provider.py @@ -35,7 +35,7 @@ def __init__(self, self.result_format = result_format - super(GCPProvider, self).__init__(report_dir, timestamp, + super().__init__(report_dir, timestamp, services, skipped_services, result_format) def get_report_name(self): @@ -82,7 +82,7 @@ def preprocessing(self, ip_ranges=None, ip_ranges_name_key=None): self._match_instances_and_snapshots() self._match_networks_and_instances() - super(GCPProvider, self).preprocessing() + super().preprocessing() def _match_instances_and_snapshots(self): """ diff --git a/ScoutSuite/providers/gcp/resources/cloudsql/backups.py b/ScoutSuite/providers/gcp/resources/cloudsql/backups.py index b5338e037..4e57ea8cb 100755 --- a/ScoutSuite/providers/gcp/resources/cloudsql/backups.py +++ b/ScoutSuite/providers/gcp/resources/cloudsql/backups.py @@ -4,7 +4,7 @@ class Backups(Resources): def __init__(self, facade: GCPFacade, project_id: str, instance_name: str): - super(Backups, self).__init__(facade) + super().__init__(facade) self.project_id = project_id self.instance_name = instance_name diff --git a/ScoutSuite/providers/gcp/resources/cloudsql/database_instances.py b/ScoutSuite/providers/gcp/resources/cloudsql/database_instances.py index 5bef07ea7..ca9a5e4cc 100755 --- a/ScoutSuite/providers/gcp/resources/cloudsql/database_instances.py +++ b/ScoutSuite/providers/gcp/resources/cloudsql/database_instances.py @@ -13,7 +13,7 @@ class DatabaseInstances(GCPCompositeResources): ] def __init__(self, facade: GCPFacade, project_id: str): - super(DatabaseInstances, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/cloudsql/users.py b/ScoutSuite/providers/gcp/resources/cloudsql/users.py index e40bb9fbf..ba2a5fc4f 100755 --- a/ScoutSuite/providers/gcp/resources/cloudsql/users.py +++ b/ScoutSuite/providers/gcp/resources/cloudsql/users.py @@ -4,7 +4,7 @@ class Users(Resources): def __init__(self, facade: GCPFacade, project_id: str, instance_name: str): - super(Users, self).__init__(facade) + super().__init__(facade) self.project_id = project_id self.instance_name = instance_name diff --git a/ScoutSuite/providers/gcp/resources/cloudstorage/buckets.py b/ScoutSuite/providers/gcp/resources/cloudstorage/buckets.py index c8ff1b83b..9a9f8fd85 100755 --- a/ScoutSuite/providers/gcp/resources/cloudstorage/buckets.py +++ b/ScoutSuite/providers/gcp/resources/cloudstorage/buckets.py @@ -6,7 +6,7 @@ class Buckets(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(Buckets, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/gce/firewalls.py b/ScoutSuite/providers/gcp/resources/gce/firewalls.py index f79214517..b7c53e0d1 100755 --- a/ScoutSuite/providers/gcp/resources/gce/firewalls.py +++ b/ScoutSuite/providers/gcp/resources/gce/firewalls.py @@ -4,7 +4,7 @@ class Firewalls(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(Firewalls, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/gce/instance_disks.py b/ScoutSuite/providers/gcp/resources/gce/instance_disks.py index 178548b0d..a82128f2e 100755 --- a/ScoutSuite/providers/gcp/resources/gce/instance_disks.py +++ b/ScoutSuite/providers/gcp/resources/gce/instance_disks.py @@ -3,7 +3,7 @@ class InstanceDisks(Disks): def __init__(self, facade, instance): - super(InstanceDisks, self).__init__(facade) + super().__init__(facade) self.instance = instance def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/gce/networks.py b/ScoutSuite/providers/gcp/resources/gce/networks.py index 9c82754c2..12e8c0f11 100755 --- a/ScoutSuite/providers/gcp/resources/gce/networks.py +++ b/ScoutSuite/providers/gcp/resources/gce/networks.py @@ -4,7 +4,7 @@ class Networks(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(Networks, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/gce/snapshots.py b/ScoutSuite/providers/gcp/resources/gce/snapshots.py index cce1eb334..dd3248b8c 100755 --- a/ScoutSuite/providers/gcp/resources/gce/snapshots.py +++ b/ScoutSuite/providers/gcp/resources/gce/snapshots.py @@ -4,7 +4,7 @@ class Snapshots(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(Snapshots, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/gce/subnetworks.py b/ScoutSuite/providers/gcp/resources/gce/subnetworks.py index 3df21ce4d..56aab2a34 100755 --- a/ScoutSuite/providers/gcp/resources/gce/subnetworks.py +++ b/ScoutSuite/providers/gcp/resources/gce/subnetworks.py @@ -4,7 +4,7 @@ class Subnetworks(Resources): def __init__(self, facade: GCPFacade, project_id: str, region: str): - super(Subnetworks, self).__init__(facade) + super().__init__(facade) self.project_id = project_id self.region = region @@ -19,7 +19,7 @@ def _parse_subnetwork(self, raw_subnetwork): subnetwork_dict['id'] = raw_subnetwork['id'] subnetwork_dict['project_id'] = raw_subnetwork['selfLink'].split('/')[-5] subnetwork_dict['region'] = raw_subnetwork['region'].split('/')[-1] - subnetwork_dict['name'] = "%s-%s" % (raw_subnetwork['name'], subnetwork_dict['region']) + subnetwork_dict['name'] = "{}-{}".format(raw_subnetwork['name'], subnetwork_dict['region']) subnetwork_dict['subnetwork'] = raw_subnetwork['network'].split('/')[-1] subnetwork_dict['gateway_address'] = raw_subnetwork['gatewayAddress'] subnetwork_dict['ip_range'] = raw_subnetwork['ipCidrRange'] diff --git a/ScoutSuite/providers/gcp/resources/iam/groups.py b/ScoutSuite/providers/gcp/resources/iam/groups.py index edb034687..5ce52b63d 100755 --- a/ScoutSuite/providers/gcp/resources/iam/groups.py +++ b/ScoutSuite/providers/gcp/resources/iam/groups.py @@ -5,7 +5,7 @@ class Groups(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(Groups, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/iam/keys.py b/ScoutSuite/providers/gcp/resources/iam/keys.py index 683030eb2..83c567e92 100755 --- a/ScoutSuite/providers/gcp/resources/iam/keys.py +++ b/ScoutSuite/providers/gcp/resources/iam/keys.py @@ -4,7 +4,7 @@ class Keys(Resources): def __init__(self, facade: GCPFacade, project_id: str, service_account_email: str): - super(Keys, self).__init__(facade) + super().__init__(facade) self.project_id = project_id self.service_account_email = service_account_email diff --git a/ScoutSuite/providers/gcp/resources/iam/member_bindings.py b/ScoutSuite/providers/gcp/resources/iam/member_bindings.py index 0ae2999d5..ae2027f42 100755 --- a/ScoutSuite/providers/gcp/resources/iam/member_bindings.py +++ b/ScoutSuite/providers/gcp/resources/iam/member_bindings.py @@ -6,7 +6,7 @@ class Bindings(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(Bindings, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/iam/service_account_bindings.py b/ScoutSuite/providers/gcp/resources/iam/service_account_bindings.py index 668bc48d3..a5d8006d7 100755 --- a/ScoutSuite/providers/gcp/resources/iam/service_account_bindings.py +++ b/ScoutSuite/providers/gcp/resources/iam/service_account_bindings.py @@ -4,7 +4,7 @@ class ServiceAccountBindings(Resources): def __init__(self, facade: GCPFacade, project_id: str, service_account_email: str): - super(ServiceAccountBindings, self).__init__(facade) + super().__init__(facade) self.project_id = project_id self.service_account_email = service_account_email diff --git a/ScoutSuite/providers/gcp/resources/iam/service_accounts.py b/ScoutSuite/providers/gcp/resources/iam/service_accounts.py index 8fa8412a7..3ff02807f 100755 --- a/ScoutSuite/providers/gcp/resources/iam/service_accounts.py +++ b/ScoutSuite/providers/gcp/resources/iam/service_accounts.py @@ -12,7 +12,7 @@ class ServiceAccounts(GCPCompositeResources): ] def __init__(self, facade: GCPFacade, project_id: str): - super(ServiceAccounts, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): @@ -34,7 +34,7 @@ def _parse_service_account(self, raw_service_account): service_account_dict['email'] = raw_service_account['email'] service_account_dict['project_id'] = raw_service_account['projectId'] - pattern = re.compile('.+@{}\.iam\.gserviceaccount\.com'.format(service_account_dict['project_id'])) + pattern = re.compile(r'.+@{}\.iam\.gserviceaccount\.com'.format(service_account_dict['project_id'])) if pattern.match(service_account_dict['email']): service_account_dict['default_service_account'] = False else: diff --git a/ScoutSuite/providers/gcp/resources/iam/users.py b/ScoutSuite/providers/gcp/resources/iam/users.py index ac11ebeb4..36b7172e2 100755 --- a/ScoutSuite/providers/gcp/resources/iam/users.py +++ b/ScoutSuite/providers/gcp/resources/iam/users.py @@ -5,7 +5,7 @@ class Users(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(Users, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/kms/keyrings.py b/ScoutSuite/providers/gcp/resources/kms/keyrings.py index e9d1346ee..890bfb023 100755 --- a/ScoutSuite/providers/gcp/resources/kms/keyrings.py +++ b/ScoutSuite/providers/gcp/resources/kms/keyrings.py @@ -9,7 +9,7 @@ class KeyRings(GCPCompositeResources): ] def __init__(self, facade: GCPFacade, project_id: str): - super(KeyRings, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/kms/keys.py b/ScoutSuite/providers/gcp/resources/kms/keys.py index a8eae64e2..801f2f356 100755 --- a/ScoutSuite/providers/gcp/resources/kms/keys.py +++ b/ScoutSuite/providers/gcp/resources/kms/keys.py @@ -4,7 +4,7 @@ class Keys(Resources): def __init__(self, facade: GCPFacade, project_id: str, keyring_name: str, location: str): - super(Keys, self).__init__(facade) + super().__init__(facade) self.project_id = project_id self.keyring_name = keyring_name self.location = location diff --git a/ScoutSuite/providers/gcp/resources/regions.py b/ScoutSuite/providers/gcp/resources/regions.py index d1b354c15..2dff774bc 100755 --- a/ScoutSuite/providers/gcp/resources/regions.py +++ b/ScoutSuite/providers/gcp/resources/regions.py @@ -4,7 +4,7 @@ class Regions(GCPCompositeResources): def __init__(self, facade: GCPFacade, project_id: str): - super(Regions, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/stackdriverlogging/metrics.py b/ScoutSuite/providers/gcp/resources/stackdriverlogging/metrics.py index f45072291..40a2c2881 100755 --- a/ScoutSuite/providers/gcp/resources/stackdriverlogging/metrics.py +++ b/ScoutSuite/providers/gcp/resources/stackdriverlogging/metrics.py @@ -4,7 +4,7 @@ class Metrics(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(Metrics, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/stackdriverlogging/sinks.py b/ScoutSuite/providers/gcp/resources/stackdriverlogging/sinks.py index 0f582e119..62da226b1 100755 --- a/ScoutSuite/providers/gcp/resources/stackdriverlogging/sinks.py +++ b/ScoutSuite/providers/gcp/resources/stackdriverlogging/sinks.py @@ -4,7 +4,7 @@ class Sinks(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(Sinks, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/stackdrivermonitoring/alert_policies.py b/ScoutSuite/providers/gcp/resources/stackdrivermonitoring/alert_policies.py index 657740ab5..66d7b39cb 100755 --- a/ScoutSuite/providers/gcp/resources/stackdrivermonitoring/alert_policies.py +++ b/ScoutSuite/providers/gcp/resources/stackdrivermonitoring/alert_policies.py @@ -5,7 +5,7 @@ class AlertPolicies(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(AlertPolicies, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/stackdrivermonitoring/uptime_checks.py b/ScoutSuite/providers/gcp/resources/stackdrivermonitoring/uptime_checks.py index a4427ca3f..b037dbeb5 100755 --- a/ScoutSuite/providers/gcp/resources/stackdrivermonitoring/uptime_checks.py +++ b/ScoutSuite/providers/gcp/resources/stackdrivermonitoring/uptime_checks.py @@ -5,7 +5,7 @@ class UptimeChecks(Resources): def __init__(self, facade: GCPFacade, project_id: str): - super(UptimeChecks, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/resources/zones.py b/ScoutSuite/providers/gcp/resources/zones.py index bf043e55f..2f1f75e68 100755 --- a/ScoutSuite/providers/gcp/resources/zones.py +++ b/ScoutSuite/providers/gcp/resources/zones.py @@ -4,7 +4,7 @@ class Zones(GCPCompositeResources): def __init__(self, facade: GCPFacade, project_id: str): - super(Zones, self).__init__(facade) + super().__init__(facade) self.project_id = project_id async def fetch_all(self): diff --git a/ScoutSuite/providers/gcp/services.py b/ScoutSuite/providers/gcp/services.py index 636d7bd50..72ae52b95 100755 --- a/ScoutSuite/providers/gcp/services.py +++ b/ScoutSuite/providers/gcp/services.py @@ -21,7 +21,7 @@ def __init__(self, credentials=None, default_project_id=None, project_id=None, folder_id=None, organization_id=None, all_projects=None, **kwargs): - super(GCPServicesConfig, self).__init__(credentials) + super().__init__(credentials) facade = GCPFacade(default_project_id, project_id, folder_id, organization_id, all_projects) diff --git a/ScoutSuite/providers/oci/provider.py b/ScoutSuite/providers/oci/provider.py index f92995fe0..327afc409 100755 --- a/ScoutSuite/providers/oci/provider.py +++ b/ScoutSuite/providers/oci/provider.py @@ -26,7 +26,7 @@ def __init__(self, self.credentials = kwargs['credentials'] self.account_id = self.credentials.get_scope() - super(OracleProvider, self).__init__(report_dir, timestamp, services, skipped_services) + super().__init__(report_dir, timestamp, services, skipped_services) def get_report_name(self): """ @@ -39,5 +39,5 @@ def get_report_name(self): def preprocessing(self, ip_ranges=None, ip_ranges_name_key=None): - super(OracleProvider, self).preprocessing() + super().preprocessing() diff --git a/ScoutSuite/providers/oci/resources/identity/api_keys.py b/ScoutSuite/providers/oci/resources/identity/api_keys.py index 3cbef484e..7e43de224 100755 --- a/ScoutSuite/providers/oci/resources/identity/api_keys.py +++ b/ScoutSuite/providers/oci/resources/identity/api_keys.py @@ -5,7 +5,7 @@ class ApiKeys(OracleResources): def __init__(self, facade: OracleFacade, user): - super(ApiKeys, self).__init__(facade) + super().__init__(facade) self.user = user async def fetch_all(self): diff --git a/ScoutSuite/providers/oci/resources/identity/authentication_policy.py b/ScoutSuite/providers/oci/resources/identity/authentication_policy.py index 425993e72..6856f6264 100755 --- a/ScoutSuite/providers/oci/resources/identity/authentication_policy.py +++ b/ScoutSuite/providers/oci/resources/identity/authentication_policy.py @@ -4,7 +4,7 @@ class PasswordPolicy(OracleResources): def __init__(self, facade: OracleFacade): - super(PasswordPolicy, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): raw_authentication_policy = await self.facade.identity.get_authentication_policy() diff --git a/ScoutSuite/providers/oci/resources/identity/base.py b/ScoutSuite/providers/oci/resources/identity/base.py index 85fd5e2b6..727bb662a 100755 --- a/ScoutSuite/providers/oci/resources/identity/base.py +++ b/ScoutSuite/providers/oci/resources/identity/base.py @@ -15,7 +15,7 @@ class Identity(OracleCompositeResources): ] def __init__(self, facade: OracleFacade): - super(Identity, self).__init__(facade) + super().__init__(facade) self.service = 'identity' async def fetch_all(self, **kwargs): diff --git a/ScoutSuite/providers/oci/resources/identity/groups.py b/ScoutSuite/providers/oci/resources/identity/groups.py index 9a260ed4e..bd31eb89f 100755 --- a/ScoutSuite/providers/oci/resources/identity/groups.py +++ b/ScoutSuite/providers/oci/resources/identity/groups.py @@ -5,7 +5,7 @@ class Groups(OracleResources): def __init__(self, facade: OracleFacade): - super(Groups, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): for raw_group in await self.facade.identity.get_groups(): diff --git a/ScoutSuite/providers/oci/resources/identity/policies.py b/ScoutSuite/providers/oci/resources/identity/policies.py index 907b30012..b9aeb2e9d 100755 --- a/ScoutSuite/providers/oci/resources/identity/policies.py +++ b/ScoutSuite/providers/oci/resources/identity/policies.py @@ -5,7 +5,7 @@ class Policies(OracleResources): def __init__(self, facade: OracleFacade): - super(Policies, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): for raw_policy in await self.facade.identity.get_policies(): diff --git a/ScoutSuite/providers/oci/resources/kms/base.py b/ScoutSuite/providers/oci/resources/kms/base.py index 2f799c8f6..338b69270 100755 --- a/ScoutSuite/providers/oci/resources/kms/base.py +++ b/ScoutSuite/providers/oci/resources/kms/base.py @@ -9,7 +9,7 @@ class KMS(OracleCompositeResources): ] def __init__(self, facade: OracleFacade): - super(KMS, self).__init__(facade) + super().__init__(facade) self.service = 'kms' async def fetch_all(self, **kwargs): diff --git a/ScoutSuite/providers/oci/resources/kms/keys.py b/ScoutSuite/providers/oci/resources/kms/keys.py index 5546c61b6..a8179860b 100755 --- a/ScoutSuite/providers/oci/resources/kms/keys.py +++ b/ScoutSuite/providers/oci/resources/kms/keys.py @@ -5,7 +5,7 @@ class Keys(OracleResources): def __init__(self, facade: OracleFacade, keyvault): - super(Keys, self).__init__(facade) + super().__init__(facade) self.key_vault = keyvault async def fetch_all(self): diff --git a/ScoutSuite/providers/oci/resources/kms/keyvaults.py b/ScoutSuite/providers/oci/resources/kms/keyvaults.py index e187db532..86bce2beb 100755 --- a/ScoutSuite/providers/oci/resources/kms/keyvaults.py +++ b/ScoutSuite/providers/oci/resources/kms/keyvaults.py @@ -11,7 +11,7 @@ class KeyVaults(OracleCompositeResources): ] def __init__(self, facade: OracleFacade): - super(KeyVaults, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): raw_keyvaults = await self.facade.kms.get_vaults() diff --git a/ScoutSuite/providers/oci/resources/objectstorage/base.py b/ScoutSuite/providers/oci/resources/objectstorage/base.py index 82bd8b5c9..b61c35fa8 100755 --- a/ScoutSuite/providers/oci/resources/objectstorage/base.py +++ b/ScoutSuite/providers/oci/resources/objectstorage/base.py @@ -9,7 +9,7 @@ class ObjectStorage(OracleCompositeResources): ] def __init__(self, facade: OracleFacade): - super(ObjectStorage, self).__init__(facade) + super().__init__(facade) self.service = 'objectstorage' async def fetch_all(self, **kwargs): diff --git a/ScoutSuite/providers/oci/resources/objectstorage/buckets.py b/ScoutSuite/providers/oci/resources/objectstorage/buckets.py index 50f35502a..f9e4bcac8 100755 --- a/ScoutSuite/providers/oci/resources/objectstorage/buckets.py +++ b/ScoutSuite/providers/oci/resources/objectstorage/buckets.py @@ -4,7 +4,7 @@ class Buckets(OracleResources): def __init__(self, facade: OracleFacade): - super(Buckets, self).__init__(facade) + super().__init__(facade) async def fetch_all(self): diff --git a/ScoutSuite/providers/oci/services.py b/ScoutSuite/providers/oci/services.py index 3b97dd920..e9b3c7767 100755 --- a/ScoutSuite/providers/oci/services.py +++ b/ScoutSuite/providers/oci/services.py @@ -8,7 +8,7 @@ class OracleServicesConfig(BaseServicesConfig): def __init__(self, credentials: OracleCredentials = None, **kwargs): - super(OracleServicesConfig, self).__init__(credentials) + super().__init__(credentials) facade = OracleFacade(credentials) diff --git a/ScoutSuite/utils.py b/ScoutSuite/utils.py index 8da92ccb6..4babc48aa 100755 --- a/ScoutSuite/utils.py +++ b/ScoutSuite/utils.py @@ -1,5 +1,3 @@ -from __future__ import print_function - formatted_service_name = { # AWS 'acm': 'ACM', From 5e3c39afbdac775a4c23a20b0ebc40d97adb4603 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 12:23:36 -0500 Subject: [PATCH 038/312] :construction_worker: add GitHub Actions --- .github/workflows/testing.yml | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/testing.yml diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml new file mode 100644 index 000000000..74abdf9be --- /dev/null +++ b/.github/workflows/testing.yml @@ -0,0 +1,51 @@ +name: Python package + +on: [push, pull-request] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.5, 3.6, 3.7, 3.8] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -U setuptools + pip install -r requirements.txt + pip install flake8 + pip install coveralls + pip install codecov + pip install autopep8 + pip install pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Autopep 8 + run: | + autopep8 --diff --recursive --max-line-length=127 . + - name: Test with nosetests + run: | + nosetests --with-coverage tests/test-utils.py + nosetests --with-coverage tests/test-core.py + nosetests --with-coverage tests/test-output.py + nosetests --with-coverage tests/test-utils-conditions.py + nosetests --with-coverage tests/test-main.py + nosetests --with-coverage tests/test-resources.py + nosetests --with-coverage tests/test-rules-ruleset.py + nosetests --with-coverage tests/test-rules-processingengine.py + + # Not sure what the secret for this will be, but could be set in GitHub Secrets and replaced + nosetests --with-coverage --nocapture tests/test-scoutsuite.py -a "!credential" From f0bf2d72f5dc0c65641e86bc0ea55e0c762e3d13 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 12:25:55 -0500 Subject: [PATCH 039/312] fix event that GHA triggers on --- .github/workflows/testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 74abdf9be..5822428f1 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -1,6 +1,6 @@ name: Python package -on: [push, pull-request] +on: [push, pull_request] jobs: build: From 80ff6dc83ab2492e0b8fd9260e08ed979b5b5acb Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 12:28:34 -0500 Subject: [PATCH 040/312] add nose to dependencies installation --- .github/workflows/testing.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 5822428f1..ed4d71967 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -26,6 +26,7 @@ jobs: pip install codecov pip install autopep8 pip install pytest + pip install nose if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Lint with flake8 run: | From 3059401477869bf8718751e0b914678d66c8a732 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 12:31:03 -0500 Subject: [PATCH 041/312] cache dependencies to speed up builds --- .github/workflows/testing.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index ed4d71967..965c4596e 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -16,6 +16,16 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} + - name: Cache pip + uses: actions/cache@v2 + with: + # This path is specific to Ubuntu + path: ~/.cache/pip + # Look to see if there is a cache hit for the corresponding requirements file + key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- - name: Install dependencies run: | python -m pip install --upgrade pip From 784cb7ead16f5375c35e49bdebbe7bd71196f187 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 12:42:41 -0500 Subject: [PATCH 042/312] add more test deps --- .github/workflows/testing.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 965c4596e..244935812 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -36,6 +36,8 @@ jobs: pip install codecov pip install autopep8 pip install pytest + pip install mock + pip install unittest pip install nose if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Lint with flake8 From ebb9e45c7567e60871d4a6871c4221c0b502c194 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 12:45:22 -0500 Subject: [PATCH 043/312] remove unittest pip (built-in) --- .github/workflows/testing.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 244935812..16b8f6ade 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -37,7 +37,6 @@ jobs: pip install autopep8 pip install pytest pip install mock - pip install unittest pip install nose if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Lint with flake8 From f6fb177d6ae5eefd756bc53c20bf84dbc7e77de0 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 12:51:36 -0500 Subject: [PATCH 044/312] only run on pushes to master and PR's --- .github/workflows/testing.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 16b8f6ade..af47723ee 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -1,6 +1,11 @@ name: Python package -on: [push, pull_request] +on: + push: + branches: + - develop + pull_request: + jobs: build: From e8066d98290b20041095e701280b0f4a080addfa Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 12:56:39 -0500 Subject: [PATCH 045/312] fix: remove forked differences We have additional changes in our forked branch of `develop`, need to take those out --- ScoutSuite/providers/aws/facade/ec2.py | 16 +--------------- ScoutSuite/providers/aws/resources/ec2/ami.py | 7 ++----- .../providers/aws/resources/ec2/instances.py | 2 +- .../providers/aws/resources/ec2/snapshots.py | 2 -- .../providers/aws/resources/ec2/volumes.py | 2 -- ScoutSuite/providers/aws/services.py | 4 ++-- 6 files changed, 6 insertions(+), 27 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/ec2.py b/ScoutSuite/providers/aws/facade/ec2.py index 27af07f7e..7eb73e60c 100755 --- a/ScoutSuite/providers/aws/facade/ec2.py +++ b/ScoutSuite/providers/aws/facade/ec2.py @@ -102,19 +102,12 @@ async def get_network_interfaces(self, region: str, vpc: str): async def get_volumes(self, region: str): try: volumes = await AWSFacadeUtils.get_all_pages('ec2', region, self.session, 'describe_volumes', 'Volumes') - await get_and_set_concurrently([self._get_and_set_key_manager, self._get_and_set_volume_tags], volumes, region=region) + await get_and_set_concurrently([self._get_and_set_key_manager], volumes, region=region) return volumes except Exception as e: print_exception('Failed to get EC2 volumes: {}'.format(e)) return [] - async def _get_and_set_volume_tags(self, volume: {}, region: str): - if "Tags" in volume: - volume["tags"] = {x["Key"]: x["Value"] for x in volume["Tags"]} - else: - volume["tags"] = {} - return volume - async def _get_and_set_key_manager(self, volume: {}, region: str): kms_client = AWSFacadeUtils.get_client('kms', self.session, region) if 'KmsKeyId' in volume: @@ -195,13 +188,6 @@ async def _get_and_set_subnet_flow_logs(self, subnet: {}, region: str): [flow_log for flow_log in self.flow_logs_cache[region] if flow_log['ResourceId'] == subnet['SubnetId'] or flow_log['ResourceId'] == subnet['VpcId']] - async def get_and_set_ec2_instance_tags(self, raw_instance: {}): - if 'Tags' in raw_instance: - instance = {x['Key']: x['Value'] for x in raw_instance['Tags']} - else: - instance = {} - return instance - async def get_peering_connections(self, region): try: peering_connections = await AWSFacadeUtils.get_all_pages('ec2', region, self.session, 'describe_vpc_peering_connections', 'VpcPeeringConnections') diff --git a/ScoutSuite/providers/aws/resources/ec2/ami.py b/ScoutSuite/providers/aws/resources/ec2/ami.py index 2e0538846..6c6ec3565 100755 --- a/ScoutSuite/providers/aws/resources/ec2/ami.py +++ b/ScoutSuite/providers/aws/resources/ec2/ami.py @@ -14,9 +14,6 @@ async def fetch_all(self): self[name] = resource def _parse_image(self, raw_image): - raw_image['id'] = raw_image['ImageId'] - raw_image['name'] = raw_image['Name'] - if 'Tags' in raw_image: - raw_image['tags'] = {x["Key"]: x["Value"] for x in raw_image["Tags"]} - + raw_image['id'] = raw_image.get('ImageId') + raw_image['name'] = raw_image.get('Name') return raw_image['id'], raw_image diff --git a/ScoutSuite/providers/aws/resources/ec2/instances.py b/ScoutSuite/providers/aws/resources/ec2/instances.py index ab59acbe5..11d5b3105 100755 --- a/ScoutSuite/providers/aws/resources/ec2/instances.py +++ b/ScoutSuite/providers/aws/resources/ec2/instances.py @@ -28,7 +28,7 @@ async def _parse_instance(self, raw_instance): get_name(raw_instance, instance, 'InstanceId') get_keys(raw_instance, instance, - ['KeyName', 'LaunchTime', 'InstanceType', 'State', 'IamInstanceProfile', 'SubnetId', 'Tags']) + ['KeyName', 'LaunchTime', 'InstanceType', 'State', 'IamInstanceProfile', 'SubnetId']) instance['network_interfaces'] = {} for eni in raw_instance['NetworkInterfaces']: diff --git a/ScoutSuite/providers/aws/resources/ec2/snapshots.py b/ScoutSuite/providers/aws/resources/ec2/snapshots.py index d3304dd56..d48b5f9e6 100755 --- a/ScoutSuite/providers/aws/resources/ec2/snapshots.py +++ b/ScoutSuite/providers/aws/resources/ec2/snapshots.py @@ -18,8 +18,6 @@ def _parse_snapshot(self, raw_snapshot): raw_snapshot['id'] = raw_snapshot.pop('SnapshotId') raw_snapshot['name'] = get_name(raw_snapshot, raw_snapshot, 'id') raw_snapshot['public'] = self._is_public(raw_snapshot) - if "Tags" in raw_snapshot: - raw_snapshot['tags'] = {x["Key"]: x["Value"] for x in raw_snapshot["Tags"]} return raw_snapshot['id'], raw_snapshot @staticmethod diff --git a/ScoutSuite/providers/aws/resources/ec2/volumes.py b/ScoutSuite/providers/aws/resources/ec2/volumes.py index 9dc79b2da..6dec86616 100755 --- a/ScoutSuite/providers/aws/resources/ec2/volumes.py +++ b/ScoutSuite/providers/aws/resources/ec2/volumes.py @@ -17,6 +17,4 @@ async def fetch_all(self): def _parse_volume(self, raw_volume): raw_volume['id'] = raw_volume.pop('VolumeId') raw_volume['name'] = get_name(raw_volume, raw_volume, 'id') - if "Tags" in raw_volume: - raw_volume['tags'] = {x["Key"]: x["Value"] for x in raw_volume["Tags"]} return raw_volume['id'], raw_volume diff --git a/ScoutSuite/providers/aws/services.py b/ScoutSuite/providers/aws/services.py index fd0ed4e10..ba0141ea6 100755 --- a/ScoutSuite/providers/aws/services.py +++ b/ScoutSuite/providers/aws/services.py @@ -69,8 +69,8 @@ class AWSServicesConfig(BaseServicesConfig): :ivar rds: RDS configuration :ivar redshift: Redshift configuration :ivar s3: S3 configuration - :ivar ses: SES configuration - :ivar sns: SNS configuration + :ivar ses: SES configuration: + "ivar sns: SNS configuration :ivar sqs: SQS configuration """ From f4e54148b88bf9b387a98ae2ba7a1595563783f5 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 13:05:54 -0500 Subject: [PATCH 046/312] add coverage callout --- .github/workflows/testing.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index af47723ee..1f6e054c0 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -66,3 +66,8 @@ jobs: # Not sure what the secret for this will be, but could be set in GitHub Secrets and replaced nosetests --with-coverage --nocapture tests/test-scoutsuite.py -a "!credential" + + - name: run coverage + run: | + coveralls + codecov From c6e408c7963644ce981139f1bc98b31f90c20d52 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 13:07:22 -0500 Subject: [PATCH 047/312] use built-in coveralls github Action --- .github/workflows/testing.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 1f6e054c0..4b7119c96 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -69,5 +69,8 @@ jobs: - name: run coverage run: | - coveralls codecov + - name: Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} From 66c8b9608d3515257d1b311f608eca9e43bf3775 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 13:12:04 -0500 Subject: [PATCH 048/312] use codecov GHA --- .github/workflows/testing.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 4b7119c96..14f38e686 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -67,9 +67,13 @@ jobs: # Not sure what the secret for this will be, but could be set in GitHub Secrets and replaced nosetests --with-coverage --nocapture tests/test-scoutsuite.py -a "!credential" - - name: run coverage - run: | - codecov + - uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos + file: ./coverage.xml # optional + flags: unittests # optional + name: codecov-umbrella # optional + fail_ci_if_error: true # optional (default = false) - name: Coveralls uses: coverallsapp/github-action@master with: From 3388d88fb5098918640a60cece667b8320f0aec1 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 13:13:09 -0500 Subject: [PATCH 049/312] remove optional fields, don't fail build on error in coverage --- .github/workflows/testing.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 14f38e686..39abdf70a 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -68,12 +68,6 @@ jobs: nosetests --with-coverage --nocapture tests/test-scoutsuite.py -a "!credential" - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos - file: ./coverage.xml # optional - flags: unittests # optional - name: codecov-umbrella # optional - fail_ci_if_error: true # optional (default = false) - name: Coveralls uses: coverallsapp/github-action@master with: From b56db05f932e04a70cac3c64a1950236f4f5833b Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 13:20:14 -0500 Subject: [PATCH 050/312] fix: specify coverage file --- .github/workflows/testing.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 39abdf70a..c8d19bc7a 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -68,6 +68,9 @@ jobs: nosetests --with-coverage --nocapture tests/test-scoutsuite.py -a "!credential" - uses: codecov/codecov-action@v1 + with: + file: ./.coverage + - name: Coveralls uses: coverallsapp/github-action@master with: From d378a49fba032ee3da5750c65f6ca3c970651209 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 13:21:52 -0500 Subject: [PATCH 051/312] remove coveralls call --- .github/workflows/testing.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index c8d19bc7a..c9bf26b70 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -71,7 +71,8 @@ jobs: with: file: ./.coverage - - name: Coveralls - uses: coverallsapp/github-action@master - with: - github-token: ${{ secrets.GITHUB_TOKEN }} + # disabling because it can't find the .lcov coverage file + # - name: Coveralls + # uses: coverallsapp/github-action@master + # with: + # github-token: ${{ secrets.GITHUB_TOKEN }} From 52b32c338d02b29cf1c4f246a4cb954e5c503ee2 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 13:28:29 -0500 Subject: [PATCH 052/312] add additional run on 'master' branch --- .github/workflows/testing.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index c9bf26b70..4abccf2a8 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -4,6 +4,7 @@ on: push: branches: - develop + - master pull_request: From f589b3ac3343fb95c1ca80fa573f475a3810b061 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 20:42:26 -0500 Subject: [PATCH 053/312] fix: recursive descent snake_keys and tests --- ScoutSuite/providers/aws/utils.py | 5 +++ tests/test-utils.py | 71 +++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/ScoutSuite/providers/aws/utils.py b/ScoutSuite/providers/aws/utils.py index 6b59c02e7..6a3e98946 100755 --- a/ScoutSuite/providers/aws/utils.py +++ b/ScoutSuite/providers/aws/utils.py @@ -99,6 +99,11 @@ def snake_keys(d): new_key = no_camel(k) if isinstance(d[k], dict): new_table[new_key] = snake_keys(d[k]) + elif isinstance(d[k], list): + new_ary = [] + for v in d[k]: + new_ary.append(snake_keys(v)) + new_table[new_key] = new_ary else: new_table[new_key] = d[k] return new_table diff --git a/tests/test-utils.py b/tests/test-utils.py index a2435747d..f34a932fe 100755 --- a/tests/test-utils.py +++ b/tests/test-utils.py @@ -1,3 +1,5 @@ +import unittest + # Import AWS utils from ScoutSuite.providers.aws.utils import ( get_keys, @@ -6,30 +8,32 @@ is_throttled, get_aws_account_id, get_partition_name, + snake_keys, ) from ScoutSuite.utils import * import collections import mock +import datetime + # # Test methods for ScoutSuite/utils.py # -class TestScoutUtilsClass: - +class TestScoutUtilsClass(unittest.TestCase): def test_format_service_name(self): - assert (format_service_name('iAm') == 'IAM') - assert (format_service_name('cloudformation') == 'CloudFormation') + assert format_service_name("iAm") == "IAM" + assert format_service_name("cloudformation") == "CloudFormation" def test_get_keys(self): - test1 = {'a': 'b', 'c': 'd'} - test2 = {'a': '', 'e': 'f'} - get_keys(test1, test2, 'a') - assert (test2['a'] == 'b') - assert ('c' not in test2) - get_keys(test1, test2, 'c') - assert (test2['c'] == 'd') + test1 = {"a": "b", "c": "d"} + test2 = {"a": "", "e": "f"} + get_keys(test1, test2, "a") + assert test2["a"] == "b" + assert "c" not in test2 + get_keys(test1, test2, "c") + assert test2["c"] == "d" def test_no_camel(self): - assert (no_camel('TestTest') == 'test_test') + assert no_camel("TestTest") == "test_test" def test_is_throttled(self): CustomException = collections.namedtuple("CustomException", "response") @@ -79,3 +83,46 @@ def test_get_partition_name(self): return_value={"Arn": "a:b:c:d:e:f:"}, ): assert get_partition_name("") == "b" + + def test_snake_case(self): + src = { + "AttributeDefinitions": [ + {"AttributeName": "string", "AttributeType": "S"}, + ], + "TableName": "string", + "KeySchema": [{"AttributeName": "string", "KeyType": "HASH"},], + "TableStatus": "CREATING", + "CreationDateTime": datetime.datetime(2015, 1, 1, 1, 1, 1, 1, None), + "ProvisionedThroughput": { + "LastIncreaseDateTime": datetime.datetime(2015, 1, 1, 1, 1, 1, 1, None), + "LastDecreaseDateTime": datetime.datetime(2015, 1, 1, 1, 1, 1, 1, None), + "NumberOfDecreasesToday": 123, + "ReadCapacityUnits": 123, + "WriteCapacityUnits": 123, + }, + "TableSizeBytes": 123, + } + dest = { + "attribute_definitions": [ + {"attribute_name": "string", "attribute_type": "S"}, + ], + "table_name": "string", + "key_schema": [{"attribute_name": "string", "key_type": "HASH"}], + "table_status": "CREATING", + "creation_date_time": datetime.datetime(2015, 1, 1, 1, 1, 1, 1, None), + "provisioned_throughput": { + "last_increase_date_time": datetime.datetime( + 2015, 1, 1, 1, 1, 1, 1, None + ), + "last_decrease_date_time": datetime.datetime( + 2015, 1, 1, 1, 1, 1, 1, None + ), + "number_of_decreases_today": 123, + "read_capacity_units": 123, + "write_capacity_units": 123, + }, + "table_size_bytes": 123, + } + d = snake_keys(src) + self.maxDiff = None + self.assertEquals(d, dest) From 3c9af6539d216d966c48751d79eb4ba89060d436 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 20:45:48 -0500 Subject: [PATCH 054/312] fix: 3.5 doesn't support f-strings; remove them --- ScoutSuite/providers/aws/facade/dynamodb.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/dynamodb.py b/ScoutSuite/providers/aws/facade/dynamodb.py index f4d370422..cc4b7c6f7 100644 --- a/ScoutSuite/providers/aws/facade/dynamodb.py +++ b/ScoutSuite/providers/aws/facade/dynamodb.py @@ -16,7 +16,7 @@ async def get_backups(self, region, table_name): TableName=table_name, ) except Exception as e: - print_exception(f"Failed to get DynamoDB Backups for {table_name}") + print_exception("Failed to get DynamoDB Backups for {}".format(table_name)) return [] async def get_tables(self, region): @@ -25,7 +25,7 @@ async def get_tables(self, region): "dynamodb", region, self.session, "list_tables", "TableNames" ) except Exception as e: - print_exception(f"Failed to get DynamoDB tables") + print_exception("Failed to get DynamoDB tables") return [] async def get_tags_for_resource(self, region, resource_arn): @@ -39,7 +39,9 @@ async def get_tags_for_resource(self, region, resource_arn): ResourceArn=resource_arn, ) except Exception as e: - print_exception(f"Failed to get DynamoDB tags for resource {resource_arn}") + print_exception( + "Failed to get DynamoDB tags for resource {}".format(resource_arn) + ) return [] async def get_table(self, region, table_name): @@ -49,6 +51,6 @@ async def get_table(self, region, table_name): lambda: client.describe_table(TableName=table_name) ) except Exception as e: - print_exception(f"Failed to get table {table_name}: {e}") + print_exception("Failed to get table {}: {}".format(table_name, e)) raw_table = None return raw_table From 2bf098cfa20d7afdce546b5f1d47611766250641 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sat, 30 May 2020 21:20:52 -0500 Subject: [PATCH 055/312] remove unused import --- ScoutSuite/providers/aws/resources/dynamodb/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ScoutSuite/providers/aws/resources/dynamodb/base.py b/ScoutSuite/providers/aws/resources/dynamodb/base.py index 3691f52ec..479c04499 100644 --- a/ScoutSuite/providers/aws/resources/dynamodb/base.py +++ b/ScoutSuite/providers/aws/resources/dynamodb/base.py @@ -1,7 +1,6 @@ from ScoutSuite.providers.aws.facade.base import AWSFacade from ScoutSuite.providers.aws.resources.regions import Regions -from .backups import Backups from .tables import Tables From 9520bc8893421438039404726a60926d9af6af74 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sun, 31 May 2020 09:04:19 -0500 Subject: [PATCH 056/312] remove unused import --- ScoutSuite/core/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ScoutSuite/core/utils.py b/ScoutSuite/core/utils.py index f639d4edb..0d63e72e2 100755 --- a/ScoutSuite/core/utils.py +++ b/ScoutSuite/core/utils.py @@ -2,7 +2,6 @@ Single-service rule processing functions """ -from six import string_types import copy from ScoutSuite.core.console import print_exception From 43827aa019e5d1fb559d66590363543ce147586c Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Sun, 31 May 2020 10:25:04 -0500 Subject: [PATCH 057/312] fix capture variable issue (lgtm) --- ScoutSuite/providers/azure/facade/securitycenter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/providers/azure/facade/securitycenter.py b/ScoutSuite/providers/azure/facade/securitycenter.py index 5b0ed4cac..08430df36 100755 --- a/ScoutSuite/providers/azure/facade/securitycenter.py +++ b/ScoutSuite/providers/azure/facade/securitycenter.py @@ -105,7 +105,7 @@ async def get_regulatory_compliance_results(self, subscription_id: str): for standard in compliance_standards: try: compliance_controls = await run_concurrently( - lambda: list(client.regulatory_compliance_controls.list( + lambda standard=standard: list(client.regulatory_compliance_controls.list( regulatory_compliance_standard_name=standard.name)) ) for control in compliance_controls: From 6c82dc6e24a16021096dbdd43927f47690f0a544 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Mon, 1 Jun 2020 12:54:51 -0500 Subject: [PATCH 058/312] fix: only iterate over keys in dict --- ScoutSuite/providers/aws/utils.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/ScoutSuite/providers/aws/utils.py b/ScoutSuite/providers/aws/utils.py index 6a3e98946..06709240b 100755 --- a/ScoutSuite/providers/aws/utils.py +++ b/ScoutSuite/providers/aws/utils.py @@ -95,15 +95,14 @@ def snake_keys(d): """ new_table = {} - for k in d.keys(): - new_key = no_camel(k) - if isinstance(d[k], dict): - new_table[new_key] = snake_keys(d[k]) - elif isinstance(d[k], list): - new_ary = [] - for v in d[k]: - new_ary.append(snake_keys(v)) - new_table[new_key] = new_ary - else: - new_table[new_key] = d[k] + if isinstance(d, dict): + for k in d.keys(): + new_key = no_camel(k) + if isinstance(d[k], dict): + new_table[new_key] = snake_keys(d[k]) + elif isinstance(d[k], list): + new_ary = [snake_keys(v) for v in d[k]] + new_table[new_key] = new_ary + else: + new_table[new_key] = d[k] return new_table From 6322da11ffcc8d5574b79820b85d9e8e89d6a25d Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Mon, 1 Jun 2020 13:08:41 -0500 Subject: [PATCH 059/312] add test for snake_case array --- tests/test-utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test-utils.py b/tests/test-utils.py index f34a932fe..f239d26ff 100755 --- a/tests/test-utils.py +++ b/tests/test-utils.py @@ -101,6 +101,11 @@ def test_snake_case(self): "WriteCapacityUnits": 123, }, "TableSizeBytes": 123, + "AnotherArray": [ + "One", + "Two" + "AnotherThing" + ] } dest = { "attribute_definitions": [ @@ -122,6 +127,7 @@ def test_snake_case(self): "write_capacity_units": 123, }, "table_size_bytes": 123, + "another_array": ["One", "Two", "AnotherThing"] } d = snake_keys(src) self.maxDiff = None From 8b4f005df125f52667f9ca6d8416513c1a5fffb6 Mon Sep 17 00:00:00 2001 From: Pau Risa Date: Tue, 2 Jun 2020 17:17:20 +0200 Subject: [PATCH 060/312] Fixed VPC, IAM and HTML partial bugs --- ...rvices.vpc.regions.id.vpcs.id.subnets.html | 2 +- ScoutSuite/providers/aws/metadata.json | 2 +- .../providers/aws/resources/vpc/base.py | 2 - .../aws/resources/vpc/peering_connections.py | 1 + .../aws/resources/vpc/route_tables.py | 19 -------- .../cloudtrail-s3-bucket-no-logging.json | 48 ------------------- .../iam-root-account-no-hardware-mfa.json | 44 +++++++++++++++++ .../findings/iam-root-account-no-mfa.json | 15 ------ ...n => vpc-routing-tables-with-peering.json} | 3 +- .../findings/vpc-subnet-without-flow-log.json | 2 +- .../aws/rules/rulesets/cis-1.2.0.json | 18 +++++-- 11 files changed, 62 insertions(+), 94 deletions(-) delete mode 100644 ScoutSuite/providers/aws/resources/vpc/route_tables.py delete mode 100644 ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json create mode 100644 ScoutSuite/providers/aws/rules/findings/iam-root-account-no-hardware-mfa.json rename ScoutSuite/providers/aws/rules/findings/{ec2-route-tables-full-peering.json => vpc-routing-tables-with-peering.json} (90%) diff --git a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.subnets.html b/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.subnets.html index 345b4404c..7cecbe4e5 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.subnets.html +++ b/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.subnets.html @@ -31,7 +31,7 @@

      Instances

    -

    Flow logs +

    Flow logs {{> count_badge count=flow_logs.length}}

      diff --git a/ScoutSuite/providers/aws/metadata.json b/ScoutSuite/providers/aws/metadata.json index 825fddde3..4771b786c 100755 --- a/ScoutSuite/providers/aws/metadata.json +++ b/ScoutSuite/providers/aws/metadata.json @@ -124,7 +124,7 @@ "path": "services.vpc.regions.id.vpcs.id.subnets" }, "peering_connections": { - "hidden": true, + "hidden": false, "path": "services.vpc.regions.id.peering_connections", "callbacks": [ [ "process_vpc_peering_connections_callback", {} ] diff --git a/ScoutSuite/providers/aws/resources/vpc/base.py b/ScoutSuite/providers/aws/resources/vpc/base.py index f3eff169c..802c31464 100755 --- a/ScoutSuite/providers/aws/resources/vpc/base.py +++ b/ScoutSuite/providers/aws/resources/vpc/base.py @@ -7,7 +7,6 @@ from .flow_logs import FlowLogs from .vpcs import RegionalVpcs from .peering_connections import PeeringConnections -from .route_tables import RouteTables known_cidrs = {'0.0.0.0/0': 'All'} aws_ip_ranges = {} @@ -18,7 +17,6 @@ class VPC(Regions): (RegionalVpcs, 'vpcs'), (FlowLogs, 'flow_logs'), (PeeringConnections, 'peering_connections') - # (RouteTables, 'route_tables') ] def __init__(self, facade: AWSFacade): diff --git a/ScoutSuite/providers/aws/resources/vpc/peering_connections.py b/ScoutSuite/providers/aws/resources/vpc/peering_connections.py index fa8be7a2c..75ef8c98f 100755 --- a/ScoutSuite/providers/aws/resources/vpc/peering_connections.py +++ b/ScoutSuite/providers/aws/resources/vpc/peering_connections.py @@ -10,6 +10,7 @@ def __init__(self, facade: AWSFacade, region: str): async def fetch_all(self): raw_peering_connections = await self.facade.ec2.get_peering_connections(self.region) + for raw_peering_connection in raw_peering_connections: id, peering_connection = self._parse_peering_connections(raw_peering_connection) self[id] = peering_connection diff --git a/ScoutSuite/providers/aws/resources/vpc/route_tables.py b/ScoutSuite/providers/aws/resources/vpc/route_tables.py deleted file mode 100644 index 5699e4bb4..000000000 --- a/ScoutSuite/providers/aws/resources/vpc/route_tables.py +++ /dev/null @@ -1,19 +0,0 @@ -from ScoutSuite.providers.aws.facade.base import AWSFacade -from ScoutSuite.providers.aws.resources.base import AWSResources - - -class RouteTables(AWSResources): - def __init__(self, facade: AWSFacade, region: str): - super().__init__(facade) - self.facade = facade - self.region = region - - async def fetch_all(self): - raw_route_tables = await self.facade.ec2.get_route_tables(self.region) - for raw_route_table in raw_route_tables: - id, route_table = self._parse_route_tables(raw_route_table) - self[id] = route_table - - def _parse_route_tables(self, raw_route_table): - pass - # return route_table_id, raw_route_tables diff --git a/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json b/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json deleted file mode 100644 index 74f121ccf..000000000 --- a/ScoutSuite/providers/aws/rules/findings/cloudtrail-s3-bucket-no-logging.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "description": "CloudTrail S3 Bucket Access Logging Is Disabled", - "rationale": "The lack of S3 bucket logging prevents log information to be accessed in security and incident response workflows.", - "remediation": "Ensure that critical S3 buckets have Logging enabled", - "compliance": [ - { - "name": "CIS Amazon Web Services Foundations", - "version": "1.0.0", - "reference": "2.6" - }, - { - "name": "CIS Amazon Web Services Foundations", - "version": "1.1.0", - "reference": "2.6" - }, - { - "name": "CIS Amazon Web Services Foundations", - "version": "1.2.0", - "reference": "2.6" - } - ], - "dashboard_name": "Buckets", - "path": "s3.buckets.id", - "conditions": [ - "and", - [ - "s3.buckets.id.policy.id.", - "withKey", - "Statement" - ], - [ - "s3.buckets.id.policy.id.Statement.id.", - "withKey", - "Principal" - ], - [ - "s3.buckets.id.policy.id.Statement.id.Principal.Service", - "containString", - "cloudtrail.amazonaws.com" - ], - [ - "s3.buckets.id.logging", - "equal", - "Disabled" - ] - ], - "id_suffix": "logging" -} \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-hardware-mfa.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-hardware-mfa.json new file mode 100644 index 000000000..2be2b4dc6 --- /dev/null +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-hardware-mfa.json @@ -0,0 +1,44 @@ +{ + "description": "Root Account without hardware MFA", + "rationale": "The root account is the most privileged user in an account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they're prompted for their user name and password and for an authentication code from their AWS MFA device.", + "remediation": "Enable MFA for the root account", + "compliance": [ + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.0.0", + "reference": "1.13" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.1.0", + "reference": "1.14" + }, + { + "name": "CIS Amazon Web Services Foundations", + "version": "1.2.0", + "reference": "1.14" + } + ], + "references": [ + "https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-cis-controls.html#securityhub-cis-controls-1.13" + ], + "dashboard_name": "Root account", + "path": "iam.credential_reports.id", + "conditions": [ + "and", + [ + "iam.credential_reports.id.mfa_active", + "notTrue", + "" + ], + [ + "iam.credential_reports.id.name", + "equal", + "" + ] + ], + "keys": [ + "this" + ], + "id_suffix": "mfa_hardware_active" +} diff --git a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json index b51f400b1..e242c1e3b 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-root-account-no-mfa.json @@ -3,30 +3,15 @@ "rationale": "The root account is the most privileged user in an account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they're prompted for their user name and password and for an authentication code from their AWS MFA device.", "remediation": "Enable MFA for the root account", "compliance": [ - { - "name": "CIS Amazon Web Services Foundations", - "version": "1.0.0", - "reference": "1.13" - }, { "name": "CIS Amazon Web Services Foundations", "version": "1.1.0", "reference": "1.13" }, - { - "name": "CIS Amazon Web Services Foundations", - "version": "1.1.0", - "reference": "1.14" - }, { "name": "CIS Amazon Web Services Foundations", "version": "1.2.0", "reference": "1.13" - }, - { - "name": "CIS Amazon Web Services Foundations", - "version": "1.2.0", - "reference": "1.14" } ], "references": [ diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json b/ScoutSuite/providers/aws/rules/findings/vpc-routing-tables-with-peering.json similarity index 90% rename from ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json rename to ScoutSuite/providers/aws/rules/findings/vpc-routing-tables-with-peering.json index 5352a6b7d..f3927bf15 100644 --- a/ScoutSuite/providers/aws/rules/findings/ec2-route-tables-full-peering.json +++ b/ScoutSuite/providers/aws/rules/findings/vpc-routing-tables-with-peering.json @@ -15,13 +15,12 @@ } ], "dashboard_name": "Rulesets", - "display_path": "vpc.regions.id.peering_connections.peering_connections.id", "path": "vpc.regions.id.peering_connections.id", "conditions": [ "and", [ "vpc.regions.id.peering_connections.peering_connection_id", - "notNull", + "null", "" ] ], diff --git a/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json b/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json index 003925b81..3d9974718 100755 --- a/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json +++ b/ScoutSuite/providers/aws/rules/findings/vpc-subnet-without-flow-log.json @@ -37,5 +37,5 @@ "" ] ], - "id_suffix": "NoFlowLog" + "id_suffix": "no_flowlog" } \ No newline at end of file diff --git a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json index 81f858f98..a89607ad1 100644 --- a/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json +++ b/ScoutSuite/providers/aws/rules/rulesets/cis-1.2.0.json @@ -112,7 +112,15 @@ ], "iam-root-account-no-mfa.json": [ { - "comment": "Recommendation 1.13 and 1.14 (it is not possible to check if MFA is hardware or software)", + "comment": "Recommendation 1.13", + "enabled": true, + "level": "danger", + "scored": true + } + ], + "iam-root-account-no-hardware-mfa.json": [ + { + "comment": "Recommendation 1.14", "enabled": true, "level": "danger", "scored": true @@ -164,7 +172,7 @@ "scored": false } ], - "TODO.json": [ + "todo-recommendation-1-19.json": [ { "comment": "Recommendation 1.19 (TODO)", "enabled": false, @@ -526,10 +534,10 @@ "scored": "true" } ], - "ec2-route-tables-full-peering.json": [ + "vpc-routing-tables-with-peering.json": [ { - "comment": "Recommendation 4.4 TODO", - "enabled": false, + "comment": "Recommendation 4.4", + "enabled": true, "level": "warning", "scored": "false" } From 5fd185cb9ee6f68459f298e3ef6fbfe61e253d62 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Wed, 3 Jun 2020 11:09:42 -0500 Subject: [PATCH 061/312] revert addition of tag mapping Mixed a mistake from another PR into this one. --- ScoutSuite/providers/aws/facade/ec2.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/ec2.py b/ScoutSuite/providers/aws/facade/ec2.py index c316c8d21..5083fcab0 100755 --- a/ScoutSuite/providers/aws/facade/ec2.py +++ b/ScoutSuite/providers/aws/facade/ec2.py @@ -102,19 +102,12 @@ async def get_network_interfaces(self, region: str, vpc: str): async def get_volumes(self, region: str): try: volumes = await AWSFacadeUtils.get_all_pages('ec2', region, self.session, 'describe_volumes', 'Volumes') - await get_and_set_concurrently([self._get_and_set_key_manager, self._get_and_set_volume_tags], volumes, region=region) + await get_and_set_concurrently([self._get_and_set_key_manager], volumes, region=region) return volumes except Exception as e: print_exception('Failed to get EC2 volumes: {}'.format(e)) return [] - async def _get_and_set_volume_tags(self, volume: {}, region: str): - if "Tags" in volume: - volume["tags"] = {x["Key"]: x["Value"] for x in volume["Tags"]} - else: - volume["tags"] = {} - return volume - async def _get_and_set_key_manager(self, volume: {}, region: str): kms_client = AWSFacadeUtils.get_client('kms', self.session, region) if 'KmsKeyId' in volume: @@ -195,13 +188,6 @@ async def _get_and_set_subnet_flow_logs(self, subnet: {}, region: str): [flow_log for flow_log in self.flow_logs_cache[region] if flow_log['ResourceId'] == subnet['SubnetId'] or flow_log['ResourceId'] == subnet['VpcId']] - async def get_and_set_ec2_instance_tags(self, raw_instance: {}): - if 'Tags' in raw_instance: - instance = {x['Key']: x['Value'] for x in raw_instance['Tags']} - else: - instance = {} - return instance - async def get_peering_connections(self, region): try: peering_connections = await AWSFacadeUtils.get_all_pages('ec2', region, self.session, 'describe_vpc_peering_connections', 'VpcPeeringConnections') From 1c94820d2097a3489ce068acf43dc261428a40d4 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Wed, 3 Jun 2020 11:10:35 -0500 Subject: [PATCH 062/312] revert tag mapping addition Another mistake from another PR to revert the mapping of tags to the AMI instance. --- ScoutSuite/providers/aws/resources/ec2/ami.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ScoutSuite/providers/aws/resources/ec2/ami.py b/ScoutSuite/providers/aws/resources/ec2/ami.py index ca30e6a83..ffa75a8cb 100755 --- a/ScoutSuite/providers/aws/resources/ec2/ami.py +++ b/ScoutSuite/providers/aws/resources/ec2/ami.py @@ -16,7 +16,5 @@ async def fetch_all(self): def _parse_image(self, raw_image): raw_image['id'] = raw_image['ImageId'] raw_image['name'] = raw_image['Name'] - if 'Tags' in raw_image: - raw_image['tags'] = {x["Key"]: x["Value"] for x in raw_image["Tags"]} return raw_image['id'], raw_image From c654959310481a827187efb9b79f1a7823f05263 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Wed, 3 Jun 2020 11:19:12 -0500 Subject: [PATCH 063/312] revert tag mapping --- ScoutSuite/providers/aws/resources/ec2/snapshots.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ScoutSuite/providers/aws/resources/ec2/snapshots.py b/ScoutSuite/providers/aws/resources/ec2/snapshots.py index 3ee74219d..cbeb4ee44 100755 --- a/ScoutSuite/providers/aws/resources/ec2/snapshots.py +++ b/ScoutSuite/providers/aws/resources/ec2/snapshots.py @@ -18,8 +18,6 @@ def _parse_snapshot(self, raw_snapshot): raw_snapshot['id'] = raw_snapshot.pop('SnapshotId') raw_snapshot['name'] = get_name(raw_snapshot, raw_snapshot, 'id') raw_snapshot['public'] = self._is_public(raw_snapshot) - if "Tags" in raw_snapshot: - raw_snapshot['tags'] = {x["Key"]: x["Value"] for x in raw_snapshot["Tags"]} return raw_snapshot['id'], raw_snapshot @staticmethod From edd859864dd2bc120d02f29a04933122e21f97ed Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Wed, 3 Jun 2020 11:19:30 -0500 Subject: [PATCH 064/312] revert tag addition --- ScoutSuite/providers/aws/resources/ec2/volumes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ScoutSuite/providers/aws/resources/ec2/volumes.py b/ScoutSuite/providers/aws/resources/ec2/volumes.py index 5809cb502..2382b7b83 100755 --- a/ScoutSuite/providers/aws/resources/ec2/volumes.py +++ b/ScoutSuite/providers/aws/resources/ec2/volumes.py @@ -17,6 +17,4 @@ async def fetch_all(self): def _parse_volume(self, raw_volume): raw_volume['id'] = raw_volume.pop('VolumeId') raw_volume['name'] = get_name(raw_volume, raw_volume, 'id') - if "Tags" in raw_volume: - raw_volume['tags'] = {x["Key"]: x["Value"] for x in raw_volume["Tags"]} return raw_volume['id'], raw_volume From c69f2d02fc27b43c72417a77ab7590940ed420c1 Mon Sep 17 00:00:00 2001 From: Nick Klauer Date: Thu, 4 Jun 2020 10:23:01 -0500 Subject: [PATCH 065/312] fix: tests --- ScoutSuite/providers/aws/utils.py | 7 ++++++- tests/test-utils.py | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/providers/aws/utils.py b/ScoutSuite/providers/aws/utils.py index 06709240b..b7c41d919 100755 --- a/ScoutSuite/providers/aws/utils.py +++ b/ScoutSuite/providers/aws/utils.py @@ -101,7 +101,12 @@ def snake_keys(d): if isinstance(d[k], dict): new_table[new_key] = snake_keys(d[k]) elif isinstance(d[k], list): - new_ary = [snake_keys(v) for v in d[k]] + new_ary = [] + for v in d[k]: + if isinstance(v, dict): + new_ary.append(snake_keys(v)) + else: + new_ary.append(v) new_table[new_key] = new_ary else: new_table[new_key] = d[k] diff --git a/tests/test-utils.py b/tests/test-utils.py index f239d26ff..99700e654 100755 --- a/tests/test-utils.py +++ b/tests/test-utils.py @@ -103,8 +103,8 @@ def test_snake_case(self): "TableSizeBytes": 123, "AnotherArray": [ "One", - "Two" - "AnotherThing" + "Two", + "AnotherThing", ] } dest = { From c8c9486660f7470663364ab1418fc2ab42ded4c4 Mon Sep 17 00:00:00 2001 From: "Alessandro.Gonzalez" Date: Fri, 5 Jun 2020 10:54:14 +0100 Subject: [PATCH 066/312] Added env variables to aws lambda information --- .../aws/services.awslambda.regions.id.functions.html | 5 +++++ ScoutSuite/providers/aws/facade/awslambda.py | 9 +++++++++ .../providers/aws/resources/awslambda/functions.py | 12 ++++++++++++ 3 files changed, 26 insertions(+) diff --git a/ScoutSuite/output/data/html/partials/aws/services.awslambda.regions.id.functions.html b/ScoutSuite/output/data/html/partials/aws/services.awslambda.regions.id.functions.html index 4fe3b8b43..b9321b168 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.awslambda.regions.id.functions.html +++ b/ScoutSuite/output/data/html/partials/aws/services.awslambda.regions.id.functions.html @@ -21,6 +21,11 @@

      Information

      {{> accordion_policy name = 'Resource-Based Policy' policy_path = (concat 'awslambda.regions' region 'functions' @key 'access_policy') document = access_policy}}
    {{/if}} + {{#if env_variables}} +
    + {{> accordion_policy name = 'Environment Variables' policy_path = (concat 'awslambda.regions' region 'functions' @key 'env_variables') document = env_variables}} +
    + {{/if}} diff --git a/ScoutSuite/providers/azure/resources/appservice/web_apps.py b/ScoutSuite/providers/azure/resources/appservice/web_apps.py index b1ee7691d..c560dfc58 100755 --- a/ScoutSuite/providers/azure/resources/appservice/web_apps.py +++ b/ScoutSuite/providers/azure/resources/appservice/web_apps.py @@ -22,7 +22,10 @@ def _parse_web_app(self, raw_web_app): web_app_dict['kind'] = raw_web_app.kind web_app_dict['location'] = raw_web_app.location web_app_dict['type'] = raw_web_app.type - web_app_dict['tags'] = raw_web_app.tags + if raw_web_app.tags is not None: + web_app_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_web_app.tags.items()] + else: + web_app_dict['tags'] = [] web_app_dict['state'] = raw_web_app.state web_app_dict['host_names'] = raw_web_app.host_names web_app_dict['repository_site_name'] = raw_web_app.repository_site_name diff --git a/ScoutSuite/providers/azure/resources/keyvault/vaults.py b/ScoutSuite/providers/azure/resources/keyvault/vaults.py index 1db639b54..b978f4187 100755 --- a/ScoutSuite/providers/azure/resources/keyvault/vaults.py +++ b/ScoutSuite/providers/azure/resources/keyvault/vaults.py @@ -21,7 +21,10 @@ def _parse_key_vault(self, raw_vault): vault['type'] = raw_vault.type vault['location'] = raw_vault.location vault['additional_properties'] = raw_vault.additional_properties - vault['tags'] = raw_vault.tags + if raw_vault.tags is not None: + vault['tags'] = ["{}:{}".format(key, value) for key, value in raw_vault.tags.items()] + else: + vault['tags'] = [] vault['properties'] = raw_vault.properties vault['public_access_allowed'] = self._is_public_access_allowed(raw_vault) return vault['id'], vault diff --git a/ScoutSuite/providers/azure/resources/network/application_security_groups.py b/ScoutSuite/providers/azure/resources/network/application_security_groups.py index e5d325d75..dbbfcb5bb 100755 --- a/ScoutSuite/providers/azure/resources/network/application_security_groups.py +++ b/ScoutSuite/providers/azure/resources/network/application_security_groups.py @@ -20,7 +20,10 @@ def _parse_application_security_group(self, raw_application_security_group): application_security_group_dict['name'] = raw_application_security_group.name application_security_group_dict['type'] = raw_application_security_group.type application_security_group_dict['location'] = raw_application_security_group.location - application_security_group_dict['tags'] = raw_application_security_group.tags + if raw_application_security_group.tags is not None: + application_security_group_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_application_security_group.tags.items()] + else: + application_security_group_dict['tags'] = [] application_security_group_dict['resource_guid'] = raw_application_security_group.resource_guid application_security_group_dict['provisioning_state'] = raw_application_security_group.provisioning_state application_security_group_dict['etag'] = raw_application_security_group.etag diff --git a/ScoutSuite/providers/azure/resources/network/network_interfaces.py b/ScoutSuite/providers/azure/resources/network/network_interfaces.py index 4858161dc..562ad0b98 100755 --- a/ScoutSuite/providers/azure/resources/network/network_interfaces.py +++ b/ScoutSuite/providers/azure/resources/network/network_interfaces.py @@ -22,7 +22,10 @@ def _parse_network_interface(self, raw_network_interface): get_non_provider_id(raw_network_interface.virtual_machine.id.lower()) if \ raw_network_interface.virtual_machine else None network_interface_dict['name'] = raw_network_interface.name - network_interface_dict['tags'] = raw_network_interface.tags + if raw_network_interface.tags is not None: + network_interface_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_network_interface.tags.items()] + else: + network_interface_dict['tags'] = [] network_interface_dict['interface_endpoint'] = raw_network_interface.interface_endpoint if \ hasattr(raw_network_interface, 'interface_endpoint') else None network_interface_dict['primary'] = raw_network_interface.primary diff --git a/ScoutSuite/providers/azure/resources/network/security_groups.py b/ScoutSuite/providers/azure/resources/network/security_groups.py index dc543cf1f..da868f1dd 100755 --- a/ScoutSuite/providers/azure/resources/network/security_groups.py +++ b/ScoutSuite/providers/azure/resources/network/security_groups.py @@ -23,7 +23,10 @@ def _parse_network_security_group(self, network_security_group): network_security_group_dict['resource_guid'] = network_security_group.resource_guid network_security_group_dict['type'] = network_security_group.type network_security_group_dict['etag'] = network_security_group.etag - network_security_group_dict['tags'] = network_security_group.tags + if network_security_group.tags is not None: + network_security_group_dict['tags'] = ["{}:{}".format(key, value) for key, value in network_security_group.tags.items()] + else: + network_security_group_dict['tags'] = [] network_security_group_dict['additional_properties'] = network_security_group.additional_properties network_security_group_dict['security_rules'] = self._parse_security_rules(network_security_group) diff --git a/ScoutSuite/providers/azure/resources/network/virtual_networks.py b/ScoutSuite/providers/azure/resources/network/virtual_networks.py index ede523786..2b58c2eee 100755 --- a/ScoutSuite/providers/azure/resources/network/virtual_networks.py +++ b/ScoutSuite/providers/azure/resources/network/virtual_networks.py @@ -21,7 +21,10 @@ def _parse_virtual_network(self, raw_virtual_network): virtual_network_dict['enable_vm_protection'] = raw_virtual_network.enable_vm_protection virtual_network_dict['etag'] = str(raw_virtual_network.etag) - virtual_network_dict['tags'] = raw_virtual_network.tags + if raw_virtual_network.tags is not None: + virtual_network_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_virtual_network.tags.items()] + else: + virtual_network_dict['tags'] = [] virtual_network_dict['virtual_network_peerings'] = raw_virtual_network.virtual_network_peerings virtual_network_dict['enable_ddos_protection'] = raw_virtual_network.enable_ddos_protection virtual_network_dict['resource_guid'] = raw_virtual_network.resource_guid diff --git a/ScoutSuite/providers/azure/resources/network/watchers.py b/ScoutSuite/providers/azure/resources/network/watchers.py index 3a0c88dcb..cde095a73 100755 --- a/ScoutSuite/providers/azure/resources/network/watchers.py +++ b/ScoutSuite/providers/azure/resources/network/watchers.py @@ -20,7 +20,10 @@ def _parse_network_watcher(self, raw_watcher): watcher_dict['name'] = raw_watcher.name watcher_dict['type'] = raw_watcher.type watcher_dict['location'] = raw_watcher.location - watcher_dict['tags'] = raw_watcher.tags + if raw_watcher.tags is not None: + watcher_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_watcher.tags.items()] + else: + watcher_dict['tags'] = [] watcher_dict['etag'] = raw_watcher.etag watcher_dict['additional_properties'] = raw_watcher.additional_properties watcher_dict['provisioning_state'] = raw_watcher.provisioning_state From 06d282fb93914bcd198028227949f720062f4a7f Mon Sep 17 00:00:00 2001 From: Viatcheslav Zhilin Date: Thu, 11 Jun 2020 18:24:34 +0200 Subject: [PATCH 106/312] Fixed bug when empty/no tags + resource group name processing and partial view for: - Appservice: web_apps - Keyvault: vaults - Network: application_security_groups, network_interfaces, security_groups, virtual_networks, watchers - SQLdatabase: servers, databases - Storageaccounts: storage_accounts - Virtualmachines: instances Useful reference: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/move-support-resources --- ....appservice.subscriptions.id.web_apps.html | 21 +++++----- ...ices.keyvault.subscriptions.id.vaults.html | 7 ++-- ...ptions.id.application_security_groups.html | 15 +++---- ...k.subscriptions.id.network_interfaces.html | 1 + ...work.subscriptions.id.security_groups.html | 15 +++---- ...ork.subscriptions.id.virtual_networks.html | 1 + ...ces.network.subscriptions.id.watchers.html | 1 + ....sqldatabase.subscriptions.id.servers.html | 42 ++++++++++--------- ...nts.subscriptions.id.storage_accounts.html | 1 + ...almachines.subscriptions.id.instances.html | 9 ++-- .../azure/resources/appservice/web_apps.py | 2 + .../azure/resources/keyvault/vaults.py | 2 + .../network/application_security_groups.py | 2 + .../resources/network/network_interfaces.py | 2 + .../resources/network/security_groups.py | 2 + .../resources/network/virtual_networks.py | 2 + .../azure/resources/network/watchers.py | 2 + .../azure/resources/sqldatabase/databases.py | 4 +- .../azure/resources/sqldatabase/servers.py | 5 ++- .../storageaccounts/storage_accounts.py | 5 ++- .../resources/virtualmachines/instances.py | 7 +++- 21 files changed, 93 insertions(+), 55 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/azure/services.appservice.subscriptions.id.web_apps.html b/ScoutSuite/output/data/html/partials/azure/services.appservice.subscriptions.id.web_apps.html index 4507e6ba5..a16ec749b 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.appservice.subscriptions.id.web_apps.html +++ b/ScoutSuite/output/data/html/partials/azure/services.appservice.subscriptions.id.web_apps.html @@ -6,16 +6,6 @@

    {{name}}

    Information

    Name: {{value_or_none name}}
    -
    Tags: - {{#each tags}} -
    - {{value_or_none this}} -
       - {{else}} -
    None
    - {{/each}} -
    Location: {{value_or_none location}}
    State: {{value_or_none state}}
    Usage State: {{value_or_none usage_state}}
    @@ -37,6 +27,17 @@

    Information

    Traffic Manager Host Names: {{value_or_none traffic_manager_host_names}}
    Programming Language: {{value_or_none programming_language}}
    Programming Language Version: {{value_or_none programming_language_version}}
    +
    Tags: + {{#each tags}} +
    + {{value_or_none this}} +
       + {{else}} +
    None
    + {{/each}} +
    +
    Resource group: {{value_or_none resource_group_name}}

    Identities

    diff --git a/ScoutSuite/output/data/html/partials/azure/services.keyvault.subscriptions.id.vaults.html b/ScoutSuite/output/data/html/partials/azure/services.keyvault.subscriptions.id.vaults.html index 014553492..033cdf5fc 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.keyvault.subscriptions.id.vaults.html +++ b/ScoutSuite/output/data/html/partials/azure/services.keyvault.subscriptions.id.vaults.html @@ -6,7 +6,9 @@

    {{name}}

    Information

    ID: {{ id }}
    -
    Tags: +
    Location: {{value_or_none location}}
    +
    Public Access: {{ convert_bool_to_enabled public_access_allowed }}
    +
    Tags: {{#each tags}}
    @@ -16,8 +18,7 @@

    Information

    None
    {{/each}}
    -
    Location: {{value_or_none location}}
    -
    Public Access: {{ convert_bool_to_enabled public_access_allowed }}
    +
    Resource group: {{value_or_none resource_group_name}}
    diff --git a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.application_security_groups.html b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.application_security_groups.html index 5b89ae61e..51b501e3f 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.application_security_groups.html +++ b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.application_security_groups.html @@ -7,18 +7,19 @@

    {{name}}

    Information

    Name: {{value_or_none name}}
    -
    Tags: +
    Location: {{value_or_none location}}
    +
    Provisioning State: {{value_or_none provisioning_state}}
    +
    Tags: {{#each tags}} -
    - {{value_or_none this}} -
       +
    + {{value_or_none this}} +
       {{else}}
    None
    {{/each}}
    -
    Location: {{value_or_none location}}
    -
    Provisioning State: {{value_or_none provisioning_state}}
    +
    Resource group: {{value_or_none resource_group_name}}

    Attached Network Interfaces

    diff --git a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.network_interfaces.html b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.network_interfaces.html index 1fd3c7962..c57860f7a 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.network_interfaces.html +++ b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.network_interfaces.html @@ -28,6 +28,7 @@

    Information

    None
    {{/each}}
    +
    Resource group: {{value_or_none resource_group_name}}

    IP Configuration

    diff --git a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.security_groups.html b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.security_groups.html index 8fe072879..9dcb5794c 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.security_groups.html +++ b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.security_groups.html @@ -7,18 +7,19 @@

    {{name}}

    Information

    Name: {{name}}
    -
    Tags: +
    Location: {{ location }}
    +
    State: {{ provisioning_state }}
    +
    Tags: {{#each tags}} -
    - {{value_or_none this}} -
       +
    + {{value_or_none this}} +
       {{else}}
    None
    {{/each}}
    -
    Location: {{ location }}
    -
    State: {{ provisioning_state }}
    +
    Resource group: {{value_or_none resource_group_name}}
    {{!--
    Exposed Ports: diff --git a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.virtual_networks.html b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.virtual_networks.html index 6f329441f..0f9c23f47 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.virtual_networks.html +++ b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.virtual_networks.html @@ -27,6 +27,7 @@

    Information

    None
    {{/each}}
    +
    Resource group: {{value_or_none resource_group_name}}

    Subnets

    diff --git a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.watchers.html b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.watchers.html index a5bde1a3d..b15e1f821 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.watchers.html +++ b/ScoutSuite/output/data/html/partials/azure/services.network.subscriptions.id.watchers.html @@ -19,6 +19,7 @@

    Information

    None
    {{/each}}
    +
    Resource group: {{value_or_none resource_group_name}}
    diff --git a/ScoutSuite/output/data/html/partials/azure/services.sqldatabase.subscriptions.id.servers.html b/ScoutSuite/output/data/html/partials/azure/services.sqldatabase.subscriptions.id.servers.html index 92058d2c1..e06b2d54a 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.sqldatabase.subscriptions.id.servers.html +++ b/ScoutSuite/output/data/html/partials/azure/services.sqldatabase.subscriptions.id.servers.html @@ -7,16 +7,6 @@

    {{name}}

    Information

    SQL Server Name: {{name}}
    -
    Tags: - {{#each tags}} -
    - {{value_or_none this}} -
       - {{else}} -
    None
    - {{/each}} -
    -
    Azure Active Directory Admin: {{value_or_none ad_admin.login}}
    Auditing: {{ convert_bool_to_enabled auditing.auditing_enabled }}
    Auditing retention period: {{ auditing.retention_days }}
    @@ -24,6 +14,17 @@

    Information

    Threat detection alerts: {{ convert_bool_to_enabled threat_detection.alerts_enabled }}
    Send threat detection alerts: {{ convert_bool_to_enabled threat_detection.send_alerts_enabled }}
    Threat detection retention period: {{ threat_detection.retention_days }}
    +
    Tags: + {{#each tags}} +
    + {{value_or_none this}} +
       + {{else}} +
    None
    + {{/each}} +
    +
    Resource group: {{value_or_none resource_group_name}}
    @@ -32,16 +33,6 @@

    SQL Databases

    {{#each databases}}
    Database name: {{@key}}
    -
    Tags: - {{#each tags}} -
    - {{value_or_none this}} -
       - {{else}} -
    None
    - {{/each}} -
    Auditing: {{ convert_bool_to_enabled auditing.auditing_enabled }}
    Auditing retention period: {{ auditing.retention_days }}
    @@ -51,6 +42,17 @@

    SQL Databases

    Threat detection retention period: {{ threat_detection.retention_days }}
    Transparent data encryption: {{ convert_bool_to_enabled transparent_data_encryption_enabled }}
    Geo-replication configured: {{ replication_configured }}
    +
    Tags: + {{#each tags}} +
    + {{value_or_none this}} +
       + {{else}} +
    None
    + {{/each}} +
    +
    Resource group: {{value_or_none resource_group_name}}
    {{/each}} diff --git a/ScoutSuite/output/data/html/partials/azure/services.storageaccounts.subscriptions.id.storage_accounts.html b/ScoutSuite/output/data/html/partials/azure/services.storageaccounts.subscriptions.id.storage_accounts.html index 4fcb49635..f55f937c1 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.storageaccounts.subscriptions.id.storage_accounts.html +++ b/ScoutSuite/output/data/html/partials/azure/services.storageaccounts.subscriptions.id.storage_accounts.html @@ -28,6 +28,7 @@

    Information

    None
    {{/each}}
    +
    Resource group: {{value_or_none resource_group_name}}
    diff --git a/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.instances.html b/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.instances.html index 9d7865b67..55eda81a0 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.instances.html +++ b/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.instances.html @@ -15,18 +15,19 @@

    Information

    Zones: {{value_or_none zones}}
    Instance View: {{value_or_none instance_view}}
    Proximity Placement Group: {{value_or_none proximity_placement_group}}
    -
    Tags: +
    Availability Set: {{value_or_none availability_set}}
    +
    Additional Capabilities: {{value_or_none additional_capabilities}}
    +
    Tags: {{#each tags}}
    {{value_or_none this}}
       {{else}} -
    None
    +
    None
    {{/each}}
    -
    Availability Set: {{value_or_none availability_set}}
    -
    Additional Capabilities: {{value_or_none additional_capabilities}}
    +
    Resource group: {{value_or_none resource_group_name}}

    Network Interfaces

    diff --git a/ScoutSuite/providers/azure/resources/appservice/web_apps.py b/ScoutSuite/providers/azure/resources/appservice/web_apps.py index c560dfc58..56c3ca88d 100755 --- a/ScoutSuite/providers/azure/resources/appservice/web_apps.py +++ b/ScoutSuite/providers/azure/resources/appservice/web_apps.py @@ -1,6 +1,7 @@ from ScoutSuite.providers.azure.facade.base import AzureFacade from ScoutSuite.providers.azure.resources.base import AzureResources from ScoutSuite.providers.utils import get_non_provider_id +from ScoutSuite.providers.azure.utils import get_resource_group_name class WebApplication(AzureResources): @@ -26,6 +27,7 @@ def _parse_web_app(self, raw_web_app): web_app_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_web_app.tags.items()] else: web_app_dict['tags'] = [] + web_app_dict['resource_group_name'] = get_resource_group_name(raw_web_app.id) web_app_dict['state'] = raw_web_app.state web_app_dict['host_names'] = raw_web_app.host_names web_app_dict['repository_site_name'] = raw_web_app.repository_site_name diff --git a/ScoutSuite/providers/azure/resources/keyvault/vaults.py b/ScoutSuite/providers/azure/resources/keyvault/vaults.py index b978f4187..7102f522e 100755 --- a/ScoutSuite/providers/azure/resources/keyvault/vaults.py +++ b/ScoutSuite/providers/azure/resources/keyvault/vaults.py @@ -1,6 +1,7 @@ from ScoutSuite.providers.azure.facade.base import AzureFacade from ScoutSuite.providers.azure.resources.base import AzureResources from ScoutSuite.providers.utils import get_non_provider_id +from ScoutSuite.providers.azure.utils import get_resource_group_name class Vaults(AzureResources): @@ -25,6 +26,7 @@ def _parse_key_vault(self, raw_vault): vault['tags'] = ["{}:{}".format(key, value) for key, value in raw_vault.tags.items()] else: vault['tags'] = [] + vault['resource_group_name'] = get_resource_group_name(raw_vault.id) vault['properties'] = raw_vault.properties vault['public_access_allowed'] = self._is_public_access_allowed(raw_vault) return vault['id'], vault diff --git a/ScoutSuite/providers/azure/resources/network/application_security_groups.py b/ScoutSuite/providers/azure/resources/network/application_security_groups.py index dbbfcb5bb..90cd25acd 100755 --- a/ScoutSuite/providers/azure/resources/network/application_security_groups.py +++ b/ScoutSuite/providers/azure/resources/network/application_security_groups.py @@ -1,6 +1,7 @@ from ScoutSuite.providers.azure.facade.base import AzureFacade from ScoutSuite.providers.azure.resources.base import AzureResources from ScoutSuite.providers.utils import get_non_provider_id +from ScoutSuite.providers.azure.utils import get_resource_group_name class ApplicationSecurityGroups(AzureResources): @@ -24,6 +25,7 @@ def _parse_application_security_group(self, raw_application_security_group): application_security_group_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_application_security_group.tags.items()] else: application_security_group_dict['tags'] = [] + application_security_group_dict['resource_group_name'] = get_resource_group_name(raw_application_security_group.id) application_security_group_dict['resource_guid'] = raw_application_security_group.resource_guid application_security_group_dict['provisioning_state'] = raw_application_security_group.provisioning_state application_security_group_dict['etag'] = raw_application_security_group.etag diff --git a/ScoutSuite/providers/azure/resources/network/network_interfaces.py b/ScoutSuite/providers/azure/resources/network/network_interfaces.py index 562ad0b98..f79f698d4 100755 --- a/ScoutSuite/providers/azure/resources/network/network_interfaces.py +++ b/ScoutSuite/providers/azure/resources/network/network_interfaces.py @@ -1,6 +1,7 @@ from ScoutSuite.providers.azure.facade.base import AzureFacade from ScoutSuite.providers.azure.resources.base import AzureResources from ScoutSuite.providers.utils import get_non_provider_id +from ScoutSuite.providers.azure.utils import get_resource_group_name class NetworkInterfaces(AzureResources): @@ -26,6 +27,7 @@ def _parse_network_interface(self, raw_network_interface): network_interface_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_network_interface.tags.items()] else: network_interface_dict['tags'] = [] + network_interface_dict['resource_group_name'] = get_resource_group_name(raw_network_interface.id) network_interface_dict['interface_endpoint'] = raw_network_interface.interface_endpoint if \ hasattr(raw_network_interface, 'interface_endpoint') else None network_interface_dict['primary'] = raw_network_interface.primary diff --git a/ScoutSuite/providers/azure/resources/network/security_groups.py b/ScoutSuite/providers/azure/resources/network/security_groups.py index da868f1dd..75222a9f3 100755 --- a/ScoutSuite/providers/azure/resources/network/security_groups.py +++ b/ScoutSuite/providers/azure/resources/network/security_groups.py @@ -1,6 +1,7 @@ from ScoutSuite.providers.azure.facade.base import AzureFacade from ScoutSuite.providers.azure.resources.base import AzureResources from ScoutSuite.providers.utils import get_non_provider_id +from ScoutSuite.providers.azure.utils import get_resource_group_name class SecurityGroups(AzureResources): @@ -27,6 +28,7 @@ def _parse_network_security_group(self, network_security_group): network_security_group_dict['tags'] = ["{}:{}".format(key, value) for key, value in network_security_group.tags.items()] else: network_security_group_dict['tags'] = [] + network_security_group_dict['resource_group_name'] = get_resource_group_name(network_security_group.id) network_security_group_dict['additional_properties'] = network_security_group.additional_properties network_security_group_dict['security_rules'] = self._parse_security_rules(network_security_group) diff --git a/ScoutSuite/providers/azure/resources/network/virtual_networks.py b/ScoutSuite/providers/azure/resources/network/virtual_networks.py index 2b58c2eee..57e10fd94 100755 --- a/ScoutSuite/providers/azure/resources/network/virtual_networks.py +++ b/ScoutSuite/providers/azure/resources/network/virtual_networks.py @@ -1,6 +1,7 @@ from ScoutSuite.providers.azure.facade.base import AzureFacade from ScoutSuite.providers.azure.resources.base import AzureResources from ScoutSuite.providers.utils import get_non_provider_id +from ScoutSuite.providers.azure.utils import get_resource_group_name class VirtualNetworks(AzureResources): @@ -25,6 +26,7 @@ def _parse_virtual_network(self, raw_virtual_network): virtual_network_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_virtual_network.tags.items()] else: virtual_network_dict['tags'] = [] + virtual_network_dict['resource_group_name'] = get_resource_group_name(raw_virtual_network.id) virtual_network_dict['virtual_network_peerings'] = raw_virtual_network.virtual_network_peerings virtual_network_dict['enable_ddos_protection'] = raw_virtual_network.enable_ddos_protection virtual_network_dict['resource_guid'] = raw_virtual_network.resource_guid diff --git a/ScoutSuite/providers/azure/resources/network/watchers.py b/ScoutSuite/providers/azure/resources/network/watchers.py index cde095a73..b43cac14f 100755 --- a/ScoutSuite/providers/azure/resources/network/watchers.py +++ b/ScoutSuite/providers/azure/resources/network/watchers.py @@ -1,6 +1,7 @@ from ScoutSuite.providers.azure.facade.base import AzureFacade from ScoutSuite.providers.azure.resources.base import AzureResources from ScoutSuite.providers.utils import get_non_provider_id +from ScoutSuite.providers.azure.utils import get_resource_group_name class Watchers(AzureResources): @@ -24,6 +25,7 @@ def _parse_network_watcher(self, raw_watcher): watcher_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_watcher.tags.items()] else: watcher_dict['tags'] = [] + watcher_dict['resource_group_name'] = get_resource_group_name(raw_watcher.id) watcher_dict['etag'] = raw_watcher.etag watcher_dict['additional_properties'] = raw_watcher.additional_properties watcher_dict['provisioning_state'] = raw_watcher.provisioning_state diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/databases.py b/ScoutSuite/providers/azure/resources/sqldatabase/databases.py index ea29d33cc..95f3269a6 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/databases.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/databases.py @@ -1,5 +1,6 @@ from ScoutSuite.providers.azure.facade.base import AzureFacade from ScoutSuite.providers.azure.resources.base import AzureCompositeResources +from ScoutSuite.providers.azure.utils import get_resource_group_name from .database_blob_auditing_policies import DatabaseBlobAuditingPolicies from .database_threat_detection_policies import DatabaseThreatDetectionPolicies @@ -31,7 +32,8 @@ async def fetch_all(self): self[db.name] = { 'id': db.name, 'name': db.name, - 'tags': ["{}:{}".format(key, value) for key, value in db.tags.items()] + 'tags': ["{}:{}".format(key, value) for key, value in db.tags.items()] if db.tags is not None else [], + 'resource_group_name': get_resource_group_name(db.id) } await self._fetch_children_of_all_resources( diff --git a/ScoutSuite/providers/azure/resources/sqldatabase/servers.py b/ScoutSuite/providers/azure/resources/sqldatabase/servers.py index f6399cc3c..712161829 100755 --- a/ScoutSuite/providers/azure/resources/sqldatabase/servers.py +++ b/ScoutSuite/providers/azure/resources/sqldatabase/servers.py @@ -39,5 +39,8 @@ def _parse_server(self, raw_server): server['id'] = get_non_provider_id(raw_server.id) server['name'] = raw_server.name server['resource_group_name'] = get_resource_group_name(raw_server.id) - server['tags'] = ["{}:{}".format(key, value) for key, value in raw_server.tags.items()] + if raw_server.tags is not None: + server['tags'] = ["{}:{}".format(key, value) for key, value in raw_server.tags.items()] + else: + server['tags'] = [] return server['id'], server diff --git a/ScoutSuite/providers/azure/resources/storageaccounts/storage_accounts.py b/ScoutSuite/providers/azure/resources/storageaccounts/storage_accounts.py index a919ee2b3..06fac0024 100755 --- a/ScoutSuite/providers/azure/resources/storageaccounts/storage_accounts.py +++ b/ScoutSuite/providers/azure/resources/storageaccounts/storage_accounts.py @@ -41,7 +41,10 @@ def _parse_storage_account(self, raw_storage_account): storage_account['bypass'] = raw_storage_account.network_rule_set.bypass storage_account['access_keys_last_rotation_date'] = \ self._parse_access_keys_last_rotation_date(raw_storage_account.activity_logs) - storage_account['tags'] = ["{}:{}".format(key, value) for key, value in raw_storage_account.tags.items()] + if raw_storage_account.tags is not None: + storage_account['tags'] = ["{}:{}".format(key, value) for key, value in raw_storage_account.tags.items()] + else: + storage_account['tags'] = [] return storage_account['id'], storage_account diff --git a/ScoutSuite/providers/azure/resources/virtualmachines/instances.py b/ScoutSuite/providers/azure/resources/virtualmachines/instances.py index 2e1759f35..3c699bd69 100755 --- a/ScoutSuite/providers/azure/resources/virtualmachines/instances.py +++ b/ScoutSuite/providers/azure/resources/virtualmachines/instances.py @@ -1,6 +1,7 @@ from ScoutSuite.providers.azure.facade.base import AzureFacade from ScoutSuite.providers.azure.resources.base import AzureResources from ScoutSuite.providers.utils import get_non_provider_id +from ScoutSuite.providers.azure.utils import get_resource_group_name class Instances(AzureResources): @@ -26,7 +27,11 @@ def _parse_instance(self, raw_instance): instance_dict['location'] = raw_instance.location instance_dict['type'] = raw_instance.type instance_dict['resources'] = raw_instance.resources - instance_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_instance.tags.items()] + if raw_instance.tags is not None: + instance_dict['tags'] = ["{}:{}".format(key, value) for key, value in raw_instance.tags.items()] + else: + instance_dict['tags'] = [] + instance_dict['resource_group_name'] = get_resource_group_name(raw_instance.id) instance_dict['provisioning_state'] = raw_instance.provisioning_state instance_dict['plan'] = raw_instance.plan instance_dict['identity'] = raw_instance.identity From 157b2f8031eb51f9a2c2e1e328a556fb46f01ef3 Mon Sep 17 00:00:00 2001 From: Viatcheslav Zhilin Date: Fri, 12 Jun 2020 14:06:10 +0200 Subject: [PATCH 107/312] Resolve conflicts --- ...c2.regions.id.vpcs.id.security_groups.html | 6 ----- ...ices.rds.regions.id.vpcs.id.instances.html | 22 ------------------- 2 files changed, 28 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html index 722824fd9..903ca2f17 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html +++ b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html @@ -6,14 +6,8 @@

    {{name}}

    Information

    -<<<<<<< HEAD -
    ID: {{id}}
    -
    ARN: {{arn}}
    -
    Region: {{region}}
    -=======
    ID: {{id}}
    Region: {{region}}
    ->>>>>>> develop
    VPC: {{getValueAt 'services.vpc.regions' region 'vpcs' vpc 'name'}} ({{vpc}})
    Description: {{description}}
    diff --git a/ScoutSuite/output/data/html/partials/aws/services.rds.regions.id.vpcs.id.instances.html b/ScoutSuite/output/data/html/partials/aws/services.rds.regions.id.vpcs.id.instances.html index dfb7651cc..b94d5945d 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.rds.regions.id.vpcs.id.instances.html +++ b/ScoutSuite/output/data/html/partials/aws/services.rds.regions.id.vpcs.id.instances.html @@ -5,27 +5,6 @@

    {{name}}

    -<<<<<<< HEAD -

    Information

    -
      -
    • ARN: {{arn}}
    • -
    • Region: {{region}}
    • -
    • Engine: {{Engine}}
    • -
    • Status: {{makeTitle DBInstanceStatus}}
    • -
    • Is read replica: {{is_read_replica}}
    • -
    • Auto Minor Version Upgrade: {{#if AutoMinorVersionUpgrade}} Enabled {{else}} Disabled {{/if}}
    • -
    • Multi Availability Zones: {{#if MultiAZ}} Enabled {{else}} Disabled {{/if}}
    • -
    • Instance Class: {{DBInstanceClass}}
    • -
    • Created on: {{InstanceCreateTime}}
    • -
    • Backup retention period in days: {{BackupRetentionPeriod}} -
    • Publicly accessible: {{PubliclyAccessible}} -
    • Enhanced Monitoring: - {{#if EnhancedMonitoringResourceArn}} Enabled {{else}} Disabled {{/if}} -
    • -
    • Encrypted Storage: {{StorageEncrypted}}
    • -
    • CA Certificate: {{CACertificateIdentifier}}
    • -
    -=======

    Information

    • Region: {{region}}
    • @@ -43,7 +22,6 @@

      Information

    • Encrypted Storage: {{convert_bool_to_enabled StorageEncrypted}}
    • CA Certificate: {{CACertificateIdentifier}}
    ->>>>>>> develop

    Network

    From 13a393a70532d0e8a60c4b0fa6244bf271520969 Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:14:22 +0200 Subject: [PATCH 108/312] Added samp tags --- .../services.ec2.regions.id.vpcs.id.security_groups.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html index 4bde9e2b1..96671b80d 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html +++ b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html @@ -6,9 +6,9 @@

    {{name}}

    Information

    -
    ID: {{id}}
    -
    ARN: {{arn}}
    -
    Region: {{region}}
    +
    ID: {{id}}
    +
    ARN: {{arn}}
    +
    Region: {{region}}
    VPC: {{getValueAt 'services.vpc.regions' region 'vpcs' vpc 'name'}} ({{vpc}})
    Description: {{description}}
    @@ -46,4 +46,4 @@

    Usage

    \ No newline at end of file + From e9264e0e66cedf4a9bb345017c0fda8bd993982f Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:15:25 +0200 Subject: [PATCH 109/312] Add samp tags --- .../aws/services.ec2.regions.id.vpcs.id.images.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.images.html b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.images.html index 7e90fc2f2..a57eadb16 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.images.html +++ b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.images.html @@ -7,8 +7,8 @@

    {{name}}

    Information

      -
    • ARN: {{arn}}
    • -
    • ID: {{id}}
    • +
    • ARN: {{arn}}
    • +
    • ID: {{id}}
    • Architecture: {{getValueAt 'services.ec2.regions' region 'images' id 'Architecture'}}
    • Public: {{getValueAt 'services.ec2.regions' region 'images' id 'Public'}}
    @@ -25,4 +25,4 @@

    Information

    \ No newline at end of file + From cfbb198a990e22e97577e9caf14118abebbffd72 Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:17:32 +0200 Subject: [PATCH 110/312] Add samp tags --- .../partials/aws/services.vpc.regions.id.vpcs.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.html b/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.html index f92d2eb0f..76525fd97 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.html +++ b/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.html @@ -6,12 +6,12 @@

    {{name}}

    Information

    -
    ID: {{@key}}
    -
    ARN: {{arn}}
    -
    Region: {{region}}
    -
    State: {{state}}
    -
    CIDR Block: {{cidr_block}}
    -
    Default: {{default}}
    +
    ID: {{@key}}
    +
    ARN: {{arn}}
    +
    Region: {{region}}
    +
    State: {{state}}
    +
    CIDR Block: {{cidr_block}}
    +
    Default: {{default}}
    From 7deab1d3ea18255dbbef57411af37f2ef7c9cb31 Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:18:03 +0200 Subject: [PATCH 111/312] Add samp tags --- .../html/partials/aws/services.ses.regions.id.identities.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.ses.regions.id.identities.html b/ScoutSuite/output/data/html/partials/aws/services.ses.regions.id.identities.html index f712f6fd2..293843d81 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.ses.regions.id.identities.html +++ b/ScoutSuite/output/data/html/partials/aws/services.ses.regions.id.identities.html @@ -6,7 +6,7 @@

    {{name}}

    Information

    -
    ARN: {{arn}}
    +
    ARN: {{arn}}

    DKIM Configuration

    From 9b7a1fa5aac26c71b29fd268a4de03390df3f39e Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:19:01 +0200 Subject: [PATCH 112/312] Add samp tags --- .../output/data/html/partials/aws/services.s3.buckets.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.s3.buckets.html b/ScoutSuite/output/data/html/partials/aws/services.s3.buckets.html index e583c1237..56537fa1d 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.s3.buckets.html +++ b/ScoutSuite/output/data/html/partials/aws/services.s3.buckets.html @@ -6,7 +6,7 @@

    {{name}}

    Information

    -
    ARN: {{arn}}
    +
    ARN: {{arn}}
    Region: {{region}}
    Creation date: {{CreationDate}}
    Logging: {{has_logging? logging}}
    From 5d3d34960c023270a50ef2594d2eb8d90226fb9b Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:19:32 +0200 Subject: [PATCH 113/312] Add samp tags --- .../aws/services.redshift.regions.id.vpcs.id.clusters.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.redshift.regions.id.vpcs.id.clusters.html b/ScoutSuite/output/data/html/partials/aws/services.redshift.regions.id.vpcs.id.clusters.html index 4e378753c..8a5d63bb7 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.redshift.regions.id.vpcs.id.clusters.html +++ b/ScoutSuite/output/data/html/partials/aws/services.redshift.regions.id.vpcs.id.clusters.html @@ -7,7 +7,7 @@

    {{name}}

    Information

      -
    • ARN: {{arn}}
    • +
    • ARN: {{arn}}
    • Node Type: {{NodeType}}
    • Allow Version Upgrade: {{AllowVersionUpgrade}}
    • Automated Snapshot Retention Period: {{AutomatedSnapshotRetentionPeriod}}
    • From 38fd26eb691bb9b509f6f0bd93fddd0bf4b42563 Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:19:58 +0200 Subject: [PATCH 114/312] Add samp tags --- .../aws/services.redshift.regions.id.parameter_groups.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.redshift.regions.id.parameter_groups.html b/ScoutSuite/output/data/html/partials/aws/services.redshift.regions.id.parameter_groups.html index 4e8d9bf19..7877e2455 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.redshift.regions.id.parameter_groups.html +++ b/ScoutSuite/output/data/html/partials/aws/services.redshift.regions.id.parameter_groups.html @@ -6,7 +6,7 @@

      {{name}}

    Information

    -
    ARN: {{arn}}
    +
    ARN: {{arn}}
    Description: {{description}}
    Group Family: {{family}}
    Default Parameter Group: {{is_default}}
    From 1ae5abe67b767ada9ec825bb40054b2667294ae3 Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:20:33 +0200 Subject: [PATCH 115/312] Add samp tags --- .../partials/aws/services.elbv2.regions.id.vpcs.id.elbs.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.elbs.html b/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.elbs.html index 4b8e07f46..cb977dfac 100644 --- a/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.elbs.html +++ b/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.elbs.html @@ -7,7 +7,7 @@

    {{name}}

    Information

      -
    • ARN: {{arn}}
    • +
    • ARN: {{arn}}
    • VPC: {{getValueAt 'services.elbv2.regions' region 'vpcs' vpc 'name'}} ({{vpc}})
    • DNS: {{DNSName}}
    • Scheme: {{Scheme}}
    • From f8f05293ebc18881bee3a28f3c14c9e6a421d06f Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:20:58 +0200 Subject: [PATCH 116/312] Add samp tags --- .../html/partials/aws/services.elb.regions.id.vpcs.id.elbs.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.html b/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.html index 8d336311a..872c854d6 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.html +++ b/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.html @@ -7,7 +7,7 @@

      {{name}}

      Information

        -
      • ARN: {{arn}}
      • +
      • ARN: {{arn}}
      • VPC: {{getValueAt 'services.elb.regions' region 'vpcs' vpc 'name'}} ({{vpc}})
      • DNS: {{DNSName}}
      • Scheme: {{Scheme}}
      • From c8a3ddab776623dae9031ea950c3e3753e358f79 Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:21:45 +0200 Subject: [PATCH 117/312] Add samp tags --- .../aws/services.cloudformation.regions.id.stacks.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.cloudformation.regions.id.stacks.html b/ScoutSuite/output/data/html/partials/aws/services.cloudformation.regions.id.stacks.html index 3c80d85a9..62571b6f0 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.cloudformation.regions.id.stacks.html +++ b/ScoutSuite/output/data/html/partials/aws/services.cloudformation.regions.id.stacks.html @@ -9,7 +9,7 @@

        Description

      Information

      -
      ARN: {{arn}}
      +
      ARN: {{arn}}
      Region: {{region}}
      Created on: {{CreationTime}}
      Role: @@ -52,4 +52,4 @@

      Capabilities {{> count_badge count=Capabilit \ No newline at end of file + From f7e8c6dc273b99402b9329eee147430763fec1ee Mon Sep 17 00:00:00 2001 From: lowSoA <66413174+lowSoA@users.noreply.github.com> Date: Fri, 12 Jun 2020 14:25:49 +0200 Subject: [PATCH 118/312] Add samp tags --- ...ervices.rds.regions.id.vpcs.id.instances.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.rds.regions.id.vpcs.id.instances.html b/ScoutSuite/output/data/html/partials/aws/services.rds.regions.id.vpcs.id.instances.html index 5155e3d94..6f77152aa 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.rds.regions.id.vpcs.id.instances.html +++ b/ScoutSuite/output/data/html/partials/aws/services.rds.regions.id.vpcs.id.instances.html @@ -7,22 +7,22 @@

      {{name}}

      Information

        -
      • ARN: {{arn}}
      • -
      • Region: {{region}}
      • -
      • Engine: {{Engine}}
      • -
      • Status: {{makeTitle DBInstanceStatus}}
      • -
      • Is read replica: {{is_read_replica}}
      • +
      • ARN: {{arn}}
      • +
      • Region: {{region}}
      • +
      • Engine: {{Engine}}
      • +
      • Created: {{format_date InstanceCreateTime}}
      • +
      • Status: {{makeTitle DBInstanceStatus}}
      • +
      • Is read replica: {{is_read_replica}}
      • Auto Minor Version Upgrade: {{#if AutoMinorVersionUpgrade}} Enabled {{else}} Disabled {{/if}}
      • Multi Availability Zones: {{#if MultiAZ}} Enabled {{else}} Disabled {{/if}}
      • -
      • Instance Class: {{DBInstanceClass}}
      • -
      • Created on: {{InstanceCreateTime}}
      • +
      • Instance Class: {{DBInstanceClass}}
      • Backup retention period in days: {{BackupRetentionPeriod}}
      • Publicly accessible: {{PubliclyAccessible}}
      • Enhanced Monitoring: {{#if EnhancedMonitoringResourceArn}} Enabled {{else}} Disabled {{/if}}
      • Encrypted Storage: {{StorageEncrypted}}
      • -
      • CA Certificate: {{CACertificateIdentifier}}
      • +
      • CA Certificate: {{CACertificateIdentifier}}
      From 32aa6ae00b37265c0b0bd56284d6c8941337bf21 Mon Sep 17 00:00:00 2001 From: Viatcheslav Zhilin Date: Fri, 12 Jun 2020 16:17:25 +0200 Subject: [PATCH 119/312] Fixed other references after renaming file from commit 03b62cec7682c4067977c123d362b49debaa8f95 --- .../aws/services.elbv2.regions.id.vpcs.id.elbs.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.elbs.html b/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.elbs.html index 4b8e07f46..ab883e2cc 100644 --- a/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.elbs.html +++ b/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.elbs.html @@ -1,6 +1,6 @@ - - From 4059b5828d0d06749eb727ddff4eb2f2f1869d48 Mon Sep 17 00:00:00 2001 From: Rami McCarthy Date: Sun, 21 Jun 2020 16:31:47 -0400 Subject: [PATCH 122/312] fix paths instance, subnets --- .../partials/aws/services.elb.regions.id.vpcs.id.elbs.html | 4 ++-- ...rvices.elb.regions.id.vpcs.id.elbs.linked_resources.html | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.html b/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.html index 3a368de35..20448e762 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.html +++ b/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.html @@ -57,8 +57,8 @@

      Security Groups

      Destination

        - {{> services.elb.regions.vpcs.elbs.linked_resources region = region vpc = vpc resources = instances resource_type = 'instances'}} - {{> services.elb.regions.vpcs.elbs.linked_resources region = region vpc = vpc resources = Subnets resource_type = 'subnets'}} + {{> services.elb.regions.vpcs.elbs.linked_resources service='ec2' region = region vpc = vpc resources = instances resource_type = 'instances'}} + {{> services.elb.regions.vpcs.elbs.linked_resources service='vpc' region = region vpc = vpc resources = Subnets resource_type = 'subnets'}}
      {{#if tags}} diff --git a/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.linked_resources.html b/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.linked_resources.html index fb0d63843..af60d8ace 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.linked_resources.html +++ b/ScoutSuite/output/data/html/partials/aws/services.elb.regions.id.vpcs.id.elbs.linked_resources.html @@ -4,13 +4,13 @@
      {{#if resources.length}}
      {{makeTitle resource_type}}: - {{> count_badge count=resources.length target=(concat '#services.elb.regions' region 'vpcs' vpc 'elbs' @key resource_type)}} + {{> count_badge count=resources.length target=(concat '#services' service 'regions' region 'vpcs' vpc 'elbs' @key resource_type)}}
      -
      +
      From b46666fea3e98f14ec1f93ba526b1349ca5b8d9a Mon Sep 17 00:00:00 2001 From: Todd Keech Date: Mon, 22 Jun 2020 19:27:44 -0400 Subject: [PATCH 123/312] Added unit tests for get_report_name and authenticate --- .travis.yml | 1 + tests/test-aws-provider.py | 103 +++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100755 tests/test-aws-provider.py diff --git a/.travis.yml b/.travis.yml index 1e72ec433..7ce1b8e94 100755 --- a/.travis.yml +++ b/.travis.yml @@ -45,6 +45,7 @@ script: - nosetests --with-coverage tests/test-resources.py - nosetests --with-coverage tests/test-rules-ruleset.py - nosetests --with-coverage tests/test-rules-processingengine.py + - nosetests --with-coverage tests/test-aws-provider.py - nosetests --with-coverage --nocapture tests/test-scoutsuite.py -a "!credential" # Update test coverage diff --git a/tests/test-aws-provider.py b/tests/test-aws-provider.py new file mode 100755 index 000000000..6513a8028 --- /dev/null +++ b/tests/test-aws-provider.py @@ -0,0 +1,103 @@ +from ScoutSuite.providers.aws.authentication_strategy import AWSCredentials +from ScoutSuite.providers.base.authentication_strategy import AuthenticationException +from ScoutSuite.providers.base.authentication_strategy_factory import ( + get_authentication_strategy, +) +from ScoutSuite.providers import get_provider +from ScoutSuite.providers.aws.provider import AWSProvider +import mock +import pytest + +# Test methods for AWS Provider +class TestAWSProviderClass: + @mock.patch("ScoutSuite.providers.aws.authentication_strategy.boto3") + @mock.patch("ScoutSuite.providers.aws.authentication_strategy.get_caller_identity") + def test_authenticate(self, mock_get_caller_identity, mock_Session): + auth_strat = get_authentication_strategy("aws") + + boto3_session = "_boto3_session_" + mock_Session.Session.return_value = boto3_session + + test_cases = [ + # no params + { + "profile": None, + "aws_access_key_id": None, + "aws_secret_access_key": None, + "aws_session_token": None, + "call_dict": {}, + }, + # profile + { + "profile": "123", + "aws_access_key_id": None, + "aws_secret_access_key": None, + "aws_session_token": None, + "call_dict": {"profile_name": "123"}, + }, + # access and secret key + { + "profile": None, + "aws_access_key_id": "456", + "aws_secret_access_key": "789", + "aws_session_token": None, + "call_dict": { + "aws_access_key_id": "456", + "aws_secret_access_key": "789", + }, + }, + # access, secret key and token + { + "profile": None, + "aws_access_key_id": "456", + "aws_secret_access_key": "789", + "aws_session_token": "101112", + "call_dict": { + "aws_access_key_id": "456", + "aws_secret_access_key": "789", + "aws_session_token": "101112", + }, + }, + ] + + for test_case in test_cases: + result = auth_strat.authenticate( + test_case["profile"], + test_case["aws_access_key_id"], + test_case["aws_secret_access_key"], + test_case["aws_session_token"], + ) + mock_Session.Session.assert_called_with(**test_case["call_dict"]) + mock_get_caller_identity.assert_called_with(boto3_session) + assert isinstance(result, AWSCredentials) + assert result.session == boto3_session + + # exception test + mock_Session.Session.side_effect = Exception("an exception") + with pytest.raises(AuthenticationException): + result = auth_strat.authenticate(None, None, None, None) + + # mock two separate places from which get_aws_account_id is called + @mock.patch("ScoutSuite.providers.aws.facade.base.get_aws_account_id") + @mock.patch("ScoutSuite.providers.aws.provider.get_aws_account_id") + def test_get_report_name(self, mock_get_aws_account_id, mock_facade_aws_account_id): + + # no account_id, no profile + mock_get_aws_account_id.return_value = None + aws_provider = get_provider( + provider="aws", credentials=mock.MagicMock(session="123"), + ) + assert aws_provider.get_report_name() == "aws" + + # profile and account_id + mock_get_aws_account_id.return_value = "12345" + aws_provider = get_provider( + provider="aws", profile="9999", credentials=mock.MagicMock(session="123"), + ) + assert aws_provider.get_report_name() == "aws-9999" + + # account_id + aws_provider = get_provider( + provider="aws", credentials=mock.MagicMock(session="123"), + ) + assert aws_provider.get_report_name() == "aws-12345" From 4b7c1d1b8fa4a5b79f339a1f1b3338e2495d5729 Mon Sep 17 00:00:00 2001 From: Todd Keech Date: Mon, 22 Jun 2020 20:25:10 -0400 Subject: [PATCH 124/312] Updated based on latest in develop branch --- tests/test-aws-provider.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test-aws-provider.py b/tests/test-aws-provider.py index 6513a8028..fcac98e8b 100755 --- a/tests/test-aws-provider.py +++ b/tests/test-aws-provider.py @@ -80,10 +80,17 @@ def test_authenticate(self, mock_get_caller_identity, mock_Session): # mock two separate places from which get_aws_account_id is called @mock.patch("ScoutSuite.providers.aws.facade.base.get_aws_account_id") @mock.patch("ScoutSuite.providers.aws.provider.get_aws_account_id") - def test_get_report_name(self, mock_get_aws_account_id, mock_facade_aws_account_id): + @mock.patch("ScoutSuite.providers.aws.provider.get_partition_name") + def test_get_report_name( + self, + mock_get_partiton_name, + mock_get_aws_account_id, + mock_facade_aws_account_id, + ): # no account_id, no profile mock_get_aws_account_id.return_value = None + mock_get_partiton_name.return_value = None aws_provider = get_provider( provider="aws", credentials=mock.MagicMock(session="123"), ) From 5c581e9ba7971ab53a37210c0f75e98ec8201248 Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 27 Jun 2020 12:55:20 +0200 Subject: [PATCH 125/312] Update version --- ScoutSuite/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/__init__.py b/ScoutSuite/__init__.py index 1044e6bd0..049f660e4 100755 --- a/ScoutSuite/__init__.py +++ b/ScoutSuite/__init__.py @@ -1,5 +1,5 @@ __author__ = 'NCC Group' -__version__ = '5.9.0' +__version__ = '5.10.0' ERRORS_LIST = [] From abe329449d62193230a824b6e8b7b47d6b97a3e9 Mon Sep 17 00:00:00 2001 From: Rami McCarthy Date: Sun, 28 Jun 2020 17:23:26 -0400 Subject: [PATCH 126/312] conditional SG inclusion --- .../aws/services.ec2.regions.id.vpcs.id.security_groups.html | 2 +- .../partials/aws/services.elbv2.regions.id.vpcs.id.lbs.html | 2 ++ ScoutSuite/providers/aws/resources/elbv2/load_balancers.py | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html index 903ca2f17..3b023e723 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html +++ b/ScoutSuite/output/data/html/partials/aws/services.ec2.regions.id.vpcs.id.security_groups.html @@ -45,4 +45,4 @@

      Usage

      \ No newline at end of file + diff --git a/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.lbs.html b/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.lbs.html index c13169c71..70af73a07 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.lbs.html +++ b/ScoutSuite/output/data/html/partials/aws/services.elbv2.regions.id.vpcs.id.lbs.html @@ -37,6 +37,7 @@

      Attributes

      {{/each}}

    + {{#unless isNetwork}}

    Security Groups @@ -53,6 +54,7 @@

    Security Groups

    + {{/unless}} {{#if tags}}

    Tags

    diff --git a/ScoutSuite/providers/aws/resources/elbv2/load_balancers.py b/ScoutSuite/providers/aws/resources/elbv2/load_balancers.py index f8cd80da7..adb140f5d 100755 --- a/ScoutSuite/providers/aws/resources/elbv2/load_balancers.py +++ b/ScoutSuite/providers/aws/resources/elbv2/load_balancers.py @@ -37,6 +37,7 @@ def _parse_load_balancer(self, load_balancer): load_balancer['name'] = load_balancer.pop('LoadBalancerName') load_balancer['security_groups'] = [] load_balancer['listener_protocols'] = [] + load_balancer['isNetwork'] = load_balancer["Type"] == "network" if 'SecurityGroups' in load_balancer: for sg in load_balancer['SecurityGroups']: From b5064fb76db493c5ba57c3e535800aee51db4fdf Mon Sep 17 00:00:00 2001 From: Juan Jose Date: Tue, 30 Jun 2020 11:07:59 +0200 Subject: [PATCH 127/312] Removed IAM test class (now we use Boto3) --- tests/test-services-iam.py | 232 ------------------------------------- 1 file changed, 232 deletions(-) delete mode 100644 tests/test-services-iam.py diff --git a/tests/test-services-iam.py b/tests/test-services-iam.py deleted file mode 100644 index 9c0cc302c..000000000 --- a/tests/test-services-iam.py +++ /dev/null @@ -1,232 +0,0 @@ -import binascii -import copy -import os -import sys -import time -import unittest -import ScoutSuite.providers.aws.authentication_strategy - -#from opinel.services.iam import * -#from opinel.utils.aws import connect_service -#from opinel.utils.console import configPrintException, printDebug -#from opinel.utils.credentials import read_creds, read_creds_from_environment_variables - - -class TestOpinelServicesIAM(unittest.TestCase): - - def setup(self): - creds = {'AccessKeyId': None, 'SecretAccessKey': None, 'SessionToken': None, - 'Expiration': None, 'SerialNumber': None, 'TokenCode': None}; - # Check environment variables - if 'AWS_ACCESS_KEY_ID' in os.environ and 'AWS_SECRET_ACCESS_KEY' in os.environ: - creds['AccessKeyId'] = os.environ['AWS_ACCESS_KEY_ID'] - creds['SecretAccessKey'] = os.environ['AWS_SECRET_ACCESS_KEY'] - if 'AWS_SESSION_TOKEN' in os.environ: - creds['SessionToken'] = os.environ['AWS_SESSION_TOKEN'] - - #if self.creds['AccessKeyId'] == None: - #self.creds = read_creds('travislike') - #self.api_client = connect_service('iam', self.creds) - #self.python = re.sub(r'\W+', '', sys.version) - self.cleanup = {'groups': [], 'users': []} - - - def make_travisname(self, testname): - return '%s-%s-%s' % (testname, binascii.b2a_hex(os.urandom(4)).decode('utf-8'), self.python) - - - def assert_group_create(self, groups_data, error_count, force_add = False): - for group_data in groups_data: - self.assert_create('groups', group_data, error_count, force_add) - - - def assert_user_create(self, user_data, error_count, force_add = False): - self.assert_create('users', user_data, error_count, force_add) - - - def assert_create(self, resource_type, resource_data, error_count, force_add = False): - assert len(resource_data['errors']) == error_count - nameattr = '%sname' % resource_type[:-1] - if force_add or error_count == 0: - #printDebug('Successfully created %s %s' % (resource_type[:-1], resource_data[nameattr])) - self.cleanup[resource_type].append(resource_data[nameattr]) - - - def test_create_user(self): - user_data = create_user(self.api_client, self.make_travisname('OpinelUnitTest001')) - self.assert_user_create(user_data, 0) - user_data = create_user(self.api_client, self.cleanup['users'][0]) - self.assert_user_create(user_data, 1) - user_data = create_user(self.api_client, self.make_travisname('OpinelUnitTest002'), 'BlockedUsers') - self.assert_user_create(user_data, 0) - user_data = create_user(self.api_client, self.make_travisname('OpinelUnitTest003'), ['BlockedUsers', 'AllUsers']) - self.assert_user_create(user_data, 1, True) - user_data = create_user(self.api_client, self.make_travisname('OpinelUnitTest004'), with_password = True) - self.assert_user_create(user_data, 0) - assert 'password' in user_data - assert len(user_data['password']) == 16 - user_data = create_user(self.api_client, self.make_travisname('OpinelUnitTest005'), with_password=True ,require_password_reset = True) - self.assert_user_create(user_data, 0) - assert 'password' in user_data - assert len(user_data['password']) == 16 - user_data = create_user(self.api_client, self.make_travisname('OpinelUnitTest006'), with_access_key = True) - self.assert_user_create(user_data, 0) - assert 'AccessKeyId' in user_data - assert user_data['AccessKeyId'].startswith('AKIA') - assert 'SecretAccessKey' in user_data - - - def test_delete_user(self): - # Mostly tested as part of teardown - try: - delete_user(self.api_client, 'PhonyUserWithMFA') - except Exception as e: - pass - pass - - - def test_add_user_to_group(self): - user010 = create_user(self.api_client, self.make_travisname('OpinelUnitTest010')) - self.assert_user_create(user010, 0) - user011 = create_user(self.api_client, self.make_travisname('OpinelUnitTest011')) - self.assert_user_create(user011, 0) - add_user_to_group(self.api_client, user010['username'], 'BlockedUsers', True) - add_user_to_group(self.api_client, user011['username'], 'BlockedUsers', False) - - - def test_delete_virtual_mfa_device(self): - try: - delete_virtual_mfa_device(self.api_client, 'arn:aws:iam::179374595322:mfa/PhonyUserWithMFA') - except Exception as e: - assert (e.response['Error']['Code'] == 'AccessDenied') - - - def test_get_access_keys(self): - user020 = create_user(self.api_client, self.make_travisname('OpinelUnitTest020'), with_access_key = True) - self.assert_user_create(user020, 0) - access_keys = get_access_keys(self.api_client, self.cleanup['users'][0]) - assert len(access_keys) == 1 - - - def test_show_access_keys(self): - user021 = create_user(self.api_client, self.make_travisname('OpinelUnitTest021'), with_access_key = True) - self.assert_user_create(user021, 0) - show_access_keys(self.api_client, self.cleanup['users'][0]) - - - def test_init_group_category_regex(self): - result = init_group_category_regex(['a', 'b'], ['', '.*hello.*']) - assert (type(result) == list) - result = init_group_category_regex(['a', 'b'], ['', '']) - assert (result == None) - result = init_group_category_regex(['a', 'b', 'c'], ['.*hello.*']) - assert (result == None) - - - def test_create_groups(self): - group001 = self.make_travisname('OpinelUnitTest001') - groups = create_groups(self.api_client, group001) - self.assert_group_create(groups, 0) - group002 = self.make_travisname('OpinelUnitTest002') - group003 = self.make_travisname('OpinelUnitTest003') - groups = create_groups(self.api_client, [ group002, group003 ]) - self.assert_group_create(groups, 0) - group004 = self.make_travisname('HelloWorld') - groups = create_groups(self.api_client, group004) - self.assert_group_create(groups, 1) - - - def teardown(self): - if len(self.cleanup['users']): - self.delete_resources('users') - if len(self.cleanup['groups']): - self.delete_resources('groups') - - - def delete_resources(self, resource_type): - resources = copy.deepcopy(self.cleanup[resource_type]) - while True: - unmodifiable_resource = False - remaining_resources = [] - printDebug('Deleting the following %s: %s' % (resource_type, str(resources)) ) - time.sleep(5) - for resource in resources: - if resource_type == 'groups': - errors = [] - try: - self.api_client.delete_group(GroupName = resource) - except: - errors = [ 'EntityTemporarilyUnmodifiable' ] - else: - method = globals()['delete_%s' % resource_type[:-1]] - errors = method(self.api_client, resource) - if len(errors): - printDebug('Errors when deleting %s' % resource) - remaining_resources.append(resource) - for handled_code in ['EntityTemporarilyUnmodifiable', 'DeleteConflict']: - if handled_code in errors: - unmodifiable_resource = True - else: - printError('Failed to delete %s %s' % (resource_type[:-1], resource)) - assert (False) - resources = copy.deepcopy(remaining_resources) - if not unmodifiable_resource: - break -def create_user(iam_client, user, groups = [], with_password= False, with_mfa = False, with_access_key = False, require_password_reset = True): - """ - :param iam_client: AWS API client for IAM - :param user: Name of the user to create - :param groups: Name of the IAM groups to add the user to - :param with_password: Boolean indicating whether creation of a password should be done - :param with_mfa: Boolean indicating whether creation of an MFA device should be done - :param with_access_key: Boolean indicating whether creation of an API access key should be done - :param require_password_reset: Boolean indicating whether users should reset their password after first login - :return: - """ - user_data = {'username': user, 'errors': []} - printInfo('Creating user %s...' % user) - try: - iam_client.create_user(UserName = user) - except Exception as e: - user_data['errors'].append('iam:createuser') - return user_data - # Add user to groups - if type(groups) != list: - groups = [ groups ] - for group in groups: - try: - add_user_to_group(iam_client, user, group) - except Exception as e: - printException(e) - user_data['errors'].append('iam:addusertogroup - %s' % group) - # Generate password - if with_password: - try: - printInfo('Creating a login profile...') - user_data['password'] = generate_password() - iam_client.create_login_profile(UserName = user, Password = user_data['password'] , PasswordResetRequired = require_password_reset) - except Exception as e: - printException(e) - user_data['errors'].append('iam:createloginprofile') - # Enable MFA - if False and with_mfa: - printInfo('Enabling MFA...') - serial = '' - mfa_code1 = '' - mfa_code2 = '' - # Create an MFA device, Display the QR Code, and activate the MFA device - try: - mfa_serial = False # enable_mfa(iam_client, user, '%s/qrcode.png' % user) - except Exception as e: - return 42 - # Request access key - if with_access_key: - try: - printInfo('Creating an API access key...') - access_key = iam_client.create_access_key(UserName=user)['AccessKey'] - user_data['AccessKeyId'] = access_key['AccessKeyId'] - user_data['SecretAccessKey'] = access_key['SecretAccessKey'] - except Exception as e: - printException(e) - user_data['errors'].append('iam:createaccesskey') - return user_data \ No newline at end of file From 5a5d52d852753d59f9052fd645bc921ab73db2c9 Mon Sep 17 00:00:00 2001 From: Juan Jose Date: Tue, 30 Jun 2020 16:26:26 +0200 Subject: [PATCH 128/312] Added console tests --- tests/test_utils_console.py | 76 +++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100755 tests/test_utils_console.py diff --git a/tests/test_utils_console.py b/tests/test_utils_console.py new file mode 100755 index 000000000..a830f1c85 --- /dev/null +++ b/tests/test_utils_console.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +import unittest +from ScoutSuite.core.console import * + +class TestOpinelUtilsConsoleClass(unittest.TestCase): + + def test_configPrintException(self): + set_logger_configuration(False) + set_logger_configuration(True) + + + def test_printDebug(self): + print_debug('hello') + + + def test_printError(self): + print_error('hello') + + + def test_printException(self): + set_logger_configuration(True) + try: + raise Exception('opinelunittest') + except Exception as e: + print_exception(e) + set_logger_configuration(False) + try: + raise Exception('opinelunittest') + except Exception as e: + print_exception(e) + try: + raise Exception('opinelunittest') + except Exception as e: + print_exception(e, True) + + + def test_printInfo(msg, newLine=True): + print_info('hello') + + + def test_printGeneric(self): + print_generic(sys.stderr, 'hello') + + + def test_prompt(self): + assert prompt('a') == 'a' + assert prompt('') == '' + test = ['a', 'b'] + assert prompt(test) == 'a' + assert prompt(test) == 'b' + assert prompt(test) == '' + + + def test_prompt_4_value(self): + assert prompt_value('prompt_4_value', no_confirm=True, test_input='inputvalue') == 'inputvalue' + assert prompt_value('prompt_4_value', no_confirm=True, is_question=True, test_input='inputvalue') == 'inputvalue' + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], no_confirm=True, test_input='b') == 'b' + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], display_choices=False, no_confirm=True, test_input='b') == 'b' + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], display_indices=True, no_confirm=True, test_input='1') == 'b' + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], default='b', no_confirm=True, test_input='') == 'b' + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], no_confirm=True, authorize_list=True, test_input='a,b') == 'a,b' + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], required=True, no_confirm=True, test_input=['', 'b']) == 'b' + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], required=True, no_confirm=True, test_input=['invalid', 'b']) == 'b' + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], no_confirm=True, test_input='a,c') == None + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], no_confirm=True, test_input='a,b', authorize_list = True) == 'a,b' + assert prompt_value('prompt_4_value', choices=['a', 'b', 'c'], no_confirm=True, test_input='a,e', authorize_list = True) == None + + def test_prompt_4_yes_no(self): + assert prompt_yes_no('hello', 'N') == False + assert prompt_yes_no('hello', 'no') == False + assert prompt_yes_no('hello', 'Y') == True + assert prompt_yes_no('hello', 'yes') == True + assert prompt_yes_no('hello', ['foo', 'bar', 'no']) == False + assert prompt_yes_no('hello', 'Ye') == None + assert prompt_yes_no('hello', 'Non') == None \ No newline at end of file From c29432109078ae884a7a3210e112ea781dcc9588 Mon Sep 17 00:00:00 2001 From: Juan Jose Date: Wed, 1 Jul 2020 11:44:49 +0200 Subject: [PATCH 129/312] Added fs tests --- tests/data/ip-ranges-1.json | 1 + tests/data/ip-ranges-3.json | 7 ++ tests/data/protocols.json | 5 + .../results/read_ip_ranges/ip-ranges-1a.json | 1 + .../results/read_ip_ranges/ip-ranges-1b.json | 1 + .../results/read_ip_ranges/ip-ranges-1c.json | 1 + tests/results/read_ip_ranges/ip-ranges-3.json | 1 + tests/results/read_ip_ranges/ip-ranges-a.json | 1 + tests/test_utils_console.py | 2 +- tests/test_utils_fs.py | 98 +++++++++++++++++++ 10 files changed, 117 insertions(+), 1 deletion(-) create mode 100755 tests/data/ip-ranges-1.json create mode 100755 tests/data/ip-ranges-3.json create mode 100755 tests/data/protocols.json create mode 100755 tests/results/read_ip_ranges/ip-ranges-1a.json create mode 100755 tests/results/read_ip_ranges/ip-ranges-1b.json create mode 100755 tests/results/read_ip_ranges/ip-ranges-1c.json create mode 100755 tests/results/read_ip_ranges/ip-ranges-3.json create mode 100755 tests/results/read_ip_ranges/ip-ranges-a.json create mode 100755 tests/test_utils_fs.py diff --git a/tests/data/ip-ranges-1.json b/tests/data/ip-ranges-1.json new file mode 100755 index 000000000..effcd842b --- /dev/null +++ b/tests/data/ip-ranges-1.json @@ -0,0 +1 @@ +{"createDate": "2015-10-01-19-05-51","prefixes": [{"field_a": "a1","field_b": "b1","ip_prefix": "1.2.3.4"},{"field_a": "a2","field_b": "b2","ip_prefix": "5.6.7.8"}]} diff --git a/tests/data/ip-ranges-3.json b/tests/data/ip-ranges-3.json new file mode 100755 index 000000000..0739cbde7 --- /dev/null +++ b/tests/data/ip-ranges-3.json @@ -0,0 +1,7 @@ +{ + "source": "tests/data/ip-ranges-2.json", + "local_file": "True", + "conditions": [ "and", + [ "region", "match", [ "us-.*" ] ] + ] +} diff --git a/tests/data/protocols.json b/tests/data/protocols.json new file mode 100755 index 000000000..b4a1761f4 --- /dev/null +++ b/tests/data/protocols.json @@ -0,0 +1,5 @@ +{ + "protocols": { + "-2": "TEST" + } +} \ No newline at end of file diff --git a/tests/results/read_ip_ranges/ip-ranges-1a.json b/tests/results/read_ip_ranges/ip-ranges-1a.json new file mode 100755 index 000000000..f487890d9 --- /dev/null +++ b/tests/results/read_ip_ranges/ip-ranges-1a.json @@ -0,0 +1 @@ +[{"ip_prefix": "1.2.3.4", "field_b": "b1", "field_a": "a1"}, {"ip_prefix": "5.6.7.8", "field_b": "b2", "field_a": "a2"}] diff --git a/tests/results/read_ip_ranges/ip-ranges-1b.json b/tests/results/read_ip_ranges/ip-ranges-1b.json new file mode 100755 index 000000000..0e7bc9c2e --- /dev/null +++ b/tests/results/read_ip_ranges/ip-ranges-1b.json @@ -0,0 +1 @@ +["1.2.3.4", "5.6.7.8"] \ No newline at end of file diff --git a/tests/results/read_ip_ranges/ip-ranges-1c.json b/tests/results/read_ip_ranges/ip-ranges-1c.json new file mode 100755 index 000000000..c4f841a76 --- /dev/null +++ b/tests/results/read_ip_ranges/ip-ranges-1c.json @@ -0,0 +1 @@ +["1.2.3.4"] \ No newline at end of file diff --git a/tests/results/read_ip_ranges/ip-ranges-3.json b/tests/results/read_ip_ranges/ip-ranges-3.json new file mode 100755 index 000000000..ae86932a6 --- /dev/null +++ b/tests/results/read_ip_ranges/ip-ranges-3.json @@ -0,0 +1 @@ +["52.92.252.0/22", "52.92.48.0/22", "13.56.0.0/16", "13.57.0.0/16", "13.58.0.0/15"] diff --git a/tests/results/read_ip_ranges/ip-ranges-a.json b/tests/results/read_ip_ranges/ip-ranges-a.json new file mode 100755 index 000000000..efc8cc9dc --- /dev/null +++ b/tests/results/read_ip_ranges/ip-ranges-a.json @@ -0,0 +1 @@ +[{"region": "us-east-1", "ip_prefix": "23.20.0.0/14", "service": "AMAZON"}, {"region": "us-east-1", "ip_prefix": "23.20.0.0/14", "service": "EC2"}] \ No newline at end of file diff --git a/tests/test_utils_console.py b/tests/test_utils_console.py index a830f1c85..3c2130733 100755 --- a/tests/test_utils_console.py +++ b/tests/test_utils_console.py @@ -40,7 +40,7 @@ def test_printInfo(msg, newLine=True): def test_printGeneric(self): - print_generic(sys.stderr, 'hello') + print_generic('hello') def test_prompt(self): diff --git a/tests/test_utils_fs.py b/tests/test_utils_fs.py new file mode 100755 index 000000000..0b4e5227c --- /dev/null +++ b/tests/test_utils_fs.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +import unittest +from ScoutSuite.core.fs import * +from ScoutSuite.core.console import * + +class TestOpinelFsClass(unittest.TestCase): + """ + Test opinel.fs + """ + + def cmp(self, a, b): + """ + Implement cmp() for Python3 tests + """ + return (a > b) - (a < b) + + def test_CustomJSONEncoder(self): + date = datetime.datetime(2017, 6, 12) + blob1 = {'foo': 'bar', 'date': date} + print('%s' % json.dumps(blob1, cls=CustomJSONEncoder)) + blob2 = {'foo': 'bar', 'baz': {'foo': 'bar'}} + print('%s' % json.dumps(blob2, cls=CustomJSONEncoder)) + + def test_load_data(self): + test = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/protocols.json') + load_data(test, local_file=True) + load_data(test, 'protocols', local_file=True) + load_data('protocols.json', 'protocols') + load_data('aws/ip-ranges/aws.json', 'prefixes') + load_data('data/protocols.json', 'protocols', local_file=True) + test = load_data('protocols.json', 'protocols') + assert type(test) == dict + assert test['1'] == 'ICMP' + test = load_data('data/protocols.json', 'protocols', True) + assert type(test) == dict + assert test['-2'] == 'TEST' + + + def test_read_ip_ranges(self): + read_ip_ranges('aws/ip-ranges/aws.json', local_file=False) + read_ip_ranges('data/ip-ranges-1.json', local_file=True) + read_ip_ranges('data/ip-ranges-1.json', local_file=True, ip_only=True) + successful_read_ip_ranges_runs = True + test_cases = [ + { + 'filename': 'data/ip-ranges-1.json', + 'local_file': True, + 'conditions': [],'ip_only': False, + 'results': 'results/read_ip_ranges/ip-ranges-1a.json' + }, + { + 'filename': 'data/ip-ranges-1.json', + 'local_file': True, + 'conditions': [],'ip_only': True, + 'results': 'results/read_ip_ranges/ip-ranges-1b.json' + }, + { + 'filename': 'data/ip-ranges-1.json', + 'local_file': True, + 'conditions': [ + [ + 'field_a', 'equal', 'a1']], + 'ip_only': True, + 'results': 'results/read_ip_ranges/ip-ranges-1c.json' + }, + { + 'filename': 'aws/ip-ranges/aws.json', + 'local_file': False, + 'conditions': [ + [ 'ip_prefix', 'equal', '23.20.0.0/14' ] + ], + 'ip_only': False, + 'results': 'results/read_ip_ranges/ip-ranges-a.json' + }, + { + "filename": 'data/ip-ranges-3.json', + "local_file": True, + 'results': None, + "ip_only": True, + "results": "results/read_ip_ranges/ip-ranges-3.json" + }, + { + "filename": 'data/ip-ranges-3.json', + "local_file": True, + 'results': None, + "ip_only": True, + "results": "results/read_ip_ranges/ip-ranges-3.json" + } + ] + + assert successful_read_ip_ranges_runs + + def test_save_blob_as_json(self): + date = datetime.datetime.now() + save_blob_as_json('tmp1.json', {'foo': 'bar','date': date}, True) + save_blob_as_json('tmp1.json', {'foo': 'bar'}, True) + save_blob_as_json('/root/tmp1.json', {'foo': 'bar'}, True) From 4918020d77be0f886a7abe71c544ee4730a3fcee Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 1 Jul 2020 18:12:39 +0200 Subject: [PATCH 130/312] Get owner ID from raw resource --- ScoutSuite/providers/aws/resources/ec2/snapshots.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/providers/aws/resources/ec2/snapshots.py b/ScoutSuite/providers/aws/resources/ec2/snapshots.py index 591f00daa..3544bda17 100755 --- a/ScoutSuite/providers/aws/resources/ec2/snapshots.py +++ b/ScoutSuite/providers/aws/resources/ec2/snapshots.py @@ -19,8 +19,8 @@ def _parse_snapshot(self, raw_snapshot): raw_snapshot['name'] = get_name(raw_snapshot, raw_snapshot, 'id') raw_snapshot['public'] = self._is_public(raw_snapshot) raw_snapshot['arn'] = 'arn:aws:ec2:{}:{}:snapshot/{}'.format(self.get('region'), - self.facade.owner_id, - raw_snapshot.get('name')) + raw_snapshot.get('OwnerId'), + raw_snapshot.get('name')) return raw_snapshot['id'], raw_snapshot @staticmethod From 6da5365b9a1a1b4e86f4b59dcb709a14fdbbf909 Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 1 Jul 2020 18:22:10 +0200 Subject: [PATCH 131/312] Tweak partial --- ....sqldatabase.subscriptions.id.servers.html | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/azure/services.sqldatabase.subscriptions.id.servers.html b/ScoutSuite/output/data/html/partials/azure/services.sqldatabase.subscriptions.id.servers.html index e06b2d54a..28afeee76 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.sqldatabase.subscriptions.id.servers.html +++ b/ScoutSuite/output/data/html/partials/azure/services.sqldatabase.subscriptions.id.servers.html @@ -26,39 +26,35 @@

    Information

    Resource group: {{value_or_none resource_group_name}}
    -

    SQL Databases

    - {{#each databases}} -
    -
    Database name: {{@key}}
    -
    -
    Auditing: {{ convert_bool_to_enabled auditing.auditing_enabled }}
    -
    Auditing retention period: {{ auditing.retention_days }}
    -
    Threat detection: {{ convert_bool_to_enabled threat_detection.threat_detection_enabled }}
    -
    Threat detection alerts: {{ convert_bool_to_enabled threat_detection.alerts_enabled }}
    -
    Send threat detection alerts: {{ convert_bool_to_enabled threat_detection.send_alerts_enabled }}
    -
    Threat detection retention period: {{ threat_detection.retention_days }}
    -
    Transparent data encryption: {{ convert_bool_to_enabled transparent_data_encryption_enabled }}
    -
    Geo-replication configured: {{ replication_configured }}
    -
    Tags: - {{#each tags}} -
    Database name: {{@key}}
    +
    +
    Auditing: {{ convert_bool_to_enabled auditing.auditing_enabled }}
    +
    Auditing retention period: {{ auditing.retention_days }}
    +
    Threat detection: {{ convert_bool_to_enabled threat_detection.threat_detection_enabled }}
    +
    Threat detection alerts: {{ convert_bool_to_enabled threat_detection.alerts_enabled }}
    +
    Send threat detection alerts: {{ convert_bool_to_enabled threat_detection.send_alerts_enabled }}
    +
    Threat detection retention period: {{ threat_detection.retention_days }}
    +
    Transparent data encryption: {{ convert_bool_to_enabled transparent_data_encryption_enabled }}
    +
    Geo-replication configured: {{ replication_configured }}
    +
    Tags: + {{#each tags}} +
    - {{value_or_none this}} -
       - {{else}} -
    None
    - {{/each}} -
    -
    Resource group: {{value_or_none resource_group_name}}
    + {{value_or_none this}} +
       + {{else}} +
    None
    + {{/each}}
    +
    Resource group: {{value_or_none resource_group_name}}
    - {{/each}} + {{/each}}
    - From a8362f0d49564000528383063f58df7f93612613 Mon Sep 17 00:00:00 2001 From: xga Date: Sun, 19 Jul 2020 10:24:19 +0200 Subject: [PATCH 158/312] Cosmetic changes --- ScoutSuite/output/data/html/summaries/attack_surface.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/output/data/html/summaries/attack_surface.html b/ScoutSuite/output/data/html/summaries/attack_surface.html index 2908c5d07..25b7c9516 100755 --- a/ScoutSuite/output/data/html/summaries/attack_surface.html +++ b/ScoutSuite/output/data/html/summaries/attack_surface.html @@ -9,12 +9,12 @@
    {{#each items}}
    -
    Public Address: {{@key}}
    +
    Public Address: {{@key}}
    {{#if this.InstanceName}} -
    Instance Name: {{this.InstanceName}}
    +
    Instance Name: {{this.InstanceName}}
    {{/if}} {{#if this.PublicDnsName}} -
    Public DNS Name: {{this.PublicDnsName}}
    +
    Public DNS Name: {{this.PublicDnsName}}
    {{/if}}
      From b8df7da2772eb65d2d85fdeb09f9dc89afdc38e9 Mon Sep 17 00:00:00 2001 From: xga Date: Sun, 19 Jul 2020 10:46:40 +0200 Subject: [PATCH 159/312] Add dynamodb support --- .../services.dynamodb.regions.id.tables.html | 28 ++++++++ ScoutSuite/providers/aws/facade/dynamodb.py | 72 +++++++++---------- .../aws/resources/dynamodb/backups.py | 26 ------- .../providers/aws/resources/dynamodb/base.py | 7 +- .../aws/resources/dynamodb/tables.py | 42 ++++++----- 5 files changed, 89 insertions(+), 86 deletions(-) create mode 100644 ScoutSuite/output/data/html/partials/aws/services.dynamodb.regions.id.tables.html delete mode 100644 ScoutSuite/providers/aws/resources/dynamodb/backups.py diff --git a/ScoutSuite/output/data/html/partials/aws/services.dynamodb.regions.id.tables.html b/ScoutSuite/output/data/html/partials/aws/services.dynamodb.regions.id.tables.html new file mode 100644 index 000000000..9bf89b617 --- /dev/null +++ b/ScoutSuite/output/data/html/partials/aws/services.dynamodb.regions.id.tables.html @@ -0,0 +1,28 @@ + + + + + + + + + diff --git a/ScoutSuite/providers/aws/facade/dynamodb.py b/ScoutSuite/providers/aws/facade/dynamodb.py index cc4b7c6f7..8c2b3ee56 100644 --- a/ScoutSuite/providers/aws/facade/dynamodb.py +++ b/ScoutSuite/providers/aws/facade/dynamodb.py @@ -1,56 +1,50 @@ -from ScoutSuite.providers.utils import run_concurrently from ScoutSuite.core.console import print_exception +from ScoutSuite.providers.aws.facade.base import AWSBaseFacade from ScoutSuite.providers.aws.facade.utils import AWSFacadeUtils -from ScoutSuite.providers.aws.facade.basefacade import AWSBaseFacade +from ScoutSuite.providers.utils import run_concurrently, get_and_set_concurrently, map_concurrently class DynamoDBFacade(AWSBaseFacade): - async def get_backups(self, region, table_name): + _GET_TABLES_BATCH_SIZE = 100 + + async def get_tables(self, region): try: - return await AWSFacadeUtils.get_all_pages( - "dynamodb", - region, - self.session, - "list_backups", - "BackupSummaries", - TableName=table_name, - ) + tables_names = await AWSFacadeUtils.get_all_pages('dynamodb', region, self.session, 'list_tables', + 'TableNames') + return await map_concurrently(self._get_table, tables_names, region=region) except Exception as e: - print_exception("Failed to get DynamoDB Backups for {}".format(table_name)) + print_exception('Failed to get DynamoDB tables: {}'.format(e)) return [] - async def get_tables(self, region): + async def _get_table(self, table_name: str, region: str): + client = AWSFacadeUtils.get_client('dynamodb', self.session, region) + try: - return await AWSFacadeUtils.get_all_pages( - "dynamodb", region, self.session, "list_tables", "TableNames" - ) + table = await run_concurrently(lambda: client.describe_table(TableName=table_name)['Table']) except Exception as e: - print_exception("Failed to get DynamoDB tables") - return [] + print_exception('Failed to get DynamoDB table: {}'.format(e)) + raise + else: + await get_and_set_concurrently( + [self._get_and_set_backup, self._get_and_set_continuous_backups], [table], region=region) + + return table + + async def _get_and_set_backup(self, table: {}, region: str): + client = AWSFacadeUtils.get_client('dynamodb', self.session, region) - async def get_tags_for_resource(self, region, resource_arn): try: - return await AWSFacadeUtils.get_all_pages( - "dynamodb", - region, - self.session, - "list_tags_of_resource", - "Tags", - ResourceArn=resource_arn, - ) + summaries = await run_concurrently(lambda: client.list_backups(TableName=table['TableName'])) + table['BackupSummaries'] = summaries.get('BackupSummaries') except Exception as e: - print_exception( - "Failed to get DynamoDB tags for resource {}".format(resource_arn) - ) - return [] + print_exception('Failed to list DynamoDB table backups: {}'.format(e)) + + async def _get_and_set_continuous_backups(self, table: {}, region: str): + client = AWSFacadeUtils.get_client('dynamodb', self.session, region) - async def get_table(self, region, table_name): - client = AWSFacadeUtils.get_client("dynamodb", self.session, region) try: - raw_table = await run_concurrently( - lambda: client.describe_table(TableName=table_name) - ) + description = await run_concurrently( + lambda: client.describe_continuous_backups(TableName=table['TableName'])) + table['ContinuousBackups'] = description.get('ContinuousBackupsDescription') except Exception as e: - print_exception("Failed to get table {}: {}".format(table_name, e)) - raw_table = None - return raw_table + print_exception('Failed to describe DynamoDB table continuous backups: {}'.format(e)) diff --git a/ScoutSuite/providers/aws/resources/dynamodb/backups.py b/ScoutSuite/providers/aws/resources/dynamodb/backups.py deleted file mode 100644 index 7e25b78ac..000000000 --- a/ScoutSuite/providers/aws/resources/dynamodb/backups.py +++ /dev/null @@ -1,26 +0,0 @@ - -from ScoutSuite.providers.aws.facade.base import AWSFacade -from ScoutSuite.providers.aws.resources.base import AWSResources - - -class Backups(AWSResources): - - def __init__(self, facade: AWSFacade, region: str) -> None: - super(Backups, self).__init__(facade) - self.region = region - - - async def fetch_all(self): - raw_backups = await self.facade.dynamodb.get_backups(self.region) - for raw_backup in raw_backups: - name, resource = await self._parse_backup(raw_backup) - self[name] = resource - - - async def _parse_backup(self, raw_backup): - backup = { - 'table_name': raw_backup.get('TableName'), - 'id': raw_backup.get('TableId'), - 'arn': raw_backup.get('TableArn'), - } - return backup['table_name'], backup diff --git a/ScoutSuite/providers/aws/resources/dynamodb/base.py b/ScoutSuite/providers/aws/resources/dynamodb/base.py index 479c04499..09f6c0155 100644 --- a/ScoutSuite/providers/aws/resources/dynamodb/base.py +++ b/ScoutSuite/providers/aws/resources/dynamodb/base.py @@ -1,11 +1,12 @@ from ScoutSuite.providers.aws.facade.base import AWSFacade from ScoutSuite.providers.aws.resources.regions import Regions - from .tables import Tables class DynamoDB(Regions): - _children = [(Tables, "tables")] + _children = [ + (Tables, 'tables') + ] def __init__(self, facade: AWSFacade): - super(DynamoDB, self).__init__("dynamodb", facade) + super(DynamoDB, self).__init__('dynamodb', facade) diff --git a/ScoutSuite/providers/aws/resources/dynamodb/tables.py b/ScoutSuite/providers/aws/resources/dynamodb/tables.py index e44530bd9..be6aa7673 100644 --- a/ScoutSuite/providers/aws/resources/dynamodb/tables.py +++ b/ScoutSuite/providers/aws/resources/dynamodb/tables.py @@ -1,29 +1,35 @@ from ScoutSuite.providers.aws.facade.base import AWSFacade from ScoutSuite.providers.aws.resources.base import AWSResources -from ScoutSuite.providers.aws.utils import snake_keys class Tables(AWSResources): - def __init__(self, facade: AWSFacade, region: str) -> None: + def __init__(self, facade: AWSFacade, region: str): super(Tables, self).__init__(facade) self.region = region async def fetch_all(self): - tables = await self.facade.dynamodb.get_tables(self.region) - for table_name in tables: - raw_table = await self.facade.dynamodb.get_table(self.region, table_name) - table = await self._parse_table(raw_table) - self[table_name] = table + raw_tables = await self.facade.dynamodb.get_tables(self.region) + for raw_table in raw_tables: + name, resource = self._parse_table(raw_table) + self[name] = resource - async def _parse_table(self, raw_table): - table = {} - if raw_table["Table"]: - raw = raw_table["Table"] - if "SSEDescription" in raw: - table["sse_enabled"] = True - else: - table["sse_enabled"] = False - new_dict = snake_keys(raw) - table.update(new_dict) + def _parse_table(self, raw_table): + table_dict = {} + table_dict['name'] = raw_table.get('TableName') + table_dict['id'] = raw_table.get('TableId') + table_dict['arn'] = raw_table.get('TableArn') + table_dict['attribute_definitions'] = raw_table.get('AttributeDefinitions') + table_dict['key_schema'] = raw_table.get('KeySchema') + table_dict['table_status'] = raw_table.get('TableStatus') + table_dict['creation_date_time'] = raw_table.get('CreationDateTime') + table_dict['provisioned_throughput'] = raw_table.get('ProvisionedThroughput') + table_dict['table_size_bytes'] = raw_table.get('TableSizeBytes') + table_dict['item_count'] = raw_table.get('ItemCount') + table_dict['backup_summaries'] = raw_table.get('BackupSummaries') + table_dict['continuous_backups'] = raw_table.get('ContinuousBackups') - return table + table_dict['automatic_backups_enabled'] = \ + raw_table['ContinuousBackups']['PointInTimeRecoveryDescription']['PointInTimeRecoveryStatus'] == 'ENABLED' \ + if 'ContinuousBackups' in raw_table else None + + return table_dict['id'], table_dict From 3f42c408aa10012a1ba877972435e809e156cb7c Mon Sep 17 00:00:00 2001 From: xga Date: Sun, 19 Jul 2020 11:24:09 +0200 Subject: [PATCH 160/312] Add tags --- .../aws/services.dynamodb.regions.id.tables.html | 12 +++++++++++- ScoutSuite/providers/aws/facade/dynamodb.py | 15 ++++++++++++++- .../providers/aws/resources/dynamodb/tables.py | 1 + 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.dynamodb.regions.id.tables.html b/ScoutSuite/output/data/html/partials/aws/services.dynamodb.regions.id.tables.html index 9bf89b617..d72f7efdb 100644 --- a/ScoutSuite/output/data/html/partials/aws/services.dynamodb.regions.id.tables.html +++ b/ScoutSuite/output/data/html/partials/aws/services.dynamodb.regions.id.tables.html @@ -7,12 +7,22 @@

      {{name}}

      Information

      ID: {{value_or_none id}}
      -
      Arn: {{value_or_none arn}}
      +
      ARN: {{value_or_none arn}}
      Status: {{value_or_none table_status}}
      Creation Date: {{format_date creation_date_time}}
      Automatic Backups: {{convert_bool_to_enabled automatic_backups_enabled}}
      Item Count: {{value_or_none item_count}}
      + {{#if tags}} +
      +

      Tags

      +
        + {{#each tags}} +
      • {{Key}}: {{Value}}
      • + {{/each}} +
      +
      + {{/if}} + + + + + + diff --git a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.flow_logs.html b/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.flow_logs.html deleted file mode 100755 index 12cabd25f..000000000 --- a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.flow_logs.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/ScoutSuite/providers/aws/resources/vpc/flow_logs.py b/ScoutSuite/providers/aws/resources/vpc/flow_logs.py index a6a137565..807ebc221 100755 --- a/ScoutSuite/providers/aws/resources/vpc/flow_logs.py +++ b/ScoutSuite/providers/aws/resources/vpc/flow_logs.py @@ -5,17 +5,30 @@ class FlowLogs(AWSResources): def __init__(self, facade: AWSFacade, region: str): - self.region = region - super().__init__(facade) + self.facade = facade + self.region = region async def fetch_all(self): raw_logs = await self.facade.ec2.get_flow_logs(self.region) + for raw_log in raw_logs: id, log = self._parse_log(raw_log) self[id] = log - def _parse_log(self, raw_log): - get_name(raw_log, raw_log, 'FlowLogId') - log_id = raw_log.pop('FlowLogId') - return log_id, raw_log + def _parse_log(self, raw_flow_log): + flow_log_dict = {} + flow_log_dict['name'] = flow_log_dict['id'] = raw_flow_log.get('ResourceId') + flow_log_dict['creation_time'] = raw_flow_log.get('CreationTime') + flow_log_dict['deliver_logs_error_message'] = raw_flow_log.get('DeliverLogsErrorMessage') + flow_log_dict['deliver_logs_status'] = raw_flow_log.get('DeliverLogsStatus') + flow_log_dict['flow_log_status'] = raw_flow_log.get('FlowLogStatus') + flow_log_dict['resource_id'] = raw_flow_log.get('ResourceId') + flow_log_dict['traffic_type'] = raw_flow_log.get('TrafficType') + flow_log_dict['log_destination_type'] = raw_flow_log.get('LogDestinationType') + flow_log_dict['log_destination'] = raw_flow_log.get('LogDestination') + flow_log_dict['log_format'] = raw_flow_log.get('LogFormat') + flow_log_dict['tags'] = raw_flow_log.get('Tags') + flow_log_dict['max_aggregation_interval'] = raw_flow_log.get('MaxAggregationInterval') + return flow_log_dict['id'], flow_log_dict + From 9b5f1bcab589630f3c1552567b85ba87d60cdfbc Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 3 Aug 2020 11:12:27 +0200 Subject: [PATCH 181/312] Improve support for flow logs --- .../partials/aws/services.vpc.regions.id.vpcs.id.subnets.html | 2 +- ScoutSuite/providers/aws/resources/vpc/flow_logs.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.subnets.html b/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.subnets.html index 7cecbe4e5..1e661f7c9 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.subnets.html +++ b/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.id.subnets.html @@ -36,7 +36,7 @@

      {{this.name}} +
    • {{this.FlowLogId}}
    • {{/each}}

    diff --git a/ScoutSuite/providers/aws/resources/vpc/flow_logs.py b/ScoutSuite/providers/aws/resources/vpc/flow_logs.py index 807ebc221..63051c69e 100755 --- a/ScoutSuite/providers/aws/resources/vpc/flow_logs.py +++ b/ScoutSuite/providers/aws/resources/vpc/flow_logs.py @@ -18,7 +18,7 @@ async def fetch_all(self): def _parse_log(self, raw_flow_log): flow_log_dict = {} - flow_log_dict['name'] = flow_log_dict['id'] = raw_flow_log.get('ResourceId') + flow_log_dict['name'] = flow_log_dict['id'] = raw_flow_log.get('FlowLogId') flow_log_dict['creation_time'] = raw_flow_log.get('CreationTime') flow_log_dict['deliver_logs_error_message'] = raw_flow_log.get('DeliverLogsErrorMessage') flow_log_dict['deliver_logs_status'] = raw_flow_log.get('DeliverLogsStatus') From 043d1ac537d04429888b7738f271317c90115639 Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 3 Aug 2020 11:19:27 +0200 Subject: [PATCH 182/312] Restore VPC flow logs in report and callback --- .../aws/services.vpc.regions.id.vpcs.html | 10 +++ ScoutSuite/providers/aws/provider.py | 65 +++++++++---------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.html b/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.html index 76525fd97..35144b617 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.html +++ b/ScoutSuite/output/data/html/partials/aws/services.vpc.regions.id.vpcs.html @@ -52,6 +52,16 @@

    Instances accordion_id = (concat 'services.vpc.regions' region 'vpcs' @key 'peering_connections') }}

    +
    +

    Flow logs + {{> count_badge count=flow_logs.length}} +

    +
      + {{#each flow_logs}} +
    • {{this}}
    • + {{/each}} +
    +
    diff --git a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-default-rule-in-use.json b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-default-rule-in-use.json index 0732cf3d7..74211e0df 100755 --- a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-default-rule-in-use.json +++ b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-default-rule-in-use.json @@ -15,5 +15,6 @@ "default-allow-ssh" ] ] - ] + ], + "id_suffix": "name" } \ No newline at end of file diff --git a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-all-ports.json b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-all-ports.json index 40f8d11fd..11db83563 100755 --- a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-all-ports.json +++ b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-all-ports.json @@ -26,5 +26,6 @@ "equal", "0-65535" ] - ] + ], + "id_suffix": "permissive_ports" } \ No newline at end of file diff --git a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-internal-traffic.json b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-internal-traffic.json index 42c7ff669..dafd43870 100755 --- a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-internal-traffic.json +++ b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-internal-traffic.json @@ -31,5 +31,6 @@ "containAtLeastOneOf", "10.128.0.0/9" ] - ] + ], + "id_suffix": "permissive_ports" } \ No newline at end of file diff --git a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-port-range.json b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-port-range.json index dff3be0c1..bfccf44c2 100755 --- a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-port-range.json +++ b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-port-range.json @@ -31,5 +31,6 @@ "notEqual", "0-65535" ] - ] + ], + "id_suffix": "permissive_ports" } \ No newline at end of file diff --git a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-public-access.json b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-public-access.json index dbdc67133..f099de81d 100755 --- a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-public-access.json +++ b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-allows-public-access.json @@ -25,5 +25,6 @@ "containAtLeastOneOf", "0.0.0.0/0" ] - ] + ], + "id_suffix": "source_ranges" } \ No newline at end of file diff --git a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-opens-all-ports-to-all.json b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-opens-all-ports-to-all.json index ec5c96e5d..f6ae3dd11 100755 --- a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-opens-all-ports-to-all.json +++ b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-opens-all-ports-to-all.json @@ -31,5 +31,6 @@ "containAtLeastOneOf", "0.0.0.0/0" ] - ] + ], + "id_suffix": "permissive_ports" } \ No newline at end of file diff --git a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-opens-sensitive-port-to-all.json b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-opens-sensitive-port-to-all.json index 5969de7c4..0d96cefc0 100755 --- a/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-opens-sensitive-port-to-all.json +++ b/ScoutSuite/providers/gcp/rules/findings/computeengine-firewall-rule-opens-sensitive-port-to-all.json @@ -42,5 +42,6 @@ "54322" ] ] - ] + ], + "id_suffix": "permissive_ports" } \ No newline at end of file From ca015705d70bf264d2ad4479041eddba98e42b7c Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 22 Aug 2020 14:20:18 +0200 Subject: [PATCH 211/312] Fix for https://github.com/nccgroup/ScoutSuite/issues/801 --- ...virtualmachines.subscriptions.id.disks.html | 9 ++++----- ...ualmachines.subscriptions.id.snapshots.html | 2 +- .../azure/resources/virtualmachines/disks.py | 18 ++++++++++++------ .../resources/virtualmachines/snapshots.py | 16 +++++++++++----- .../virtual-machines-disk-encryption.json | 6 +++--- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.disks.html b/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.disks.html index 96d60ad33..8df5c0503 100644 --- a/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.disks.html +++ b/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.disks.html @@ -6,15 +6,14 @@

    {{name}}

    Information

    Name: {{value_or_none name}}
    -
    Unique Id: {{value_or_none unique_id}}
    +
    Unique ID: {{value_or_none unique_id}}
    +
    Location: {{value_or_none location}}
    +
    Time Created: {{format_date time_created}}
    Provisioning State: {{value_or_none provisioning_state}}
    Disk State: {{value_or_none disk_state}}
    -
    Time Created: {{format_date time_created}}
    -
    Location: {{value_or_none location}}
    Zones: {{value_or_none zones}}
    -
    Encryption: {{convert_bool_to_enabled encryption_enabled}}
    +
    Encryption Type: {{value_or_none encryption_type}}
    OS Type: {{value_or_none os_type}}
    -
    Managed By: {{value_or_none managed_by}}
    Hyper V Generation: {{value_or_none hyper_vgeneration}}
    Disk Size GB: {{value_or_none disk_size_gb}}
    diff --git a/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.snapshots.html b/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.snapshots.html index eb69d2cf6..53378eb73 100644 --- a/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.snapshots.html +++ b/ScoutSuite/output/data/html/partials/azure/services.virtualmachines.subscriptions.id.snapshots.html @@ -10,7 +10,7 @@

    Information

    Provisioning State: {{value_or_none provisioning_state}}
    Time Created: {{format_date time_created}}
    Location: {{value_or_none location}}
    -
    Encryption: {{convert_bool_to_enabled encryption_enabled}}
    +
    Encryption Type: {{value_or_none encryption_type}}
    OS Type: {{value_or_none os_type}}
    Managed By: {{value_or_none managed_by}}
    Hyper V Generation: {{value_or_none hyper_vgeneration}}
    diff --git a/ScoutSuite/providers/azure/resources/virtualmachines/disks.py b/ScoutSuite/providers/azure/resources/virtualmachines/disks.py index 05d3c5302..d0692d0e8 100644 --- a/ScoutSuite/providers/azure/resources/virtualmachines/disks.py +++ b/ScoutSuite/providers/azure/resources/virtualmachines/disks.py @@ -17,6 +17,7 @@ async def fetch_all(self): def _parse_disk(self, raw_disk): disk_dict = {} disk_dict['id'] = get_non_provider_id(raw_disk.id) + disk_dict['unique_id'] = raw_disk.unique_id disk_dict['name'] = raw_disk.name disk_dict['type'] = raw_disk.type disk_dict['location'] = raw_disk.location @@ -30,19 +31,24 @@ def _parse_disk(self, raw_disk): disk_dict['creation_data'] = raw_disk.creation_data disk_dict['disk_size_gb'] = raw_disk.disk_size_gb disk_dict['disk_size_bytes'] = raw_disk.disk_size_bytes - disk_dict['unique_id'] = raw_disk.unique_id disk_dict['provisioning_state'] = raw_disk.provisioning_state disk_dict['disk_iops_read_write'] = raw_disk.disk_iops_read_write disk_dict['disk_mbps_read_write'] = raw_disk.disk_mbps_read_write disk_dict['disk_state'] = raw_disk.disk_state disk_dict['additional_properties'] = raw_disk.additional_properties - disk_dict['encryption'] = raw_disk.encryption - disk_dict['encryption_settings_collection'] = raw_disk.encryption_settings_collection - if raw_disk.encryption_settings_collection and raw_disk.encryption_settings_collection.enabled: - disk_dict['encryption_enabled'] = True + # TODO this can be removed + # disk_dict['encryption'] = raw_disk.encryption + # disk_dict['encryption_settings_collection'] = raw_disk.encryption_settings_collection + # if raw_disk.encryption_settings_collection and raw_disk.encryption_settings_collection.enabled: + # disk_dict['encryption_enabled'] = True + # else: + # disk_dict['encryption_enabled'] = False + + if raw_disk.encryption and raw_disk.encryption.type: + disk_dict['encryption_type'] = raw_disk.encryption.type else: - disk_dict['encryption_enabled'] = False + disk_dict['encryption_type'] = None return disk_dict['id'], disk_dict diff --git a/ScoutSuite/providers/azure/resources/virtualmachines/snapshots.py b/ScoutSuite/providers/azure/resources/virtualmachines/snapshots.py index 2ff5219ad..208f9ae12 100644 --- a/ScoutSuite/providers/azure/resources/virtualmachines/snapshots.py +++ b/ScoutSuite/providers/azure/resources/virtualmachines/snapshots.py @@ -35,12 +35,18 @@ def _parse_snapshot(self, raw_snapshot): snapshot_dict['incremental'] = raw_snapshot.incremental snapshot_dict['additional_properties'] = raw_snapshot.additional_properties - snapshot_dict['encryption'] = raw_snapshot.encryption - snapshot_dict['encryption_settings_collection'] = raw_snapshot.encryption_settings_collection - if raw_snapshot.encryption_settings_collection and raw_snapshot.encryption_settings_collection.enabled: - snapshot_dict['encryption_enabled'] = True + # TODO this can be removed + # snapshot_dict['encryption'] = raw_snapshot.encryption + # snapshot_dict['encryption_settings_collection'] = raw_snapshot.encryption_settings_collection + # if raw_snapshot.encryption_settings_collection and raw_snapshot.encryption_settings_collection.enabled: + # snapshot_dict['encryption_enabled'] = True + # else: + # snapshot_dict['encryption_enabled'] = False + + if raw_snapshot.encryption and raw_snapshot.encryption.type: + snapshot_dict['encryption_type'] = raw_snapshot.encryption.type else: - snapshot_dict['encryption_enabled'] = False + snapshot_dict['encryption_type'] = None return snapshot_dict['id'], snapshot_dict diff --git a/ScoutSuite/providers/azure/rules/findings/virtual-machines-disk-encryption.json b/ScoutSuite/providers/azure/rules/findings/virtual-machines-disk-encryption.json index a80b8fd64..2feb4a840 100644 --- a/ScoutSuite/providers/azure/rules/findings/virtual-machines-disk-encryption.json +++ b/ScoutSuite/providers/azure/rules/findings/virtual-machines-disk-encryption.json @@ -38,10 +38,10 @@ "conditions": [ "and", [ - "virtualmachines.subscriptions.id.disks.id.encryption_enabled", - "false", + "virtualmachines.subscriptions.id.disks.id.encryption_type", + "null", "" ] ], - "id_suffix": "encryption_enabled" + "id_suffix": "encryption_type" } \ No newline at end of file From 785e9e0dbca3e52b581ff96ec51394814af86fe6 Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 22 Aug 2020 14:23:20 +0200 Subject: [PATCH 212/312] Remove redundant output --- ScoutSuite/providers/azure/facade/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ScoutSuite/providers/azure/facade/base.py b/ScoutSuite/providers/azure/facade/base.py index 3f4cc3fe5..48d282b1c 100755 --- a/ScoutSuite/providers/azure/facade/base.py +++ b/ScoutSuite/providers/azure/facade/base.py @@ -102,7 +102,6 @@ def _set_subscriptions(self): print_exception('Unable to infer a Subscription ID') # raise finally: - print_info(f'Running against the "{s.subscription_id}" subscription') subscriptions_list.append(s) # All subscriptions From 72ccd7c818c1b1d94f3b032a4e310d8021884993 Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 22 Aug 2020 14:31:14 +0200 Subject: [PATCH 213/312] Set debug level --- ScoutSuite/providers/azure/authentication_strategy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ScoutSuite/providers/azure/authentication_strategy.py b/ScoutSuite/providers/azure/authentication_strategy.py index 312b5acb0..59c67b0a8 100755 --- a/ScoutSuite/providers/azure/authentication_strategy.py +++ b/ScoutSuite/providers/azure/authentication_strategy.py @@ -92,6 +92,7 @@ def authenticate(self, # Set logging level to error for libraries as otherwise generates a lot of warnings logging.getLogger('adal-python').setLevel(logging.ERROR) logging.getLogger('msrest').setLevel(logging.ERROR) + logging.getLogger('msrestazure.azure_active_directory').setLevel(logging.ERROR) logging.getLogger('urllib3').setLevel(logging.ERROR) logging.getLogger('cli.azure.cli.core').setLevel(logging.ERROR) From 6375ed9ca876308e8a594775401de0c797c20e49 Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 22 Aug 2020 14:33:13 +0200 Subject: [PATCH 214/312] Debug --- ScoutSuite/providers/azure/provider.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ScoutSuite/providers/azure/provider.py b/ScoutSuite/providers/azure/provider.py index 4da8d9ed8..19f5be98a 100755 --- a/ScoutSuite/providers/azure/provider.py +++ b/ScoutSuite/providers/azure/provider.py @@ -39,6 +39,8 @@ def __init__(self, try: self.account_id = self.credentials.get_tenant_id() except Exception as e: + print_exception('CANT FIND TENANT ID') + print(self.credentials) self.account_id = 'undefined' self.services = AzureServicesConfig(self.credentials, From 3d2481d78a80162339e886e3bd07b7cb201cdeb3 Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 22 Aug 2020 21:20:44 +0200 Subject: [PATCH 215/312] Fix tenant ID pulling --- .../providers/azure/authentication_strategy.py | 15 +++++++++++++-- ScoutSuite/providers/azure/provider.py | 2 -- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/ScoutSuite/providers/azure/authentication_strategy.py b/ScoutSuite/providers/azure/authentication_strategy.py index 59c67b0a8..33e7933c2 100755 --- a/ScoutSuite/providers/azure/authentication_strategy.py +++ b/ScoutSuite/providers/azure/authentication_strategy.py @@ -1,11 +1,12 @@ import json import logging +import requests from getpass import getpass from datetime import datetime, timedelta from azure.common.credentials import ServicePrincipalCredentials, UserPassCredentials, get_azure_cli_credentials from msrestazure.azure_active_directory import MSIAuthentication -from ScoutSuite.core.console import print_info, print_debug +from ScoutSuite.core.console import print_info, print_debug, print_exception from msrestazure.azure_active_directory import AADTokenCredentials import adal @@ -32,8 +33,18 @@ def __init__(self, def get_tenant_id(self): if self.tenant_id: return self.tenant_id - else: + elif 'tenant_id' in self.aad_graph_credentials.token: return self.aad_graph_credentials.token['tenant_id'] + else: + # This is a last resort, e.g. for MSI authentication + try: + h = {'Authorization': 'Bearer {}'.format(self.arm_credentials.token['access_token'])} + r = requests.get('https://management.azure.com/tenants?api-version=2020-01-01', headers=h) + r2 = r.json() + return r2.get('value')[0].get('tenantId') + except Exception as e: + print_exception('Unable to infer tenant ID: {}'.format(e)) + return None def get_credentials(self, resource): if resource == 'arm': diff --git a/ScoutSuite/providers/azure/provider.py b/ScoutSuite/providers/azure/provider.py index 19f5be98a..4da8d9ed8 100755 --- a/ScoutSuite/providers/azure/provider.py +++ b/ScoutSuite/providers/azure/provider.py @@ -39,8 +39,6 @@ def __init__(self, try: self.account_id = self.credentials.get_tenant_id() except Exception as e: - print_exception('CANT FIND TENANT ID') - print(self.credentials) self.account_id = 'undefined' self.services = AzureServicesConfig(self.credentials, From d566a64f7278e1b42d1d84cc5f702006937eea6e Mon Sep 17 00:00:00 2001 From: Thomas Morledge Date: Wed, 26 Aug 2020 10:03:08 +0100 Subject: [PATCH 216/312] Fixed Azure CLI not installing. Install vim and nano to make the docker image more usable --- container/docker/src/Dockerfile | 10 ++++- .../src/bin/container-install-additional.sh | 5 +++ .../docker/src/bin/container-install-azure.sh | 38 +++++++++---------- 3 files changed, 32 insertions(+), 21 deletions(-) create mode 100755 container/docker/src/bin/container-install-additional.sh diff --git a/container/docker/src/Dockerfile b/container/docker/src/Dockerfile index 01aa9ed29..6f15525d1 100644 --- a/container/docker/src/Dockerfile +++ b/container/docker/src/Dockerfile @@ -1,4 +1,4 @@ -FROM python:latest +FROM python:3.8 LABEL maintainer="Jason Ross " @@ -24,6 +24,9 @@ LABEL \ # Copy helper scripts to container COPY ./bin /root/bin +# Install any additional software +RUN ["/bin/bash", "-c", "/root/bin/container-install-additional.sh"] + # Set a nice message RUN ["/bin/bash", "-c", "/root/bin/container-set-motd.sh"] @@ -39,5 +42,8 @@ RUN ["/bin/bash", "-c", "/root/bin/container-install-gcp.sh"] # Install ScoutSuite RUN ["/bin/bash", "-c", "/root/bin/container-install-scoutsuite.sh"] -# Entrypoint +# Remove scripts +RUN ["rm", "-rf", "/root/bin"] + +# Command CMD ["/bin/bash"] \ No newline at end of file diff --git a/container/docker/src/bin/container-install-additional.sh b/container/docker/src/bin/container-install-additional.sh new file mode 100755 index 000000000..da24cd350 --- /dev/null +++ b/container/docker/src/bin/container-install-additional.sh @@ -0,0 +1,5 @@ +#!/bin/bash +apt-get update +apt-get install -y vim nano + +echo -e "Additional Software Installation Complete!\n\n" \ No newline at end of file diff --git a/container/docker/src/bin/container-install-azure.sh b/container/docker/src/bin/container-install-azure.sh index 1255b6de3..8e9024072 100755 --- a/container/docker/src/bin/container-install-azure.sh +++ b/container/docker/src/bin/container-install-azure.sh @@ -20,25 +20,25 @@ echo -e "\n\nAzure CLI Installation Starting...\n\n" # manual process -# add msft gpg key to apt -curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.asc.gpg - -# set the right repo name -CLI_REPO=$(lsb_release -cs) - -# MSFT has no repo for focal yet, force the system to use eoan instead -if [[ ${CLI_REPO} -eq "focal" ]]; then - CLI_REPO="eoan" -fi - -# add the msft repo to apt -echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ ${CLI_REPO} main" \ - > /etc/apt/sources.list.d/azure-cli.list - -# install the software -apt-get update && apt-get install -y azure-cli - -# curl -sL https://aka.ms/InstallAzureCLIDeb | bash +# # add msft gpg key to apt +# curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.asc.gpg +# +# # set the right repo name +# CLI_REPO=$(lsb_release -cs) +# +# # MSFT has no repo for focal yet, force the system to use eoan instead +# if [[ ${CLI_REPO} -eq "focal" ]]; then +# CLI_REPO="eoan" +# fi +# +# # add the msft repo to apt +# echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ ${CLI_REPO} main" \ +# > /etc/apt/sources.list.d/azure-cli.list +# +# # install the software +# apt-get update && apt-get install -y azure-cli + +curl -sL https://aka.ms/InstallAzureCLIDeb | bash echo -e "\n" az --version From 4dca0e4f7d4f8691bf1c05e6ea9bf11a4f971f27 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Fri, 28 Aug 2020 10:38:57 -0400 Subject: [PATCH 217/312] added less to install-additional --- container/docker/src/bin/container-install-additional.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/container/docker/src/bin/container-install-additional.sh b/container/docker/src/bin/container-install-additional.sh index da24cd350..3502d7fb1 100755 --- a/container/docker/src/bin/container-install-additional.sh +++ b/container/docker/src/bin/container-install-additional.sh @@ -1,5 +1,5 @@ #!/bin/bash apt-get update -apt-get install -y vim nano +apt-get install -y vim nano less -echo -e "Additional Software Installation Complete!\n\n" \ No newline at end of file +echo -e "Additional Software Installation Complete!\n\n" From 6fc0dae9177b012dd7c9cf826c15052be1ec95d9 Mon Sep 17 00:00:00 2001 From: Rami McCarthy Date: Sat, 29 Aug 2020 16:39:35 -0400 Subject: [PATCH 218/312] Scaffhold for GuardDuty --- ScoutSuite/output/data/inc-scoutsuite/scoutsuite.js | 2 ++ ScoutSuite/providers/aws/facade/base.py | 8 ++++++++ ScoutSuite/providers/aws/metadata.json | 7 +++++++ ScoutSuite/providers/aws/services.py | 9 +++++++++ ScoutSuite/utils.py | 1 + 5 files changed, 27 insertions(+) diff --git a/ScoutSuite/output/data/inc-scoutsuite/scoutsuite.js b/ScoutSuite/output/data/inc-scoutsuite/scoutsuite.js index 09134ece1..c9c5ea5bd 100755 --- a/ScoutSuite/output/data/inc-scoutsuite/scoutsuite.js +++ b/ScoutSuite/output/data/inc-scoutsuite/scoutsuite.js @@ -1208,6 +1208,8 @@ function makeTitle(title) { return 'DocumentDB' } else if (title === 'dynamodb') { return 'DynamoDB' + } else if (title === 'guardduty') { + return 'GuardDuty' } else if (title === 'secretsmanager') { return 'Secrets Manager' } else if (title === 'elasticache') { diff --git a/ScoutSuite/providers/aws/facade/base.py b/ScoutSuite/providers/aws/facade/base.py index 74dcbe818..f74c01637 100755 --- a/ScoutSuite/providers/aws/facade/base.py +++ b/ScoutSuite/providers/aws/facade/base.py @@ -51,6 +51,10 @@ from ScoutSuite.providers.aws.facade.eks_private import EKSFacade except ImportError: pass +try: + from ScoutSuite.providers.aws.facade.guardduty_private import GuardDutyFacade +except ImportError: + pass class AWSFacade(AWSBaseFacade): @@ -281,3 +285,7 @@ def _instantiate_facades(self): self.eks = EKSFacade(self.session) except NameError: pass + try: + self.guardduty = GuardDuty(self.session) + except NameError: + pass diff --git a/ScoutSuite/providers/aws/metadata.json b/ScoutSuite/providers/aws/metadata.json index 131db99cb..b5aba6320 100755 --- a/ScoutSuite/providers/aws/metadata.json +++ b/ScoutSuite/providers/aws/metadata.json @@ -399,6 +399,13 @@ } } }, + "guardduty": { + "resources": { + "detectors": { + "path": "services.guardduty.regions.id.detectors" + } + } + }, "kms": { "resources": { "keys": { diff --git a/ScoutSuite/providers/aws/services.py b/ScoutSuite/providers/aws/services.py index c5ef852f9..70f9d27ac 100755 --- a/ScoutSuite/providers/aws/services.py +++ b/ScoutSuite/providers/aws/services.py @@ -47,6 +47,10 @@ from ScoutSuite.providers.aws.resources.private_eks.base import EKS except ImportError: pass +try: + from ScoutSuite.providers.aws.resources.private_guardduty.base import GuardDuty +except ImportError: + pass class AWSServicesConfig(BaseServicesConfig): @@ -61,6 +65,7 @@ class AWSServicesConfig(BaseServicesConfig): :ivar ecs: ECS configuration :ivar ecr: ECR configuration :ivar eks: EKS configuration + :ivar guarduty: GuardDuty configuration :ivar iam: IAM configuration :ivar kms: KMS configuration :ivar rds: RDS configuration @@ -124,6 +129,10 @@ def __init__(self, credentials=None, **kwargs): self.eks = EKS(facade) except NameError as _: pass + try: + self.guardduty = GuardDuty(facade) + except NameError as _: + pass def _is_provider(self, provider_name): return provider_name == 'aws' diff --git a/ScoutSuite/utils.py b/ScoutSuite/utils.py index 0c72b57da..c2cde17c7 100755 --- a/ScoutSuite/utils.py +++ b/ScoutSuite/utils.py @@ -24,6 +24,7 @@ 'elbv2': 'ELBv2', 'eks': 'EKS', 'elasticache': 'ElastiCache', + 'guardduty': 'GuardDuty', 'lambda': 'Lambda', 'awslambda': 'Lambda', 'redshift': 'RedShift', From 3d6303b016c6954b1e073ea6e7c442d3891d0d80 Mon Sep 17 00:00:00 2001 From: Rami McCarthy Date: Sat, 29 Aug 2020 17:31:16 -0400 Subject: [PATCH 219/312] fix facade ref --- ScoutSuite/providers/aws/facade/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/providers/aws/facade/base.py b/ScoutSuite/providers/aws/facade/base.py index f74c01637..bf7ff8029 100755 --- a/ScoutSuite/providers/aws/facade/base.py +++ b/ScoutSuite/providers/aws/facade/base.py @@ -286,6 +286,6 @@ def _instantiate_facades(self): except NameError: pass try: - self.guardduty = GuardDuty(self.session) + self.guardduty = GuardDutyFacade(self.session) except NameError: pass From c28bfc8507746e042964b9cc97ce3fa85f9d96cd Mon Sep 17 00:00:00 2001 From: Rami McCarthy Date: Sat, 29 Aug 2020 20:15:25 -0400 Subject: [PATCH 220/312] Gather addtional context for Cloudformation Stacks --- .../services.cloudformation.regions.id.stacks.html | 11 +++++++++++ ScoutSuite/providers/aws/facade/cloudformation.py | 13 ++++++++++++- .../aws/resources/cloudformation/stacks.py | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.cloudformation.regions.id.stacks.html b/ScoutSuite/output/data/html/partials/aws/services.cloudformation.regions.id.stacks.html index 62571b6f0..8bc5e1aa7 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.cloudformation.regions.id.stacks.html +++ b/ScoutSuite/output/data/html/partials/aws/services.cloudformation.regions.id.stacks.html @@ -23,6 +23,17 @@

    Information

    Termination protection enabled: {{EnableTerminationProtection}}
    Configuration has drifted: {{drifted}}
    Deletion policy: {{deletion_policy}}
    +
    Notification ARNs: + +
      + {{#each notificationARNs}} +
    • {{this}}
    • + {{else}} +
    • None
    • + {{/each}} +
    +
    +

    Capabilities {{> count_badge count=Capabilities.length}}

    diff --git a/ScoutSuite/providers/aws/facade/cloudformation.py b/ScoutSuite/providers/aws/facade/cloudformation.py index 2593eadf7..4b5365d52 100755 --- a/ScoutSuite/providers/aws/facade/cloudformation.py +++ b/ScoutSuite/providers/aws/facade/cloudformation.py @@ -19,7 +19,7 @@ async def get_stacks(self, region: str): else: stacks = [stack for stack in stacks if not CloudFormation._is_stack_deleted(stack)] await get_and_set_concurrently( - [self._get_and_set_description, self._get_and_set_template, self._get_and_set_policy], + [self._get_and_set_description, self._get_and_set_template, self._get_and_set_policy, self._get_stack_notifications], stacks, region=region) finally: return stacks @@ -54,6 +54,17 @@ async def _get_and_set_policy(self, stack: {}, region: str): if 'StackPolicyBody' in stack_policy: stack['policy'] = json.loads(stack_policy['StackPolicyBody']) + async def _get_stack_notifications(self, stack: {}, region: str): + client = AWSFacadeUtils.get_client('cloudformation', self.session, region) + try: + stack_notifications = await run_concurrently( + lambda: client.describe_stacks(StackName=stack['StackName'])['Stacks']) + except Exception as e: + print_exception(f'Failed to describe CloudFormation stack: {e}') + else: + if 'NotificationARNs' in stack_notifications: + stack['NotificationARNs'] = stack_notifications['NotificationARNs'] + @staticmethod def _is_stack_deleted(stack): return stack.get('StackStatus', None) == 'DELETE_COMPLETE' diff --git a/ScoutSuite/providers/aws/resources/cloudformation/stacks.py b/ScoutSuite/providers/aws/resources/cloudformation/stacks.py index 7909ba24a..18db43e9d 100755 --- a/ScoutSuite/providers/aws/resources/cloudformation/stacks.py +++ b/ScoutSuite/providers/aws/resources/cloudformation/stacks.py @@ -22,7 +22,7 @@ def _parse_stack(self, raw_stack): 'StackDriftStatus'] == 'DRIFTED' raw_stack['termination_protection'] = raw_stack['EnableTerminationProtection'] raw_stack['arn'] = raw_stack['id'] - + raw_stack['notificationARNs'] = raw_stack['NotificationARNs'] template = raw_stack.pop('template') raw_stack['deletion_policy'] = self.has_deletion_policy(template) From 49d013586f92f7539e7b9f4def00c8fb42970e54 Mon Sep 17 00:00:00 2001 From: Juan Jose Date: Tue, 1 Sep 2020 12:00:58 +0200 Subject: [PATCH 221/312] Added tags to users --- ScoutSuite/providers/aws/facade/iam.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ScoutSuite/providers/aws/facade/iam.py b/ScoutSuite/providers/aws/facade/iam.py index 4bdf5fbde..af9f44a3e 100755 --- a/ScoutSuite/providers/aws/facade/iam.py +++ b/ScoutSuite/providers/aws/facade/iam.py @@ -99,6 +99,7 @@ async def get_users(self): await get_and_set_concurrently( [functools.partial(self._get_and_set_inline_policies, iam_resource_type='user'), self._get_and_set_user_groups, + self._get_and_set_user_tags, self._get_and_set_user_login_profile, self._get_and_set_user_access_keys, self._get_and_set_user_mfa_devices], @@ -124,6 +125,10 @@ async def _get_and_set_user_groups(self, user: {}): 'iam', None, self.session, 'list_groups_for_user', 'Groups', UserName=user['UserName']) user['groups'] = [group['GroupName'] for group in groups] + async def _get_and_set_user_tags(self, user: {}): + client = AWSFacadeUtils.get_client('iam', self.session) + user['tags'] = client.list_user_tags(UserName=user['UserName']) + async def get_roles(self): roles = await AWSFacadeUtils.get_all_pages('iam', None, self.session, 'list_roles', 'Roles') for role in roles: From f1c5c71d5466086338e202b2e907e6fb8fd40488 Mon Sep 17 00:00:00 2001 From: Rami McCarthy Date: Tue, 1 Sep 2020 10:55:49 -0400 Subject: [PATCH 222/312] improve rationale, id_suffix, fix #823 --- .../findings/iam-inline-policy-allows-non-sts-action.json | 7 ++++--- .../findings/iam-managed-policy-allows-non-sts-action.json | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/iam-inline-policy-allows-non-sts-action.json b/ScoutSuite/providers/aws/rules/findings/iam-inline-policy-allows-non-sts-action.json index 7e02c749d..5aacfc5c2 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-inline-policy-allows-non-sts-action.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-inline-policy-allows-non-sts-action.json @@ -1,6 +1,6 @@ { "description": "Inline _ARG_0_ Policy Allows Non STS Action", - "rationale": "This configuration goes against organizational policies.", + "rationale": "When the principle of least privilege is implemented by exclusively using roles for privilege management, users should only be granted permissions to assume roles. This policy may violate that organizational standard.", "references": [ "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html" ], @@ -33,5 +33,6 @@ "IAM entity type", "Service", "Action" - ] -} \ No newline at end of file + ], + "id_suffix": "inline_non_sts" +} diff --git a/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-non-sts-action.json b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-non-sts-action.json index 5109cfc69..49b54d579 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-non-sts-action.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-non-sts-action.json @@ -1,6 +1,6 @@ { "description": "Managed Policy Allows Non STS Action", - "rationale": "This configuration goes against organizational policies.", + "rationale": "When the principle of least privilege is implemented by exclusively using roles for privilege management, users should only be granted permissions to assume roles. This policy may violate that organizational standard.", "references": [ "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html" ], @@ -31,5 +31,6 @@ "arg_names": [ "Service", "Action" - ] -} \ No newline at end of file + ], + "id_suffix": "managed_non_sts" +} From c11989cae0d3283bcc7c2345749b1d8683f39171 Mon Sep 17 00:00:00 2001 From: Juan Jose Date: Wed, 2 Sep 2020 15:04:58 +0200 Subject: [PATCH 223/312] Show user tags on HTML --- .../output/data/html/partials/aws/services.iam.users.html | 6 ++++++ ScoutSuite/providers/aws/resources/iam/users.py | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.iam.users.html b/ScoutSuite/output/data/html/partials/aws/services.iam.users.html index f92b7450b..c70558327 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.iam.users.html +++ b/ScoutSuite/output/data/html/partials/aws/services.iam.users.html @@ -7,6 +7,12 @@

    {{name}}

    Information

    Creation date: {{CreateDate}}
    +

    Tags:

    +
      + {{#each Tags}} +
    • {{Key}} - {{Value}}
    • + {{/each}} +

    Authentication methods

    diff --git a/ScoutSuite/providers/aws/resources/iam/users.py b/ScoutSuite/providers/aws/resources/iam/users.py index 1474256a9..ace1dcb7a 100755 --- a/ScoutSuite/providers/aws/resources/iam/users.py +++ b/ScoutSuite/providers/aws/resources/iam/users.py @@ -16,5 +16,6 @@ def _parse_user(self, raw_user): raw_user['id'] = raw_user.pop('UserId') raw_user['name'] = raw_user.pop('UserName') raw_user['arn'] = raw_user.pop('Arn') - + if (len(raw_user['tags']['Tags']) > 0): + raw_user['Tags'] = raw_user['tags']['Tags'] return raw_user['id'], raw_user From 375e7876e360b211473b277dc66f35debc892019 Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 5 Sep 2020 12:52:32 +0200 Subject: [PATCH 224/312] Add badges --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 854457468..024c9db1b 100755 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ [![CodeCov](https://codecov.io/gh/nccgroup/ScoutSuite/branch/master/graph/badge.svg)](https://codecov.io/gh/nccgroup/ScoutSuite) [![PyPI version](https://badge.fury.io/py/ScoutSuite.svg)](https://badge.fury.io/py/ScoutSuite) [![PyPI downloads](https://img.shields.io/pypi/dm/scoutsuite)](https://img.shields.io/pypi/dm/scoutsuite) +[![Docker Hub](https://img.shields.io/badge/Docker%20Hub-rossja%2Fncc--scoutsuite-blue)](https://hub.docker.com/r/rossja/ncc-scoutsuite/) +[![Docker Pulls](https://img.shields.io/docker/pulls/rossja/ncc-scoutsuite.svg?style=flat-square)](https://hub.docker.com/r/rossja/ncc-scoutsuite/) ## Description From 198e9e8934ca89f171df109b13875665d30d4443 Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 5 Sep 2020 12:52:42 +0200 Subject: [PATCH 225/312] Prepare for wiki move --- container/docker/README.md | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/container/docker/README.md b/container/docker/README.md index 43bdf8992..e8cb9446d 100644 --- a/container/docker/README.md +++ b/container/docker/README.md @@ -1,11 +1,4 @@ -# NCC-ScoutSuite - -[![Docker build status](https://img.shields.io/docker/cloud/build/rossja/ncc-scoutsuite)]( https://img.shields.io/docker/cloud/build/rossja/ncc-scoutsuite) -[![](https://images.microbadger.com/badges/image/rossja/ncc-scoutsuite.svg)](https://microbadger.com/images/rossja/ncc-scoutsuite) -[![](https://images.microbadger.com/badges/version/rossja/ncc-scoutsuite.svg)](https://microbadger.com/images/rossja/ncc-scoutsuite) -[![Docker Pulls](https://img.shields.io/docker/pulls/rossja/ncc-scoutsuite.svg?style=flat-square)](https://hub.docker.com/r/rossja/ncc-scoutsuite/) -[![Docker Hub](https://img.shields.io/badge/Docker%20Hub-rossja%2Fncc--scoutsuite-blue)](https://hub.docker.com/r/rossja/ncc-scoutsuite/) - +# Docker Image ## Quick Links @@ -20,7 +13,7 @@ ## Overview -This image is an Ubuntu based container that comes with all pre-requisite software required to run ScoutSuite. It's based on the Ubuntu 20.04 docker base. The current version of ScoutSuite installed in the [DockerHub image](https://hub.docker.com/r/rossja/ncc-scoutsuite) is: `Scout Suite 5.8.1` +This image is an Ubuntu based container that comes with all pre-requisite software required to run ScoutSuite. It's based on the Ubuntu 20.04 docker base. The following CLI tools are also installed: @@ -61,7 +54,6 @@ gsutil 4.50 kubectl 2020.05.01 ~~~ - ---- @@ -72,10 +64,10 @@ There are two ways to run the ScoutSuite Docker image: 1. Grab the image from DockerHub and run it: `docker run -it rossja/ncc-scoutsuite bash` 1. Build the container from this source: - 1. Clone the [ScoutSuite GitHub Repo](https://github.com/nccgroup/ScoutSuite) - 1. Change to the `ScoutSuite/container/docker` directory - 1. Run `docker-compose up --build` to create the container - 1. Run ScoutSuite in the container using `docker run -it scoutsuite bash`. + 1. Clone the [ScoutSuite GitHub Repo](https://github.com/nccgroup/ScoutSuite) + 1. Change to the `ScoutSuite/container/docker` directory + 1. Run `docker-compose up --build` to create the container + 1. Run ScoutSuite in the container using `docker run -it scoutsuite bash`. ---- @@ -99,7 +91,6 @@ root@1350ede02c47:~# source scoutsuite/bin/activate * Since this is a container, there's no GUI, and no browser, so passing the `--no-browser` probably makes sense. * Likewise, setting a specific report directory using something like `--report-dir /root/scout-report` is a good idea. *(The default location is `$HOME/scoutsuite-report`)* - ---- @@ -141,7 +132,6 @@ scout aws --profile scout-user01 --no-browser --report-dir /root/scout-report 2020-01-03 17:46:16 460837197ae9 scout[7087] INFO Creating /root/scout-report/aws-scout-user01.html ~~~ - ---- @@ -188,16 +178,17 @@ You can shortcut this process by simply combining the `docker ps` command with t docker cp $(docker ps -f ancestor=rossja/ncc-scoutsuite --format "{{.ID}}"):/root/scout-report ./ ~~~ - ---- ## Viewing the Output File The report itself can be viewed using a web browser, by opening the file `./scout-report/aws-.html`. + For example, if you ran the scout tool against AWS using the profile `scout-user01`, the report HTML file is at `./scout-report/aws-scout-01.html`. **NOTES**: **AWS**: If you used the default AWS profile credentials, the profile name is the numerical ID portion of the ARN for the user, rather than a specific profile or user name. + **GCP**: The scout report will be named using the project ID that was passed in. From e9351b2109144a2881ef2d63cf1774d39bb6f279 Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 5 Sep 2020 12:58:50 +0200 Subject: [PATCH 226/312] Remove useless suffixes --- .../findings/iam-inline-policy-allows-non-sts-action.json | 3 +-- .../findings/iam-managed-policy-allows-non-sts-action.json | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/iam-inline-policy-allows-non-sts-action.json b/ScoutSuite/providers/aws/rules/findings/iam-inline-policy-allows-non-sts-action.json index 5aacfc5c2..ce7b88bd5 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-inline-policy-allows-non-sts-action.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-inline-policy-allows-non-sts-action.json @@ -33,6 +33,5 @@ "IAM entity type", "Service", "Action" - ], - "id_suffix": "inline_non_sts" + ] } diff --git a/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-non-sts-action.json b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-non-sts-action.json index 49b54d579..bb1f2ef82 100755 --- a/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-non-sts-action.json +++ b/ScoutSuite/providers/aws/rules/findings/iam-managed-policy-allows-non-sts-action.json @@ -31,6 +31,5 @@ "arg_names": [ "Service", "Action" - ], - "id_suffix": "managed_non_sts" + ] } From 04a334158ab5cca4b38f99c4fd79339040408bdd Mon Sep 17 00:00:00 2001 From: xga Date: Sat, 5 Sep 2020 16:24:12 +0200 Subject: [PATCH 227/312] Normalize implementation --- .../html/partials/aws/services.iam.users.html | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/aws/services.iam.users.html b/ScoutSuite/output/data/html/partials/aws/services.iam.users.html index c70558327..5a4ccffd9 100755 --- a/ScoutSuite/output/data/html/partials/aws/services.iam.users.html +++ b/ScoutSuite/output/data/html/partials/aws/services.iam.users.html @@ -6,13 +6,7 @@

    {{name}}

    Information

    -
    Creation date: {{CreateDate}}
    -

    Tags:

    -
      - {{#each Tags}} -
    • {{Key}} - {{Value}}
    • - {{/each}} -
    +
    Creation date: {{format_date CreateDate}}

    Authentication methods

    @@ -59,6 +53,16 @@

    Groups

    {{> services.iam.inline_policies resource_type = 'users' resource_id = id}} {{> services.iam.policies_list resource_type = 'users' resource_id = id}} + {{#if Tags}} +
    +

    Tags

    +
      + {{#each Tags}} +
    • {{Key}}: {{Value}}
    • + {{/each}} +
    +
    + {{/if}} diff --git a/ScoutSuite/providers/aws/provider.py b/ScoutSuite/providers/aws/provider.py index 7a6b1780c..d5f40d22f 100755 --- a/ScoutSuite/providers/aws/provider.py +++ b/ScoutSuite/providers/aws/provider.py @@ -79,6 +79,9 @@ def preprocessing(self, ip_ranges=None, ip_ranges_name_key=None): if 'ec2' in self.service_list and 'iam' in self.service_list: self._match_instances_and_roles() + + if 'awslambda' in self.service_list and 'iam' in self.service_list: + self._match_lambdas_and_roles() if 'elbv2' in self.service_list and 'ec2' in self.service_list: self._add_security_group_data_to_elbv2() @@ -412,6 +415,25 @@ def _match_instances_and_roles(self): iam_config['roles'][role_id]['instances_count'] += len( role_instances[instance_profile_id]) + def _match_lambdas_and_roles(self): + if self.services.get('awslambda') and self.services.get('iam'): + awslambda_config = self.services['awslambda'] + iam_config = self.services['iam'] + awslambda_funtions = {} + for r in awslambda_config['regions']: + for lambda_function in awslambda_config['regions'][r]['functions']: + awslambda_function = awslambda_config['regions'][r]['functions'][lambda_function] + awslambda_function['region'] = r + if awslambda_function['role_arn'] in awslambda_funtions: + awslambda_funtions[awslambda_function['role_arn']][awslambda_function['name']] = awslambda_function + else: + awslambda_funtions[awslambda_function['role_arn']] = {awslambda_function['name']: awslambda_function} + for role_id in iam_config['roles']: + iam_config['roles'][role_id]['awslambdas_count'] = 0 + if iam_config['roles'][role_id]['arn'] in awslambda_funtions: + iam_config['roles'][role_id]['awslambdas'] = awslambda_funtions[iam_config['roles'][role_id]['arn']] + iam_config['roles'][role_id]['awslambdas_count'] = len(awslambda_funtions[iam_config['roles'][role_id]['arn']]) + def process_vpc_peering_connections_callback(self, current_config, path, current_path, pc_id, callback_args): # Create a list of peering connection IDs in each VPC From 7ed1f0ce56222a44ed222171d9211a408c70552a Mon Sep 17 00:00:00 2001 From: Viatcheslav Zhilin Date: Tue, 8 Sep 2020 17:21:25 +0200 Subject: [PATCH 237/312] Improved NSG port/s management --- ScoutSuite/core/conditions.py | 21 +++++ .../resources/network/security_groups.py | 78 ++----------------- ...-security-groups-rule-inbound-service.json | 2 +- 3 files changed, 27 insertions(+), 74 deletions(-) diff --git a/ScoutSuite/core/conditions.py b/ScoutSuite/core/conditions.py index 83d4b424a..7e602a802 100755 --- a/ScoutSuite/core/conditions.py +++ b/ScoutSuite/core/conditions.py @@ -210,6 +210,27 @@ def pass_condition(b, test, a): elif test == 'notInSubnets': result = (not pass_condition(b, 'inSubnets', a)) + # Port/port ranges tests + elif test == 'portsInPortList': + if not type(b) == list: + b = [b] + if not type(a) == list: + a = [a] + for port_range in b: + if '-' in port_range: + bottom_limit_port = int(port_range.split('-')[0]) + upper_limit_port = int(port_range.split('-')[1]) + for port in a: + if type(port) != int: + port = int(port) + if bottom_limit_port <= port <= upper_limit_port: + return True + else: #A single port + for port in a: + if port == port_range: + return True + return False + # Policy statement tests elif test == 'containAction': result = False diff --git a/ScoutSuite/providers/azure/resources/network/security_groups.py b/ScoutSuite/providers/azure/resources/network/security_groups.py index c91b799a8..c7c234fad 100755 --- a/ScoutSuite/providers/azure/resources/network/security_groups.py +++ b/ScoutSuite/providers/azure/resources/network/security_groups.py @@ -45,11 +45,6 @@ def _parse_network_security_group(self, network_security_group): identifier = get_non_provider_id(network_interface.id) network_security_group_dict['network_interfaces'][identifier] = {'id': identifier} - # FIXME this is broken and badly implemented (not efficient at all) - # exposed_ports = self._parse_exposed_ports(network_security_group) - # network_security_group_dict['exposed_ports'] = exposed_ports - # network_security_group_dict['exposed_port_ranges'] = self._format_ports(exposed_ports) - return network_security_group_dict['id'], network_security_group_dict def _parse_security_rules(self, network_security_group): @@ -88,18 +83,13 @@ def _parse_security_rule(self, rule, default=False): else: security_rule_dict['source_address_prefixes_is_asg'] = False - source_port_ranges = self._merge_prefixes_or_ports(rule.source_port_range, rule.source_port_ranges) - security_rule_dict['source_port_ranges'] = source_port_ranges - security_rule_dict['source_ports'] = self._parse_ports(source_port_ranges) + security_rule_dict['source_port_ranges'] = self._merge_prefixes_or_ports(rule.source_port_range, rule.source_port_ranges) + security_rule_dict['source_ports'] = ['0-65535'] if '*' in security_rule_dict['source_port_ranges'] else security_rule_dict['source_port_ranges'] - destination_address_prefixes = self._merge_prefixes_or_ports(rule.destination_address_prefix, - rule.destination_address_prefixes) - security_rule_dict['destination_address_prefixes'] = destination_address_prefixes + security_rule_dict['destination_address_prefixes'] = self._merge_prefixes_or_ports(rule.destination_address_prefix, rule.destination_address_prefixes) - destination_port_ranges = self._merge_prefixes_or_ports(rule.destination_port_range, - rule.destination_port_ranges) - security_rule_dict['destination_port_ranges'] = destination_port_ranges - security_rule_dict['destination_ports'] = self._parse_ports(destination_port_ranges) + security_rule_dict['destination_port_ranges'] = self._merge_prefixes_or_ports(rule.destination_port_range, rule.destination_port_ranges) + security_rule_dict['destination_ports'] = ['0-65535'] if '*' in security_rule_dict['destination_port_ranges'] else security_rule_dict['destination_port_ranges'] security_rule_dict['etag'] = rule.etag @@ -107,66 +97,8 @@ def _parse_security_rule(self, rule, default=False): return security_rule_dict['id'], security_rule_dict - def _parse_ports(self, port_ranges): - # FIXME this is inefficient - ports = set() - for pr in port_ranges: - if pr == "*": - for p in range(0, 65535 + 1): - ports.add(p) - break - elif "-" in pr: - lower, upper = pr.split("-") - for p in range(int(lower), int(upper) + 1): - ports.add(p) - else: - ports.add(int(pr)) - ports = list(ports) - ports.sort() - return ports - - def _parse_exposed_ports(self, network_security_group): - exposed_ports = set() - - # Sort by priority. - rules = network_security_group.default_security_rules + network_security_group.security_rules - rules.sort(key=lambda x: x.priority, reverse=True) - - for sr in rules: - if sr.direction == "Inbound" and (sr.source_address_prefix == "*" - or sr.source_address_prefix == "Internet"): - port_ranges = self._merge_prefixes_or_ports(sr.destination_port_range, - sr.destination_port_ranges) - ports = self._parse_ports(port_ranges) - if sr.access == "Allow": - for p in ports: - exposed_ports.add(p) - else: - for p in ports: - exposed_ports.discard(p) - exposed_ports = list(exposed_ports) - exposed_ports.sort() - return exposed_ports - def _merge_prefixes_or_ports(self, port_range, port_ranges): port_ranges = port_ranges if port_ranges else [] if port_range: port_ranges.append(port_range) return port_ranges - - def _format_ports(self, ports): - # FIXME this is inefficient - port_ranges = [] - start = None - for i in range(0, 65535 + 1): - if i in ports: - if not start: - start = i - else: - if start: - if i - 1 == start: - port_ranges.append(str(start)) - else: - port_ranges.append(str(start) + "-" + str(i - 1)) - start = None - return port_ranges diff --git a/ScoutSuite/providers/azure/rules/findings/network-security-groups-rule-inbound-service.json b/ScoutSuite/providers/azure/rules/findings/network-security-groups-rule-inbound-service.json index 12f3fec83..d44c3802a 100755 --- a/ScoutSuite/providers/azure/rules/findings/network-security-groups-rule-inbound-service.json +++ b/ScoutSuite/providers/azure/rules/findings/network-security-groups-rule-inbound-service.json @@ -15,7 +15,7 @@ "and", [ "network.subscriptions.id.security_groups.id.security_rules.id.destination_ports", - "containAtLeastOneOf", + "portsInPortList", "_ARG_1_" ], [ From 3fde85ee3c36067ec8f35e84eecc83d2cb8df19e Mon Sep 17 00:00:00 2001 From: Viatcheslav Zhilin Date: Tue, 8 Sep 2020 17:48:36 +0200 Subject: [PATCH 238/312] Normalize implementation --- ScoutSuite/core/conditions.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/core/conditions.py b/ScoutSuite/core/conditions.py index 7e602a802..c20f920e5 100755 --- a/ScoutSuite/core/conditions.py +++ b/ScoutSuite/core/conditions.py @@ -212,6 +212,7 @@ def pass_condition(b, test, a): # Port/port ranges tests elif test == 'portsInPortList': + result = False if not type(b) == list: b = [b] if not type(a) == list: @@ -224,12 +225,13 @@ def pass_condition(b, test, a): if type(port) != int: port = int(port) if bottom_limit_port <= port <= upper_limit_port: - return True + result = True + break else: #A single port for port in a: if port == port_range: - return True - return False + result = True + break # Policy statement tests elif test == 'containAction': From 76eed3954b8e22216eafeaef0e27b75c74c619f1 Mon Sep 17 00:00:00 2001 From: Viatcheslav Zhilin Date: Wed, 9 Sep 2020 12:40:05 +0200 Subject: [PATCH 239/312] Added: parameter to check if a security group has default rules --- .../aws/resources/ec2/securitygroups.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ScoutSuite/providers/aws/resources/ec2/securitygroups.py b/ScoutSuite/providers/aws/resources/ec2/securitygroups.py index 083edcd8b..b3ca38071 100755 --- a/ScoutSuite/providers/aws/resources/ec2/securitygroups.py +++ b/ScoutSuite/providers/aws/resources/ec2/securitygroups.py @@ -41,8 +41,30 @@ def _parse_security_group(self, raw_security_group): raw_security_group['IpPermissionsEgress']) security_group['rules']['egress']['protocols'] = egress_protocols security_group['rules']['egress']['count'] = egress_rules_count + + if self._has_default_egress_rule(raw_security_group['IpPermissionsEgress']) and self._has_default_ingress_rule(raw_security_group['IpPermissions'], raw_security_group['GroupId']): + security_group['is_default_configuration'] = True + else: + security_group['is_default_configuration'] = False + return security_group['id'], security_group + def _has_default_egress_rule(self, rule_list): + for rule in rule_list: + if rule['IpProtocol'] == '-1': + for ip_range in rule['IpRanges']: + if ip_range['CidrIp'] == '0.0.0.0/0': + return True + return False + + def _has_default_ingress_rule(self, rule_list, group_id): + for rule in rule_list: + if rule['IpProtocol'] == '-1': + for source_group in rule['UserIdGroupPairs']: + if source_group['GroupId'] == group_id: + return True + return False + def _parse_security_group_rules(self, rules): protocols = {} rules_count = 0 From 59dab9c4708040ceef5a849c47741f0514e753f1 Mon Sep 17 00:00:00 2001 From: Viatcheslav Zhilin Date: Wed, 9 Sep 2020 13:04:04 +0200 Subject: [PATCH 240/312] Added: a check if SG rules have default rules --- .../rules/findings/ec2-default-security-group-in-use.json | 5 +++++ .../findings/ec2-default-security-group-with-rules.json | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json index 1d705cfbe..05716660b 100755 --- a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-in-use.json @@ -35,6 +35,11 @@ "ec2.regions.id.vpcs.id.security_groups.id.", "withKey", "used_by" + ], + [ + "ec2.regions.id.vpcs.id.security_groups.id.is_default_configuration", + "true", + "" ] ], "id_suffix": "default_in_use" diff --git a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json index 172524721..df5a48cac 100755 --- a/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json +++ b/ScoutSuite/providers/aws/rules/findings/ec2-default-security-group-with-rules.json @@ -36,6 +36,11 @@ "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols", "notEmpty", "" + ], + [ + "ec2.regions.id.vpcs.id.security_groups.id.is_default_configuration", + "true", + "" ] ], "id_suffix": "default_with_rules" From c7f9f136f07cf7da9497f5bfcdff7c809613636a Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 9 Sep 2020 16:20:29 +0200 Subject: [PATCH 241/312] Minor change --- ScoutSuite/providers/aws/resources/ec2/instances.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ScoutSuite/providers/aws/resources/ec2/instances.py b/ScoutSuite/providers/aws/resources/ec2/instances.py index 4ada60bb9..284572d99 100755 --- a/ScoutSuite/providers/aws/resources/ec2/instances.py +++ b/ScoutSuite/providers/aws/resources/ec2/instances.py @@ -38,7 +38,11 @@ async def _parse_instance(self, raw_instance): instance['metadata_options'] = raw_instance['MetadataOptions'] - instance['iam_role'] = raw_instance['IamInstanceProfile']['Arn'].split('/')[-1] if 'IamInstanceProfile' in raw_instance else '' + + if 'IamInstanceProfile' in raw_instance: + instance['iam_role'] = raw_instance['IamInstanceProfile']['Arn'].split('/')[-1] + else: + instance['iam_role'] = None return id, instance From 70a6064db8ed96e2395d985d7fa39cf73ed3ee3a Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 9 Sep 2020 16:38:26 +0200 Subject: [PATCH 242/312] Improve error handling --- ScoutSuite/providers/aws/facade/awslambda.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/providers/aws/facade/awslambda.py b/ScoutSuite/providers/aws/facade/awslambda.py index c4ef157be..3710f2907 100755 --- a/ScoutSuite/providers/aws/facade/awslambda.py +++ b/ScoutSuite/providers/aws/facade/awslambda.py @@ -19,8 +19,10 @@ async def get_access_policy(self, function_name, region): policy = client.get_policy(FunctionName=function_name) if policy is not None and 'Policy' in policy: return json.loads(policy['Policy']) - except Exception: - # Policy not found for this function + except Exception as e: + # If there's no policy, it will return this exception. Hence why we ignore. + if "ResourceNotFoundException" not in str(e): + print_exception('Failed to get Lambda access policy: {}'.format(e)) return None async def get_role_with_managed_policies(self, role_name): @@ -37,7 +39,8 @@ async def get_role_with_managed_policies(self, role_name): policy['Document'] = document['PolicyVersion']['Document'] role['policies'] = managed_policies return role - except Exception: + except Exception as e: + print_exception('Failed to get role from managed policies: {}'.format(e)) return None From 5c535d10f66474cdf8e99ddf73eb5c20f7ba7a0a Mon Sep 17 00:00:00 2001 From: xga Date: Tue, 15 Sep 2020 14:13:16 +0200 Subject: [PATCH 243/312] Set correct dashboard name --- .../aws/rules/findings/s3-bucket-world-policy-arg.json | 2 +- .../aws/rules/findings/s3-bucket-world-policy-star.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-arg.json b/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-arg.json index bccc9288d..6264cc36a 100755 --- a/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-arg.json +++ b/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-arg.json @@ -1,7 +1,7 @@ { "description": "_ARG_0_ Actions Authorized to All Principals", "rationale": "Allowing IAM actions to all principals is contrary to the principle of least privilege and presents and opportunity for abuse. This policy should be reviewed to ensure it is secure and in line with the resource's intended use.", - "dashboard_name": "Buckets", + "dashboard_name": "Bucket Policy Statements", "display_path": "s3.buckets.id", "path": "s3.buckets.id.policy.Statement.id", "conditions": [ diff --git a/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-star.json b/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-star.json index 3a276cacd..34babf80e 100755 --- a/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-star.json +++ b/ScoutSuite/providers/aws/rules/findings/s3-bucket-world-policy-star.json @@ -19,7 +19,7 @@ "reference": "2.3" } ], - "dashboard_name": "Buckets", + "dashboard_name": "Bucket Policy Statements", "display_path": "s3.buckets.id", "path": "s3.buckets.id.policy.Statement.id", "conditions": [ From 6b4592ff71c70480872b122e794b8ad2a055cc94 Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 17 Sep 2020 10:00:18 +0200 Subject: [PATCH 244/312] Remove reference to Scout Suite --- ScoutSuite/output/data/html/partials/last_run_details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/last_run_details.html b/ScoutSuite/output/data/html/partials/last_run_details.html index 30e44e0f2..b6f1b5a84 100755 --- a/ScoutSuite/output/data/html/partials/last_run_details.html +++ b/ScoutSuite/output/data/html/partials/last_run_details.html @@ -20,7 +20,7 @@ {{#if last_run.run_parameters.regions}}

    Regions: {{last_run.run_parameters.regions}}

    {{/if}} -

    Report generated with Scout Suite version {{last_run.version}}

    +

    Version: {{last_run.version}}

    Using ruleset {{last_run.ruleset_name}}:

    {{last_run.ruleset_about}}

    From 0ad01e7e37c6e5aa9fb94384879b0f495ae2797c Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 17 Sep 2020 10:30:29 +0200 Subject: [PATCH 245/312] Use generic "Scout" term --- ScoutSuite/output/data/html/partials/last_run_details.html | 2 +- ScoutSuite/output/data/html/partials/metadata.html | 4 ++-- ScoutSuite/output/data/html/report.html | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/last_run_details.html b/ScoutSuite/output/data/html/partials/last_run_details.html index b6f1b5a84..1c41b2c37 100755 --- a/ScoutSuite/output/data/html/partials/last_run_details.html +++ b/ScoutSuite/output/data/html/partials/last_run_details.html @@ -20,7 +20,7 @@ {{#if last_run.run_parameters.regions}}

    Regions: {{last_run.run_parameters.regions}}

    {{/if}} -

    Version: {{last_run.version}}

    +

    Scout version: {{last_run.version}}

    Using ruleset {{last_run.ruleset_name}}:

    {{last_run.ruleset_about}}

    diff --git a/ScoutSuite/output/data/html/partials/metadata.html b/ScoutSuite/output/data/html/partials/metadata.html index aea9cf889..2921317c4 100755 --- a/ScoutSuite/output/data/html/partials/metadata.html +++ b/ScoutSuite/output/data/html/partials/metadata.html @@ -2,7 +2,7 @@ + + + + + + diff --git a/ScoutSuite/providers/gcp/facade/base.py b/ScoutSuite/providers/gcp/facade/base.py index b94a87058..d2b26fdf8 100755 --- a/ScoutSuite/providers/gcp/facade/base.py +++ b/ScoutSuite/providers/gcp/facade/base.py @@ -8,15 +8,10 @@ from ScoutSuite.providers.gcp.facade.kms import KMSFacade from ScoutSuite.providers.gcp.facade.stackdriverlogging import StackdriverLoggingFacade from ScoutSuite.providers.gcp.facade.stackdrivermonitoring import StackdriverMonitoringFacade +from ScoutSuite.providers.gcp.facade.gke import GKEFacade from ScoutSuite.providers.gcp.facade.utils import GCPFacadeUtils from ScoutSuite.utils import format_service_name -# Try to import proprietary facades -try: - from ScoutSuite.providers.gcp.facade.gke_private import GKEFacade -except ImportError: - pass - class GCPFacade(GCPBaseFacade): def __init__(self, diff --git a/ScoutSuite/providers/gcp/facade/gke.py b/ScoutSuite/providers/gcp/facade/gke.py new file mode 100644 index 000000000..40b8aa9ef --- /dev/null +++ b/ScoutSuite/providers/gcp/facade/gke.py @@ -0,0 +1,41 @@ +import re + +from ScoutSuite.core.console import print_exception +from ScoutSuite.providers.gcp.facade.base import GCPBaseFacade +from ScoutSuite.providers.utils import run_concurrently, get_and_set_concurrently + + +class GKEFacade(GCPBaseFacade): + def __init__(self, gce_facade): + super(GKEFacade, self).__init__('container', 'v1') + self._gce_facade = gce_facade + + async def get_clusters(self, project_id, zone): + try: + gke_client = self._get_client() + response = await run_concurrently( + lambda: gke_client.projects().zones().clusters().list(projectId=project_id, zone=zone).execute() + ) + clusters = response.get('clusters', []) + await get_and_set_concurrently([self._get_and_set_private_google_access_enabled], + clusters, project_id=project_id) + return clusters + except Exception as e: + print_exception('Failed to retrieve clusters: {}'.format(e)) + return [] + + async def _get_and_set_private_google_access_enabled(self, cluster, project_id): + try: + region = self._get_cluster_region(cluster) + subnetwork = await self._gce_facade.get_subnetwork(project_id, region, cluster['subnetwork']) + cluster['privateIpGoogleAccess'] = subnetwork.get('privateIpGoogleAccess') + except Exception as e: + print_exception('Failed to retrieve cluster private IP Google access config: {}'.format(e)) + cluster['privateIpGoogleAccess'] = None + + # The cluster location is given as -. See the the following link for more info: + # https://cloud.google.com/compute/docs/regions-zones/#identifying_a_region_or_zone + def _get_cluster_region(self, cluster): + region_regex = re.compile("(.+)-[^-]+") + result = region_regex.search(cluster['location']) + return result.group(1) diff --git a/ScoutSuite/providers/gcp/resources/gke/__init__.py b/ScoutSuite/providers/gcp/resources/gke/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ScoutSuite/providers/gcp/resources/gke/base.py b/ScoutSuite/providers/gcp/resources/gke/base.py new file mode 100644 index 000000000..418e90281 --- /dev/null +++ b/ScoutSuite/providers/gcp/resources/gke/base.py @@ -0,0 +1,19 @@ +from ScoutSuite.providers.gcp.resources.private_gke.zones import GKEZones +from ScoutSuite.providers.gcp.resources.projects import Projects + + +class KubernetesEngine(Projects): + _children = [ + (GKEZones, 'zones'), + ] + + async def fetch_all(self): + await Projects.fetch_all(self) + # Clusters are resources with 2 levels of filtering + # (project and zone), so we need to propagate their count up. + # Normally this would be done by setting the resource counts in the + # Zone class, but having a "zones_count" field in its + # dictionary causes errors in the rule engine. + self['clusters_count'] = sum(sum( + zone['clusters_count'] for zone in project['zones'].values()) for project in self['projects'].values()) + del self['zones_count'] diff --git a/ScoutSuite/providers/gcp/resources/gke/clusters.py b/ScoutSuite/providers/gcp/resources/gke/clusters.py new file mode 100644 index 000000000..bb3ac579d --- /dev/null +++ b/ScoutSuite/providers/gcp/resources/gke/clusters.py @@ -0,0 +1,72 @@ +from ScoutSuite.providers.base.resources.base import Resources +from ScoutSuite.providers.gcp.facade.base import GCPFacade +from ScoutSuite.providers.gcp.resources.private_gke.node_pools import NodePools +from ScoutSuite.providers.utils import get_non_provider_id + + +class Clusters(Resources): + def __init__(self, facade: GCPFacade, project_id, zone): + super(Clusters, self).__init__(facade) + self.project_id = project_id + self.zone = zone + + async def fetch_all(self): + raw_clusters = await self.facade.gke.get_clusters(self.project_id, self.zone) + for raw_cluster in raw_clusters: + cluster_id, cluster = await self._parse_cluster(raw_cluster) + self[cluster_id] = cluster + self[cluster_id]['node_pools'].fetch_all() + + async def _parse_cluster(self, raw_cluster): + cluster_dict = {} + cluster_dict['id'] = get_non_provider_id(raw_cluster['name']) + cluster_dict['name'] = raw_cluster['name'] + cluster_dict['alias_ip_enabled'] = raw_cluster.get('ipAllocationPolicy', {}).get('useIpAliases', False) + cluster_dict['basic_authentication_enabled'] = self._is_basic_authentication_enabled(raw_cluster) + cluster_dict['client_certificate_enabled'] = self._is_client_certificate_enabled(raw_cluster) + cluster_dict['dashboard_status'] = self._get_dashboard_status(raw_cluster) + cluster_dict['has_limited_scopes'] = self._has_limited_scopes(raw_cluster) + cluster_dict['image_type'] = raw_cluster.get('nodeConfig', {}).get('imageType', None) + cluster_dict['labels'] = raw_cluster.get('resourceLabels', []) + cluster_dict['has_labels'] = len(cluster_dict['labels']) > 0 + cluster_dict['legacy_abac_enabled'] = raw_cluster.get('legacyAbac', {}).get('enabled', False) + cluster_dict['logging_enabled'] = self._is_logging_enabled(raw_cluster) + cluster_dict['master_authorized_networks_enabled'] = raw_cluster.get( + 'masterAuthorizedNetworksConfig', {}).get('enabled', False) + cluster_dict['monitoring_enabled'] = self._is_monitoring_enabled(raw_cluster) + cluster_dict['network_policy_enabled'] = raw_cluster.get('networkPolicy', {}).get('enabled', False) + cluster_dict['node_pools'] = NodePools(raw_cluster) + cluster_dict['private_cluster_enabled'] = raw_cluster.get( + 'privateClusterConfig', {}).get('enablePrivateNodes', False) + cluster_dict['private_ip_google_access_enabled'] = raw_cluster.get('privateIpGoogleAccess', False) + cluster_dict['scopes'] = self._get_scopes(raw_cluster) + cluster_dict['service_account'] = raw_cluster.get('nodeConfig', {}).get('serviceAccount', None) + return cluster_dict['id'], cluster_dict + + def _is_basic_authentication_enabled(self, raw_cluster): + return raw_cluster['masterAuth'].get('username', None) != '' + + def _is_client_certificate_enabled(self, raw_cluster): + return raw_cluster['masterAuth'].get('clientCertificate', None) != '' + + def _is_logging_enabled(self, raw_cluster): + return raw_cluster['loggingService'] != 'none' + + def _is_monitoring_enabled(self, raw_cluster): + return raw_cluster['monitoringService'] != 'none' + + def _parse_scope(self, scope_url): + return scope_url.split('/')[-1] + + def _get_scopes(self, raw_cluster): + return [self._parse_scope(scope_url) for scope_url in raw_cluster['nodeConfig'].get('oauthScopes', [])] + + def _has_limited_scopes(self, raw_cluster): + minimum_scopes = {'devstorage.read_only', 'logging.write', 'monitoring'} + cluster_scopes = self._get_scopes(raw_cluster) + return all(scope in minimum_scopes for scope in cluster_scopes) + + def _get_dashboard_status(self, raw_cluster): + is_disabled = 'kubernetesDashboard' not in raw_cluster['addonsConfig'] or \ + raw_cluster['addonsConfig']['kubernetesDashboard'].get('disabled') + return 'Disabled' if is_disabled else 'Enabled' diff --git a/ScoutSuite/providers/gcp/resources/gke/node_pools.py b/ScoutSuite/providers/gcp/resources/gke/node_pools.py new file mode 100644 index 000000000..e39b70873 --- /dev/null +++ b/ScoutSuite/providers/gcp/resources/gke/node_pools.py @@ -0,0 +1,27 @@ +from ScoutSuite.providers.base.resources.base import Resources + + +class NodePools(Resources): + def __init__(self, cluster): + super(NodePools, self).__init__(service_facade=None) + self.cluster = cluster + + def fetch_all(self): + raw_node_pools = self.cluster['nodePools'] + for raw_node_pool in raw_node_pools: + node_pool_id, node_pool = self._parse_node_pool(raw_node_pool) + self[node_pool_id] = node_pool + # We need self.cluster to get the node pools, but we do + # not want to have it in the generated JSON. + del self.cluster + + def _parse_node_pool(self, raw_node_pool): + node_pool_dict = {} + node_pool_dict['id'] = raw_node_pool['name'] + node_pool_dict['auto_repair_enabled'] = raw_node_pool.get('management', {}).get('autoRepair', False) + node_pool_dict['auto_upgrade_enabled'] = raw_node_pool.get('management', {}).get('autoUpgrade', False) + node_pool_dict['legacy_metadata_endpoints_enabled'] = self._is_legacy_metadata_endpoints_enabled(raw_node_pool) + return node_pool_dict['id'], node_pool_dict + + def _is_legacy_metadata_endpoints_enabled(self, raw_node_pool): + return raw_node_pool['config'].get('metadata', {}).get('disable-legacy-endpoints') == 'false' diff --git a/ScoutSuite/providers/gcp/resources/gke/zones.py b/ScoutSuite/providers/gcp/resources/gke/zones.py new file mode 100644 index 000000000..7dc0a1fce --- /dev/null +++ b/ScoutSuite/providers/gcp/resources/gke/zones.py @@ -0,0 +1,8 @@ +from ScoutSuite.providers.gcp.resources.private_gke.clusters import Clusters +from ScoutSuite.providers.gcp.resources.zones import Zones + + +class GKEZones(Zones): + _children = [ + (Clusters, 'clusters'), + ] diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-basic-authentication-enabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-basic-authentication-enabled.json new file mode 100644 index 000000000..3d4318ebe --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-basic-authentication-enabled.json @@ -0,0 +1,32 @@ +{ + "description": "Basic Authentication Enabled", + "rationale": "Basic authentication allows a user to authenticate to the cluster with a username and password and it is stored in plain text without any encryption. Disabling Basic authentication will prevent attacks like brute force. Its recommended to use either client certificate or IAM for authentication.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.10" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.8.1" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#restrict_authn_methods", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#evaluation_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.basic_authentication_enabled", + "true", + "" + ] + ], + "id_suffix": "basic_authentication_enabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-certificate-authentication-enabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-certificate-authentication-enabled.json new file mode 100644 index 000000000..828fcff17 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-certificate-authentication-enabled.json @@ -0,0 +1,27 @@ +{ + "description": "Certificate Authentication Enabled", + "rationale": "Unless applications use the client certificate authentication method, it should be disabled.", + "compliance": [ + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.8.2" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#restrict_authn_methods", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#evaluation_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.client_certificate_enabled", + "true", + "" + ] + ], + "id_suffix": "client_certificate_enabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-alias-ip-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-alias-ip-disabled.json new file mode 100644 index 000000000..6f3b76dab --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-alias-ip-disabled.json @@ -0,0 +1,32 @@ +{ + "description": "Alias IP Disabled", + "rationale": "With Alias IPs ranges enabled, Kubernetes Engine clusters can allocate IP addresses from a CIDR block known to Google Cloud Platform. This makes your cluster more scalable and allows your cluster to better interact with other GCP products and entities.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.13" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.6.2" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#restrict_network_access_to_the_control_plane_and_nodes", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.alias_ip_enabled", + "false", + "" + ] + ], + "id_suffix": "alias_ip_disabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-has-no-labels.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-has-no-labels.json new file mode 100644 index 000000000..bc375ba29 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-has-no-labels.json @@ -0,0 +1,25 @@ +{ + "description": "Clusters Lacking Labels", + "rationale": "Labels enable users to map their own organizational structures onto system objects in a loosely coupled fashion, without requiring clients to store these mappings. Labels can also be used to apply specific security settings and auto configure objects at creation.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.5" + } + ], + "references": [ + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#use_namespaces_and_rbac_to_restrict_access_to_cluster_resources" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.has_labels", + "false", + "" + ] + ], + "id_suffix": "has_no_labels" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-logging-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-logging-disabled.json new file mode 100644 index 000000000..c8fac4642 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-logging-disabled.json @@ -0,0 +1,33 @@ +{ + "description": "Cluster Logging Disabled", + "rationale": "You should enable cluster logging and use a logging service so your cluster can export logs about its activities.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.1" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.7.1" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://kubernetes.io/docs/tasks/debug-application-cluster/audit/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#stackdriver_logging", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.logging_enabled", + "false", + "" + ] + ], + "id_suffix": "logging_disabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-master-authorized-networks-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-master-authorized-networks-disabled.json new file mode 100644 index 000000000..7f8faefc1 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-master-authorized-networks-disabled.json @@ -0,0 +1,33 @@ +{ + "description": "Master Authorized Networks Disabled", + "rationale": "Master authorized networks blocks untrusted IP addresses from outside Google Cloud Platform. Addresses from inside GCP can still reach your master through HTTPS provided that they have the necessary Kubernetes credentials.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.4" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.6.3" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/authorized-networks", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#restrict_network_access_to_the_control_plane_and_nodes", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.master_authorized_networks_enabled", + "false", + "" + ] + ], + "id_suffix": "master_authorized_networks_disabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-monitoring-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-monitoring-disabled.json new file mode 100644 index 000000000..3728e7dc7 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-monitoring-disabled.json @@ -0,0 +1,33 @@ +{ + "description": "Cluster Monitoring Disabled", + "rationale": "You should enable cluster monitoring and use a monitoring service so your cluster can export metrics about its activities.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.2" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.7.1" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#stackdriver_logging", + "https://cloud.google.com/monitoring/kubernetes-engine#about-skm", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.monitoring_enabled", + "false", + "" + ] + ], + "id_suffix": "monitoring_disabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-network-policy-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-network-policy-disabled.json new file mode 100644 index 000000000..7bfe05992 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-network-policy-disabled.json @@ -0,0 +1,33 @@ +{ + "description": "Network Policy Disabled", + "rationale": "By default, pods are non-isolated; they accept traffic from any source. Pods become isolated by having a NetworkPolicy that selects them. Once there is any NetworkPolicy in a namespace selecting a particular pod, that pod will reject any connections that are not allowed by any NetworkPolicy.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.11" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.6.7" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#restrict_with_network_policy", + "https://cloud.google.com/kubernetes-engine/docs/concepts/security-overview#network_security", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.network_policy_enabled", + "false", + "" + ] + ], + "id_suffix": "network_policy_disabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-private-google-access-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-private-google-access-disabled.json new file mode 100644 index 000000000..5c1a05c5f --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-private-google-access-disabled.json @@ -0,0 +1,25 @@ +{ + "description": "Private Google Access Disabled", + "rationale": "Enabling Private Google Access allows VMs on a subnetwork to use a private IP address to reach Google APIs rather than an external IP address.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.16" + } + ], + "references": [ + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#restrict_network_access_to_the_control_plane_and_nodes" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.private_ip_google_access_enabled", + "false", + "" + ] + ], + "id_suffix": "private_ip_google_access_disabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-dashboard-enabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-dashboard-enabled.json new file mode 100644 index 000000000..22e3ce32d --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-dashboard-enabled.json @@ -0,0 +1,32 @@ +{ + "description": "The GKE Dashboard Enabled", + "rationale": "You should disable the Kubernetes Web UI (Dashboard) when running on Kubernetes Engine. The Kubernetes Web UI (Dashboard) is backed by a highly privileged Kubernetes Service Account.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.6" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.10.1" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#disable_kubernetes_dashboard", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.dashboard_status", + "equal", + "Enabled" + ] + ], + "id_suffix": "dashboard_status" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-default-service-account-used.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-default-service-account-used.json new file mode 100644 index 000000000..1a0d60091 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-default-service-account-used.json @@ -0,0 +1,32 @@ +{ + "description": "Default Service Account in Use", + "rationale": "You should create and use a minimally privileged service account to run your Kubernetes Engine cluster instead of using the Compute Engine default service account.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.17" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.2.1" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#use_least_privilege_sa", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.service_account", + "equal", + "default" + ] + ], + "id_suffix": "default_service_account_used" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-legacy-abac-enabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-legacy-abac-enabled.json new file mode 100644 index 000000000..3011785a2 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-legacy-abac-enabled.json @@ -0,0 +1,32 @@ +{ + "description": "Legacy Authorization (ABAC) Enabled", + "rationale": "The legacy authorizer in Kubernetes Engine grants broad, statically defined permissions. To ensure that RBAC limits permissions correctly, you must disable the legacy authorizer. RBAC has significant security advantages, can help you ensure that users only have access to cluster resources within their own namespace and is now stable in Kubernetes.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.3" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.8.4" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#leave_abac_disabled_default_for_110", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.legacy_abac_enabled", + "true", + "" + ] + ], + "id_suffix": "legacy_abac_enabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-legacy-metadata-endpoints-enabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-legacy-metadata-endpoints-enabled.json new file mode 100644 index 000000000..47707db19 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-legacy-metadata-endpoints-enabled.json @@ -0,0 +1,28 @@ +{ + "description": "Legacy Metadata Endpoints Enabled", + "rationale": "Unless your app uses the legacy metadata endpoints, you should disable them.", + "compliance": [ + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.4.1" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#protect_node_metadata_default_for_112", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "display_path": "kubernetesengine.projects.id.zones.id.clusters.id", + "path": "kubernetesengine.projects.id.zones.id.clusters.id.node_pools.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.node_pools.id.legacy_metadata_endpoints_enabled", + "true", + "" + ] + ], + "id_suffix": "legacy_metadata_endpoints_enabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-node-auto-repair-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-node-auto-repair-disabled.json new file mode 100644 index 000000000..5d9def8a2 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-node-auto-repair-disabled.json @@ -0,0 +1,33 @@ +{ + "description": "Nodes Auto-Repair Disabled", + "rationale": "Auto-repair helps you keep the nodes in your cluster in a healthy, running state.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.7" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.5.2" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/node-auto-repair", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "display_path": "kubernetesengine.projects.id.zones.id.clusters.id", + "path": "kubernetesengine.projects.id.zones.id.clusters.id.node_pools.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.node_pools.id.auto_repair_enabled", + "false", + "" + ] + ], + "id_suffix": "auto_repair_disabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-node-auto-upgrade-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-node-auto-upgrade-disabled.json new file mode 100644 index 000000000..252ebf383 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-node-auto-upgrade-disabled.json @@ -0,0 +1,33 @@ +{ + "description": "Nodes Auto-Upgrade Disabled", + "rationale": "Auto-upgrades automatically ensures that security updates are applied and kept up to date.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.8" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.5.3" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/node-auto-upgrades", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "display_path": "kubernetesengine.projects.id.zones.id.clusters.id", + "path": "kubernetesengine.projects.id.zones.id.clusters.id.node_pools.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.node_pools.id.auto_upgrade_enabled", + "false", + "" + ] + ], + "id_suffix": "auto_upgrade_disabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-node-container-optimized-os-not-used.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-node-container-optimized-os-not-used.json new file mode 100644 index 000000000..ed544c3e9 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-node-container-optimized-os-not-used.json @@ -0,0 +1,32 @@ +{ + "description": "Lack of Container-Optimized OS Node Images", + "rationale": "The Container-Optimized OS image provides better support, security, and stability than previous images.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.9" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.5.1" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/container-optimized-os/docs/concepts/features-and-benefits", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.image_type", + "notEqual", + "COS" + ] + ], + "id_suffix": "container_optimized_os_not_used" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-private-cluster-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-private-cluster-disabled.json new file mode 100644 index 000000000..9c075173d --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-private-cluster-disabled.json @@ -0,0 +1,37 @@ +{ + "description": "Private Cluster Disabled", + "rationale": "A private cluster is a cluster that makes your master inaccessible from the public internet. In a private cluster, nodes do not have public IP addresses, so your workloads run in an environment that is isolated from the internet. Nodes have addressed only in the private RFC 1918 address space. Nodes and masters communicate with each other privately using VPC peering.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.15" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.6.4" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.6.5" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#restrict_network_access_to_the_control_plane_and_nodes", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.private_cluster_enabled", + "false", + "" + ] + ], + "id_suffix": "private_cluster_disabled" +} diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-scopes-not-limited.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-scopes-not-limited.json new file mode 100644 index 000000000..28c28bb06 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-scopes-not-limited.json @@ -0,0 +1,25 @@ +{ + "description": "Lack of Access Scope Limitation", + "rationale": "If you are not creating a separate service account for your nodes, you should limit the scopes of the node service account to reduce the possibility of a privilege escalation in an attack. This ensures that your default service account does not have permissions beyond those necessary to run your cluster. While the default scopes are limited, they may include scopes beyond the minimally required scopes needed to run your cluster. If you are accessing private images in Google Container Registry, the minimally required scopes are only logging.write, monitoring, and devstorage.read_only.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.18" + } + ], + "references": [ + "https://cloud.google.com/kubernetes-engine/docs/how-to/access-scopes" + ], + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.has_limited_scopes", + "false", + "" + ] + ], + "id_suffix": "scopes_not_limited" +} diff --git a/ScoutSuite/providers/gcp/rules/rulesets/cis-1.0.0.json b/ScoutSuite/providers/gcp/rules/rulesets/cis-1.0.0.json index 6fe570a0c..625711231 100755 --- a/ScoutSuite/providers/gcp/rules/rulesets/cis-1.0.0.json +++ b/ScoutSuite/providers/gcp/rules/rulesets/cis-1.0.0.json @@ -60,6 +60,114 @@ "enabled": true, "level": "warning" } + ], + "kubernetesengine-basic-authentication-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-certificate-authentication-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-alias-ip-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-has-no-labels.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-logging-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-master-authorized-networks-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-monitoring-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-network-policy-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-private-google-access-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-dashboard-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-default-service-account-used.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-legacy-abac-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-legacy-metadata-endpoints-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-node-auto-repair-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-node-auto-upgrade-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-node-container-optimized-os-not-used.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-private-cluster-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-scopes-not-limited.json": [ + { + "enabled": true, + "level": "warning" + } ], "iam-service-account-with-user-managed-keys.json": [ { diff --git a/ScoutSuite/providers/gcp/rules/rulesets/default.json b/ScoutSuite/providers/gcp/rules/rulesets/default.json index 93ba537b7..54d463042 100755 --- a/ScoutSuite/providers/gcp/rules/rulesets/default.json +++ b/ScoutSuite/providers/gcp/rules/rulesets/default.json @@ -193,6 +193,114 @@ "enabled": true, "level": "warning" } + ], + "kubernetesengine-basic-authentication-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-certificate-authentication-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-alias-ip-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-has-no-labels.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-logging-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-master-authorized-networks-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-monitoring-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-network-policy-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-cluster-private-google-access-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-dashboard-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-default-service-account-used.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-legacy-abac-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-legacy-metadata-endpoints-enabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-node-auto-repair-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-node-auto-upgrade-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-node-container-optimized-os-not-used.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-private-cluster-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], + "kubernetesengine-scopes-not-limited.json": [ + { + "enabled": true, + "level": "warning" + } ], "stackdriverlogging-no-export-sinks.json": [ { diff --git a/ScoutSuite/providers/gcp/services.py b/ScoutSuite/providers/gcp/services.py index 72ae52b95..f90fbdc80 100755 --- a/ScoutSuite/providers/gcp/services.py +++ b/ScoutSuite/providers/gcp/services.py @@ -7,12 +7,7 @@ from ScoutSuite.providers.gcp.resources.kms.base import KMS from ScoutSuite.providers.gcp.resources.stackdriverlogging.base import StackdriverLogging from ScoutSuite.providers.gcp.resources.stackdrivermonitoring.base import StackdriverMonitoring - -# Try to import proprietary services -try: - from ScoutSuite.providers.gcp.resources.private_gke.base import KubernetesEngine -except ImportError: - pass +from ScoutSuite.providers.gcp.resources.gke.base import KubernetesEngine class GCPServicesConfig(BaseServicesConfig): @@ -32,12 +27,7 @@ def __init__(self, credentials=None, default_project_id=None, self.kms = KMS(facade) self.stackdriverlogging = StackdriverLogging(facade) self.stackdrivermonitoring = StackdriverMonitoring(facade) - - # Instantiate proprietary services - try: - self.kubernetesengine = KubernetesEngine(facade) - except NameError as _: - pass + self.kubernetesengine = KubernetesEngine(facade) def _is_provider(self, provider_name): return provider_name == 'gcp' From 8b5a5bb7b28e6c1ac05141db4ea6da08357bd8f7 Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 10:30:56 +0200 Subject: [PATCH 258/312] Add support for GKE --- ScoutSuite/providers/gcp/resources/gke/base.py | 2 +- ScoutSuite/providers/gcp/resources/gke/clusters.py | 2 +- ScoutSuite/providers/gcp/resources/gke/zones.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ScoutSuite/providers/gcp/resources/gke/base.py b/ScoutSuite/providers/gcp/resources/gke/base.py index 418e90281..af59dd1bc 100644 --- a/ScoutSuite/providers/gcp/resources/gke/base.py +++ b/ScoutSuite/providers/gcp/resources/gke/base.py @@ -1,4 +1,4 @@ -from ScoutSuite.providers.gcp.resources.private_gke.zones import GKEZones +from ScoutSuite.providers.gcp.resources.gke.zones import GKEZones from ScoutSuite.providers.gcp.resources.projects import Projects diff --git a/ScoutSuite/providers/gcp/resources/gke/clusters.py b/ScoutSuite/providers/gcp/resources/gke/clusters.py index bb3ac579d..37019e074 100644 --- a/ScoutSuite/providers/gcp/resources/gke/clusters.py +++ b/ScoutSuite/providers/gcp/resources/gke/clusters.py @@ -1,6 +1,6 @@ from ScoutSuite.providers.base.resources.base import Resources from ScoutSuite.providers.gcp.facade.base import GCPFacade -from ScoutSuite.providers.gcp.resources.private_gke.node_pools import NodePools +from ScoutSuite.providers.gcp.resources.gke.node_pools import NodePools from ScoutSuite.providers.utils import get_non_provider_id diff --git a/ScoutSuite/providers/gcp/resources/gke/zones.py b/ScoutSuite/providers/gcp/resources/gke/zones.py index 7dc0a1fce..efd420f81 100644 --- a/ScoutSuite/providers/gcp/resources/gke/zones.py +++ b/ScoutSuite/providers/gcp/resources/gke/zones.py @@ -1,4 +1,4 @@ -from ScoutSuite.providers.gcp.resources.private_gke.clusters import Clusters +from ScoutSuite.providers.gcp.resources.gke.clusters import Clusters from ScoutSuite.providers.gcp.resources.zones import Zones From f2a1188558c4817e16740fc08d0314da05ddb184 Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 10:37:33 +0200 Subject: [PATCH 259/312] Fix for https://github.com/nccgroup/ScoutSuite-Proprietary/issues/221 --- ScoutSuite/providers/gcp/resources/gke/clusters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/providers/gcp/resources/gke/clusters.py b/ScoutSuite/providers/gcp/resources/gke/clusters.py index 37019e074..d8164f1d2 100644 --- a/ScoutSuite/providers/gcp/resources/gke/clusters.py +++ b/ScoutSuite/providers/gcp/resources/gke/clusters.py @@ -44,10 +44,10 @@ async def _parse_cluster(self, raw_cluster): return cluster_dict['id'], cluster_dict def _is_basic_authentication_enabled(self, raw_cluster): - return raw_cluster['masterAuth'].get('username', None) != '' + return raw_cluster['masterAuth'].get('username', '') != '' def _is_client_certificate_enabled(self, raw_cluster): - return raw_cluster['masterAuth'].get('clientCertificate', None) != '' + return raw_cluster['masterAuth'].get('clientCertificate', '') != '' def _is_logging_enabled(self, raw_cluster): return raw_cluster['loggingService'] != 'none' From 73ca429df7114ed9c1d12e69f94143a8c696b42e Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 11:43:20 +0200 Subject: [PATCH 260/312] Use beta library --- ScoutSuite/providers/gcp/facade/gke.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/providers/gcp/facade/gke.py b/ScoutSuite/providers/gcp/facade/gke.py index 40b8aa9ef..7d2a0f8de 100644 --- a/ScoutSuite/providers/gcp/facade/gke.py +++ b/ScoutSuite/providers/gcp/facade/gke.py @@ -7,7 +7,7 @@ class GKEFacade(GCPBaseFacade): def __init__(self, gce_facade): - super(GKEFacade, self).__init__('container', 'v1') + super(GKEFacade, self).__init__('container', 'v1beta1') self._gce_facade = gce_facade async def get_clusters(self, project_id, zone): From b438362f07f27e63026fa24d3d7d9997dd29f4ed Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 11:43:36 +0200 Subject: [PATCH 261/312] Include pod security policy --- .../gcp/services.kubernetesengine.clusters.html | 3 ++- ScoutSuite/providers/gcp/resources/gke/clusters.py | 14 ++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html b/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html index 9e9ac740a..24dcf6e79 100644 --- a/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html +++ b/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html @@ -13,9 +13,9 @@

    Information

    Basic authentication: {{convert_bool_to_enabled basic_authentication_enabled}}
    Client certificate authentication: {{convert_bool_to_enabled client_certificate_enabled}}
    Image type: {{image_type}}
    -
    Labels: {{labels}}
    Legacy authorization: {{convert_bool_to_enabled legacy_abac_enabled}}
    Master authorized networks: {{convert_bool_to_enabled master_authorized_networks_enabled}}
    +
    Pod Security Policy: {{convert_bool_to_enabled pod_security_policy_enabled}}
    Network policy: {{convert_bool_to_enabled network_policy_enabled}}
    Private cluster: {{convert_bool_to_enabled private_cluster_enabled}}
    Private Google access: {{convert_bool_to_enabled private_ip_google_access_enabled}}
    @@ -33,6 +33,7 @@

    Information

    None {{/if}}
    +
    Labels: {{labels}}
    diff --git a/ScoutSuite/providers/gcp/resources/gke/clusters.py b/ScoutSuite/providers/gcp/resources/gke/clusters.py index d8164f1d2..2c7eaa100 100644 --- a/ScoutSuite/providers/gcp/resources/gke/clusters.py +++ b/ScoutSuite/providers/gcp/resources/gke/clusters.py @@ -24,6 +24,7 @@ async def _parse_cluster(self, raw_cluster): cluster_dict['alias_ip_enabled'] = raw_cluster.get('ipAllocationPolicy', {}).get('useIpAliases', False) cluster_dict['basic_authentication_enabled'] = self._is_basic_authentication_enabled(raw_cluster) cluster_dict['client_certificate_enabled'] = self._is_client_certificate_enabled(raw_cluster) + cluster_dict['pod_security_policy_enabled'] = self._is_pod_security_policy_enabled(raw_cluster) cluster_dict['dashboard_status'] = self._get_dashboard_status(raw_cluster) cluster_dict['has_limited_scopes'] = self._has_limited_scopes(raw_cluster) cluster_dict['image_type'] = raw_cluster.get('nodeConfig', {}).get('imageType', None) @@ -31,18 +32,23 @@ async def _parse_cluster(self, raw_cluster): cluster_dict['has_labels'] = len(cluster_dict['labels']) > 0 cluster_dict['legacy_abac_enabled'] = raw_cluster.get('legacyAbac', {}).get('enabled', False) cluster_dict['logging_enabled'] = self._is_logging_enabled(raw_cluster) - cluster_dict['master_authorized_networks_enabled'] = raw_cluster.get( - 'masterAuthorizedNetworksConfig', {}).get('enabled', False) + cluster_dict['master_authorized_networks_enabled'] = raw_cluster.get('masterAuthorizedNetworksConfig', {}).get('enabled', False) cluster_dict['monitoring_enabled'] = self._is_monitoring_enabled(raw_cluster) cluster_dict['network_policy_enabled'] = raw_cluster.get('networkPolicy', {}).get('enabled', False) cluster_dict['node_pools'] = NodePools(raw_cluster) - cluster_dict['private_cluster_enabled'] = raw_cluster.get( - 'privateClusterConfig', {}).get('enablePrivateNodes', False) + cluster_dict['private_cluster_enabled'] = raw_cluster.get('privateClusterConfig', {}).get('enablePrivateNodes', False) cluster_dict['private_ip_google_access_enabled'] = raw_cluster.get('privateIpGoogleAccess', False) cluster_dict['scopes'] = self._get_scopes(raw_cluster) cluster_dict['service_account'] = raw_cluster.get('nodeConfig', {}).get('serviceAccount', None) return cluster_dict['id'], cluster_dict + def _is_pod_security_policy_enabled(self, raw_cluster): + if 'podSecurityPolicyConfig' in raw_cluster: + return raw_cluster['podSecurityPolicyConfig'].get('enabled', False) + return False + + return raw_cluster['masterAuth'].get('username', '') != '' + def _is_basic_authentication_enabled(self, raw_cluster): return raw_cluster['masterAuth'].get('username', '') != '' From 83be94cb714ed3588bad45c863f23a4ac31df959 Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 12:07:37 +0200 Subject: [PATCH 262/312] Add rule --- ...r-pod-security-policy-config-disabled.json | 34 +++++++++++++++++++ .../gcp/rules/rulesets/cis-1.0.0.json | 6 ++++ .../providers/gcp/rules/rulesets/default.json | 6 ++++ 3 files changed, 46 insertions(+) create mode 100644 ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-pod-security-policy-config-disabled.json diff --git a/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-pod-security-policy-config-disabled.json b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-pod-security-policy-config-disabled.json new file mode 100644 index 000000000..33b7d2670 --- /dev/null +++ b/ScoutSuite/providers/gcp/rules/findings/kubernetesengine-cluster-pod-security-policy-config-disabled.json @@ -0,0 +1,34 @@ +{ + "description": "Pod Security Policy Disabled", + "rationale": "A Pod Security Policy is a cluster-level resource that controls security sensitive aspects of the pod specification. The PodSecurityPolicy objects define a set of conditions that a pod must run with in order to be accepted into the system, as well as defaults for the related fields.", + "compliance": [ + { + "name": "CIS Google Cloud Platform Foundations", + "version": "1.0.0", + "reference": "7.14" + }, + { + "name": "CIS GKE Benchmark", + "version": "1.0.0", + "reference": "6.10.3" + } + ], + "references": [ + "https://www.cisecurity.org/benchmark/kubernetes/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/pod-security-policies", + "https://kubernetes.io/docs/concepts/policy/pod-security-policy", + "https://cloud.google.com/kubernetes-engine/docs/concepts/cis-benchmarks#default_values_on" + ], + "remediation": "Enable the Pod Security Policy. By default, Pod Security Policy is disabled when you create a new cluster.", + "dashboard_name": "Clusters", + "path": "kubernetesengine.projects.id.zones.id.clusters.id", + "conditions": [ + "and", + [ + "kubernetesengine.projects.id.zones.id.clusters.id.pod_security_policy_enabled", + "false", + "" + ] + ], + "id_suffix": "pod_security_policy_enabled" +} diff --git a/ScoutSuite/providers/gcp/rules/rulesets/cis-1.0.0.json b/ScoutSuite/providers/gcp/rules/rulesets/cis-1.0.0.json index 625711231..24a0e53db 100755 --- a/ScoutSuite/providers/gcp/rules/rulesets/cis-1.0.0.json +++ b/ScoutSuite/providers/gcp/rules/rulesets/cis-1.0.0.json @@ -145,6 +145,12 @@ "level": "warning" } ], + "kubernetesengine-cluster-pod-security-policy-config-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], "kubernetesengine-node-auto-upgrade-disabled.json": [ { "enabled": true, diff --git a/ScoutSuite/providers/gcp/rules/rulesets/default.json b/ScoutSuite/providers/gcp/rules/rulesets/default.json index 54d463042..a36aba77d 100755 --- a/ScoutSuite/providers/gcp/rules/rulesets/default.json +++ b/ScoutSuite/providers/gcp/rules/rulesets/default.json @@ -272,6 +272,12 @@ "level": "warning" } ], + "kubernetesengine-cluster-pod-security-policy-config-disabled.json": [ + { + "enabled": true, + "level": "warning" + } + ], "kubernetesengine-node-auto-repair-disabled.json": [ { "enabled": true, From 8c501a97adc69a20d6c58297938f55923c3fab91 Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 12:37:31 +0200 Subject: [PATCH 263/312] Add support for master authorized networks --- .../services.kubernetesengine.clusters.html | 54 ++++++++++++------- .../providers/gcp/resources/gke/clusters.py | 8 +++ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html b/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html index 24dcf6e79..5691a11a9 100644 --- a/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html +++ b/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html @@ -10,47 +10,63 @@

    Information

    Project ID: {{project}}
    Dashboard: {{dashboard_status}}
    Alias IP: {{convert_bool_to_enabled alias_ip_enabled}}
    -
    Basic authentication: {{convert_bool_to_enabled basic_authentication_enabled}}
    -
    Client certificate authentication: {{convert_bool_to_enabled client_certificate_enabled}}
    -
    Image type: {{image_type}}
    -
    Legacy authorization: {{convert_bool_to_enabled legacy_abac_enabled}}
    -
    Master authorized networks: {{convert_bool_to_enabled master_authorized_networks_enabled}}
    +
    Basic Authentication: {{convert_bool_to_enabled basic_authentication_enabled}}
    +
    Client Certificate Authentication: {{convert_bool_to_enabled client_certificate_enabled}}
    +
    Image Type: {{image_type}}
    +
    Legacy Authorization: {{convert_bool_to_enabled legacy_abac_enabled}}
    +
    Master Authorized Networks: {{convert_bool_to_enabled master_authorized_networks_enabled}}
    Pod Security Policy: {{convert_bool_to_enabled pod_security_policy_enabled}}
    -
    Network policy: {{convert_bool_to_enabled network_policy_enabled}}
    -
    Private cluster: {{convert_bool_to_enabled private_cluster_enabled}}
    -
    Private Google access: {{convert_bool_to_enabled private_ip_google_access_enabled}}
    -
    Service account: {{service_account}}
    +
    Network Policy: {{convert_bool_to_enabled network_policy_enabled}}
    +
    Private Cluster: {{convert_bool_to_enabled private_cluster_enabled}}
    +
    Private Google Access: {{convert_bool_to_enabled private_ip_google_access_enabled}}
    +
    Service Account: {{service_account}}
    Stackdriver Logging: {{convert_bool_to_enabled logging_enabled}}
    Stackdriver Monitoring: {{convert_bool_to_enabled monitoring_enabled}}
    -
    Scopes: +
    Scopes: {{#if scopes}} +
      + {{#each scopes}} +
    • {{this}}
    • + {{/each}} +
    + {{else}} + None + {{/if}} +
    +
    Labels: {{labels}}
    +
    + +
    +

    Master Authorized Networks

    +
    Status: {{convert_bool_to_enabled master_authorized_networks_config.enabled}}
    +
    CIDR Blocks: + {{#if master_authorized_networks_config.cidrBlocks}}
      - {{#each scopes}} -
    • {{this}}
    • + {{#each master_authorized_networks_config.cidrBlocks}} +
    • {{this.displayName}}: {{this.cidrBlock}}
    • {{/each}}
    {{else}} - None + None {{/if}}
    -
    Labels: {{labels}}

    Node pools

    - {{#each node_pools}} + {{#each node_pools}} {{@key}}
    - Automatic node upgrades: {{convert_bool_to_enabled auto_upgrade_enabled}} + Automatic node upgrades: {{convert_bool_to_enabled auto_upgrade_enabled}}
    - Automatic node repair: {{convert_bool_to_enabled auto_repair_enabled}} + Automatic node repair: {{convert_bool_to_enabled auto_repair_enabled}}
    - Legacy metadata endpoints: {{convert_bool_to_enabled legacy_metadata_endpoints_enabled}} + Legacy metadata endpoints: {{convert_bool_to_enabled legacy_metadata_endpoints_enabled}}
    - {{/each}} + {{/each}}
    diff --git a/ScoutSuite/providers/gcp/resources/gke/clusters.py b/ScoutSuite/providers/gcp/resources/gke/clusters.py index 2c7eaa100..2880b6481 100644 --- a/ScoutSuite/providers/gcp/resources/gke/clusters.py +++ b/ScoutSuite/providers/gcp/resources/gke/clusters.py @@ -40,8 +40,16 @@ async def _parse_cluster(self, raw_cluster): cluster_dict['private_ip_google_access_enabled'] = raw_cluster.get('privateIpGoogleAccess', False) cluster_dict['scopes'] = self._get_scopes(raw_cluster) cluster_dict['service_account'] = raw_cluster.get('nodeConfig', {}).get('serviceAccount', None) + cluster_dict['master_authorized_networks_config'] = self._get_master_authorized_netowrks_config(raw_cluster) return cluster_dict['id'], cluster_dict + + def _get_master_authorized_netowrks_config(self, raw_cluster): + if raw_cluster.get('masterAuthorizedNetworksConfig'): + return raw_cluster.get('masterAuthorizedNetworksConfig') + else: + return {'enabled': False, 'cidrBlocks': []} + def _is_pod_security_policy_enabled(self, raw_cluster): if 'podSecurityPolicyConfig' in raw_cluster: return raw_cluster['podSecurityPolicyConfig'].get('enabled', False) From 12daf05150003d6196306c0d94bdf56d23fad79a Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 12:46:56 +0200 Subject: [PATCH 264/312] Improve partial --- .../html/partials/gcp/services.kubernetesengine.clusters.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html b/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html index 5691a11a9..b8c31a83e 100644 --- a/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html +++ b/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html @@ -26,14 +26,16 @@

    Information

    {{#if scopes}}
      {{#each scopes}} -
    • {{this}}
    • +
    • {{this}}
    • {{/each}}
    {{else}} None {{/if}}
    + {{#if labels}}
    Labels: {{labels}}
    + {{/if}}
    From dd7a7caf84c3d2ea582cdc6c29e91f95701a87fe Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 13:15:14 +0200 Subject: [PATCH 265/312] Add support for master authorized networks --- .../gcp/services.kubernetesengine.clusters.html | 4 ++-- .../providers/gcp/resources/gke/clusters.py | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html b/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html index b8c31a83e..0b426a6f8 100644 --- a/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html +++ b/ScoutSuite/output/data/html/partials/gcp/services.kubernetesengine.clusters.html @@ -17,7 +17,7 @@

    Information

    Master Authorized Networks: {{convert_bool_to_enabled master_authorized_networks_enabled}}
    Pod Security Policy: {{convert_bool_to_enabled pod_security_policy_enabled}}
    Network Policy: {{convert_bool_to_enabled network_policy_enabled}}
    -
    Private Cluster: {{convert_bool_to_enabled private_cluster_enabled}}
    +
    Private Cluster: {{convert_bool_to_enabled private_cluster_enabled}}
    Private Google Access: {{convert_bool_to_enabled private_ip_google_access_enabled}}
    Service Account: {{service_account}}
    Stackdriver Logging: {{convert_bool_to_enabled logging_enabled}}
    @@ -39,7 +39,7 @@

    Information

    -

    Master Authorized Networks

    +

    Master Authorized Networks

    Status: {{convert_bool_to_enabled master_authorized_networks_config.enabled}}
    CIDR Blocks: {{#if master_authorized_networks_config.cidrBlocks}} diff --git a/ScoutSuite/providers/gcp/resources/gke/clusters.py b/ScoutSuite/providers/gcp/resources/gke/clusters.py index 2880b6481..82a8b2aff 100644 --- a/ScoutSuite/providers/gcp/resources/gke/clusters.py +++ b/ScoutSuite/providers/gcp/resources/gke/clusters.py @@ -40,15 +40,23 @@ async def _parse_cluster(self, raw_cluster): cluster_dict['private_ip_google_access_enabled'] = raw_cluster.get('privateIpGoogleAccess', False) cluster_dict['scopes'] = self._get_scopes(raw_cluster) cluster_dict['service_account'] = raw_cluster.get('nodeConfig', {}).get('serviceAccount', None) - cluster_dict['master_authorized_networks_config'] = self._get_master_authorized_netowrks_config(raw_cluster) + cluster_dict['master_authorized_networks_config'] = self._get_master_authorized_networks_config(raw_cluster) return cluster_dict['id'], cluster_dict - def _get_master_authorized_netowrks_config(self, raw_cluster): + def _get_master_authorized_networks_config(self, raw_cluster): if raw_cluster.get('masterAuthorizedNetworksConfig'): - return raw_cluster.get('masterAuthorizedNetworksConfig') + config = raw_cluster.get('masterAuthorizedNetworksConfig') + config['includes_public_cidr'] = False + for block in config['cidrBlocks']: + if block['cidrBlock'] == '0.0.0.0/0': + config['includes_public_cidr'] = True + return config else: - return {'enabled': False, 'cidrBlocks': []} + return {'enabled': False, + 'cidrBlocks': [], + 'includes_public_cidr': False + } def _is_pod_security_policy_enabled(self, raw_cluster): if 'podSecurityPolicyConfig' in raw_cluster: From aec79bc8d4e995f21ee56e44b024dd66bd0d0e00 Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 14:02:56 +0200 Subject: [PATCH 266/312] Update requirement --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index adfd8bc1e..d8399aa71 100755 --- a/requirements.txt +++ b/requirements.txt @@ -43,7 +43,7 @@ azure-mgmt-security==0.4.1 azure-mgmt-keyvault==1.1.0 azure-mgmt-network==2.5.1 azure-mgmt-redis==6.0.0 -azure-mgmt-web==0.41.0 +azure-mgmt-web==0.47.0 azure-mgmt-compute==5.0.0 azure-mgmt-authorization==0.60.0 From d1156930fcf012a551b85bccd70cfdbb8609ffa9 Mon Sep 17 00:00:00 2001 From: xga Date: Mon, 21 Sep 2020 14:30:27 +0200 Subject: [PATCH 267/312] Improve parsing and partial --- ....appservice.subscriptions.id.web_apps.html | 54 +++++++++++++------ .../azure/resources/appservice/web_apps.py | 5 +- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/azure/services.appservice.subscriptions.id.web_apps.html b/ScoutSuite/output/data/html/partials/azure/services.appservice.subscriptions.id.web_apps.html index a16ec749b..4b2f3a097 100755 --- a/ScoutSuite/output/data/html/partials/azure/services.appservice.subscriptions.id.web_apps.html +++ b/ScoutSuite/output/data/html/partials/azure/services.appservice.subscriptions.id.web_apps.html @@ -6,25 +6,14 @@

    {{name}}

    Information

    Name: {{value_or_none name}}
    +
    Repository Site Name: {{value_or_none repository_site_name}}
    +
    Resource Group: {{value_or_none resource_group}}
    Location: {{value_or_none location}}
    State: {{value_or_none state}}
    Usage State: {{value_or_none usage_state}}
    Availability State: {{value_or_none availability_state}}
    -
    Last Modified Time:{{format_date last_modified_time_utc}}
    -
    HTTPS-Only Traffic: {{convert_bool_to_enabled https_only}}
    -
    HTTPS 2.0 Support: {{convert_bool_to_enabled http_2_enabled}}
    -
    Minimum TLS Version Supported: {{value_or_none minimum_tls_version_supported}}
    -
    Authentication: {{convert_bool_to_enabled authentication_enabled}}
    -
    Resource Group: {{value_or_none resource_group}}
    Kind: {{value_or_none kind}}
    -
    Outbound IP Addresses: {{value_or_none outbound_ip_addresses}}
    -
    Possible Outbound IP Addresses: {{value_or_none possible_outbound_ip_addresses}}
    -
    Client Certificates: {{convert_bool_to_enabled client_cert_enabled}}
    -
    Default Host Name: {{value_or_none default_host_name}}
    -
    Host Names: {{value_or_none host_names}}
    -
    Host Names: {{convert_bool_to_enabled enabled_host_names}}
    -
    Repository Site Name: {{value_or_none repository_site_name}}
    -
    Traffic Manager Host Names: {{value_or_none traffic_manager_host_names}}
    +
    Last Modified Time:{{format_date last_modified_time_utc}}
    Programming Language: {{value_or_none programming_language}}
    Programming Language Version: {{value_or_none programming_language_version}}
    Tags: @@ -38,9 +27,18 @@

    Information

    {{/each}}
    Resource group: {{value_or_none resource_group_name}}
    -

    - Identities -

    +
    +
    +

    Configuration

    +
    Authentication: {{convert_bool_to_enabled authentication_enabled}}
    +
    HTTPS-Only Traffic: {{convert_bool_to_enabled https_only}}
    +
    HTTPS 2.0 Support: {{convert_bool_to_enabled http_2_enabled}}
    +
    Minimum TLS Version Supported: {{value_or_none minimum_tls_version_supported}}
    +
    Client Certificates: {{convert_bool_to_enabled client_cert_enabled}}
    +
    + {{#if identity}} +
    +

    Identities

    System Assigned Identity: {{value_or_none identity.principal_id}}
    {{#if identity.user_assigned_identities}}
    @@ -53,6 +51,28 @@

    {{/if}}
    + {{/if}} +
    +

    Networking

    +
    Host Names: {{convert_bool_to_enabled enabled_host_names}}
    +
    Default Host Name: {{value_or_none default_host_name}}
    +
    Host Names: {{value_or_none host_names}}
    +
    Traffic Manager Host Names: {{value_or_none traffic_manager_host_names}}
    +
    Outbound IP Addresses: +
      + {{#each outbound_ip_addresses}} +
    • {{this}}
    • + {{/each}} +
    +
    +
    Possible Outbound IP Addresses: +
      + {{#each possible_outbound_ip_addresses}} +
    • {{this}}
    • + {{/each}} +
    +
    +
    diff --git a/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.zones.id.instances.html b/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.zones.id.instances.html index 7a81f1f87..3ca80ed68 100755 --- a/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.zones.id.instances.html +++ b/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.zones.id.instances.html @@ -34,6 +34,23 @@

    Information

    {{/if}}
    +
    +
    Network Interfaces
    + {{#if network_interfaces}} + + {{/if}} +
    Identity & API Access
    Service Account: {{value_or_none service_account}}
    diff --git a/ScoutSuite/providers/gcp/provider.py b/ScoutSuite/providers/gcp/provider.py index 19db7487b..cc0b319cf 100755 --- a/ScoutSuite/providers/gcp/provider.py +++ b/ScoutSuite/providers/gcp/provider.py @@ -83,6 +83,7 @@ def preprocessing(self, ip_ranges=None, ip_ranges_name_key=None): self._match_instances_and_snapshots() self._match_networks_and_instances() + self._match_subnetworks_and_instances() super().preprocessing() @@ -128,8 +129,39 @@ def _match_networks_and_instances(self): if zone is int: continue for instance in zone['instances'].values(): + instance['network_id'] = None for network_interface in instance['network_interfaces']: if network_interface['network'] == network['network_url']: - network['instances'].append(instance['id']) + network['instances'].append({'instance_id': instance['id'], + 'instance_zone': instance['zone']}) + network_interface['network_id'] = network['id'] except Exception as e: print_exception('Unable to match instances and networks: {}'.format(e)) + + def _match_subnetworks_and_instances(self): + """ + For each subnetwork, math instances in that subnetwork + + :return: + """ + + try: + if 'computeengine' in self.service_list: + for project in self.services['computeengine']['projects'].values(): + for region in project['regions'].values(): + for subnetwork in region['subnetworks'].values(): + subnetwork['instances'] = [] + for zone in project['zones'].values(): + # Skip the counts contained in the zones dictionary + if zone is int: + continue + for instance in zone['instances'].values(): + instance['subnetwork_id'] = None + for network_interface in instance['network_interfaces']: + if network_interface['subnetwork'] == subnetwork['subnetwork_url']: + subnetwork['instances'].append({'instance_id': instance['id'], + 'instance_zone': instance['zone']}) + network_interface['subnetwork_id'] = subnetwork['id'] + network_interface['subnetwork_region'] = subnetwork['region'] + except Exception as e: + print_exception('Unable to match instances and subnetworks: {}'.format(e)) diff --git a/ScoutSuite/providers/gcp/resources/gce/networks.py b/ScoutSuite/providers/gcp/resources/gce/networks.py index 12e8c0f11..fbf120323 100755 --- a/ScoutSuite/providers/gcp/resources/gce/networks.py +++ b/ScoutSuite/providers/gcp/resources/gce/networks.py @@ -20,10 +20,12 @@ def _parse_network(self, raw_network): network_dict['name'] = raw_network['name'] network_dict['description'] = self._get_description(raw_network) network_dict['creation_timestamp'] = raw_network['creationTimestamp'] - network_dict['network_url'] = raw_network['selfLink'] - network_dict['subnetwork_urls'] = raw_network.get('subnetworks', None) network_dict['auto_subnet'] = raw_network.get('autoCreateSubnetworks', None) network_dict['routing_config'] = raw_network['routingConfig'] + + network_dict['network_url'] = raw_network['selfLink'] + network_dict['subnetwork_urls'] = raw_network.get('subnetworks', None) + return network_dict['id'], network_dict def _get_description(self, raw_network): diff --git a/ScoutSuite/providers/gcp/resources/gce/subnetworks.py b/ScoutSuite/providers/gcp/resources/gce/subnetworks.py index 56aab2a34..c25332585 100755 --- a/ScoutSuite/providers/gcp/resources/gce/subnetworks.py +++ b/ScoutSuite/providers/gcp/resources/gce/subnetworks.py @@ -20,9 +20,12 @@ def _parse_subnetwork(self, raw_subnetwork): subnetwork_dict['project_id'] = raw_subnetwork['selfLink'].split('/')[-5] subnetwork_dict['region'] = raw_subnetwork['region'].split('/')[-1] subnetwork_dict['name'] = "{}-{}".format(raw_subnetwork['name'], subnetwork_dict['region']) - subnetwork_dict['subnetwork'] = raw_subnetwork['network'].split('/')[-1] subnetwork_dict['gateway_address'] = raw_subnetwork['gatewayAddress'] subnetwork_dict['ip_range'] = raw_subnetwork['ipCidrRange'] subnetwork_dict['creation_timestamp'] = raw_subnetwork['creationTimestamp'] subnetwork_dict['private_ip_google_access'] = raw_subnetwork['privateIpGoogleAccess'] + + subnetwork_dict['subnetwork_url'] = raw_subnetwork['selfLink'] + subnetwork_dict['network_url'] = raw_subnetwork['network'] + return subnetwork_dict['id'], subnetwork_dict From 75f9a0fdb786de8a2961f671e6bdba7a8b1fdd00 Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 23 Sep 2020 14:58:56 +0200 Subject: [PATCH 280/312] Match GCE networks and firewall rules --- ...s.computeengine.projects.id.firewalls.html | 2 +- ...es.computeengine.projects.id.networks.html | 16 +++++++++++++- ScoutSuite/providers/gcp/provider.py | 21 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.firewalls.html b/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.firewalls.html index 77f2fe3a8..863ead6d7 100755 --- a/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.firewalls.html +++ b/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.firewalls.html @@ -9,7 +9,7 @@

    Information

    Firewall name: {{name}}
    Project ID: {{project_id}}
    Description: {{description}}
    -
    VPC network: {{network}}
    +
    Creation Date: {{format_date creation_timestamp}}
    Priority: {{priority}}
    Disabled: {{disabled}}
    diff --git a/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.networks.html b/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.networks.html index 53a83264c..ccb8c486c 100755 --- a/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.networks.html +++ b/ScoutSuite/output/data/html/partials/gcp/services.computeengine.projects.id.networks.html @@ -12,9 +12,23 @@

    Information

    Description: {{description}}
    Creation Date: {{format_date creation_timestamp}}
    +
    +

    Firewall Rules + {{> count_badge count=(count_vpc_instances firewalls) target=(concat '#services.computeengine.projects' project 'networks' @key 'firewalls')}} +

    + +

    Compute Engine Instances - {{> count_badge count=(count_vpc_instances instances) target=(concat '#services.compouteengine.projects' project 'neworks' @key 'instances')}} + {{> count_badge count=(count_vpc_instances instances) target=(concat '#services.computeengine.projects' project 'neworks' @key 'instances')}}

    diff --git a/ScoutSuite/providers/gcp/provider.py b/ScoutSuite/providers/gcp/provider.py index cc0b319cf..72a432765 100755 --- a/ScoutSuite/providers/gcp/provider.py +++ b/ScoutSuite/providers/gcp/provider.py @@ -83,6 +83,7 @@ def preprocessing(self, ip_ranges=None, ip_ranges_name_key=None): self._match_instances_and_snapshots() self._match_networks_and_instances() + self._match_networks_and_firewalls() self._match_subnetworks_and_instances() super().preprocessing() @@ -138,6 +139,26 @@ def _match_networks_and_instances(self): except Exception as e: print_exception('Unable to match instances and networks: {}'.format(e)) + def _match_networks_and_firewalls(self): + """ + For each network, math firewall rules in that network + + :return: + """ + + try: + if 'computeengine' in self.service_list: + for project in self.services['computeengine']['projects'].values(): + for network in project['networks'].values(): + network['firewalls'] = [] + for firewall in project['firewalls'].values(): + firewall['network_id'] = None + if firewall['network_url'] == network['network_url']: + network['firewalls'].append(firewall['id']) + firewall['network_id'] = network['id'] + except Exception as e: + print_exception('Unable to match firewalls and networks: {}'.format(e)) + def _match_subnetworks_and_instances(self): """ For each subnetwork, math instances in that subnetwork From 2794c3eecb0b6eba8823794312f875ead57fadeb Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 23 Sep 2020 19:24:51 +0200 Subject: [PATCH 281/312] Add AWS user agent --- ScoutSuite/providers/aws/authentication_strategy.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ScoutSuite/providers/aws/authentication_strategy.py b/ScoutSuite/providers/aws/authentication_strategy.py index 099af7698..806460e45 100755 --- a/ScoutSuite/providers/aws/authentication_strategy.py +++ b/ScoutSuite/providers/aws/authentication_strategy.py @@ -1,6 +1,8 @@ import boto3 +from botocore.config import Config import logging +from ScoutSuite import __version__ from ScoutSuite.providers.aws.utils import get_caller_identity from ScoutSuite.providers.base.authentication_strategy import AuthenticationStrategy, AuthenticationException @@ -48,6 +50,11 @@ def authenticate(self, # Test querying for current user get_caller_identity(session) + # Set custom user agent + session._session.user_agent_name = 'Scout Suite' + session._session.user_agent_extra = 'Scout Suite/{} (https://github.com/nccgroup/ScoutSuite)'.format(__version__) + session._session.user_agent_version= __version__ + return AWSCredentials(session=session) except Exception as e: From d2a400c75c96f39dfd499d5e63bdc4cb1a7f3c79 Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 23 Sep 2020 19:26:57 +0200 Subject: [PATCH 282/312] Remove unused import --- ScoutSuite/providers/aws/authentication_strategy.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ScoutSuite/providers/aws/authentication_strategy.py b/ScoutSuite/providers/aws/authentication_strategy.py index 806460e45..8d271839c 100755 --- a/ScoutSuite/providers/aws/authentication_strategy.py +++ b/ScoutSuite/providers/aws/authentication_strategy.py @@ -1,5 +1,4 @@ import boto3 -from botocore.config import Config import logging from ScoutSuite import __version__ From 1578a70a4005eda895191b55b3c7b1600203e57b Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 23 Sep 2020 19:37:37 +0200 Subject: [PATCH 283/312] Add method --- ScoutSuite/utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ScoutSuite/utils.py b/ScoutSuite/utils.py index c2cde17c7..0fd1c41e6 100755 --- a/ScoutSuite/utils.py +++ b/ScoutSuite/utils.py @@ -1,4 +1,5 @@ from __future__ import print_function +from ScoutSuite import __version__ formatted_provider_name = { 'aliyun': 'Aliyun', @@ -94,3 +95,7 @@ def format_service_name(service): :return: """ return formatted_service_name[service] if service in formatted_service_name else service.upper() + + +def get_user_agent(): + return 'Scout Suite/{} (https://github.com/nccgroup/ScoutSuite)'.format(__version__) From 647bb844eaea6f96138ff71b33384be85028bd7e Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 23 Sep 2020 19:37:54 +0200 Subject: [PATCH 284/312] Minor change --- ScoutSuite/providers/aws/authentication_strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScoutSuite/providers/aws/authentication_strategy.py b/ScoutSuite/providers/aws/authentication_strategy.py index 8d271839c..d8d2fe2b6 100755 --- a/ScoutSuite/providers/aws/authentication_strategy.py +++ b/ScoutSuite/providers/aws/authentication_strategy.py @@ -52,7 +52,7 @@ def authenticate(self, # Set custom user agent session._session.user_agent_name = 'Scout Suite' session._session.user_agent_extra = 'Scout Suite/{} (https://github.com/nccgroup/ScoutSuite)'.format(__version__) - session._session.user_agent_version= __version__ + session._session.user_agent_version = __version__ return AWSCredentials(session=session) From 7c537fd3418885a953162a1335fa0b9edd1fa65a Mon Sep 17 00:00:00 2001 From: xga Date: Wed, 23 Sep 2020 21:22:07 +0200 Subject: [PATCH 285/312] Add user agent for Azure provider --- ScoutSuite/providers/azure/facade/aad.py | 6 +++++- ScoutSuite/providers/azure/facade/appservice.py | 5 ++++- ScoutSuite/providers/azure/facade/base.py | 2 ++ ScoutSuite/providers/azure/facade/keyvault.py | 5 ++++- ScoutSuite/providers/azure/facade/network.py | 5 ++++- ScoutSuite/providers/azure/facade/rbac.py | 5 ++++- ScoutSuite/providers/azure/facade/securitycenter.py | 5 ++++- ScoutSuite/providers/azure/facade/sqldatabase.py | 5 ++++- ScoutSuite/providers/azure/facade/storageaccounts.py | 6 +++++- ScoutSuite/providers/azure/facade/virtualmachines.py | 5 ++++- 10 files changed, 40 insertions(+), 9 deletions(-) diff --git a/ScoutSuite/providers/azure/facade/aad.py b/ScoutSuite/providers/azure/facade/aad.py index 8a4b38d17..a26e1a17c 100755 --- a/ScoutSuite/providers/azure/facade/aad.py +++ b/ScoutSuite/providers/azure/facade/aad.py @@ -1,6 +1,8 @@ from azure.graphrbac import GraphRbacManagementClient + from ScoutSuite.core.console import print_exception from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent class AADFacade: @@ -9,8 +11,10 @@ def __init__(self, credentials): self.credentials = credentials def get_client(self): - return GraphRbacManagementClient(self.credentials.get_credentials('aad_graph'), + client = GraphRbacManagementClient(self.credentials.get_credentials('aad_graph'), tenant_id=self.credentials.get_tenant_id()) + client._client.config.add_user_agent(get_user_agent()) + return client async def get_users(self): try: diff --git a/ScoutSuite/providers/azure/facade/appservice.py b/ScoutSuite/providers/azure/facade/appservice.py index c345d81ad..d74ad690e 100755 --- a/ScoutSuite/providers/azure/facade/appservice.py +++ b/ScoutSuite/providers/azure/facade/appservice.py @@ -3,6 +3,7 @@ from ScoutSuite.core.console import print_exception from ScoutSuite.providers.azure.utils import get_resource_group_name from ScoutSuite.providers.utils import run_concurrently, get_and_set_concurrently +from ScoutSuite.utils import get_user_agent class AppServiceFacade: @@ -11,8 +12,10 @@ def __init__(self, credentials): self.credentials = credentials def get_client(self, subscription_id: str): - return WebSiteManagementClient(self.credentials.get_credentials('arm'), + client = WebSiteManagementClient(self.credentials.get_credentials('arm'), subscription_id=subscription_id) + client._client.config.add_user_agent(get_user_agent()) + return client async def get_web_apps(self, subscription_id: str): try: diff --git a/ScoutSuite/providers/azure/facade/base.py b/ScoutSuite/providers/azure/facade/base.py index 48d282b1c..f97bdbc70 100755 --- a/ScoutSuite/providers/azure/facade/base.py +++ b/ScoutSuite/providers/azure/facade/base.py @@ -11,6 +11,7 @@ from azure.mgmt.resource import SubscriptionClient from ScoutSuite.providers.base.authentication_strategy import AuthenticationException +from ScoutSuite.utils import get_user_agent from ScoutSuite.core.console import print_info, print_exception @@ -78,6 +79,7 @@ def _set_subscriptions(self): # Create the client subscription_client = SubscriptionClient(self.credentials.arm_credentials) + subscription_client._client.config.add_user_agent(get_user_agent()) # Get all the accessible subscriptions accessible_subscriptions_list = list(subscription_client.subscriptions.list()) diff --git a/ScoutSuite/providers/azure/facade/keyvault.py b/ScoutSuite/providers/azure/facade/keyvault.py index add83ad59..301bc0920 100755 --- a/ScoutSuite/providers/azure/facade/keyvault.py +++ b/ScoutSuite/providers/azure/facade/keyvault.py @@ -2,6 +2,7 @@ from ScoutSuite.core.console import print_exception from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent class KeyVaultFacade: @@ -10,8 +11,10 @@ def __init__(self, credentials): self.credentials = credentials def get_client(self, subscription_id: str): - return KeyVaultManagementClient(self.credentials.get_credentials('arm'), + client = KeyVaultManagementClient(self.credentials.get_credentials('arm'), subscription_id=subscription_id) + client._client.config.add_user_agent(get_user_agent()) + return client async def get_key_vaults(self, subscription_id: str): try: diff --git a/ScoutSuite/providers/azure/facade/network.py b/ScoutSuite/providers/azure/facade/network.py index 2ee494b8d..56d3a6666 100755 --- a/ScoutSuite/providers/azure/facade/network.py +++ b/ScoutSuite/providers/azure/facade/network.py @@ -2,6 +2,7 @@ from ScoutSuite.core.console import print_exception from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent class NetworkFacade: @@ -10,8 +11,10 @@ def __init__(self, credentials): self.credentials = credentials def get_client(self, subscription_id: str): - return NetworkManagementClient(self.credentials.get_credentials('arm'), + client = NetworkManagementClient(self.credentials.get_credentials('arm'), subscription_id=subscription_id) + client._client.config.add_user_agent(get_user_agent()) + return client async def get_network_watchers(self, subscription_id: str): try: diff --git a/ScoutSuite/providers/azure/facade/rbac.py b/ScoutSuite/providers/azure/facade/rbac.py index d61fb100c..bae28ae05 100755 --- a/ScoutSuite/providers/azure/facade/rbac.py +++ b/ScoutSuite/providers/azure/facade/rbac.py @@ -2,6 +2,7 @@ from ScoutSuite.core.console import print_exception from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent class RBACFacade: @@ -10,8 +11,10 @@ def __init__(self, credentials): self.credentials = credentials def get_client(self, subscription_id: str): - return AuthorizationManagementClient(self.credentials.get_credentials('arm'), + client = AuthorizationManagementClient(self.credentials.get_credentials('arm'), subscription_id=subscription_id) + client._client.config.add_user_agent(get_user_agent()) + return client async def get_roles(self, subscription_id: str): try: diff --git a/ScoutSuite/providers/azure/facade/securitycenter.py b/ScoutSuite/providers/azure/facade/securitycenter.py index 998db0f1d..c49870816 100755 --- a/ScoutSuite/providers/azure/facade/securitycenter.py +++ b/ScoutSuite/providers/azure/facade/securitycenter.py @@ -2,6 +2,7 @@ from ScoutSuite.core.console import print_exception, print_debug from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent class SecurityCenterFacade: @@ -10,8 +11,10 @@ def __init__(self, credentials): self.credentials = credentials def get_client(self, subscription_id: str): - return SecurityCenter(self.credentials.get_credentials('arm'), + client = SecurityCenter(self.credentials.get_credentials('arm'), subscription_id, '') + client._client.config.add_user_agent(get_user_agent()) + return client async def get_pricings(self, subscription_id: str): try: diff --git a/ScoutSuite/providers/azure/facade/sqldatabase.py b/ScoutSuite/providers/azure/facade/sqldatabase.py index 40d0f514f..9a9e580e5 100755 --- a/ScoutSuite/providers/azure/facade/sqldatabase.py +++ b/ScoutSuite/providers/azure/facade/sqldatabase.py @@ -3,6 +3,7 @@ from azure.mgmt.sql import SqlManagementClient from ScoutSuite.providers.utils import run_concurrently from ScoutSuite.core.console import print_exception +from ScoutSuite.utils import get_user_agent class SQLDatabaseFacade: @@ -11,8 +12,10 @@ def __init__(self, credentials): self.credentials = credentials def get_client(self, subscription_id: str): - return SqlManagementClient(self.credentials.get_credentials('arm'), + client = SqlManagementClient(self.credentials.get_credentials('arm'), subscription_id=subscription_id) + client._client.config.add_user_agent(get_user_agent()) + return client async def get_database_blob_auditing_policies(self, resource_group_name, server_name, database_name, subscription_id: str): try: diff --git a/ScoutSuite/providers/azure/facade/storageaccounts.py b/ScoutSuite/providers/azure/facade/storageaccounts.py index e838ed78e..6e3a8ebc3 100755 --- a/ScoutSuite/providers/azure/facade/storageaccounts.py +++ b/ScoutSuite/providers/azure/facade/storageaccounts.py @@ -5,6 +5,7 @@ from ScoutSuite.core.console import print_exception from ScoutSuite.providers.utils import run_concurrently, get_and_set_concurrently +from ScoutSuite.utils import get_user_agent class StorageAccountsFacade: @@ -13,8 +14,10 @@ def __init__(self, credentials): self.credentials = credentials def get_client(self, subscription_id: str): - return StorageManagementClient(self.credentials.get_credentials('arm'), + client = StorageManagementClient(self.credentials.get_credentials('arm'), subscription_id=subscription_id) + client._client.config.add_user_agent(get_user_agent()) + return client async def get_storage_accounts(self, subscription_id: str): try: @@ -44,6 +47,7 @@ async def get_blob_containers(self, resource_group_name, storage_account_name, s async def _get_and_set_activity_logs(self, storage_account, subscription_id: str): client = MonitorManagementClient(self.credentials.arm_credentials, subscription_id) + client._client.config.add_user_agent(get_user_agent()) # Time format used by Azure API: time_format = "%Y-%m-%dT%H:%M:%S.%f" diff --git a/ScoutSuite/providers/azure/facade/virtualmachines.py b/ScoutSuite/providers/azure/facade/virtualmachines.py index f2602b4d1..217c67ba8 100755 --- a/ScoutSuite/providers/azure/facade/virtualmachines.py +++ b/ScoutSuite/providers/azure/facade/virtualmachines.py @@ -2,6 +2,7 @@ from ScoutSuite.core.console import print_exception from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent class VirtualMachineFacade: @@ -10,8 +11,10 @@ def __init__(self, credentials): self.credentials = credentials def get_client(self, subscription_id: str): - return ComputeManagementClient(self.credentials.get_credentials('arm'), + client = ComputeManagementClient(self.credentials.get_credentials('arm'), subscription_id=subscription_id) + client._client.config.add_user_agent(get_user_agent()) + return client async def get_instances(self, subscription_id: str): try: From 56ec49aeec3fd63c470c3f55acf99764258fe228 Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 24 Sep 2020 10:25:11 +0200 Subject: [PATCH 286/312] Fix list output --- ScoutSuite/providers/base/provider.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ScoutSuite/providers/base/provider.py b/ScoutSuite/providers/base/provider.py index d27f34cea..a90c45671 100755 --- a/ScoutSuite/providers/base/provider.py +++ b/ScoutSuite/providers/base/provider.py @@ -41,6 +41,10 @@ def __init__(self, report_dir=None, timestamp=None, self.services = self.services_config(self.credentials) supported_services = vars(self.services).keys() + # Ensures "credentials" is not included + supported_services = list(supported_services) + supported_services.remove('credentials') + self.service_list = self._build_services_list(supported_services, services, skipped_services) def get_report_name(self): From f8e28a894c3a534fef249b9c918b6446eddbf5ec Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 24 Sep 2020 11:09:39 +0200 Subject: [PATCH 287/312] Add user agent for client libraries --- ScoutSuite/providers/gcp/facade/cloudstorage.py | 11 ++++++++++- ScoutSuite/providers/gcp/facade/kms.py | 9 ++++++++- .../providers/gcp/facade/stackdriverlogging.py | 12 ++++++++++-- .../gcp/facade/stackdrivermonitoring.py | 16 ++++++++++++++-- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/ScoutSuite/providers/gcp/facade/cloudstorage.py b/ScoutSuite/providers/gcp/facade/cloudstorage.py index 7d2de630b..359d632a6 100755 --- a/ScoutSuite/providers/gcp/facade/cloudstorage.py +++ b/ScoutSuite/providers/gcp/facade/cloudstorage.py @@ -1,13 +1,22 @@ from google.cloud import storage +from google.api_core.gapic_v1.client_info import ClientInfo from ScoutSuite.core.console import print_exception from ScoutSuite.providers.utils import run_concurrently, get_and_set_concurrently +from ScoutSuite.utils import get_user_agent class CloudStorageFacade: + + def get_client(self, project_id: str): + client_info = ClientInfo(user_agent=get_user_agent()) + client = storage.Client(project=project_id, + client_info=client_info) + return client + async def get_buckets(self, project_id: str): try: - client = storage.Client(project=project_id) + client = self.get_client(project_id) buckets = await run_concurrently(lambda: list(client.list_buckets())) await get_and_set_concurrently([self._get_and_set_bucket_logging, self._get_and_set_bucket_iam_policy], buckets) diff --git a/ScoutSuite/providers/gcp/facade/kms.py b/ScoutSuite/providers/gcp/facade/kms.py index 700716fd7..a83e84ad6 100755 --- a/ScoutSuite/providers/gcp/facade/kms.py +++ b/ScoutSuite/providers/gcp/facade/kms.py @@ -1,15 +1,22 @@ from google.cloud import kms +from google.api_core.gapic_v1.client_info import ClientInfo from ScoutSuite.core.console import print_exception from ScoutSuite.providers.gcp.facade.basefacade import GCPBaseFacade from ScoutSuite.providers.gcp.facade.utils import GCPFacadeUtils from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent class KMSFacade(GCPBaseFacade): def __init__(self): # This facade is currently using both libraries as the Cloud Client library doesn't support locations - self.cloud_client = kms.KeyManagementServiceClient() # Cloud Client + + # Cloud Client + client_info = ClientInfo(user_agent=get_user_agent()) + self.cloud_client = kms.KeyManagementServiceClient(client_info=client_info) + # self.cloud_client = kms.KeyManagementServiceClient() + super().__init__('cloudkms', 'v1') # API Client async def get_locations(self, project_id: str): diff --git a/ScoutSuite/providers/gcp/facade/stackdriverlogging.py b/ScoutSuite/providers/gcp/facade/stackdriverlogging.py index 7d96d4d62..2ecb76a6e 100755 --- a/ScoutSuite/providers/gcp/facade/stackdriverlogging.py +++ b/ScoutSuite/providers/gcp/facade/stackdriverlogging.py @@ -1,14 +1,22 @@ from google.cloud import logging as stackdriverlogging +from google.api_core.gapic_v1.client_info import ClientInfo from ScoutSuite.core.console import print_exception from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent class StackdriverLoggingFacade: + def get_client(self, project_id: str): + client_info = ClientInfo(user_agent=get_user_agent()) + client = stackdriverlogging.Client(project=project_id, + client_info=client_info) + return client + async def get_sinks(self, project_id: str): try: - client = stackdriverlogging.Client(project=project_id) + client = self.get_client(project_id) return await run_concurrently(lambda: [sink for sink in client.list_sinks()]) except Exception as e: print_exception(f'Failed to retrieve sinks: {e}') @@ -16,7 +24,7 @@ async def get_sinks(self, project_id: str): async def get_metrics(self, project_id: str): try: - client = stackdriverlogging.Client(project=project_id) + client = self.get_client(project_id) return await run_concurrently(lambda: [metric for metric in client.list_metrics()]) except Exception as e: print_exception(f'Failed to retrieve metrics: {e}') diff --git a/ScoutSuite/providers/gcp/facade/stackdrivermonitoring.py b/ScoutSuite/providers/gcp/facade/stackdrivermonitoring.py index 91ff94678..20d85bca6 100644 --- a/ScoutSuite/providers/gcp/facade/stackdrivermonitoring.py +++ b/ScoutSuite/providers/gcp/facade/stackdrivermonitoring.py @@ -1,14 +1,26 @@ from google.cloud import monitoring as stackdrivermonitoring +from google.api_core.gapic_v1.client_info import ClientInfo from ScoutSuite.core.console import print_exception from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent class StackdriverMonitoringFacade: + def get_uptime_client(self): + client_info = ClientInfo(user_agent=get_user_agent()) + client = stackdrivermonitoring.UptimeCheckServiceClient(client_info=client_info) + return client + + def get_alerts_client(self): + client_info = ClientInfo(user_agent=get_user_agent()) + client = stackdrivermonitoring.AlertPolicyServiceClient(client_info=client_info) + return client + async def get_uptime_checks(self, project_id: str): try: - client = stackdrivermonitoring.UptimeCheckServiceClient() + client = self.get_uptime_client() name = client.project_path(project_id) return await run_concurrently(lambda: [r for r in client.list_uptime_check_configs(name)]) except Exception as e: @@ -17,7 +29,7 @@ async def get_uptime_checks(self, project_id: str): async def get_alert_policies(self, project_id: str): try: - client = stackdrivermonitoring.AlertPolicyServiceClient() + client = self.get_alerts_client() name = client.project_path(project_id) return await run_concurrently(lambda: [r for r in client.list_alert_policies(name)]) except Exception as e: From 67a79bc98dbd6b3a988c1e5e316f697450c8749f Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 24 Sep 2020 11:09:51 +0200 Subject: [PATCH 288/312] Add user agent for native --- ScoutSuite/providers/gcp/facade/basefacade.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/providers/gcp/facade/basefacade.py b/ScoutSuite/providers/gcp/facade/basefacade.py index 24deaab91..31c7a2228 100755 --- a/ScoutSuite/providers/gcp/facade/basefacade.py +++ b/ScoutSuite/providers/gcp/facade/basefacade.py @@ -6,8 +6,12 @@ import httplib2shim httplib2shim.patch() +from googleapiclient import http from googleapiclient import discovery +from ScoutSuite.utils import get_user_agent + + class GCPBaseFacade: def __init__(self, client_name: str, client_version: str): self._client_name = client_name @@ -24,11 +28,16 @@ def _build_arbitrary_client(self, client_name, client_version, force_new=False): :param force_new: whether to create a new client - useful to create arbitrary clients from facades :return: """ + if force_new: - return discovery.build(client_name, client_version, cache_discovery=False, cache=MemoryCache()) + client = discovery.build(client_name, client_version, cache_discovery=False, cache=MemoryCache()) + http.set_user_agent(client._http, get_user_agent()) # force set custom user agent + return client else: if not self._client: - self._client = discovery.build(client_name, client_version, cache_discovery=False, cache=MemoryCache()) + client = discovery.build(client_name, client_version, cache_discovery=False, cache=MemoryCache()) + http.set_user_agent(client._http, get_user_agent()) # force set custom user agent + self._client = client return self._client def _get_client(self) -> discovery.Resource: From 83a8214e60f5c8df993c4c0c85fc126754ef1c16 Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 24 Sep 2020 11:53:51 +0200 Subject: [PATCH 289/312] Fix test --- tests/test_aws_provider.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/test_aws_provider.py b/tests/test_aws_provider.py index b15524e6b..395c9df63 100755 --- a/tests/test_aws_provider.py +++ b/tests/test_aws_provider.py @@ -10,15 +10,20 @@ from unittest import mock +class Object(object): + pass + + # Test methods for AWS Provider class TestAWSProviderClass(unittest.TestCase): @mock.patch("ScoutSuite.providers.aws.authentication_strategy.boto3") @mock.patch("ScoutSuite.providers.aws.authentication_strategy.get_caller_identity") - def test_authenticate(self, mock_get_caller_identity, mock_Session): + def test_authenticate(self, mock_get_caller_identity, mock_session): auth_strat = get_authentication_strategy("aws") - boto3_session = "_boto3_session_" - mock_Session.Session.return_value = boto3_session + boto3_session = Object() + boto3_session._session = Object() + mock_session.Session.return_value = boto3_session test_cases = [ # no params @@ -69,13 +74,13 @@ def test_authenticate(self, mock_get_caller_identity, mock_Session): test_case["aws_secret_access_key"], test_case["aws_session_token"], ) - mock_Session.Session.assert_called_with(**test_case["call_dict"]) + mock_session.Session.assert_called_with(**test_case["call_dict"]) mock_get_caller_identity.assert_called_with(boto3_session) assert isinstance(result, AWSCredentials) assert result.session == boto3_session # exception test - mock_Session.Session.side_effect = Exception("an exception") + mock_session.Session.side_effect = Exception("an exception") with pytest.raises(AuthenticationException): result = auth_strat.authenticate(None, None, None, None) From 9ba42ee928276a04b092e04cc8c8c12581854949 Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 24 Sep 2020 12:46:25 +0200 Subject: [PATCH 290/312] Move concurrency to paginator --- ScoutSuite/providers/gcp/facade/utils.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ScoutSuite/providers/gcp/facade/utils.py b/ScoutSuite/providers/gcp/facade/utils.py index 543eb5a6e..eb4c0ef55 100755 --- a/ScoutSuite/providers/gcp/facade/utils.py +++ b/ScoutSuite/providers/gcp/facade/utils.py @@ -1,17 +1,18 @@ from ScoutSuite.providers.utils import run_concurrently + class GCPFacadeUtils: @staticmethod - def _get_all(resources, resource_key: str, request, resources_group): + async def _get_all(resources, resource_key: str, request, resources_group): while request is not None: response = request.execute() resources.extend(response.get(resource_key, [])) - request = resources_group.list_next(previous_request=request, previous_response=response) + request = await run_concurrently( + lambda: resources_group.list_next(previous_request=request, previous_response=response) + ) @staticmethod async def get_all(resource_key: str, request, resources_group): resources = [] - await run_concurrently( - lambda: GCPFacadeUtils._get_all(resources, resource_key, request, resources_group) - ) + await GCPFacadeUtils._get_all(resources, resource_key, request, resources_group) return resources From 9b815c6babe135f443a79ae32df39e641dc2ea9a Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 24 Sep 2020 13:43:01 +0200 Subject: [PATCH 291/312] Add throttling detection for GCP --- ScoutSuite/providers/gcp/utils.py | 17 +++++++++++++++++ ScoutSuite/providers/utils.py | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 ScoutSuite/providers/gcp/utils.py diff --git a/ScoutSuite/providers/gcp/utils.py b/ScoutSuite/providers/gcp/utils.py new file mode 100644 index 000000000..16f1eae9b --- /dev/null +++ b/ScoutSuite/providers/gcp/utils.py @@ -0,0 +1,17 @@ +from ScoutSuite.core.console import print_exception + +def is_throttled(e): + """ + Determines whether the exception is due to API throttling. + + :param e: Exception raised + :return: True if it's a throttling exception else False + """ + try: + if 'Quota exceeded' in str(e): + return True + else: + return False + except Exception as e: + print_exception(f'Unable to validate exception for throttling: {e}') + return False diff --git a/ScoutSuite/providers/utils.py b/ScoutSuite/providers/utils.py index 26ae594d5..537fc1cc3 100755 --- a/ScoutSuite/providers/utils.py +++ b/ScoutSuite/providers/utils.py @@ -3,6 +3,7 @@ from ScoutSuite.core.console import print_info from ScoutSuite.providers.aws.utils import is_throttled as aws_is_throttled +from ScoutSuite.providers.gcp.utils import is_throttled as gcp_is_throttled def get_non_provider_id(name): @@ -118,4 +119,4 @@ def is_throttled(e): 'projects/' in e.message): return False else: - return aws_is_throttled(e) + return aws_is_throttled(e) or gcp_is_throttled(e) From b9a1d94fc68d923be23b40e3d2eceb83de81e17c Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 24 Sep 2020 13:52:41 +0200 Subject: [PATCH 292/312] Add user agent setting into this method too --- ScoutSuite/providers/gcp/facade/utils.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ScoutSuite/providers/gcp/facade/utils.py b/ScoutSuite/providers/gcp/facade/utils.py index 543eb5a6e..e6fce5eb5 100755 --- a/ScoutSuite/providers/gcp/facade/utils.py +++ b/ScoutSuite/providers/gcp/facade/utils.py @@ -1,4 +1,7 @@ from ScoutSuite.providers.utils import run_concurrently +from ScoutSuite.utils import get_user_agent + +from googleapiclient import http class GCPFacadeUtils: @staticmethod @@ -10,6 +13,10 @@ def _get_all(resources, resource_key: str, request, resources_group): @staticmethod async def get_all(resource_key: str, request, resources_group): + # force set custom user agent + http.set_user_agent(request.http, get_user_agent()) + request.headers['user-agent'] = get_user_agent() + resources = [] await run_concurrently( lambda: GCPFacadeUtils._get_all(resources, resource_key, request, resources_group) From 6d58c9f532ca87ca0dd0623d51420935d7f715a8 Mon Sep 17 00:00:00 2001 From: xga Date: Thu, 24 Sep 2020 13:52:49 +0200 Subject: [PATCH 293/312] Reformat code --- ScoutSuite/providers/gcp/facade/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ScoutSuite/providers/gcp/facade/utils.py b/ScoutSuite/providers/gcp/facade/utils.py index e6fce5eb5..8ca4755af 100755 --- a/ScoutSuite/providers/gcp/facade/utils.py +++ b/ScoutSuite/providers/gcp/facade/utils.py @@ -3,6 +3,7 @@ from googleapiclient import http + class GCPFacadeUtils: @staticmethod def _get_all(resources, resource_key: str, request, resources_group): From b763d287bc52ccda24102047c5c2f778d5764725 Mon Sep 17 00:00:00 2001 From: xga Date: Fri, 25 Sep 2020 13:59:07 +0200 Subject: [PATCH 294/312] Fix button positioning --- ScoutSuite/output/data/html/partials/resources_details.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ScoutSuite/output/data/html/partials/resources_details.html b/ScoutSuite/output/data/html/partials/resources_details.html index 168155e2b..db8518e53 100755 --- a/ScoutSuite/output/data/html/partials/resources_details.html +++ b/ScoutSuite/output/data/html/partials/resources_details.html @@ -2,8 +2,9 @@