From 0db97d5a24be4f1fdee07b31a8ac4c20938a9058 Mon Sep 17 00:00:00 2001 From: gabrielsoltz Date: Tue, 11 Jun 2019 20:36:40 +0200 Subject: [PATCH 01/16] improve AWS CLI parameters order, same as other checks --- checks/check_extra757 | 4 ++-- checks/check_extra758 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/checks/check_extra757 b/checks/check_extra757 index 6cc8e175..162c7fc5 100644 --- a/checks/check_extra757 +++ b/checks/check_extra757 @@ -20,9 +20,9 @@ extra757(){ OLDAGE="$(get_date_previous_than_months 6)" textInfo "Looking for EC2 instances in all regions..." for regx in $REGIONS; do - EC2_RUNNING="$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query "Reservations[*].Instances[*].[InstanceId]" --output text)" + EC2_RUNNING="$($AWSCLI ec2 describe-instances --query "Reservations[*].Instances[*].[InstanceId]" $PROFILE_OPT --region $regx --output text)" if [[ $EC2_RUNNING ]]; then - INSTACES_OLD_THAN_AGE=$($AWSCLI $PROFILE_OPT --region $regx ec2 describe-instances --query "Reservations[].Instances[?LaunchTime<='$OLDAGE'][].{id: InstanceId, launched: LaunchTime}" --output text) + INSTACES_OLD_THAN_AGE=$($AWSCLI ec2 describe-instances --query "Reservations[].Instances[?LaunchTime<='$OLDAGE'][].{id: InstanceId, launched: LaunchTime}" $PROFILE_OPT --region $regx --output text) if [[ $INSTACES_OLD_THAN_AGE ]]; then while IFS= read -r ec2_instace do diff --git a/checks/check_extra758 b/checks/check_extra758 index 48a04a4c..93f1d16e 100644 --- a/checks/check_extra758 +++ b/checks/check_extra758 @@ -20,9 +20,9 @@ extra758(){ OLDAGE="$(get_date_previous_than_months 12)" textInfo "Looking for EC2 instances in all regions..." for regx in $REGIONS; do - EC2_RUNNING="$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query "Reservations[*].Instances[*].[InstanceId]" --output text)" + EC2_RUNNING="$($AWSCLI ec2 describe-instances --query "Reservations[*].Instances[*].[InstanceId]" $PROFILE_OPT --region $regx --output text)" if [[ $EC2_RUNNING ]]; then - INSTACES_OLD_THAN_AGE=$($AWSCLI $PROFILE_OPT --region $regx ec2 describe-instances --query "Reservations[].Instances[?LaunchTime<='$OLDAGE'][].{id: InstanceId, launched: LaunchTime}" --output text) + INSTACES_OLD_THAN_AGE=$($AWSCLI ec2 describe-instances --query "Reservations[].Instances[?LaunchTime<='$OLDAGE'][].{id: InstanceId, launched: LaunchTime}" $PROFILE_OPT --region $regx --output text) if [[ $INSTACES_OLD_THAN_AGE ]]; then while IFS= read -r ec2_instace do From 3947ee2aae828c9a9babf618167760e2dc93e6fe Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 11 Jun 2019 20:37:18 +0200 Subject: [PATCH 02/16] Improved -l option to list uniq checks --- prowler | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prowler b/prowler index 5a3be417..f1249b43 100755 --- a/prowler +++ b/prowler @@ -271,7 +271,8 @@ execute_all() { # Function to show the titles of everything show_all_titles() { - for i in "${!GROUP_TITLE[@]}"; do + MAIN_GROUPS=(1 2 3 4 7) + for i in "${MAIN_GROUPS[@]}"; do show_group_title $i # Display the title of the checks IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$i]} From c7320ec7e2df1e46e53a51f103a48b3366c85918 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 12 Jun 2019 10:13:58 +0200 Subject: [PATCH 03/16] Added comment to clarify change --- prowler | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prowler b/prowler index f1249b43..b66ac495 100755 --- a/prowler +++ b/prowler @@ -274,7 +274,8 @@ show_all_titles() { MAIN_GROUPS=(1 2 3 4 7) for i in "${MAIN_GROUPS[@]}"; do show_group_title $i - # Display the title of the checks + # Display the title of the checks in groups 1,2,3,4 and 7 + # Any other group has checks in these groups IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$i]} for j in ${CHECKS[@]}; do show_check_title $j From d50c3afebd00d22f590e905da48d162db1a88bd2 Mon Sep 17 00:00:00 2001 From: gabrielsoltz Date: Thu, 13 Jun 2019 12:04:52 +0200 Subject: [PATCH 04/16] add check for explicit deny --- checks/check_extra73 | 53 +++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/checks/check_extra73 b/checks/check_extra73 index 216d198f..915e26d4 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -53,31 +53,38 @@ extra73(){ if [[ "EU" == $BUCKET_LOCATION ]]; then BUCKET_LOCATION="eu-west-1" fi - # check if AllUsers is in the ACL as Grantee - CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) - CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL) - # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only - CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE) - CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL) - # to prevent error NoSuchBucketPolicy first clean the output controlling stderr - TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) - $AWSCLI s3api get-bucket-policy $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null - # check if the S3 policy has Principal as * - CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) - if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then - if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then - textFail "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" - fi - if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then - textFail "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" - fi - if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then - textFail "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" - fi + # Check Explicit Deny and Avoid Error + CHEK_FOR_EXPLICIT_DENY=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket 2> /dev/null) + CHEK_FOR_EXPLICIT_DENY="$?" + if [[ $CHEK_FOR_EXPLICIT_DENY -eq 255 ]]; then + textPass "$BUCKET_LOCATION: bucket have an explicit Deny. Not possible to get ACL." "$regx" else - textPass "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" + # check if AllUsers is in the ACL as Grantee + CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) + CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL) + # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only + CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE) + CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL) + # to prevent error NoSuchBucketPolicy first clean the output controlling stderr + TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) + $AWSCLI s3api get-bucket-policy $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null + # check if the S3 policy has Principal as * + CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) + if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then + if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then + textFail "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" + fi + if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then + textFail "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" + fi + if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then + textFail "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + fi + else + textPass "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" + fi + rm -fr $TEMP_POLICY_FILE fi - rm -fr $TEMP_POLICY_FILE done } From de8336092be4a1ac22f28ddc38988a2ad72b9f11 Mon Sep 17 00:00:00 2001 From: gabrielsoltz Date: Thu, 13 Jun 2019 12:05:39 +0200 Subject: [PATCH 05/16] fix locations --- checks/check_extra73 | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/checks/check_extra73 b/checks/check_extra73 index 915e26d4..fa5c90da 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -34,9 +34,9 @@ CHECK_ALTERNATE_check703="extra73" # # BUCKET_POLICY_STATUS=$($AWSCLI s3api get-bucket-policy-status --bucket $bucket --query PolicyStatus.IsPublic --output text | grep False) # if [[ $BUCKET_POLICY_STATUS ]];then -# textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$regx" +# textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$BUCKET_LOCATION" # else -# textPass "$BUCKET_LOCATION: $bucket bucket is not Public" "$regx" +# textPass "$BUCKET_LOCATION: $bucket bucket is not Public" "$BUCKET_LOCATION" # fi # done # } @@ -57,7 +57,7 @@ extra73(){ CHEK_FOR_EXPLICIT_DENY=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket 2> /dev/null) CHEK_FOR_EXPLICIT_DENY="$?" if [[ $CHEK_FOR_EXPLICIT_DENY -eq 255 ]]; then - textPass "$BUCKET_LOCATION: bucket have an explicit Deny. Not possible to get ACL." "$regx" + textPass "$BUCKET_LOCATION: bucket have an explicit Deny. Not possible to get ACL." "$BUCKET_LOCATION" else # check if AllUsers is in the ACL as Grantee CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) @@ -72,16 +72,16 @@ extra73(){ CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then - textFail "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" + textFail "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$BUCKET_LOCATION" fi if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then - textFail "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" + textFail "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$BUCKET_LOCATION" fi if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then - textFail "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + textFail "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$BUCKET_LOCATION" fi else - textPass "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" + textPass "$BUCKET_LOCATION: $bucket bucket is not open" "$BUCKET_LOCATION" fi rm -fr $TEMP_POLICY_FILE fi @@ -122,16 +122,16 @@ extra73(){ # CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) # if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then # if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then -# textWarn "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" +# textWarn "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$BUCKET_LOCATION" # fi # if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then -# textWarn "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" +# textWarn "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$BUCKET_LOCATION" # fi # if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then -# textWarn "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" +# textWarn "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$BUCKET_LOCATION" # fi # else -# textOK "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" +# textOK "$BUCKET_LOCATION: $bucket bucket is not open" "$BUCKET_LOCATION" # fi # rm -fr $TEMP_POLICY_FILE # } From 76e6657e42dae2cce30545f2b67277162caf5168 Mon Sep 17 00:00:00 2001 From: gabrielsoltz Date: Thu, 13 Jun 2019 14:12:43 +0200 Subject: [PATCH 06/16] refactor check_extra734 --- checks/check_extra734 | 45 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/checks/check_extra734 b/checks/check_extra734 index dae7869a..1c5916ae 100644 --- a/checks/check_extra734 +++ b/checks/check_extra734 @@ -21,34 +21,33 @@ extra734(){ if [[ $LIST_OF_BUCKETS ]]; then for bucket in $LIST_OF_BUCKETS;do # query to get if has encryption enabled or not - RESULT=$(echo $bucket $($AWSCLI s3api get-bucket-encryption $PROFILE_OPT --bucket $bucket --query ServerSideEncryptionConfiguration.Rules[].ApplyServerSideEncryptionByDefault[].SSEAlgorithm --output text 2>&1 | grep -v ServerSideEncryptionConfigurationNotFoundError)) - TEMP_SSE_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) - # get bucket policy - $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_SSE_POLICY_FILE 2> /dev/null - # check if the S3 policy forces SSE s3:x-amz-server-side-encryption:true - CHECK_BUCKET_SSE_POLICY_PRESENT=$(cat $TEMP_SSE_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'| awk '/Condition/ && !skip { print } { skip = /x-amz-server-side-encryption/} '|grep \"true\") - CHECK_BUCKET_SSE_POLICY_VALUE=$(cat $TEMP_SSE_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'| awk '/Condition/ && !skip { print } { skip = /x-amz-server-side-encryption/} '|grep -Eo "AES256|aws:kms") - ENCRYPTION=false + RESULT=$($AWSCLI s3api get-bucket-encryption $PROFILE_OPT --bucket $bucket --query ServerSideEncryptionConfiguration.Rules[].ApplyServerSideEncryptionByDefault[].SSEAlgorithm --output text 2>&1) + if [[ $(echo "$RESULT" | grep ServerSideEncryptionConfigurationNotFoundError) ]] ; then + textFail "Bucket does not enforce encryption!" "$bucket" + elif [[ $(echo "$RESULT" | grep AccessDenied) ]] ; then + textFail "Access Denied Trying to Get Encryption!" "$bucket" + else + TEMP_SSE_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) + # get bucket policy + $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_SSE_POLICY_FILE 2> /dev/null + # check if the S3 policy forces SSE s3:x-amz-server-side-encryption:true + CHECK_BUCKET_SSE_POLICY_PRESENT=$(cat $TEMP_SSE_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'| awk '/Condition/ && !skip { print } { skip = /x-amz-server-side-encryption/} '|grep \"true\") + CHECK_BUCKET_SSE_POLICY_VALUE=$(cat $TEMP_SSE_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'| awk '/Condition/ && !skip { print } { skip = /x-amz-server-side-encryption/} '|grep -Eo "AES256|aws:kms") - echo "$RESULT" | while read RBUCKET SSEALG; do - if [[ $SSEALG ]]; then - textPass "Bucket $RBUCKET has default encryption enabled with algorithm $SSEALG" - ENCRYPTION=true + echo "$RESULT" | while read RBUCKET SSEALG; do + if [[ $SSEALG ]]; then + textPass "Bucket $RBUCKET has default encryption enabled with algorithm $SSEALG" + fi + done + if [[ $CHECK_BUCKET_SSE_POLICY_PRESENT && $CHECK_BUCKET_SSE_POLICY_VALUE ]]; then + textPass "Bucket $bucket has S3 bucket policy to enforce encryption with $CHECK_BUCKET_SSE_POLICY_VALUE" fi - done - if [[ $CHECK_BUCKET_SSE_POLICY_PRESENT && $CHECK_BUCKET_SSE_POLICY_VALUE ]]; then - textPass "Bucket $bucket has S3 bucket policy to enforce encryption with $CHECK_BUCKET_SSE_POLICY_VALUE" - ENCRYPTION=true - fi - - if [ "$ENCRYPTION" == false ]; then - textFail "Bucket $bucket does not enforce encryption!" - fi + rm -fr $TEMP_SSE_POLICY_FILE + fi done - rm -fr $TEMP_SSE_POLICY_FILE + else textInfo "No S3 Buckets found" fi } - From c8622bc3471c1fcdab434b1c39a4c64279680fa2 Mon Sep 17 00:00:00 2001 From: gabrielsoltz Date: Thu, 13 Jun 2019 14:32:19 +0200 Subject: [PATCH 07/16] better check denied --- checks/check_extra73 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/checks/check_extra73 b/checks/check_extra73 index fa5c90da..a83f9e55 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -54,9 +54,8 @@ extra73(){ BUCKET_LOCATION="eu-west-1" fi # Check Explicit Deny and Avoid Error - CHEK_FOR_EXPLICIT_DENY=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket 2> /dev/null) - CHEK_FOR_EXPLICIT_DENY="$?" - if [[ $CHEK_FOR_EXPLICIT_DENY -eq 255 ]]; then + CHEK_FOR_EXPLICIT_DENY=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --output text 2>&1) + if [[ $(echo "$CHEK_FOR_EXPLICIT_DENY" | grep AccessDenied) ]] ; then textPass "$BUCKET_LOCATION: bucket have an explicit Deny. Not possible to get ACL." "$BUCKET_LOCATION" else # check if AllUsers is in the ACL as Grantee From cea45f43c8c44cf9303866e8f0e7b788c7950f3c Mon Sep 17 00:00:00 2001 From: gabrielsoltz Date: Thu, 20 Jun 2019 17:36:15 +0200 Subject: [PATCH 08/16] remove REGION from Bucket Listing --- checks/check_extra73 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checks/check_extra73 b/checks/check_extra73 index a83f9e55..7ca96c7f 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -44,9 +44,9 @@ CHECK_ALTERNATE_check703="extra73" extra73(){ textInfo "Looking for open S3 Buckets (ACLs and Policies) in all regions... " - ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text) + ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --output text) for bucket in $ALL_BUCKETS_LIST; do - BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text) + BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --output text) if [[ "None" == $BUCKET_LOCATION ]]; then BUCKET_LOCATION="us-east-1" fi From ea6d9c93fc05215088bd7d05014107862611a285 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 25 Jun 2019 08:28:50 -0400 Subject: [PATCH 09/16] Integration with Yelp detect-secrets --- checks/check_extra741 | 50 ++++++++++++--------- checks/check_extra742 | 43 ++++++++++-------- checks/check_extra759 | 54 +++++++++++++++++++++++ checks/check_extra760 | 55 ++++++++++++++++++++++++ groups/{group11_keys => group11_secrets} | 15 ++++--- groups/group7_extras | 3 ++ include/python_detector | 32 ++++++++++++++ include/secrets_detector | 54 +++++++++++++++++++++++ prowler | 4 +- 9 files changed, 267 insertions(+), 43 deletions(-) create mode 100644 checks/check_extra759 create mode 100644 checks/check_extra760 rename groups/{group11_keys => group11_secrets} (66%) create mode 100644 include/python_detector create mode 100644 include/secrets_detector diff --git a/checks/check_extra741 b/checks/check_extra741 index 2bf05f1a..f4e54d2c 100644 --- a/checks/check_extra741 +++ b/checks/check_extra741 @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) 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 @@ -11,48 +11,58 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra741="7.41" -CHECK_TITLE_extra741="[extra741] Find keys in EC2 UserData (Not Scored) (Not part of CIS benchmark)" +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_ALTERNATE_check741="extra741" extra741(){ - textInfo "Looking for keys in EC2 User Data in instances across all regions... (max 100 instances per region use -m to increase it) " + SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM" + if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then + # this folder is deleted once this check is finished + mkdir $SECRETS_TEMP_FOLDER + fi + + textInfo "Looking for secrets in EC2 User Data in instances across all regions... (max 100 instances per region use -m to increase it) " for regx in $REGIONS; do LIST_OF_EC2_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query Reservations[*].Instances[*].InstanceId --output text --max-items $MAXITEMS | grep -v None) if [[ $LIST_OF_EC2_INSTANCES ]];then for instance in $LIST_OF_EC2_INSTANCES; do - USERDATA_FILE=$instance-userdata.decoded - USERDATA=$($AWSCLI ec2 describe-instance-attribute --attribute userData --query UserData.Value $PROFILE_OPT --region $regx --instance-id $instance --output text | decode_report > $USERDATA_FILE) - if [ -s $USERDATA_FILE ];then - FILE_FORMAT_ASCII=$(file -b $USERDATA_FILE|grep ASCII) - #FINDINGS=$(grep '[A-Za-z0-9]\{20,40\}' $USERDATA_FILE | grep -i -e key -e secret -e token -e pass - |wc -l|tr -d '\ ') - #FINDINGS=$(grep -i -e key -e secret -e token -e pass $USERDATA_FILE |wc -l|tr -d '\ ') + EC2_USERDATA_FILE="$SECRETS_TEMP_FOLDER/extra741-$instance-userData.decoded" + EC2_USERDATA=$($AWSCLI ec2 describe-instance-attribute --attribute userData $PROFILE_OPT --region $regx --instance-id $instance --query UserData.Value --output text| grep -v ^None | decode_report > $EC2_USERDATA_FILE) + if [ -s $EC2_USERDATA_FILE ];then + FILE_FORMAT_ASCII=$(file -b $EC2_USERDATA_FILE|grep ASCII) # This finds ftp or http URLs with credentials and common keywords - FINDINGS=$(egrep -i '[[:alpha:]]*://[[:alnum:]]*:[[:alnum:]]*@.*/|key|secret|token|pass' $USERDATA_FILE |wc -l|tr -d '\ ') + # FINDINGS=$(egrep -i '[[:alpha:]]*://[[:alnum:]]*:[[:alnum:]]*@.*/|key|secret|token|pass' $EC2_USERDATA_FILE |wc -l|tr -d '\ ') + # New implementation using https://github.com/Yelp/detect-secrets if [[ $FILE_FORMAT_ASCII ]]; then - if [[ $FINDINGS -eq "0" ]]; then - textPass "$regx: No keys found in $instance" "$regx" + FINDINGS=$(secretsDetector file $EC2_USERDATA_FILE) + if [[ $FINDINGS -eq 0 ]]; then + textPass "$regx: No secrets found in $instance" "$regx" # delete file if nothing interesting is there - rm -f $USERDATA_FILE + rm -f $EC2_USERDATA_FILE else - textFail "$regx: Found $FINDINGS keys in $instance! Check file $USERDATA_FILE" "$regx" + textFail "$regx: Potential secret found in $instance" "$regx" + # delete file to not leave trace, user must look at the instance User Data + rm -f $EC2_USERDATA_FILE fi else - mv $USERDATA_FILE $USERDATA_FILE.gz ; gunzip $USERDATA_FILE.gz + mv $EC2_USERDATA_FILE $EC2_USERDATA_FILE.gz ; gunzip $EC2_USERDATA_FILE.gz + FINDINGS=$(secretsDetector file $EC2_USERDATA_FILE) if [[ $FINDINGS -eq 0 ]]; then - textPass "$regx: No keys found in $instance" "$regx" - rm -f $USERDATA_FILE.gz + textPass "$regx: No secrets found in $instance User Data" "$regx" + rm -f $EC2_USERDATA_FILE else - textFail "$regx: Found $FINDINGS keys in $instance! Check file $USERDATA_FILE" "$regx" + textFail "$regx: Potential secret found in $instance" "$regx" fi fi - else - textPass "$regx: $instance nothing found" "$regx" + else + textPass "$regx: No secrets found in $instance User Data or it is empty" "$regx" fi done else textInfo "$regx: No EC2 instances found" "$regx" fi done + rm -rf $SECRETS_TEMP_FOLDER } diff --git a/checks/check_extra742 b/checks/check_extra742 index 43420f08..f34afff4 100644 --- a/checks/check_extra742 +++ b/checks/check_extra742 @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) 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 @@ -11,37 +11,46 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra742="7.42" -CHECK_TITLE_extra742="[extra742] Find keys in CloudFormation outputs (Not Scored) (Not part of CIS benchmark)" +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_ALTERNATE_check742="extra742" extra742(){ - textInfo "Looking for keys in CloudFormation output across all regions... " + SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM" + if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then + # this folder is deleted once this check is finished + mkdir $SECRETS_TEMP_FOLDER + fi + + textInfo "Looking for secrets in CloudFormation output across all regions... " for regx in $REGIONS; do LIST_OF_CFN_STACKS=$($AWSCLI cloudformation describe-stacks $PROFILE_OPT --region $regx --query Stacks[*].[StackName] --output text) if [[ $LIST_OF_CFN_STACKS ]];then for stack in $LIST_OF_CFN_STACKS; do - OUTPUTS_FILE=$stack-$regx-output.txt - OUTPUTS=$($AWSCLI $PROFILE_OPT --region $regx cloudformation describe-stacks --query "Stacks[?StackName==\`$stack\`].Outputs[*].[OutputKey,OutputValue]" --output text > $OUTPUTS_FILE) - if [ -s $OUTPUTS ];then - #FINDINGS=$(grep '[A-Za-z0-9]\{20,40\}' $USERDATA_FILE | grep -i -e key -e secret -e token -e pass - |wc -l|tr -d '\ ') - #FINDINGS=$(grep -i -e key -e secret -e token -e pass $USERDATA_FILE |wc -l|tr -d '\ ') + CFN_OUTPUTS_FILE="$SECRETS_TEMP_FOLDER/extra742-$stack-$regx-outputs.txt" + CFN_OUTPUTS=$($AWSCLI $PROFILE_OPT --region $regx cloudformation describe-stacks --query "Stacks[?StackName==\`$stack\`].Outputs[*].[OutputKey,OutputValue]" --output text > $CFN_OUTPUTS_FILE) + if [ -s $CFN_OUTPUTS_FILE ];then # This finds ftp or http URLs with credentials and common keywords - FINDINGS=$(egrep -i '[[:alpha:]]*://[[:alnum:]]*:[[:alnum:]]*@.*/|key|secret|token|pass' $OUTPUTS_FILE |wc -l|tr -d '\ ') - if [[ $FINDINGS -eq "0" ]]; then - textPass "$regx: No keys found in Stack $stack" "$regx" - # delete file if nothing interesting is there - rm -f $OUTPUTS_FILE - else - textFail "$regx: Found $FINDINGS keys in $stack! Check file $OUTPUTS_FILE" "$regx" - fi + # FINDINGS=$(egrep -i '[[:alpha:]]*://[[:alnum:]]*:[[:alnum:]]*@.*/|key|secret|token|pass' $CFN_OUTPUTS_FILE |wc -l|tr -d '\ ') + # New implementation using https://github.com/Yelp/detect-secrets + FINDINGS=$(secretsDetector file $CFN_OUTPUTS_FILE) + if [[ $FINDINGS -eq 0 ]]; then + textPass "$regx: No secrets found in stack $stack Outputs" "$regx" + # delete file if nothing interesting is there + rm -f $CFN_OUTPUTS_FILE + else + textFail "$regx: Potential secret found in stack $stack Outputs" "$regx" + # delete file to not leave trace, user must look at the CFN Stack + rm -f $CFN_OUTPUTS_FILE + fi else - textPass "$regx: Stack $stack has not Outputs" "$regx" + textInfo "$regx: CloudFormation stack $stack has not Outputs" "$regx" fi done else textInfo "$regx: No CloudFormation stacks found" "$regx" fi done + rm -rf $SECRETS_TEMP_FOLDER } diff --git a/checks/check_extra759 b/checks/check_extra759 new file mode 100644 index 00000000..dbd07632 --- /dev/null +++ b/checks/check_extra759 @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2019) 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_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_ALTERNATE_check759="extra759" + +extra759(){ + SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM" + if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then + # this folder is deleted once this check is finished + mkdir $SECRETS_TEMP_FOLDER + fi + + textInfo "Looking for secrets in Lambda variables across all regions... " + for regx in $REGIONS; do + LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) + if [[ $LIST_OF_FUNCTIONS ]]; then + for lambdafunction in $LIST_OF_FUNCTIONS;do + LAMBDA_FUNCTION_VARIABLES_FILE="$SECRETS_TEMP_FOLDER/extra759-$lambdafunction-$regx-variables.txt" + LAMBDA_FUNCTION_VARIABLES=$($AWSCLI lambda $PROFILE_OPT --region $regx get-function-configuration --function-name $lambdafunction --query 'Environment.Variables' --output text > $LAMBDA_FUNCTION_VARIABLES_FILE) + if [ -s $LAMBDA_FUNCTION_VARIABLES_FILE ];then + # Implementation using https://github.com/Yelp/detect-secrets + FINDINGS=$(secretsDetector file $LAMBDA_FUNCTION_VARIABLES_FILE) + if [[ $FINDINGS -eq 0 ]]; then + textPass "$regx: No secrets found in Lambda function $lambdafunction variables" "$regx" + # delete file if nothing interesting is there + rm -f $LAMBDA_FUNCTION_VARIABLES_FILE + else + textFail "$regx: Potential secret found in Lambda function $lambdafunction variables" "$regx" + # delete file to not leave trace, user must look at the function + rm -f $LAMBDA_FUNCTION_VARIABLES_FILE + fi + else + textInfo "$regx: Lambda function $stalambdafunction has not variables" "$regx" + fi + done + else + textInfo "$regx: No Lambda functions found" "$regx" + fi + done + rm -rf $SECRETS_TEMP_FOLDER +} diff --git a/checks/check_extra760 b/checks/check_extra760 new file mode 100644 index 00000000..eac466e7 --- /dev/null +++ b/checks/check_extra760 @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2019) 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_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_ALTERNATE_check760="extra760" + +extra760(){ + SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM" + if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then + # this folder is deleted once this check is finished + mkdir $SECRETS_TEMP_FOLDER + fi + + textInfo "Looking for secrets in Lambda functions code across all regions... " + textInfo "This check may take a while depending on your functions size! " + for regx in $REGIONS; do + LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) + if [[ $LIST_OF_FUNCTIONS ]]; then + for lambdafunction in $LIST_OF_FUNCTIONS;do + LAMBDA_FUNCTION_FOLDER="$SECRETS_TEMP_FOLDER/extra760-$lambdafunction-$regx" + LAMBDA_FUNCTION_FILE="$lambdafunction-code.zip" + LAMBDA_CODE_LOCATION=$($AWSCLI lambda get-function $PROFILE_OPT --region $regx --function-name $lambdafunction --query Code.Location --output text) + mkdir $LAMBDA_FUNCTION_FOLDER + # DOWNLOAD the code in a zip file + curl -s $LAMBDA_CODE_LOCATION -o $LAMBDA_FUNCTION_FOLDER/$LAMBDA_FUNCTION_FILE + unzip -qq $LAMBDA_FUNCTION_FOLDER/$LAMBDA_FUNCTION_FILE -d $LAMBDA_FUNCTION_FOLDER + FINDINGS=$(secretsDetector folder $LAMBDA_FUNCTION_FOLDER) + if [[ $FINDINGS -eq 0 ]]; then + textPass "$regx: No secrets found in Lambda function $lambdafunction code" "$regx" + # delete files if nothing interesting is there + rm -fr $LAMBDA_FUNCTION_FOLDER + else + textFail "$regx: Potential secret found in Lambda function $lambdafunction code" "$regx" + # delete files to not leave trace, user must look at the function + rm -fr $LAMBDA_FUNCTION_FOLDER + fi + done + else + textInfo "$regx: No Lambda functions found" "$regx" + fi + done + rm -fr $SECRETS_TEMP_FOLDER +} diff --git a/groups/group11_keys b/groups/group11_secrets similarity index 66% rename from groups/group11_keys rename to groups/group11_secrets index 5c47e4fe..ec0b971f 100644 --- a/groups/group11_keys +++ b/groups/group11_secrets @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) 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 @@ -11,12 +11,17 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. -GROUP_ID[11]='keys' +GROUP_ID[11]='secrets' GROUP_NUMBER[11]='11.0' -GROUP_TITLE[11]='Look for keys secrets or passwords around resources - [keys] **' -GROUP_RUN_BY_DEFAULT[11]='N' # run it when execute_all is called -GROUP_CHECKS[11]='extra741,extra742' +GROUP_TITLE[11]='Look for keys secrets or passwords around resources - [secrets] **' +GROUP_RUN_BY_DEFAULT[11]='N' # but it runs when execute_all is called (default) +GROUP_CHECKS[11]='extra741,extra742,extra759,extra760' + +# requires https://github.com/Yelp/detect-secrets +# `pip install detect-secrets` # Initially: # - EC2 UserData # - CloudFormation Outputs +# - Lambda variables +# - Lambda code diff --git a/groups/group7_extras b/groups/group7_extras index 6077c111..2d51b260 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -16,3 +16,6 @@ GROUP_NUMBER[7]='7.0' GROUP_TITLE[7]='Extras - [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' + +# Extras 759 and 760 (lambda variables and code secrets finder are not included) +# to run detect-secrets use `./prowler -g secrets` \ No newline at end of file diff --git a/include/python_detector b/include/python_detector new file mode 100644 index 00000000..712bf84a --- /dev/null +++ b/include/python_detector @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2019) 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. + +# detector of python and boto3 +pythonDetector(){ + PYTHON_BIN=$(which python) + PYTHON_PIP_BOTO3=$(pip list|grep boto3) + if [ -z "${PYTHON_BIN}" ]; then + echo -e "\n$RED ERROR!$NORMAL python not found. Make sure it is installed correctly and in your \$PATH\n" + EXITCODE=1 + exit $EXITCODE + else + PYTHON_INSTALLED=1 + if [ -z "${PYTHON_PIP_BOTO3}" ]; then + echo -e "\n$RED ERROR!$NORMAL python library boto3 not found. Make sure it is installed correctly\n" + EXITCODE=1 + exit $EXITCODE + else + PYTHON_PIP_BOTO3_INSTALLED=1 + fi + fi +} \ No newline at end of file diff --git a/include/secrets_detector b/include/secrets_detector new file mode 100644 index 00000000..5b55ac7d --- /dev/null +++ b/include/secrets_detector @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2019) 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. + +# detector and configuration of detect-secrets +secretsDetector(){ + PYTHON_PIP_DETECTSECRETS=$(which detect-secrets) + if [ -z "${PYTHON_PIP_DETECTSECRETS}" ]; then + echo -e "\n$RED ERROR!$NORMAL python library detect-secrets not found. Make sure it is installed correctly and in your \$PATH\n" + EXITCODE=1 + exit $EXITCODE + else + SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM" + if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then + mkdir $SECRETS_TEMP_FOLDER + fi + PYTHON_PIP_DETECTSECRETS_INSTALLED=1 + # Sets the entropy limit for high entropy base64 strings. Value + # must be between 0.0 and 8.0, defaults is 4.5. + BASE64_LIMIT=3.0 + # Sets the entropy limit for high entropy hex strings. Value + # must be between 0.0 and 8.0, defaults is 3.0. + HEX_LIMIT=3.0 + case $1 in + file ) + # this is to scan a file + detect-secrets scan --hex-limit $HEX_LIMIT --base64-limit $BASE64_LIMIT $2 | \ + jq -r '.results[]|.[] | [.line_number, .type]|@csv' | wc -l + #jq -r '.results[] | .[] | "\(.line_number)\t\(.type)"' + # this command must return values in two colums: + # line in file and type of secrets found + ;; + string ) + # this is to scan a given string + detect-secrets scan --hex-limit $HEX_LIMIT --base64-limit $BASE64_LIMIT --string $2 | \ + grep True| wc -l + ;; + folder ) + # this is to scan a given folder with all lambda files + detect-secrets scan --hex-limit $HEX_LIMIT --base64-limit $BASE64_LIMIT --all-files $2 | \ + jq -r '.results[]|.[] | [.line_number, .type]|@csv' | wc -l + ;; + esac + fi +} \ No newline at end of file diff --git a/prowler b/prowler index b66ac495..c74f2db8 100755 --- a/prowler +++ b/prowler @@ -32,7 +32,7 @@ OPTRED="" OPTNORMAL="" # Set the defaults variables -PROWLER_VERSION=2.0.2 +PROWLER_VERSION=2.1.0 PROWLER_DIR=$(dirname "$0") REGION="" @@ -163,6 +163,8 @@ done . $PROWLER_DIR/include/whoami . $PROWLER_DIR/include/credentials_report . $PROWLER_DIR/include/scoring +. $PROWLER_DIR/include/python_detector +. $PROWLER_DIR/include/secrets_detector # Get a list of all available AWS Regions REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \ From e273ae31237e2deafcef2e91b27bf26109a14b32 Mon Sep 17 00:00:00 2001 From: David Lladro Date: Thu, 27 Jun 2019 15:27:19 -0500 Subject: [PATCH 10/16] Adding detect_secrets support to Docker --- util/Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/util/Dockerfile b/util/Dockerfile index 2af2f3d5..98d049f1 100644 --- a/util/Dockerfile +++ b/util/Dockerfile @@ -5,11 +5,12 @@ ARG USERID=34000 RUN addgroup -g ${USERID} ${USERNAME} && \ adduser -s /bin/sh -G ${USERNAME} -D -u ${USERID} ${USERNAME} && \ - apk --update --no-cache add python3 bash curl git jq && \ + apk --update --no-cache add python3 bash curl git jq file && \ pip3 install --upgrade pip && \ - pip install awscli ansi2html boto3 &&\ + pip install awscli ansi2html boto3 detect-secrets &&\ git clone https://github.com/toniblyx/prowler/ + chown -R prowler /prowler/ USER ${USERNAME} -ENTRYPOINT ["/prowler/prowler"] \ No newline at end of file +ENTRYPOINT ["/prowler/prowler"] From a259571cb0a213fdbeae65867b95abb959b427aa Mon Sep 17 00:00:00 2001 From: David Lladro Date: Thu, 4 Jul 2019 08:38:25 +0200 Subject: [PATCH 11/16] Fixing missing && --- util/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/Dockerfile b/util/Dockerfile index 98d049f1..116bc1f4 100644 --- a/util/Dockerfile +++ b/util/Dockerfile @@ -8,7 +8,7 @@ RUN addgroup -g ${USERID} ${USERNAME} && \ apk --update --no-cache add python3 bash curl git jq file && \ pip3 install --upgrade pip && \ pip install awscli ansi2html boto3 detect-secrets &&\ - git clone https://github.com/toniblyx/prowler/ + git clone https://github.com/toniblyx/prowler/ &&\ chown -R prowler /prowler/ USER ${USERNAME} From 5bd3f0b9958479ebd2e14eb7aa067468eae2948b Mon Sep 17 00:00:00 2001 From: Kevin Pawloski Date: Thu, 11 Jul 2019 18:04:45 -0700 Subject: [PATCH 12/16] Fix typo Fix a small typo in the messaging. --- checks/check_extra74 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checks/check_extra74 b/checks/check_extra74 index cf736188..68dbfa92 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -28,7 +28,7 @@ extra74(){ if [[ $SG_NO_INGRESS_FILTER -ne 0 ]];then textFail "$regx: $SG_ID has no ingress filtering and it is being used!" "$regx" else - textInfo "$regx: $SG_ID has no ingress filtering but it is no being used" "$regx" + textInfo "$regx: $SG_ID has no ingress filtering but it is not being used" "$regx" fi done done From 4bc64e938e6bfddfa1f55d3b301e158362164bcf Mon Sep 17 00:00:00 2001 From: Barak Schoster Goihman Date: Sun, 14 Jul 2019 01:07:21 +0300 Subject: [PATCH 13/16] Create Pipfile add python dependencies --- Pipfile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Pipfile diff --git a/Pipfile b/Pipfile new file mode 100644 index 00000000..3f64ab19 --- /dev/null +++ b/Pipfile @@ -0,0 +1,14 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +boto3="1.9.188" +ansi2html="1.5.2" +detect-secrets="0.12.4" + +[requires] +python_version = "3.7" From 2b95f69fa6f396d410d2714210053ab8a075bb29 Mon Sep 17 00:00:00 2001 From: Kim Oliver Fehrs Date: Wed, 7 Aug 2019 16:06:51 +0200 Subject: [PATCH 14/16] [FIX] allow 1.22 checks on policies with only one statement block | kf/aa/if --- checks/check122 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checks/check122 b/checks/check122 index 2670a9b5..be885311 100644 --- a/checks/check122 +++ b/checks/check122 @@ -22,7 +22,7 @@ check122(){ for policy in $LIST_CUSTOM_POLICIES; do POLICY_ARN=$(echo $policy | awk -F ',' '{print $1}') POLICY_VERSION=$(echo $policy | awk -F ',' '{print $2}') - POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $POLICY_ARN --version-id $POLICY_VERSION --query "PolicyVersion.Document.Statement[?Action!=null]|[?Effect == 'Allow' && Resource == '*' && Action == '*']" $PROFILE_OPT --region $REGION) + POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $POLICY_ARN --version-id $POLICY_VERSION --query "[PolicyVersion.Document.Statement] | [] | [?Action!=null] | [?Effect == 'Allow' && Resource == '*' && Action == '*'] | [?Effect == 'Allow' && Resource == '*' && Action == '*']" $PROFILE_OPT --region $REGION) if [[ $POLICY_WITH_FULL ]]; then POLICIES_ALLOW_LIST="$POLICIES_ALLOW_LIST $POLICY_ARN" fi From 033e2623d3bb9328e46b2337b44c4c651e038d39 Mon Sep 17 00:00:00 2001 From: Kim Oliver Fehrs Date: Wed, 7 Aug 2019 16:13:26 +0200 Subject: [PATCH 15/16] [FIX] remove duplicated filter condition | kf/aa/if --- checks/check122 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checks/check122 b/checks/check122 index be885311..0ae9e6c3 100644 --- a/checks/check122 +++ b/checks/check122 @@ -22,7 +22,7 @@ check122(){ for policy in $LIST_CUSTOM_POLICIES; do POLICY_ARN=$(echo $policy | awk -F ',' '{print $1}') POLICY_VERSION=$(echo $policy | awk -F ',' '{print $2}') - POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $POLICY_ARN --version-id $POLICY_VERSION --query "[PolicyVersion.Document.Statement] | [] | [?Action!=null] | [?Effect == 'Allow' && Resource == '*' && Action == '*'] | [?Effect == 'Allow' && Resource == '*' && Action == '*']" $PROFILE_OPT --region $REGION) + POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $POLICY_ARN --version-id $POLICY_VERSION --query "[PolicyVersion.Document.Statement] | [] | [?Action!=null] | [?Effect == 'Allow' && Resource == '*' && Action == '*']" $PROFILE_OPT --region $REGION) if [[ $POLICY_WITH_FULL ]]; then POLICIES_ALLOW_LIST="$POLICIES_ALLOW_LIST $POLICY_ARN" fi From 7313628cc6902de58357d2cf64b41c2c037a7828 Mon Sep 17 00:00:00 2001 From: james-portman-contino <52815991+james-portman-contino@users.noreply.github.com> Date: Thu, 8 Aug 2019 08:50:28 +0100 Subject: [PATCH 16/16] Stop colorizing the JSON output If using a terminal then jq prints out JSON with color. I suggest color should either be disabled always or with some other flag (more complicated) jq flag: -M monochrome (don't colorize JSON); --- include/outputs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/outputs b/include/outputs index a343a4ae..6e379d0f 100644 --- a/include/outputs +++ b/include/outputs @@ -27,7 +27,7 @@ textPass(){ else REPREGION=$REGION fi - jq -c \ + jq -M -c \ --arg PROFILE "$PROFILE" \ --arg ACCOUNT_NUM "$ACCOUNT_NUM" \ --arg TITLE_TEXT "$TITLE_TEXT" \