def test_empty_statements(self): """If there are no statements, it should not break.""" empty_statements = {"Version": "2012-10-17", "Statement": []} empty_statements_document = PolicyDocument( policy=empty_statements, service="iam", ) results = json.loads(empty_statements_document.__str__()) print(json.dumps(results, indent=4)) self.assertDictEqual(results, empty_statements)
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" # If you do not know the names of the policies that are attached to the identity, you can use ListIdentityPolicies logger.debug("Getting resource policy for %s" % self.arn) # When there is no policy, let's return an empty policy to avoid breaking things policy = constants.get_empty_policy() try: # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ses.html#SES.Client.list_identity_policies response = self.client.list_identity_policies(Identity=self.name) # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ses.html#SES.Client.get_identity_policies policy_names = response.get("PolicyNames") if policy_names: response = self.client.get_identity_policies(Identity=self.name, PolicyNames=policy_names) policies = response.get("Policies") if constants.SID_SIGNATURE in policies: policy = json.loads(policies.get(constants.SID_SIGNATURE)) success = True else: policy = constants.get_empty_policy() success = True except botocore.exceptions.ClientError: success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self.override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" logger.debug("Getting resource policy for %s" % self.arn) # When there is no policy, let's return an empty policy to avoid breaking things policy = constants.get_empty_policy() try: # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glacier.html#Glacier.Client.get_vault_access_policy response = self.client.get_vault_access_policy(vaultName=self.name) policy = json.loads(response.get("policy").get("Policy")) success = True # This is silly. If there is no access policy set on the vault, then it returns the same error as if the vault didn't exist. except self.client.exceptions.ResourceNotFoundException as error: logger.debug(error) success = True except botocore.exceptions.ClientError: success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" logger.debug("Getting resource policy for %s" % self.arn) try: response = self.client.get_role(RoleName=self.name) policy = response.get("Role").get("AssumeRolePolicyDocument") success = True except self.client.exceptions.NoSuchEntityException: logger.critical(f"There is no resource with the name {self.name}") policy = constants.get_empty_policy() success = False except botocore.exceptions.ClientError: # When there is no policy, let's return an empty policy to avoid breaking things policy = constants.get_empty_policy() success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" logger.debug("Getting resource policy for %s" % self.arn) policy = constants.get_empty_policy() try: # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ecr.html#ECR.Client.get_repository_policy response = self.client.get_repository_policy( repositoryName=self.name) policy = json.loads(response.get("policyText")) success = True except self.client.exceptions.RepositoryPolicyNotFoundException: logger.debug("Policy not found. Setting policy document to empty.") success = True except self.client.exceptions.RepositoryNotFoundException: logger.critical("Repository does not exist") success = False except botocore.exceptions.ClientError: # When there is no policy, let's return an empty policy to avoid breaking things success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" logger.debug("Getting resource policy for %s" % self.arn) # When there is no policy, let's return an empty policy to avoid breaking things policy = constants.get_empty_policy() try: response = self.client.get_topic_attributes(TopicArn=self.arn) attributes = response.get("Attributes") if attributes.get("Policy"): policy = constants.get_empty_policy() policy["Statement"].extend( json.loads(attributes.get("Policy")).get("Statement")) else: policy = constants.get_empty_policy() success = True except self.client.exceptions.ResourceNotFoundException as error: logger.critical(error) success = False except botocore.exceptions.ClientError as error: logger.critical(error) success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" policy = constants.get_empty_policy() try: # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/acm-pca.html#ACMPCA.Client.get_policy response = self.client.get_policy(ResourceArn=self.arn) policy = json.loads(response.get("Policy")) success = True # This is dumb. "If either the private CA resource or the policy cannot be found, this action returns a ResourceNotFoundException." # That means we have to set it to true, even when the resource doesn't exist. smh. # That will only affect the expose command and not the smash command. except self.client.exceptions.ResourceNotFoundException: logger.debug(f"Resource {self.name} not found") success = True except botocore.exceptions.ClientError: # When there is no policy, let's return an empty policy to avoid breaking things success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" logger.debug("Getting resource policy for %s" % self.arn) policy = constants.get_empty_policy() try: response = self.client.get_bucket_policy(Bucket=self.name) policy = json.loads(response.get("Policy")) message = "200: Successfully obtained bucket policy for %s" % self.arn success = True except botocore.exceptions.ClientError as error: error_code = error.response['Error']['Code'] message = f"{error_code}: {error.response.get('Error').get('Message')} for {error.response.get('Error').get('BucketName')}" if error.response['Error']['Code'] == "AccessDenied": success = False elif error.response['Error']['Code'] == "NoSuchBucketPolicy": success = True else: # This occurs when there is no resource policy attached success = True except Exception as error: message = error success = False logger.debug(message) policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: logger.debug("Getting resource policy for %s" % self.arn) # When there is no policy, let's return an empty policy to avoid breaking things policy = constants.get_empty_policy() try: response = self.client.get_layer_version_policy( LayerName=self.name, VersionNumber=self.version) policy = json.loads(response.get("Policy")) success = True except self.client.exceptions.ResourceNotFoundException as error: logger.debug("The Policy does not exist. We will have to add it.") success = True except botocore.exceptions.ClientError as error: logger.critical(error) success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/kms.html#KMS.Client.get_key_policy logger.debug("Getting resource policy for %s" % self.arn) try: response = self.client.get_key_policy(KeyId=self.arn, PolicyName="default") if response.get("Policy"): policy = constants.get_empty_policy() policy["Statement"].extend( json.loads(response.get("Policy")).get("Statement")) else: policy = constants.get_empty_policy() success = True except botocore.exceptions.ClientError: # When there is no policy, let's return an empty policy to avoid breaking things policy = constants.get_empty_policy() success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" logger.debug("Getting resource policy for %s" % self.arn) try: # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ses.html#SES.Client.list_identity_policies response = self.client.describe_elasticsearch_domain_config(DomainName=self.name) domain_config = response.get("DomainConfig") policy = domain_config.get("AccessPolicies").get("Options") if policy: policy = json.loads(policy) else: policy = constants.get_empty_policy() success = True except botocore.exceptions.ClientError: # When there is no policy, let's return an empty policy to avoid breaking things policy = constants.get_empty_policy() success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self.override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def _get_rbp(self) -> ResponseGetRbp: """Get the resource based policy for this resource and store it""" logger.debug("Getting resource policy for %s" % self.arn) try: response = self.client.get_resource_policy(SecretId=self.name) if response.get("ResourcePolicy"): policy = json.loads(response.get("ResourcePolicy")) else: policy = constants.get_empty_policy() success = True except botocore.exceptions.ClientError: # When there is no policy, let's return an empty policy to avoid breaking things policy = constants.get_empty_policy() success = False policy_document = PolicyDocument( policy=policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) response = ResponseGetRbp(policy_document=policy_document, success=success) return response
def test_policy_plus_evil_principal(self): empty_statements = {"Version": "2012-10-17", "Statement": []} empty_statements_document = PolicyDocument( policy=empty_statements, service="iam", override_resource_block="*", ) policy = empty_statements_document.policy_plus_evil_principal( victim_account_id="111122223333", evil_principal="arn:aws:iam::999988887777:user/mwahahaha") print(json.dumps(policy, indent=4)) self.assertEqual(policy["Statement"][0]["Sid"], "AllowCurrentAccount") self.assertEqual(policy["Statement"][0]["Principal"]["AWS"][0], "arn:aws:iam::111122223333:root") self.assertEqual(policy["Statement"][1]["Sid"], "Endgame") self.assertEqual(policy["Statement"][1]["Principal"]["AWS"][0], "arn:aws:iam::999988887777:user/mwahahaha")
def set_rbp(self, evil_policy: dict) -> ResponseMessage: logger.debug("Setting resource policy for %s" % self.arn) new_policy_document = PolicyDocument( policy=evil_policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) new_policy_json = {"Version": "2012-10-17", "Statement": []} current_sids = get_sid_names_with_error_handling(self.original_policy) success = True try: for statement in new_policy_document.statements: if statement.sid not in current_sids: if ":" in statement.aws_principals[0]: account_id = get_account_from_arn( statement.aws_principals[0]) principal = f"arn:aws:iam::{account_id}:root" elif "*" == statement.aws_principals[0]: principal = "*" else: principal = statement.aws_principals[0] try: self.client.add_layer_version_permission( LayerName=self.arn_without_version, VersionNumber=self.version, StatementId=statement.sid, Action="lambda:GetLayerVersion", Principal=principal, ) except botocore.exceptions.ClientError as error: success = False logger.critical( f"Operation was not successful for {self.service} {self.resource_type} " f"{self.name}. %s" % error) new_policy_json["Statement"].append( json.loads(statement.__str__())) message = "success" except botocore.exceptions.ClientError as error: message = str(error) success = False policy_document = self._get_rbp().policy_document response_message = ResponseMessage( message=message, operation="set_rbp", success=success, evil_principal="", victim_resource_arn=self.arn, original_policy=self.original_policy, updated_policy=policy_document.json, resource_type=self.resource_type, resource_name=self.name, service=self.service) return response_message
def test_get_allow_current_account_id(self): """Allow Current account ID""" empty_statements = {"Version": "2012-10-17", "Statement": []} empty_statements_document = PolicyDocument(policy=empty_statements, service="iam", override_resource_block="*") statement = empty_statements_document.statement_allow_account_id( "999988887777", "*") # results = json.loads(empty_statements_document.__str__()) print(json.dumps(statement, indent=4)) # self.assertDictEqual(results, empty_statements) expected_result = { "Sid": "AllowCurrentAccount", "Effect": "Allow", "Principal": { "AWS": ["arn:aws:iam::999988887777:root"] }, "Resource": ["*"], "Action": ["iam:*"] } self.assertEqual(statement["Resource"][0], "*") self.assertDictEqual(statement, expected_result)
def set_rbp(self, evil_policy: dict) -> ResponseMessage: logger.debug("Setting resource policy for %s" % self.arn) new_policy_document = PolicyDocument( policy=evil_policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) new_policy_json = {"Version": "2012-10-17", "Statement": []} current_sids = get_sid_names_with_error_handling(self.original_policy) try: for statement in new_policy_document.statements: if statement.sid not in current_sids: account_ids = [] for principal in statement.aws_principals: if ":" in principal: account_ids.append(get_account_from_arn(principal)) self.client.add_permission( QueueUrl=self.queue_url, Label=statement.sid, AWSAccountIds=account_ids, Actions=self.sqs_actions_without_prefixes( statement.actions)) else: new_policy_json["Statement"].append( json.loads(statement.__str__())) message = "success" success = True except botocore.exceptions.ClientError as error: message = str(error) success = False get_rbp_response = self._get_rbp() response_message = ResponseMessage( message=message, operation="set_rbp", success=success, evil_principal="", victim_resource_arn=self.arn, original_policy=self.original_policy, updated_policy=get_rbp_response.policy_document.json, resource_type=self.resource_type, resource_name=self.name, service=self.service) return response_message
def set_rbp(self, evil_policy: dict) -> ResponseMessage: logger.debug("Setting resource policy for %s" % self.arn) new_policy_document = PolicyDocument( policy=evil_policy, service=self.service, override_action=self.override_action, include_resource_block=self.include_resource_block, override_resource_block=self.override_resource_block, override_account_id_instead_of_principal=self. override_account_id_instead_of_principal, ) new_policy_json = {"Version": "2012-10-17", "Statement": []} current_sids = get_sid_names_with_error_handling(self.original_policy) try: for statement in new_policy_document.statements: if statement.sid not in current_sids: self.client.add_permission( TopicArn=self.arn, Label=statement.sid, ActionName=self.sns_actions_without_prefixes( statement.actions), AWSAccountId=statement.aws_principals, ) new_policy_json["Statement"].append( json.loads(statement.__str__())) message = "success" success = True except botocore.exceptions.ClientError as error: message = str(error) success = False logger.critical( f"Operation was not successful for {self.service} {self.resource_type} " f"{self.name}. %s" % error) get_rbp_response = self._get_rbp() response_message = ResponseMessage( message=message, operation="set_rbp", success=success, evil_principal="", victim_resource_arn=self.arn, original_policy=self.original_policy, updated_policy=get_rbp_response.policy_document.json, resource_type=self.resource_type, resource_name=self.name, service=self.service) return response_message
def setUp(self): self.override_account_id_document = PolicyDocument( policy=kms_policy, service="kms", override_account_id_instead_of_principal=True, override_resource_block="*") self.policy_with_principal_service = PolicyDocument( policy=ec2_assume_role_policy, service="iam", override_action="sts:AssumeRole", override_account_id_instead_of_principal=False, include_resource_block=False) self.override_action_policy = PolicyDocument( policy=ec2_assume_role_policy, service="iam", override_action="sts:Yolo", override_account_id_instead_of_principal=False, include_resource_block=False)
class PolicyDocumentTestCase(unittest.TestCase): def setUp(self): self.override_account_id_document = PolicyDocument( policy=kms_policy, service="kms", override_account_id_instead_of_principal=True, override_resource_block="*") self.policy_with_principal_service = PolicyDocument( policy=ec2_assume_role_policy, service="iam", override_action="sts:AssumeRole", override_account_id_instead_of_principal=False, include_resource_block=False) self.override_action_policy = PolicyDocument( policy=ec2_assume_role_policy, service="iam", override_action="sts:Yolo", override_account_id_instead_of_principal=False, include_resource_block=False) def test_override_account_id_instead_of_principal(self): results = json.loads(self.override_account_id_document.__str__()) allow_current_account_id = results['Statement'][0]['Principal']['AWS'][ 0] self.assertEqual(allow_current_account_id, "123456789012") evil_current_account_id = results['Statement'][1]['Principal']['AWS'][ 0] self.assertEqual(evil_current_account_id, "999988887777") # print(json.dumps(results, indent=4)) def test_statement_with_principal_service(self): results = json.loads(self.policy_with_principal_service.__str__()) print(json.dumps(results, indent=4)) expected_results = { "Version": "2012-10-17", "Statement": [{ "Sid": "", "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" }] } self.assertDictEqual(results, expected_results) def test_override_action(self): results = json.loads(self.override_action_policy.__str__()) print(json.dumps(results, indent=4)) expected_results = { "Version": "2012-10-17", "Statement": [{ "Sid": "", "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:Yolo" }] } self.assertDictEqual(results, expected_results) def test_empty_statements(self): """If there are no statements, it should not break.""" empty_statements = {"Version": "2012-10-17", "Statement": []} empty_statements_document = PolicyDocument( policy=empty_statements, service="iam", ) results = json.loads(empty_statements_document.__str__()) print(json.dumps(results, indent=4)) self.assertDictEqual(results, empty_statements) def test_get_allow_current_account_id(self): """Allow Current account ID""" empty_statements = {"Version": "2012-10-17", "Statement": []} empty_statements_document = PolicyDocument(policy=empty_statements, service="iam", override_resource_block="*") statement = empty_statements_document.statement_allow_account_id( "999988887777", "*") # results = json.loads(empty_statements_document.__str__()) print(json.dumps(statement, indent=4)) # self.assertDictEqual(results, empty_statements) expected_result = { "Sid": "AllowCurrentAccount", "Effect": "Allow", "Principal": { "AWS": ["arn:aws:iam::999988887777:root"] }, "Resource": ["*"], "Action": ["iam:*"] } self.assertEqual(statement["Resource"][0], "*") self.assertDictEqual(statement, expected_result) def test_policy_plus_evil_principal(self): empty_statements = {"Version": "2012-10-17", "Statement": []} empty_statements_document = PolicyDocument( policy=empty_statements, service="iam", override_resource_block="*", ) policy = empty_statements_document.policy_plus_evil_principal( victim_account_id="111122223333", evil_principal="arn:aws:iam::999988887777:user/mwahahaha") print(json.dumps(policy, indent=4)) self.assertEqual(policy["Statement"][0]["Sid"], "AllowCurrentAccount") self.assertEqual(policy["Statement"][0]["Principal"]["AWS"][0], "arn:aws:iam::111122223333:root") self.assertEqual(policy["Statement"][1]["Sid"], "Endgame") self.assertEqual(policy["Statement"][1]["Principal"]["AWS"][0], "arn:aws:iam::999988887777:user/mwahahaha")