diff --git a/checks/check21 b/checks/check21 index d34ed292b5..90ba9c9e70 100644 --- a/checks/check21 +++ b/checks/check21 @@ -53,16 +53,16 @@ check21(){ textFail "$regx: Trail $trail is configured for all regions but it is OFF" "$regx" "$trail" else textPass "$regx: Trail $trail is enabled for all regions" "$regx" "$trail" - fi + fi fi done fi + if [[ $trail_count == 0 ]]; then + if [[ $FILTERREGION ]]; then + textFail "$regx: No CloudTrail trails were found in the filtered region" "$regx" "$trail" + else + textFail "$regx: No CloudTrail trails were found in the account" "$regx" "$trail" + fi + fi done - if [[ $trail_count == 0 ]]; then - if [[ $FILTERREGION ]]; then - textFail "$regx: No CloudTrail trails were found in the filtered region" "$regx" "$trail" - else - textFail "$regx: No CloudTrail trails were found in the account" "$regx" "$trail" - fi - fi -} \ No newline at end of file +} diff --git a/checks/check22 b/checks/check22 index 98488b2b56..3b1a1d203c 100644 --- a/checks/check22 +++ b/checks/check22 @@ -53,8 +53,8 @@ check22(){ done fi + if [[ $trail_count == 0 ]]; then + textFail "$regx: No CloudTrail trails were found in the account" "$regx" "$trail" + fi done - if [[ $trail_count == 0 ]]; then - textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" - fi } diff --git a/checks/check23 b/checks/check23 index 55be872c92..ea00f4a1d4 100644 --- a/checks/check23 +++ b/checks/check23 @@ -87,8 +87,8 @@ check23(){ done fi + if [[ $trail_count == 0 ]]; then + textFail "$regx: No CloudTrail trails were found in the account" "$regx" "$trail" + fi done - if [[ $trail_count == 0 ]]; then - textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" - fi } diff --git a/checks/check24 b/checks/check24 index 9a04d0aeda..b117124d86 100644 --- a/checks/check24 +++ b/checks/check24 @@ -59,8 +59,8 @@ check24(){ done fi + if [[ $trail_count == 0 ]]; then + textFail "$regx: No CloudTrail trails were found in the account" "$regx" "$trail" + fi done - if [[ $trail_count == 0 ]]; then - textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" - fi } diff --git a/checks/check26 b/checks/check26 index 405e6800d6..6e81868838 100644 --- a/checks/check26 +++ b/checks/check26 @@ -86,8 +86,8 @@ check26(){ done fi + if [[ $trail_count == 0 ]]; then + textFail "$regx: No CloudTrail trails were found in the account" "$regx" "$trail" + fi done - if [[ $trail_count == 0 ]]; then - textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" - fi } diff --git a/checks/check27 b/checks/check27 index 166b1a07e6..0a5530db01 100644 --- a/checks/check27 +++ b/checks/check27 @@ -52,8 +52,8 @@ check27(){ fi done fi + if [[ $trail_count == 0 ]]; then + textFail "$regx: No CloudTrail trails were found in the account" "$regx" "$trail" + fi done - if [[ $trail_count == 0 ]]; then - textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" - fi } diff --git a/checks/check_extra7102 b/checks/check_extra7102 index bb04ea3d34..a0a9d5194d 100644 --- a/checks/check_extra7102 +++ b/checks/check_extra7102 @@ -32,31 +32,31 @@ CHECK_CAF_EPIC_extra7102='Infrastructure Security' # Each finding will be saved in prowler/output folder for further review. extra7102(){ - if [[ ! $SHODAN_API_KEY ]]; then - textInfo "[extra7102] Requires a Shodan API key to work. Use -N " "$REGION" - else for regx in $REGIONS; do - LIST_OF_EIP=$($AWSCLI $PROFILE_OPT --region $regx ec2 describe-network-interfaces --query 'NetworkInterfaces[*].Association.PublicIp' --output text 2>&1) - if [[ $(echo "$LIST_OF_EIP" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then - textInfo "$regx: Access Denied trying to describe network interfaces" "$regx" - continue - fi - if [[ $LIST_OF_EIP ]]; then - for ip in $LIST_OF_EIP;do - SHODAN_QUERY=$(curl -ks https://api.shodan.io/shodan/host/$ip?key=$SHODAN_API_KEY) - # Shodan has a request rate limit of 1 request/second. - sleep 1 - if [[ $SHODAN_QUERY == *"No information available for that IP"* ]]; then - textPass "$regx: IP $ip is not listed in Shodan" "$regx" - else - echo $SHODAN_QUERY > $OUTPUT_DIR/shodan-output-$ip.json - IP_SHODAN_INFO=$(cat $OUTPUT_DIR/shodan-output-$ip.json | jq -r '. | { ports: .ports, org: .org, country: .country_name }| @text' | tr -d \"\{\}\}\]\[ | tr , '\ ' ) - textFail "$regx: IP $ip is listed in Shodan with data $IP_SHODAN_INFO. More info https://www.shodan.io/host/$ip and $OUTPUT_DIR/shodan-output-$ip.json" "$regx" "$ip" - fi - done + if [[ ! $SHODAN_API_KEY ]]; then + textInfo "$regx: Requires a Shodan API key to work. Use -N " "$regx" else - textInfo "$regx: No Public or Elastic IPs found" "$regx" + LIST_OF_EIP=$($AWSCLI $PROFILE_OPT --region $regx ec2 describe-network-interfaces --query 'NetworkInterfaces[*].Association.PublicIp' --output text 2>&1) + if [[ $(echo "$LIST_OF_EIP" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe network interfaces" "$regx" + continue + fi + if [[ $LIST_OF_EIP ]]; then + for ip in $LIST_OF_EIP;do + SHODAN_QUERY=$(curl -ks https://api.shodan.io/shodan/host/$ip?key=$SHODAN_API_KEY) + # Shodan has a request rate limit of 1 request/second. + sleep 1 + if [[ $SHODAN_QUERY == *"No information available for that IP"* ]]; then + textPass "$regx: IP $ip is not listed in Shodan" "$regx" + else + echo $SHODAN_QUERY > $OUTPUT_DIR/shodan-output-$ip.json + IP_SHODAN_INFO=$(cat $OUTPUT_DIR/shodan-output-$ip.json | jq -r '. | { ports: .ports, org: .org, country: .country_name }| @text' | tr -d \"\{\}\}\]\[ | tr , '\ ' ) + textFail "$regx: IP $ip is listed in Shodan with data $IP_SHODAN_INFO. More info https://www.shodan.io/host/$ip and $OUTPUT_DIR/shodan-output-$ip.json" "$regx" "$ip" + fi + done + else + textInfo "$regx: No Public or Elastic IPs found" "$regx" + fi fi done - fi } diff --git a/checks/check_extra7166 b/checks/check_extra7166 index d4cc93bdcc..ecc1fe3d16 100644 --- a/checks/check_extra7166 +++ b/checks/check_extra7166 @@ -25,11 +25,11 @@ CHECK_DOC_extra7166='https://docs.aws.amazon.com/waf/latest/developerguide/confi CHECK_CAF_EPIC_extra7166='Infrastructure security' extra7166() { - if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then - CALLER_IDENTITY=$($AWSCLI sts get-caller-identity $PROFILE_OPT --query Arn) - PARTITION=$(echo $CALLER_IDENTITY | cut -d: -f2) - ACCOUNT_ID=$(echo $CALLER_IDENTITY | cut -d: -f5) - for regx in $REGIONS; do + for regx in $REGIONS; do + if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then + CALLER_IDENTITY=$($AWSCLI sts get-caller-identity $PROFILE_OPT --query Arn) + PARTITION=$(echo $CALLER_IDENTITY | cut -d: -f2) + ACCOUNT_ID=$(echo $CALLER_IDENTITY | cut -d: -f5) LIST_OF_ELASTIC_IPS_WITH_ASSOCIATIONS=$($AWSCLI ec2 describe-addresses $PROFILE_OPT --region $regx --query 'Addresses[?AssociationId].AllocationId' --output text) if [[ $LIST_OF_ELASTIC_IPS_WITH_ASSOCIATIONS ]]; then for elastic_ip in $LIST_OF_ELASTIC_IPS_WITH_ASSOCIATIONS; do @@ -41,10 +41,10 @@ extra7166() { fi done else - textInfo "$regx: no elastic IP addresses with assocations found" "$regx" + textInfo "$regx: No elastic IP addresses with assocations found" "$regx" fi - done - else - textInfo "$regx: no AWS Shield Advanced subscription found. Skipping check" "$regx" - fi + else + textInfo "$regx: No AWS Shield Advanced subscription found. Skipping check" "$regx" + fi + done } diff --git a/checks/check_extra7170 b/checks/check_extra7170 index ee197f9e1a..2c55c45971 100644 --- a/checks/check_extra7170 +++ b/checks/check_extra7170 @@ -25,8 +25,8 @@ CHECK_DOC_extra7170='https://docs.aws.amazon.com/waf/latest/developerguide/confi CHECK_CAF_EPIC_extra7170='Infrastructure security' extra7170() { - if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then - for regx in $REGIONS; do + for regx in $REGIONS; do + if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then LIST_OF_APPLICATION_LOAD_BALANCERS=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Type == `application` && Scheme == `internet-facing`].[LoadBalancerName,LoadBalancerArn]' --output text) if [[ $LIST_OF_APPLICATION_LOAD_BALANCERS ]]; then while read -r alb; do @@ -39,10 +39,10 @@ extra7170() { fi done <<<"$LIST_OF_APPLICATION_LOAD_BALANCERS" else - textInfo "$regx: no application load balancers found" "$regx" + textInfo "$regx: No application load balancers found" "$regx" fi - done - else - textInfo "$REGION: no AWS Shield Advanced subscription found. Skipping check." "$REGION" - fi + else + textInfo "$regx: No AWS Shield Advanced subscription found. Skipping check." "$regx" + fi + done } diff --git a/checks/check_extra7171 b/checks/check_extra7171 index a713083303..cd11f06269 100644 --- a/checks/check_extra7171 +++ b/checks/check_extra7171 @@ -25,11 +25,11 @@ CHECK_DOC_extra7171='https://docs.aws.amazon.com/waf/latest/developerguide/confi CHECK_CAF_EPIC_extra7171='Infrastructure security' extra7171() { - if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then - CALLER_IDENTITY=$($AWSCLI sts get-caller-identity $PROFILE_OPT --query Arn) - PARTITION=$(echo $CALLER_IDENTITY | cut -d: -f2) - ACCOUNT_ID=$(echo $CALLER_IDENTITY | cut -d: -f5) - for regx in $REGIONS; do + for regx in $REGIONS; do + if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then + CALLER_IDENTITY=$($AWSCLI sts get-caller-identity $PROFILE_OPT --query Arn) + PARTITION=$(echo $CALLER_IDENTITY | cut -d: -f2) + ACCOUNT_ID=$(echo $CALLER_IDENTITY | cut -d: -f5) LIST_OF_CLASSIC_LOAD_BALANCERS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[?Scheme == `internet-facing`].[LoadBalancerName]' --output text |grep -v '^None$') if [[ $LIST_OF_CLASSIC_LOAD_BALANCERS ]]; then for elb in $LIST_OF_CLASSIC_LOAD_BALANCERS; do @@ -41,10 +41,10 @@ extra7171() { fi done else - textInfo "$regx: no classic load balancers found" "$regx" + textInfo "$regx: No classic load balancers found" "$regx" fi - done - else - textInfo "$REGION: no AWS Shield Advanced subscription found. Skipping check." "$REGION" - fi + else + textInfo "$regx: No AWS Shield Advanced subscription found. Skipping check." "$regx" + fi + done } diff --git a/checks/check_extra771 b/checks/check_extra771 index 792ce42404..f46aa845f4 100644 --- a/checks/check_extra771 +++ b/checks/check_extra771 @@ -33,8 +33,8 @@ extra771(){ for bucket in ${LIST_OF_BUCKETS};do # Recover Bucket region BUCKET_REGION=$("${AWSCLI}" ${PROFILE_OPT} s3api get-bucket-location --bucket "${bucket}" --query LocationConstraint --output text) - if grep -q -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' <<< "${BUCKET_POLICY_STATEMENTS}"; then - textInfo "${REGION}: Access Denied trying to get bucket policy for ${bucket}" "${REGION}" + if grep -q -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' <<< "${BUCKET_REGION}"; then + textInfo "${REGION}: Access Denied trying to get bucket location for ${bucket}" "${REGION}" fi # If None use default region if [[ "${BUCKET_REGION}" == "None" ]]; then @@ -43,11 +43,11 @@ extra771(){ # Recover Bucket policy statements BUCKET_POLICY_STATEMENTS=$("${AWSCLI}" s3api ${PROFILE_OPT} get-bucket-policy --region "${BUCKET_REGION}" --bucket "${bucket}" --output json --query Policy 2>&1) if grep -q -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' <<< "${BUCKET_POLICY_STATEMENTS}"; then - textInfo "${REGION}: Access Denied trying to get bucket policy for ${bucket}" "${REGION}" + textInfo "${BUCKET_REGION}: Access Denied trying to get bucket policy for ${bucket}" "${BUCKET_REGION}" continue fi if grep -q -E 'NoSuchBucketPolicy'<<< "${BUCKET_POLICY_STATEMENTS}"; then - textInfo "${REGION}: Bucket policy does not exist for bucket ${bucket}" "${REGION}" + textInfo "${BUCKET_REGION}: Bucket policy does not exist for bucket ${bucket}" "${BUCKET_REGION}" else BUCKET_POLICY_BAD_STATEMENTS=$(jq --compact-output --arg arn "arn:${AWS_PARTITION}:s3:::$bucket" 'fromjson | .Statement[]|select( .Effect=="Allow" and @@ -66,9 +66,9 @@ extra771(){ # 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}" + textFail "${BUCKET_REGION}: Bucket ${bucket} allows public write: ${BUCKET_POLICY_BAD_STATEMENTS}" "${BUCKET_REGION}" "${bucket}" else - textPass "${REGION}: Bucket ${bucket} has S3 bucket policy which does not allow public write access" "${REGION}" "${bucket}" + textPass "${BUCKET_REGION}: Bucket ${bucket} has S3 bucket policy which does not allow public write access" "${BUCKET_REGION}" "${bucket}" fi fi done diff --git a/checks/check_extra773 b/checks/check_extra773 index 346f204336..baa73a9e41 100644 --- a/checks/check_extra773 +++ b/checks/check_extra773 @@ -31,12 +31,12 @@ extra773(){ for dist in $LIST_OF_DISTRIBUTIONS; do WEB_ACL_ID=$($AWSCLI cloudfront get-distribution $PROFILE_OPT --id "$dist" --query 'Distribution.DistributionConfig.WebACLId' --output text) if [[ $WEB_ACL_ID ]]; then - textPass "CloudFront distribution $dist is using AWS WAF web ACL $WEB_ACL_ID" "us-east-1" "$dist" + textPass "$REGION: CloudFront distribution $dist is using AWS WAF web ACL $WEB_ACL_ID" "$REGION" "$dist" else - textFail "CloudFront distribution $dist is not using AWS WAF web ACL" "us-east-1" "$dist" + textFail "$REGION: CloudFront distribution $dist is not using AWS WAF web ACL" "$REGION" "$dist" fi done else - textInfo "No CloudFront distributions found" "us-east-1" + textInfo "$REGION: No CloudFront distributions found" "$REGION" fi } diff --git a/checks/check_extra778 b/checks/check_extra778 index c1771752d6..4636f6afde 100644 --- a/checks/check_extra778 +++ b/checks/check_extra778 @@ -19,7 +19,7 @@ CHECK_SEVERITY_extra778="Medium" CHECK_ASFF_RESOURCE_TYPE_extra778="AwsEc2SecurityGroup" CHECK_ALTERNATE_check778="extra778" CHECK_SERVICENAME_extra778="ec2" -CHECK_RISK_extra778='If Security groups are not properly configured the attack surface is increased. ' +CHECK_RISK_extra778='If Security groups are not properly configured the attack surface is increased.' CHECK_REMEDIATION_extra778='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.' CHECK_DOC_extra778='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html' CHECK_CAF_EPIC_extra778='Infrastructure Security' @@ -54,6 +54,7 @@ extra778(){ continue fi + PASS="true" for CIDR_IP in ${CIDR_IP_LIST}; do if [[ ! ${CIDR_IP} =~ ${RFC1918_REGEX} ]]; then CIDR=$(echo ${CIDR_IP} | cut -d"/" -f2 | xargs) @@ -61,11 +62,14 @@ extra778(){ # Edge case "0.0.0.0/0" for RDP and SSH are checked already by check41 and check42 if [[ ${CIDR} < ${CIDR_THRESHOLD} && 0 < ${CIDR} ]]; then textFail "${REGION}: ${SECURITY_GROUP} has potential wide-open non-RFC1918 address ${CIDR_IP} in ${DIRECTION} rule" "${REGION}" "${SECURITY_GROUP}" - else - textPass "${REGION}: ${SECURITY_GROUP} has no potential wide-open non-RFC1918 address" "${REGION}" "${SECURITY_GROUP}" + PASS="false" fi fi done + if [[ ${PASS} == "true" ]] + then + textPass "${REGION}: ${SECURITY_GROUP} has no potential ${DIRECTION} rule with a wide-open non-RFC1918 address" "${REGION}" "${SECURITY_GROUP}" + fi } for regx in ${REGIONS}; do diff --git a/checks/check_extra791 b/checks/check_extra791 index 22f1ee8353..3ed239767b 100644 --- a/checks/check_extra791 +++ b/checks/check_extra791 @@ -29,12 +29,12 @@ extra791(){ for dist in $LIST_OF_DISTRIBUTIONS; do CHECK_ORIGINSSLPROTOCOL_STATUS=$($AWSCLI cloudfront get-distribution --id $dist --query Distribution.DistributionConfig.Origins.Items[].CustomOriginConfig.OriginSslProtocols.Items $PROFILE_OPT --output text) if [[ $CHECK_ORIGINSSLPROTOCOL_STATUS == *"SSLv2"* ]] || [[ $CHECK_ORIGINSSLPROTOCOL_STATUS == *"SSLv3"* ]]; then - textFail "CloudFront distribution $dist is using a deprecated SSL protocol!" "$regx" "$dist" + textFail "$REGION: CloudFront distribution $dist is using a deprecated SSL protocol!" "$REGION" "$dist" else - textPass "CloudFront distribution $dist is not using a deprecated SSL protocol" "$regx" "$dist" + textPass "$REGION: CloudFront distribution $dist is not using a deprecated SSL protocol" "$REGION" "$dist" fi done else - textInfo "No CloudFront distributions found" "$regx" + textInfo "$REGION: No CloudFront distributions found" "$REGION" fi }