mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-11 07:15:15 +00:00
Merge branch 'master' into fix_check_extra741
This commit is contained in:
14
Pipfile
Normal file
14
Pipfile
Normal file
@@ -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"
|
||||
@@ -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 == '*']" $PROFILE_OPT --region $REGION)
|
||||
if [[ $POLICY_WITH_FULL ]]; then
|
||||
POLICIES_ALLOW_LIST="$POLICIES_ALLOW_LIST $POLICY_ARN"
|
||||
fi
|
||||
|
||||
@@ -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
|
||||
# }
|
||||
@@ -44,40 +44,46 @@ 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
|
||||
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 --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
|
||||
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" "$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" "$BUCKET_LOCATION"
|
||||
fi
|
||||
if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then
|
||||
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" "$BUCKET_LOCATION"
|
||||
fi
|
||||
rm -fr $TEMP_POLICY_FILE
|
||||
fi
|
||||
rm -fr $TEMP_POLICY_FILE
|
||||
done
|
||||
}
|
||||
|
||||
@@ -115,16 +121,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
|
||||
# }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,13 +11,19 @@
|
||||
# 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
|
||||
@@ -60,4 +66,5 @@ extra741(){
|
||||
textInfo "$regx: No EC2 instances found" "$regx"
|
||||
fi
|
||||
done
|
||||
rm -rf $SECRETS_TEMP_FOLDER
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
54
checks/check_extra759
Normal file
54
checks/check_extra759
Normal file
@@ -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
|
||||
}
|
||||
55
checks/check_extra760
Normal file
55
checks/check_extra760
Normal file
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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`
|
||||
@@ -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" \
|
||||
|
||||
32
include/python_detector
Normal file
32
include/python_detector
Normal file
@@ -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
|
||||
}
|
||||
54
include/secrets_detector
Normal file
54
include/secrets_detector
Normal file
@@ -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
|
||||
}
|
||||
10
prowler
10
prowler
@@ -32,7 +32,7 @@ OPTRED="[1;31m"
|
||||
OPTNORMAL="[0;39m"
|
||||
|
||||
# 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' \
|
||||
@@ -271,9 +273,11 @@ 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
|
||||
# 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
|
||||
|
||||
@@ -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 &&\
|
||||
git clone https://github.com/toniblyx/prowler/
|
||||
pip install awscli ansi2html boto3 detect-secrets &&\
|
||||
git clone https://github.com/toniblyx/prowler/ &&\
|
||||
chown -R prowler /prowler/
|
||||
|
||||
USER ${USERNAME}
|
||||
|
||||
ENTRYPOINT ["/prowler/prowler"]
|
||||
ENTRYPOINT ["/prowler/prowler"]
|
||||
|
||||
Reference in New Issue
Block a user