From fa72e7c21fbf3e681827873e81f95c0199773793 Mon Sep 17 00:00:00 2001 From: nikirby Date: Fri, 20 Nov 2020 15:16:22 -0500 Subject: [PATCH 1/9] Ensures JSON is the default AWS command output. --- prowler | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/prowler b/prowler index c88fab83..6293c257 100755 --- a/prowler +++ b/prowler @@ -51,6 +51,15 @@ TITLE_TEXT="CALLER ERROR - UNSET TITLE" WHITELIST_FILE="" TOTAL_CHECKS=() +# Ensures command output will always be set to JSON. +# If the default value is already set, ORIGINAL_OUTPUT will be used to store it and reset it at cleanup +if [[ -z "${AWS_DEFAULT_OUTPUT}" ]]; then + ORIGINAL_OUTPUT=$AWS_DEFAULT_OUTPUT + export AWS_DEFAULT_OUTPUT="json" +else + export AWS_DEFAULT_OUTPUT="json" +fi + # Command usage menu usage(){ echo " @@ -200,6 +209,12 @@ clean_up() { if [[ "${MODES[@]}" =~ "html" ]]; then addHtmlFooter >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML fi + # puts the AWS_DEFAULT_OUTPUT back to what it was at the start + if [ -z "$ORIGINAL_OUTPUT"]; then + export AWS_DEFAULT_OUTPUT="$ORIGINAL_OUTPUT" + else + unset AWS_DEFAULT_OUTPUT + fi } handle_ctrl_c() { From cbcc8c61a5a627625dbf6316667c004c7b0a5c1f Mon Sep 17 00:00:00 2001 From: "C.J" <31103058+zfLQ2qx2@users.noreply.github.com> Date: Tue, 26 Jan 2021 13:37:48 -0500 Subject: [PATCH 2/9] Implement OS neutral method of converting rfc3339 dates to epoch --- include/assume_role | 2 +- include/os_detector | 36 +++++------------------------------- 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/include/assume_role b/include/assume_role index 2921563f..197e9006 100644 --- a/include/assume_role +++ b/include/assume_role @@ -70,7 +70,7 @@ assume_role(){ export AWS_ACCESS_KEY_ID=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.AccessKeyId') export AWS_SECRET_ACCESS_KEY=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SecretAccessKey') export AWS_SESSION_TOKEN=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SessionToken') - export AWS_SESSION_EXPIRATION=$(convert_date_to_timestamp "$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.Expiration')") + export AWS_SESSION_EXPIRATION=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.Expiration | fromdateiso8601') rm -fr $TEMP_STS_ASSUMED_FILE } diff --git a/include/os_detector b/include/os_detector index a6667cbe..b01a892a 100644 --- a/include/os_detector +++ b/include/os_detector @@ -34,26 +34,26 @@ bsd_how_older_from_today() { gnu_timestamp_to_date() { # if date comes from cli v2 in format like 2020-04-29T10:13:09.191000-04:00 # we have to get only '%Y-%m-%d' - if [[ $1 = 20* ]];then + if [[ $1 = 20* ]]; then echo $1 | cut -f1 -d"T" - else + else # remove fractions of a second TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") OUTPUT_DATE=$("$DATE_CMD" -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') echo $OUTPUT_DATE - fi + fi } bsd_timestamp_to_date() { # if date comes from cli v2 in format like 2020-04-29T10:13:09.191000-04:00 # we have to get only '%Y-%m-%d' - if [[ $1 = 20* ]];then + if [[ $1 = 20* ]]; then echo $1 | cut -f1 -d"T" else # remove fractions of a second TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") OUTPUT_DATE=$("$DATE_CMD" -r $TIMESTAMP_TO_CONVERT +'%Y-%m-%d') echo $OUTPUT_DATE - fi + fi } gnu_decode_report() { @@ -108,20 +108,6 @@ bsd_get_iso8601_timestamp() { "$DATE_CMD" -u +"%Y-%m-%dT%H:%M:%SZ" } -gnu_convert_date_to_timestamp() { - # if [ "$OSTYPE" == "linux-musl" ]; then - # date -D "%Y-%m-%dT%H:%M:%SZ" -d "$1" +%s - # else - date -d "$1" +%s - # fi -} - -bsd_convert_date_to_timestamp() { - echo $(( $(date -j -f %Y-%m-%dT%H:%M:%S "$1" +%s) + 3600 )) - # Change above is because epoch time generator in BSD is 1h less than in Linux ¯\_(ツ)_/¯ - #date -j -f "%Y-%m-%dT%H:%M:%S" "$1" "+%s" -} - gnu_test_tcp_connectivity() { HOST=$1 PORT=$2 @@ -168,9 +154,6 @@ if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then test_tcp_connectivity() { gnu_test_tcp_connectivity "$1" "$2" "$3" } - convert_date_to_timestamp() { - gnu_convert_date_to_timestamp "$1" - } elif [[ "$OSTYPE" == "darwin"* ]] || [[ "$OSTYPE" == "freebsd"* ]]; then # BSD/OSX commands compatibility TEMP_REPORT_FILE=$(mktemp -t prowler.cred_report-XXXXXX) @@ -206,9 +189,6 @@ elif [[ "$OSTYPE" == "darwin"* ]] || [[ "$OSTYPE" == "freebsd"* ]]; then get_iso8601_timestamp() { gnu_get_iso8601_timestamp } - convert_date_to_timestamp() { - gnu_convert_date_to_timestamp "$1" - } else how_older_from_today() { bsd_how_older_from_today "$1" @@ -228,9 +208,6 @@ elif [[ "$OSTYPE" == "darwin"* ]] || [[ "$OSTYPE" == "freebsd"* ]]; then get_iso8601_timestamp() { bsd_get_iso8601_timestamp } - convert_date_to_timestamp() { - bsd_convert_date_to_timestamp "$1" - } fi if "$BASE64_CMD" --version >/dev/null 2>&1 ; then decode_report() { @@ -271,9 +248,6 @@ elif [[ "$OSTYPE" == "cygwin" ]]; then test_tcp_connectivity() { gnu_test_tcp_connectivity "$1" "$2" "$3" } - convert_date_to_timestamp() { - gnu_convert_date_to_timestamp "$1" - } else echo "Unknown Operating System! Valid \$OSTYPE: linux-gnu, linux-musl, darwin* or cygwin" echo "Found: $OSTYPE" From de87de3b39b4d8de2d1f0bebd6cfbaf9f18e7ba2 Mon Sep 17 00:00:00 2001 From: "C.J" <31103058+zfLQ2qx2@users.noreply.github.com> Date: Thu, 14 Jan 2021 13:16:06 -0500 Subject: [PATCH 3/9] Add access checks for several checks --- checks/check21 | 6 ++- checks/check22 | 10 +++-- checks/check23 | 78 +++++++++++++++++++++++++++++-------- checks/check24 | 6 ++- checks/check25 | 17 +++++++-- checks/check26 | 89 +++++++++++++++++++++++++++++-------------- checks/check27 | 6 ++- checks/check28 | 68 ++++++++++++++++++++++----------- checks/check29 | 20 +++++++--- checks/check_extra720 | 16 ++++++-- checks/check_extra725 | 18 ++++++--- 11 files changed, 240 insertions(+), 94 deletions(-) diff --git a/checks/check21 b/checks/check21 index d011cc1e..6dd8e214 100644 --- a/checks/check21 +++ b/checks/check21 @@ -23,7 +23,11 @@ check21(){ trail_count=0 # "Ensure CloudTrail is enabled in all regions (Scored)" for regx in $REGIONS; do - TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text | tr " " ',') + TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') + if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then + textFail "Access Denied trying to describe trails in $regx" + continue + fi if [[ $TRAILS_AND_REGIONS ]]; then for reg_trail in $TRAILS_AND_REGIONS; do TRAIL_REGION=$(echo $reg_trail | cut -d',' -f1) diff --git a/checks/check22 b/checks/check22 index 27250905..faf624a5 100644 --- a/checks/check22 +++ b/checks/check22 @@ -23,7 +23,11 @@ check22(){ trail_count=0 # "Ensure CloudTrail log file validation is enabled (Scored)" for regx in $REGIONS; do - TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text | tr " " ',') + TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') + if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then + textFail "Access Denied trying to describe trails in $regx" + continue + fi if [[ $TRAILS_AND_REGIONS ]]; then for reg_trail in $TRAILS_AND_REGIONS; do TRAIL_REGION=$(echo $reg_trail | cut -d',' -f1) @@ -35,9 +39,9 @@ check22(){ LOGFILEVALIDATION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $TRAIL_REGION --query 'trailList[*].LogFileValidationEnabled' --output text --trail-name-list $trail) if [[ "$LOGFILEVALIDATION_TRAIL_STATUS" == 'False' ]];then - textFail "Trail $trail in $regx has not log file validation enabled" + textFail "Trail $trail in $regx log file validation disabled" else - textPass "Trail $trail in $regx has log file validation enabled" + textPass "Trail $trail in $regx log file validation enabled" fi done diff --git a/checks/check23 b/checks/check23 index 237fdf68..149b7149 100644 --- a/checks/check23 +++ b/checks/check23 @@ -20,22 +20,68 @@ CHECK_ASFF_COMPLIANCE_TYPE_check23="ens-op.exp.10.aws.trail.3 ens-op.exp.10.aws. CHECK_SERVICENAME_check23="cloudtrail" check23(){ + trail_count=0 # "Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" - CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].S3BucketName' --output text $PROFILE_OPT --region $REGION) - if [[ $CLOUDTRAILBUCKET ]]; then - for bucket in $CLOUDTRAILBUCKET;do - CLOUDTRAILBUCKET_HASALLPERMISIONS=$($AWSCLI s3api get-bucket-acl --bucket $bucket --query 'Grants[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers`]' $PROFILE_OPT --region $REGION --output text 2>&1) - if [[ $(echo "$CLOUDTRAILBUCKET_HASALLPERMISIONS" | grep AccessDenied) ]]; then - textInfo "Access Denied Trying to Get Bucket Acl for $bucket" - continue - fi - if [[ $CLOUDTRAILBUCKET_HASALLPERMISIONS ]]; then - textFail "check your $bucket CloudTrail bucket ACL and Policy!" - else - textPass "Bucket $bucket is set correctly" - fi - done - else - textFail "No CloudTrail bucket found!" + for regx in $REGIONS; do + TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') + if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then + textFail "Access Denied trying to describe trails in $regx" + continue + fi + if [[ $TRAILS_AND_REGIONS ]]; then + for reg_trail in $TRAILS_AND_REGIONS; do + TRAIL_REGION=$(echo $reg_trail | cut -d',' -f1) + if [ $TRAIL_REGION != $regx ]; then # Only report trails once in home region + continue + fi + trail=$(echo $reg_trail | cut -d',' -f2) + trail_count=$((trail_count + 1)) + + CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $TRAIL_REGION --query 'trailList[*].[S3BucketName]' --output text --trail-name-list $trail) + if [[ -z $CLOUDTRAILBUCKET ]]; then + textFail "Trail $trail in $TRAIL_REGION does not publish to S3" + continue + fi + + CLOUDTRAIL_ACCOUNT_ID=$(echo $trail | awk -F: '{ print $5 }') + if [ "$CLOUDTRAIL_ACCOUNT_ID" != "$ACCOUNT_NUM" ]; then + textInfo "Trail $trail in $TRAIL_REGION S3 logging bucket $CLOUDTRAILBUCKET is not in current account" + continue + fi + + # + # LOCATION - requests referencing buckets created after March 20, 2019 + # must be made to S3 endpoints in the same region as the bucket was + # created. + # + BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location $PROFILE_OPT --region $regx --bucket $CLOUDTRAILBUCKET --output text 2>&1) + if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then + textFail "Trail $trail in $TRAIL_REGION Access Denied getting bucket location for $CLOUDTRAILBUCKET" + continue + fi + if [[ $BUCKET_LOCATION == "None" ]]; then + BUCKET_LOCATION="us-east-1" + fi + if [[ $BUCKET_LOCATION == "EU" ]]; then + BUCKET_LOCATION="eu-west-1" + fi + + CLOUDTRAILBUCKET_HASALLPERMISIONS=$($AWSCLI s3api get-bucket-acl --bucket $CLOUDTRAILBUCKET $PROFILE_OPT --region $BUCKET_LOCATION --query 'Grants[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers`]' --output text 2>&1) + if [[ $(echo "$CLOUDTRAILBUCKET_HASALLPERMISIONS" | grep AccessDenied) ]]; then + textInfo "Trail $trail in $TRAIL_REGION Access Denied getting bucket acl for $CLOUDTRAILBUCKET" + continue + fi + + if [[ -z $CLOUDTRAILBUCKET_HASALLPERMISIONS ]]; then + textPass "Trail $trail in $TRAIL_REGION S3 logging bucket $CLOUDTRAILBUCKET is not publicly accessible" + else + textFail "Trail $trail in $TRAIL_REGION S3 logging bucket $CLOUDTRAILBUCKET is publicly accessible" + fi + + done + fi + done + if [[ $trail_count == 0 ]]; then + textFail "No CloudTrail trails were found in the account" fi } diff --git a/checks/check24 b/checks/check24 index 0e018afd..e4265424 100644 --- a/checks/check24 +++ b/checks/check24 @@ -23,7 +23,11 @@ check24(){ trail_count=0 # "Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" for regx in $REGIONS; do - TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text | tr " " ',') + TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') + if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then + textFail "Access Denied trying to describe trails in $regx" + continue + fi if [[ $TRAILS_AND_REGIONS ]]; then for reg_trail in $TRAILS_AND_REGIONS; do TRAIL_REGION=$(echo $reg_trail | cut -d',' -f1) diff --git a/checks/check25 b/checks/check25 index bdeaabba..010e8e3f 100644 --- a/checks/check25 +++ b/checks/check25 @@ -21,11 +21,20 @@ CHECK_SERVICENAME_check25="configservice" check25(){ # "Ensure AWS Config is enabled in all regions (Scored)" for regx in $REGIONS; do - CHECK_AWSCONFIG_STATUS=$($AWSCLI configservice get-status $PROFILE_OPT --region $regx --output json| grep "recorder: ON") - if [[ $CHECK_AWSCONFIG_STATUS ]];then - textPass "Region $regx has AWS Config recorder: ON" "$regx" + CHECK_AWSCONFIG_RECORDING=$($AWSCLI configservice describe-configuration-recorder-status $PROFILE_OPT --region $regx --query 'ConfigurationRecordersStatus[*].recording' --output text 2>&1) + CHECK_AWSCONFIG_STATUS=$($AWSCLI configservice describe-configuration-recorder-status $PROFILE_OPT --region $regx --query 'ConfigurationRecordersStatus[*].lastStatus' --output text 2>&1) + if [[ $(echo "$CHECK_AWSCONFIG_STATUS" | grep AccessDenied) ]]; then + textFail "Access Denied trying to describe configuration recorder status in $regx" + continue + fi + if [[ $CHECK_AWSCONFIG_RECORDING == "True" ]]; then + if [[ $CHECK_AWSCONFIG_STATUS == "SUCCESS" ]]; then + textPass "Region $regx AWS Config recorder enabled" + else + textFail "Region $regx AWS Config recorder in failure state" + fi else - textFail "Region $regx has AWS Config disabled or not configured" "$regx" + textFail "Region $regx AWS Config recorder disabled" fi done } diff --git a/checks/check26 b/checks/check26 index 8b7c5fd4..47d791d4 100644 --- a/checks/check26 +++ b/checks/check26 @@ -19,37 +19,68 @@ CHECK_ALTERNATE_check206="check26" CHECK_SERVICENAME_check26="s3" check26(){ + trail_count=0 # "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" - - CLOUDTRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region "$REGION" --query 'trailList[*].Name' --output text| tr '\011' '\012' | awk -F: '{print $1}') - - if [[ $CLOUDTRAILS ]]; then - for trail in $CLOUDTRAILS; do - CLOUDTRAIL_ACCOUNT_ID=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region "$REGION" --query 'trailList[*].TrailARN' --output text | tr '\011' '\012' | grep "$trail" | awk -F: '{ print $5 }' | head -n 1) - CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].[Name, S3BucketName]' --output text | tr '\011' ':' | grep "$trail" | awk -F: '{ print $2 }' ) - - if [[ $CLOUDTRAILBUCKET ]]; then - bucket=$CLOUDTRAILBUCKET - if [ "$CLOUDTRAIL_ACCOUNT_ID" == "$ACCOUNT_NUM" ]; then - CLOUDTRAILBUCKET_LOGENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --region $REGION --query 'LoggingEnabled.TargetBucket' 2>&1) - if [[ $(echo "$CLOUDTRAILBUCKET_LOGENABLED" | grep AccessDenied) ]]; then - textInfo "Access Denied Trying to Get Bucket Logging for $bucket" - continue - fi - if [[ $CLOUDTRAILBUCKET_LOGENABLED != "null" ]]; then - textPass "Bucket access logging enabled in CloudTrail S3 bucket $bucket for $trail" - else - textFail "Bucket access logging is not enabled in CloudTrail S3 bucket $bucket for $trail" - fi - else - textInfo "CloudTrail S3 bucket $bucket for trail $trail is not in current account" + for regx in $REGIONS; do + TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') + if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then + textFail "Access Denied trying to describe trails in $regx" + continue + fi + if [[ $TRAILS_AND_REGIONS ]]; then + for reg_trail in $TRAILS_AND_REGIONS; do + TRAIL_REGION=$(echo $reg_trail | cut -d',' -f1) + if [ $TRAIL_REGION != $regx ]; then # Only report trails once in home region + continue fi - else - textFail "CloudTrail bucket not found!" - fi - done + trail=$(echo $reg_trail | cut -d',' -f2) + trail_count=$((trail_count + 1)) - else - textFail "No CloudWatch group found and no CloudTrail bucket" + CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $TRAIL_REGION --query 'trailList[*].[S3BucketName]' --output text --trail-name-list $trail) + if [[ -z $CLOUDTRAILBUCKET ]]; then + textFail "Trail $trail in $TRAIL_REGION does not publish to S3" + continue + fi + + CLOUDTRAIL_ACCOUNT_ID=$(echo $trail | awk -F: '{ print $5 }') + if [ "$CLOUDTRAIL_ACCOUNT_ID" != "$ACCOUNT_NUM" ]; then + textInfo "Trail $trail in $TRAIL_REGION S3 logging bucket $CLOUDTRAILBUCKET is not in current account" + continue + fi + + # + # LOCATION - requests referencing buckets created after March 20, 2019 + # must be made to S3 endpoints in the same region as the bucket was + # created. + # + BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location $PROFILE_OPT --region $regx --bucket $CLOUDTRAILBUCKET --output text 2>&1) + if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then + textFail "Trail $trail in $TRAIL_REGION Access Denied getting bucket location for $CLOUDTRAILBUCKET" + continue + fi + if [[ $BUCKET_LOCATION == "None" ]]; then + BUCKET_LOCATION="us-east-1" + fi + if [[ $BUCKET_LOCATION == "EU" ]]; then + BUCKET_LOCATION="eu-west-1" + fi + + CLOUDTRAILBUCKET_LOGENABLED=$($AWSCLI s3api get-bucket-logging --bucket $CLOUDTRAILBUCKET $PROFILE_OPT --region $BUCKET_LOCATION --query 'LoggingEnabled.TargetBucket' --output text 2>&1) + if [[ $(echo "$CLOUDTRAILBUCKET_LOGENABLED" | grep AccessDenied) ]]; then + textInfo "Trail $trail in $TRAIL_REGION Access Denied getting bucket logging for $CLOUDTRAILBUCKET" + continue + fi + + if [[ $CLOUDTRAILBUCKET_LOGENABLED != "None" ]]; then + textPass "Trail $trail in $TRAIL_REGION S3 bucket access logging is enabled for $CLOUDTRAILBUCKET" + else + textFail "Trail $trail in $TRAIL_REGION S3 bucket access logging is not enabled for $CLOUDTRAILBUCKET" + fi + + done + fi + done + if [[ $trail_count == 0 ]]; then + textFail "No CloudTrail trails were found in the account" fi } diff --git a/checks/check27 b/checks/check27 index bba7a604..927da424 100644 --- a/checks/check27 +++ b/checks/check27 @@ -23,7 +23,11 @@ check27(){ trail_count=0 # "Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" for regx in $REGIONS; do - TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text | tr " " ',') + TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') + if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then + textFail "Access Denied trying to describe trails in $regx" + continue + fi if [[ $TRAILS_AND_REGIONS ]]; then for reg_trail in $TRAILS_AND_REGIONS; do TRAIL_REGION=$(echo $reg_trail | cut -d',' -f1) diff --git a/checks/check28 b/checks/check28 index d15e9fec..677f732b 100644 --- a/checks/check28 +++ b/checks/check28 @@ -21,31 +21,53 @@ CHECK_SERVICENAME_check28="kms" check28(){ # "Ensure rotation for customer created CMKs is enabled (Scored)" for regx in $REGIONS; do - CHECK_KMS_KEYLIST=$($AWSCLI kms list-keys $PROFILE_OPT --region $regx --output text --query 'Keys[*].KeyId') - if [[ $CHECK_KMS_KEYLIST ]];then - CHECK_KMS_KEYLIST_NO_DEFAULT=$( - for key in $CHECK_KMS_KEYLIST; do - $AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --query 'KeyMetadata.{key:KeyId,state:KeyState,man:KeyManager}' --output text|grep Enabled$|grep -v AWS| awk '{ print $1 }' - done ) - if [[ $CHECK_KMS_KEYLIST_NO_DEFAULT ]]; then - for key in $CHECK_KMS_KEYLIST_NO_DEFAULT; do - CHECK_KMS_KEY_TYPE=$($AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --query 'KeyMetadata.Origin' | sed 's/["]//g') - if [[ "$CHECK_KMS_KEY_TYPE" == "EXTERNAL" ]];then - textPass "$regx: Key $key in Region $regx Customer Uploaded Key Material" "$regx" - else - CHECK_KMS_KEY_ROTATION=$($AWSCLI kms get-key-rotation-status --key-id $key $PROFILE_OPT --region $regx --output text) - if [[ "$CHECK_KMS_KEY_ROTATION" == "True" ]];then - textPass "$regx: Key $key is set correctly" "$regx" - else - textFail "$regx: Key $key is not set to rotate!" "$regx" - fi - fi - done - else - textInfo "$regx: This region doesn't have CUSTOM encryption keys" "$regx" + CHECK_KMS_KEYLIST=$($AWSCLI kms list-keys $PROFILE_OPT --region $regx --output text --query 'Keys[*].KeyId' --output text 2>&1) + if [[ $(echo "$CHECK_KMS_KEYLIST" | grep AccessDenied) ]]; then + textFail "Access Denied trying to list keys in $regx" + continue + fi + if [[ $CHECK_KMS_KEYLIST ]]; then + cmk_count=0 + for key in $CHECK_KMS_KEYLIST; do + KMSDETAILS=$($AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --query 'KeyMetadata.{key:KeyId,man:KeyManager,origin:Origin,state:KeyState}' --output text 2>&1) + if [[ $(echo "$KMSDETAILS" | grep AccessDenied) ]]; then + textFail "$regx: Key $key Access Denied describing key" + continue + fi + + KEYID=$(echo $KMSDETAILS | awk '{print $1}') + KEYMANAGER=$(echo $KMSDETAILS | awk '{print $2}') + KEYORIGIN=$(echo $KMSDETAILS | awk '{print $3}') + KEYSTATE=$(echo $KMSDETAILS | awk '{print $4}') + + if [[ "$KEYMANAGER" == "AWS" ]]; then + continue + fi + if [[ "$KEYSTATE" != "Enabled" ]]; then + continue + fi + cmk_count=$((cmk_count + 1)) + + if [[ "$KEYORIGIN" == "EXTERNAL" ]]; then + textPass "$regx: Key $key uses imported key material" + else + CHECK_KMS_KEY_ROTATION=$($AWSCLI kms get-key-rotation-status --key-id $key $PROFILE_OPT --region $regx --output text 2>&1) + if [[ $(echo "$CHECK_KMS_KEY_ROTATION" | grep AccessDenied) ]]; then + textFail "$regx: Key $key Access Denied getting key rotation status" + continue + fi + if [[ "$CHECK_KMS_KEY_ROTATION" == "True" ]];then + textPass "$regx: Key $key automatic rotation of the key material is enabled" + else + textFail "$regx: Key $key automatic rotation of the key material is disabled" + fi + fi + done + if [[ $cmk_count == 0 ]]; then + textInfo "$regx: This region has no customer managed keys" fi else - textInfo "$regx: This region doesn't have ANY encryption keys" "$regx" + textInfo "$regx: This region has no KMS keys" fi done } diff --git a/checks/check29 b/checks/check29 index 9c93d50a..c71571ef 100644 --- a/checks/check29 +++ b/checks/check29 @@ -22,15 +22,23 @@ CHECK_SERVICENAME_check29="vpc" check29(){ # "Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" for regx in $REGIONS; do - AVAILABLE_VPC=$($AWSCLI ec2 describe-vpcs $PROFILE_OPT --region $regx --query 'Vpcs[?State==`available`].VpcId' --output text) + AVAILABLE_VPC=$($AWSCLI ec2 describe-vpcs $PROFILE_OPT --region $regx --query 'Vpcs[?State==`available`].VpcId' --output text 2>&1) + if [[ $(echo "$AVAILABLE_VPC" | grep AccessDenied) ]]; then + textFail "$regx: Access Denied trying to describe VPCs" + continue + fi for vpcx in $AVAILABLE_VPC; do - CHECK_FL=$($AWSCLI ec2 describe-flow-logs $PROFILE_OPT --region $regx --filter Name="resource-id",Values="${vpcx}" --query 'FlowLogs[?FlowLogStatus==`ACTIVE`].FlowLogId' --output text) - if [[ $CHECK_FL ]];then - for FL in $CHECK_FL;do - textPass "VPC $vpcx: VPCFlowLog is enabled for LogGroupName: $FL in Region $regx" "$regx" + CHECK_FL=$($AWSCLI ec2 describe-flow-logs $PROFILE_OPT --region $regx --filter Name="resource-id",Values="${vpcx}" --query 'FlowLogs[?FlowLogStatus==`ACTIVE`].FlowLogId' --output text 2>&1) + if [[ $(echo "$CHECK_FL" | grep AccessDenied) ]]; then + textFail "$regx: VPC $vpcx Access Denied trying to describe flow logs" + continue + fi + if [[ $CHECK_FL ]]; then + for FL in $CHECK_FL; do + textPass "$regx: VPC $vpcx VPCFlowLog is enabled for LogGroupName: $FL" done else - textFail "VPC $vpcx: No VPCFlowLog has been found in Region $regx" "$regx" + textFail "$regx: VPC $vpcx VPCFlowLog is disabled" fi done done diff --git a/checks/check_extra720 b/checks/check_extra720 index 8e0647fd..f36ab448 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -22,10 +22,18 @@ CHECK_SERVICENAME_extra720="lambda" extra720(){ # "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" for regx in $REGIONS; do - LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) + LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query 'Functions[*].FunctionName' --output text 2>&1) + if [[ $(echo "$LIST_OF_FUNCTIONS" | grep AccessDenied) ]]; then + textFail "$regx: Access Denied trying to list functions" + continue + fi if [[ $LIST_OF_FUNCTIONS ]]; then - for lambdafunction in $LIST_OF_FUNCTIONS;do - LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query trailList[].TrailARN --output text) + LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].TrailARN' --output text 2>&1) + if [[ $(echo "$LIST_OF_TRAILS" | grep AccessDenied) ]]; then + textFail "$regx: Access Denied trying to describe trails" + continue + fi + for lambdafunction in $LIST_OF_FUNCTIONS; do if [[ $LIST_OF_TRAILS ]]; then for trail in $LIST_OF_TRAILS; do FUNCTION_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $regx --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:${AWS_PARTITION}:lambda.*function:$lambdafunction$|^arn:${AWS_PARTITION}:lambda$") @@ -52,7 +60,7 @@ extra720(){ else textFail "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" fi - done + done else textInfo "$regx: No Lambda functions found" "$regx" fi diff --git a/checks/check_extra725 b/checks/check_extra725 index 28d2557f..d12fd367 100644 --- a/checks/check_extra725 +++ b/checks/check_extra725 @@ -26,19 +26,25 @@ extra725(){ # "Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark)" textInfo "Looking for S3 Buckets Object-level logging information in all trails... " - LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --region $REGION --query 'Buckets[*].{Name:Name}' --output text) - LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[].TrailARN' --output text) + LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --region $REGION --query 'Buckets[*].{Name:Name}' --output text 2>&1) + if [[ $(echo "$LIST_OF_BUCKETS" | grep AccessDenied) ]]; then + textFail "Access Denied trying to list buckets" + return + fi + LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[].TrailARN' --output text 2>&1) + if [[ $(echo "$LIST_OF_TRAILS" | grep AccessDenied) ]]; then + textFail "Access Denied trying to describe trails" + return + fi if [[ $LIST_OF_BUCKETS ]]; then - for bucketName in $LIST_OF_BUCKETS;do + for bucketName in $LIST_OF_BUCKETS; do if [[ $LIST_OF_TRAILS ]]; then BUCKET_ENABLED_TRAILS=() + for trail in $LIST_OF_TRAILS; do BUCKET_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors --region $REGION $PROFILE_OPT --trail-name $trail --query "EventSelectors[*].DataResources[?Type == \`AWS::S3::Object\`].Values" --output text |xargs -n1| grep -E "^arn:${AWS_PARTITION}:s3:::$bucketName/\S*$|^arn:${AWS_PARTITION}:s3$|^arn:${AWS_PARTITION}:s3:::$") if [[ $BUCKET_ENABLED_IN_TRAIL ]]; then BUCKET_ENABLED_TRAILS+=($trail) - # textPass "$regx: S3 bucket $bucketName has Object-level logging enabled in trail $trail" "$regx" - #else - # textFail "$regx: S3 bucket $bucketName has Object-level logging disabled" "$regx" fi done From 073d2ab7275b6dadc854e9d9f1d37f05db8b6ff3 Mon Sep 17 00:00:00 2001 From: Martina Rath Date: Thu, 21 Jan 2021 07:04:09 +0100 Subject: [PATCH 4/9] Add check if Enhanced monitoring is enabled on RDS instances --- checks/check_extra7132 | 38 ++++++++++++++++++++++++++++++++++++++ groups/group7_extras | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 checks/check_extra7132 diff --git a/checks/check_extra7132 b/checks/check_extra7132 new file mode 100644 index 00000000..6ea3ee69 --- /dev/null +++ b/checks/check_extra7132 @@ -0,0 +1,38 @@ +#!/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_extra7132="7.132" +CHECK_TITLE_extra7132="[extra7132] Check if Enhanced monitoring is enabled on RDS instances" +CHECK_SCORED_extra7132="NOT_SCORED" +CHECK_TYPE_extra7132="EXTRA" +CHECK_SEVERITY_extra7132="Low" +CHECK_ASFF_RESOURCE_TYPE_extra7132="AwsRdsDbInstance" +CHECK_ALTERNATE_check7131="extra7132" + +extra7132(){ + for regx in $REGIONS; do + RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].DBInstanceIdentifier' --output text) + if [[ $RDS_INSTANCES ]];then + for rdsinstance in ${RDS_INSTANCES}; do + RDS_NAME="$rdsinstance" + MONITORING_FLAG=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --db-instance-identifier $rdsinstance --query 'DBInstances[*].[EnhancedMonitoringResourceArn]' --output text) + if [[ $MONITORING_FLAG == "None" ]];then + textFail "$regx: RDS instance: $RDS_NAME has Enhanced monitoring disabled!" "$rex" + else + textPass "$regx: RDS instance: $RDS_NAME has Enhanced monitoring enabled." "$regx" + fi + done + else + textInfo "$regx: no RDS instances found" "$regx" + fi + done +} diff --git a/groups/group7_extras b/groups/group7_extras index e95fd308..512a3744 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -15,7 +15,7 @@ GROUP_ID[7]='extras' GROUP_NUMBER[7]='7.0' GROUP_TITLE[7]='Extras - all non CIS specific checks - [extras] ****************' GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called -GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788,extra791,extra792,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122,extra7123,extra7124,extra7125,extra7126,extra7127,extra7128,extra7129,extra7130,extra7131' +GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788,extra791,extra792,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122,extra7123,extra7124,extra7125,extra7126,extra7127,extra7128,extra7129,extra7130,extra7131,extra7132' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` From 696a776e2e7028c0f73527d19e15bab946fba8e9 Mon Sep 17 00:00:00 2001 From: Martina Rath Date: Fri, 5 Feb 2021 08:32:06 +0100 Subject: [PATCH 5/9] Move extra7132 to rd group and add CHECK_SERVICENAME to check --- checks/check_extra7132 | 1 + groups/group13_rds | 2 +- groups/group7_extras | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/checks/check_extra7132 b/checks/check_extra7132 index 6ea3ee69..1f0f414c 100644 --- a/checks/check_extra7132 +++ b/checks/check_extra7132 @@ -17,6 +17,7 @@ CHECK_TYPE_extra7132="EXTRA" CHECK_SEVERITY_extra7132="Low" CHECK_ASFF_RESOURCE_TYPE_extra7132="AwsRdsDbInstance" CHECK_ALTERNATE_check7131="extra7132" +CHECK_SERVICENAME_extra7132="rds" extra7132(){ for regx in $REGIONS; do diff --git a/groups/group13_rds b/groups/group13_rds index e684654b..e4fa3079 100644 --- a/groups/group13_rds +++ b/groups/group13_rds @@ -15,4 +15,4 @@ GROUP_ID[13]='rds' GROUP_NUMBER[13]='13.0' GROUP_TITLE[13]='RDS security checks - [rds] ***********************************' GROUP_RUN_BY_DEFAULT[13]='N' # run it when execute_all is called -GROUP_CHECKS[13]='extra78,extra723,extra735,extra739,extra747,extra7113,extra7131' +GROUP_CHECKS[13]='extra78,extra723,extra735,extra739,extra747,extra7113,extra7131,extra7132' diff --git a/groups/group7_extras b/groups/group7_extras index 512a3744..e95fd308 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -15,7 +15,7 @@ GROUP_ID[7]='extras' GROUP_NUMBER[7]='7.0' GROUP_TITLE[7]='Extras - all non CIS specific checks - [extras] ****************' GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called -GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788,extra791,extra792,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122,extra7123,extra7124,extra7125,extra7126,extra7127,extra7128,extra7129,extra7130,extra7131,extra7132' +GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788,extra791,extra792,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122,extra7123,extra7124,extra7125,extra7126,extra7127,extra7128,extra7129,extra7130,extra7131' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` From 5d04febf81e7c9799967d8e780501b3624213f7c Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Fri, 5 Feb 2021 08:34:34 +0100 Subject: [PATCH 6/9] Adjusted severity like in Security Hub --- checks/check43 | 2 +- checks/check_extra7127 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/checks/check43 b/checks/check43 index fa5d18f5..1742e675 100644 --- a/checks/check43 +++ b/checks/check43 @@ -12,7 +12,7 @@ CHECK_ID_check43="4.3" CHECK_TITLE_check43="[check43] Ensure the default security group of every VPC restricts all traffic (Scored)" CHECK_SCORED_check43="SCORED" CHECK_TYPE_check43="LEVEL2" -CHECK_SEVERITY_check43="Medium" +CHECK_SEVERITY_check43="High" CHECK_ASFF_TYPE_check43="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check43="AwsEc2SecurityGroup" CHECK_ALTERNATE_check403="check43" diff --git a/checks/check_extra7127 b/checks/check_extra7127 index 65566690..9f28c605 100644 --- a/checks/check_extra7127 +++ b/checks/check_extra7127 @@ -14,7 +14,7 @@ CHECK_ID_extra7127="7.127" CHECK_TITLE_extra7127="[extra7127] Check if EC2 instances managed by Systems Manager are compliant with patching requirements" CHECK_SCORED_extra7127="NOT_SCORED" CHECK_TYPE_extra7127="EXTRA" -CHECK_SEVERITY_extra7127="Medium" +CHECK_SEVERITY_extra7127="High" CHECK_ASFF_RESOURCE_TYPE_extra7127="AwsEc2Instance" CHECK_ASFF_TYPE_extra7127="Software and Configuration Checks/ENS op.exp.4.aws.sys.1" CHECK_ALTERNATE_check7127="extra7127" From 138ece153e96fe70a0d758f5b6b77a37443e9177 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Fri, 5 Feb 2021 08:38:12 +0100 Subject: [PATCH 7/9] Adjusted severity to secrets and Shodan checks --- checks/check_extra7102 | 2 +- checks/check_extra741 | 2 +- checks/check_extra742 | 2 +- checks/check_extra759 | 2 +- checks/check_extra760 | 2 +- checks/check_extra768 | 2 +- checks/check_extra775 | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/checks/check_extra7102 b/checks/check_extra7102 index 8f1cb17a..3be4629e 100644 --- a/checks/check_extra7102 +++ b/checks/check_extra7102 @@ -14,7 +14,7 @@ CHECK_ID_extra7102="7.102" CHECK_TITLE_extra7102="[extra7102] Check if any of the Elastic or Public IP are in Shodan (requires Shodan API KEY)" CHECK_SCORED_extra7102="NOT_SCORED" CHECK_TYPE_extra7102="EXTRA" -CHECK_SEVERITY_extra7102="Medium" +CHECK_SEVERITY_extra7102="High" CHECK_ASFF_RESOURCE_TYPE_extra7102="AwsEc2Eip" CHECK_ALTERNATE_check7102="extra7102" CHECK_SERVICENAME_extra7102="ec2" diff --git a/checks/check_extra741 b/checks/check_extra741 index 7643e512..d0501ce9 100644 --- a/checks/check_extra741 +++ b/checks/check_extra741 @@ -14,7 +14,7 @@ CHECK_ID_extra741="7.41" CHECK_TITLE_extra741="[extra741] Find secrets in EC2 User Data (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra741="NOT_SCORED" CHECK_TYPE_extra741="EXTRA" -CHECK_SEVERITY_extra741="Medium" +CHECK_SEVERITY_extra741="Critical" CHECK_ASFF_RESOURCE_TYPE_extra741="AwsEc2Instance" CHECK_ALTERNATE_check741="extra741" CHECK_SERVICENAME_extra741="ec2" diff --git a/checks/check_extra742 b/checks/check_extra742 index 1aa2adda..957ef0c2 100644 --- a/checks/check_extra742 +++ b/checks/check_extra742 @@ -14,7 +14,7 @@ CHECK_ID_extra742="7.42" CHECK_TITLE_extra742="[extra742] Find secrets in CloudFormation outputs (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra742="NOT_SCORED" CHECK_TYPE_extra742="EXTRA" -CHECK_SEVERITY_extra742="Medium" +CHECK_SEVERITY_extra742="Critical" CHECK_ASFF_RESOURCE_TYPE_extra742="AwsCloudFormationStack" CHECK_ALTERNATE_check742="extra742" CHECK_SERVICENAME_extra742="cloudformation" diff --git a/checks/check_extra759 b/checks/check_extra759 index 4414712b..bf4d8052 100644 --- a/checks/check_extra759 +++ b/checks/check_extra759 @@ -14,7 +14,7 @@ CHECK_ID_extra759="7.59" CHECK_TITLE_extra759="[extra759] Find secrets in Lambda functions variables (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra759="NOT_SCORED" CHECK_TYPE_extra759="EXTRA" -CHECK_SEVERITY_extra759="High" +CHECK_SEVERITY_extra759="Critical" CHECK_ASFF_RESOURCE_TYPE_extra759="AwsLambdaFunction" CHECK_ALTERNATE_check759="extra759" CHECK_SERVICENAME_extra759="lambda" diff --git a/checks/check_extra760 b/checks/check_extra760 index 5a3b0ece..ba54aa89 100644 --- a/checks/check_extra760 +++ b/checks/check_extra760 @@ -14,7 +14,7 @@ CHECK_ID_extra760="7.60" CHECK_TITLE_extra760="[extra760] Find secrets in Lambda functions code (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra760="NOT_SCORED" CHECK_TYPE_extra760="EXTRA" -CHECK_SEVERITY_extra760="Medium" +CHECK_SEVERITY_extra760="Critical" CHECK_ASFF_RESOURCE_TYPE_extra760="AwsLambdaFunction" CHECK_ALTERNATE_check760="extra760" CHECK_SERVICENAME_extra760="lambda" diff --git a/checks/check_extra768 b/checks/check_extra768 index e82b98a5..25078fd8 100644 --- a/checks/check_extra768 +++ b/checks/check_extra768 @@ -14,7 +14,7 @@ CHECK_ID_extra768="7.68" CHECK_TITLE_extra768="[extra768] Find secrets in ECS task definitions variables (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra768="NOT_SCORED" CHECK_TYPE_extra768="EXTRA" -CHECK_SEVERITY_extra768="Medium" +CHECK_SEVERITY_extra768="Critical" CHECK_ASFF_RESOURCE_TYPE_extra768="AwsEcsTaskDefinition" CHECK_ALTERNATE_check768="extra768" CHECK_SERVICENAME_extra768="ecs" diff --git a/checks/check_extra775 b/checks/check_extra775 index 1cbefab0..5a60b320 100644 --- a/checks/check_extra775 +++ b/checks/check_extra775 @@ -14,7 +14,7 @@ CHECK_ID_extra775="7.75" CHECK_TITLE_extra775="[extra775] Find secrets in EC2 Auto Scaling Launch Configuration (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra775="NOT_SCORED" CHECK_TYPE_extra775="EXTRA" -CHECK_SEVERITY_extra775="Medium" +CHECK_SEVERITY_extra775="Critical" CHECK_ALTERNATE_check775="extra775" CHECK_SERVICENAME_extra775="autoscaling" From 3d834fae42ff8eccc0048d11751b00c4fefe028c Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 22 Feb 2021 21:44:48 +0100 Subject: [PATCH 8/9] Fix typos and add to extras extra7132 --- checks/check_extra7132 | 8 ++++---- groups/group7_extras | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/checks/check_extra7132 b/checks/check_extra7132 index 1f0f414c..8a704100 100644 --- a/checks/check_extra7132 +++ b/checks/check_extra7132 @@ -11,12 +11,12 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra7132="7.132" -CHECK_TITLE_extra7132="[extra7132] Check if Enhanced monitoring is enabled on RDS instances" +CHECK_TITLE_extra7132="[extra7132] Check if RDS instances has enhanced monitoring enabled" CHECK_SCORED_extra7132="NOT_SCORED" CHECK_TYPE_extra7132="EXTRA" CHECK_SEVERITY_extra7132="Low" CHECK_ASFF_RESOURCE_TYPE_extra7132="AwsRdsDbInstance" -CHECK_ALTERNATE_check7131="extra7132" +CHECK_ALTERNATE_check7132="extra7132" CHECK_SERVICENAME_extra7132="rds" extra7132(){ @@ -27,9 +27,9 @@ extra7132(){ RDS_NAME="$rdsinstance" MONITORING_FLAG=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --db-instance-identifier $rdsinstance --query 'DBInstances[*].[EnhancedMonitoringResourceArn]' --output text) if [[ $MONITORING_FLAG == "None" ]];then - textFail "$regx: RDS instance: $RDS_NAME has Enhanced monitoring disabled!" "$rex" + textFail "$regx: RDS instance: $RDS_NAME has enhanced monitoring disabled!" "$rex" else - textPass "$regx: RDS instance: $RDS_NAME has Enhanced monitoring enabled." "$regx" + textPass "$regx: RDS instance: $RDS_NAME has enhanced monitoring enabled." "$regx" fi done else diff --git a/groups/group7_extras b/groups/group7_extras index e95fd308..512a3744 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -15,7 +15,7 @@ GROUP_ID[7]='extras' GROUP_NUMBER[7]='7.0' GROUP_TITLE[7]='Extras - all non CIS specific checks - [extras] ****************' GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called -GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788,extra791,extra792,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122,extra7123,extra7124,extra7125,extra7126,extra7127,extra7128,extra7129,extra7130,extra7131' +GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788,extra791,extra792,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122,extra7123,extra7124,extra7125,extra7126,extra7127,extra7128,extra7129,extra7130,extra7131,extra7132' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` From 97a7471f2450f2c4429605d99fc6148c6bc52607 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 22 Feb 2021 21:52:19 +0100 Subject: [PATCH 9/9] Revert "Implement OS neutral method of converting rfc3339 dates to epoch" --- include/assume_role | 2 +- include/os_detector | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/include/assume_role b/include/assume_role index 197e9006..2921563f 100644 --- a/include/assume_role +++ b/include/assume_role @@ -70,7 +70,7 @@ assume_role(){ export AWS_ACCESS_KEY_ID=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.AccessKeyId') export AWS_SECRET_ACCESS_KEY=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SecretAccessKey') export AWS_SESSION_TOKEN=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SessionToken') - export AWS_SESSION_EXPIRATION=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.Expiration | fromdateiso8601') + export AWS_SESSION_EXPIRATION=$(convert_date_to_timestamp "$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.Expiration')") rm -fr $TEMP_STS_ASSUMED_FILE } diff --git a/include/os_detector b/include/os_detector index b01a892a..a6667cbe 100644 --- a/include/os_detector +++ b/include/os_detector @@ -34,26 +34,26 @@ bsd_how_older_from_today() { gnu_timestamp_to_date() { # if date comes from cli v2 in format like 2020-04-29T10:13:09.191000-04:00 # we have to get only '%Y-%m-%d' - if [[ $1 = 20* ]]; then + if [[ $1 = 20* ]];then echo $1 | cut -f1 -d"T" - else + else # remove fractions of a second TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") OUTPUT_DATE=$("$DATE_CMD" -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') echo $OUTPUT_DATE - fi + fi } bsd_timestamp_to_date() { # if date comes from cli v2 in format like 2020-04-29T10:13:09.191000-04:00 # we have to get only '%Y-%m-%d' - if [[ $1 = 20* ]]; then + if [[ $1 = 20* ]];then echo $1 | cut -f1 -d"T" else # remove fractions of a second TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") OUTPUT_DATE=$("$DATE_CMD" -r $TIMESTAMP_TO_CONVERT +'%Y-%m-%d') echo $OUTPUT_DATE - fi + fi } gnu_decode_report() { @@ -108,6 +108,20 @@ bsd_get_iso8601_timestamp() { "$DATE_CMD" -u +"%Y-%m-%dT%H:%M:%SZ" } +gnu_convert_date_to_timestamp() { + # if [ "$OSTYPE" == "linux-musl" ]; then + # date -D "%Y-%m-%dT%H:%M:%SZ" -d "$1" +%s + # else + date -d "$1" +%s + # fi +} + +bsd_convert_date_to_timestamp() { + echo $(( $(date -j -f %Y-%m-%dT%H:%M:%S "$1" +%s) + 3600 )) + # Change above is because epoch time generator in BSD is 1h less than in Linux ¯\_(ツ)_/¯ + #date -j -f "%Y-%m-%dT%H:%M:%S" "$1" "+%s" +} + gnu_test_tcp_connectivity() { HOST=$1 PORT=$2 @@ -154,6 +168,9 @@ if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then test_tcp_connectivity() { gnu_test_tcp_connectivity "$1" "$2" "$3" } + convert_date_to_timestamp() { + gnu_convert_date_to_timestamp "$1" + } elif [[ "$OSTYPE" == "darwin"* ]] || [[ "$OSTYPE" == "freebsd"* ]]; then # BSD/OSX commands compatibility TEMP_REPORT_FILE=$(mktemp -t prowler.cred_report-XXXXXX) @@ -189,6 +206,9 @@ elif [[ "$OSTYPE" == "darwin"* ]] || [[ "$OSTYPE" == "freebsd"* ]]; then get_iso8601_timestamp() { gnu_get_iso8601_timestamp } + convert_date_to_timestamp() { + gnu_convert_date_to_timestamp "$1" + } else how_older_from_today() { bsd_how_older_from_today "$1" @@ -208,6 +228,9 @@ elif [[ "$OSTYPE" == "darwin"* ]] || [[ "$OSTYPE" == "freebsd"* ]]; then get_iso8601_timestamp() { bsd_get_iso8601_timestamp } + convert_date_to_timestamp() { + bsd_convert_date_to_timestamp "$1" + } fi if "$BASE64_CMD" --version >/dev/null 2>&1 ; then decode_report() { @@ -248,6 +271,9 @@ elif [[ "$OSTYPE" == "cygwin" ]]; then test_tcp_connectivity() { gnu_test_tcp_connectivity "$1" "$2" "$3" } + convert_date_to_timestamp() { + gnu_convert_date_to_timestamp "$1" + } else echo "Unknown Operating System! Valid \$OSTYPE: linux-gnu, linux-musl, darwin* or cygwin" echo "Found: $OSTYPE"