#!/usr/bin/env bash # Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy # of the License at http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software distributed # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra771="7.71" CHECK_TITLE_extra771="[extra771] Check if S3 buckets have policies which allow WRITE access " CHECK_SCORED_extra771="NOT_SCORED" CHECK_CIS_LEVEL_extra771="EXTRA" CHECK_SEVERITY_extra771="Critical" CHECK_ASFF_RESOURCE_TYPE_extra771="AwsS3Bucket" CHECK_ALTERNATE_check771="extra771" CHECK_SERVICENAME_extra771="s3" CHECK_RISK_extra771='Non intended users can put objects in a given bucket.' CHECK_REMEDIATION_extra771='Ensure proper bucket policy is in place with the least privilege principle applied.' CHECK_DOC_extra771='https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_rw-bucket.html' CHECK_CAF_EPIC_extra771='IAM' extra771(){ LIST_OF_BUCKETS=$("${AWSCLI}" s3api list-buckets $PROFILE_OPT --region "${REGION}" --query "sort_by(Buckets, &Name)[].Name" --output text 2>&1) if [[ $(echo "${LIST_OF_BUCKETS}" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then textInfo "${REGION}: Access Denied trying to list buckets" "${REGION}" return fi if [[ "${LIST_OF_BUCKETS}" ]]; then for bucket in ${LIST_OF_BUCKETS};do BUCKET_POLICY_STATEMENTS=$("${AWSCLI}" s3api $PROFILE_OPT get-bucket-policy --region "${REGION}" --bucket "${bucket}" --output json --query Policy 2>&1) if [[ $(echo "${BUCKET_POLICY_STATEMENTS}" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then textInfo "${REGION}: Access Denied trying to get bucket policy for ${bucket}" "${REGION}" continue fi if [[ $(echo "${BUCKET_POLICY_STATEMENTS}" | grep 'NoSuchBucketPolicy') ]]; then textInfo "$REGION: Bucket policy does not exist for bucket $bucket" "$REGION" else BUCKET_POLICY_BAD_STATEMENTS=$(echo "${BUCKET_POLICY_STATEMENTS}" | jq --compact-output --arg arn "arn:${AWS_PARTITION}:s3:::$bucket" 'fromjson | .Statement[]|select( .Effect=="Allow" and ( ( (.Principal|type == "object") and (.Principal.AWS == "*") ) or ( (.Principal|type == "string") and (.Principal == "*") ) ) and ( ( (.Action|type == "string") and (.Action|startswith("s3:Put")) ) or ( (.Action|type == "string") and (.Action|startswith("s3:*")) ) or ( (.Action|type == "array") and (.Action[]|startswith("s3:Put")) ) or ( (.Action|type == "array") and (.Action[]|startswith("s3:*")) ) ) and .Condition == null )' | tr '\n' ' ') # Make sure JSON comma characted will not break CSV output. Replace "," by word "[comma]" BUCKET_POLICY_BAD_STATEMENTS="${BUCKET_POLICY_BAD_STATEMENTS//,/[comma]}" if [[ "${BUCKET_POLICY_BAD_STATEMENTS}" != "" ]]; then textFail "${REGION}: Bucket ${bucket} allows public write: ${BUCKET_POLICY_BAD_STATEMENTS}" "${REGION}" "${bucket}" else textPass "${REGION}: Bucket ${bucket} has S3 bucket policy which does not allow public write access" "${REGION}" "${bucket}" fi fi done else textInfo "${REGION}: No S3 Buckets found" fi }