From c02811f4115a4b8556e3b62c0a93f9f9d20cfe19 Mon Sep 17 00:00:00 2001 From: Marc Jay Date: Sat, 11 Apr 2020 03:34:32 +0100 Subject: [PATCH] Add CHECK_ASFF_RESOURCE_TYPE variables for recently added checks --- checks/check_extra786 | 15 ++++++++------- checks/check_extra787 | 27 ++++++++++++++------------- checks/check_extra788 | 25 +++++++++++++------------ checks/check_extra789 | 11 ++++++----- checks/check_extra790 | 11 ++++++----- 5 files changed, 47 insertions(+), 42 deletions(-) diff --git a/checks/check_extra786 b/checks/check_extra786 index dd9f378e488..f011a7f40a8 100644 --- a/checks/check_extra786 +++ b/checks/check_extra786 @@ -14,30 +14,31 @@ CHECK_ID_extra786="7.86" CHECK_TITLE_extra786="[extra786] Check if EC2 Instance Metadata Service Version 2 (IMDSv2) is Enabled and Required (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra786="NOT_SCORED" CHECK_TYPE_extra786="EXTRA" +CHECK_ASFF_RESOURCE_TYPE_extra786="AwsEc2Instance" CHECK_ALTERNATE_check786="extra786" extra786(){ - for regx in $REGIONS; do + for regx in $REGIONS; do TEMP_EXTRA786_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.EXTRA786.XXXXXXXXXX) $AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx \ --query 'Reservations[*].Instances[*].{HttpTokens:MetadataOptions.HttpTokens,HttpEndpoint:MetadataOptions.HttpEndpoint,InstanceId:InstanceId}' \ --output text --max-items $MAXITEMS > $TEMP_EXTRA786_FILE - # if the file contains data, there are instances in that region + # if the file contains data, there are instances in that region if [[ -s "$TEMP_EXTRA786_FILE" ]];then # here we read content from the file fields instanceid httptokens_status httpendpoint - while read httpendpoint httptokens_status instanceid ; do + while read httpendpoint httptokens_status instanceid ; do #echo i:$instanceid tok:$httptokens_status end:$httpendpoint if [[ "$httpendpoint" == "enabled" && "$httptokens_status" == "required" ]];then textPass "$regx: EC2 Instance $instanceid has IMDSv2 enabled and required" "$regx" - elif [[ "$httpendpoint" == "disabled" ]];then + elif [[ "$httpendpoint" == "disabled" ]];then textInfo "$regx: EC2 Instance $instanceid has HTTP endpoint access to metadata service disabled" "$regx" else textFail "$regx: EC2 Instance $instanceid has IMDSv2 disabled or not required" "$regx" - fi + fi done < <(cat $TEMP_EXTRA786_FILE) - else + else textInfo "$regx: no EC2 Instances found" "$regx" - fi + fi rm -fr $TEMP_EXTRA786_FILE done } diff --git a/checks/check_extra787 b/checks/check_extra787 index 6f867902484..ea681f8e1b8 100644 --- a/checks/check_extra787 +++ b/checks/check_extra787 @@ -12,8 +12,9 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra787="7.87" CHECK_TITLE_extra787="[extra787] Check connection and authentication for Internet exposed Elasticsearch/Kibana ports" -CHECK_SCORED_extra787="NOT_SCORED" +CHECK_SCORED_extra787="NOT_SCORED" CHECK_TYPE_extra787="EXTRA" +CHECK_ASFF_RESOURCE_TYPE_extra787="AwsEc2Instance" CHECK_ALTERNATE_check787="extra787" extra787(){ @@ -25,7 +26,7 @@ extra787(){ ES_KIBANA_PORT="5601" for regx in $REGIONS; do - # crate a list of SG open to the world with port $ES_API_PORT or $ES_DATA_PORT or $ES_KIBANA_PORT + # create a list of SG open to the world with port $ES_API_PORT or $ES_DATA_PORT or $ES_KIBANA_PORT SG_LIST=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --output text \ --query "SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=\`$ES_API_PORT\` && ToPort>=\`$ES_API_PORT\`) || (FromPort<=\`$ES_DATA_PORT\` && ToPort>=\`$ES_DATA_PORT\`) || (FromPort<=\`$ES_KIBANA_PORT\` && ToPort>=\`$ES_KIBANA_PORT\`)) && (contains(IpRanges[].CidrIp, \`0.0.0.0/0\`) || contains(Ipv6Ranges[].CidrIpv6, \`::/0\`))]) > \`0\`].{GroupId:GroupId}") # in case of open security groups goes through each one @@ -37,28 +38,28 @@ extra787(){ $AWSCLI $PROFILE_OPT --region $regx ec2 describe-instances --filters Name=instance.group-id,Values=$sg --query 'Reservations[*].Instances[*].[InstanceId,PublicIpAddress]' --output text > $TEMP_EXTRA787_FILE # in case of exposed instances it does access checks if [[ -s "$TEMP_EXTRA787_FILE" ]];then - while read instance eip ; do - if [[ "$eip" != "None" ]];then + while read instance eip ; do + if [[ "$eip" != "None" ]];then # check for Elasticsearch on port $ES_API_PORT, rest API HTTP. CHECH_HTTP_ES_API=$(curl -m 2 -s -w "%{http_code}" -o /dev/null -X GET "http://$eip:$ES_API_PORT/_cat/indices") httpStatus $CHECH_HTTP_ES_API - if [[ $CHECH_HTTP_ES_API -eq "200" ]];then + if [[ $CHECH_HTTP_ES_API -eq "200" ]];then textFail "$regx: Found instance $instance with public IP $eip on Security Group: $sg with Elasticsearch port $ES_API_PORT response $SERVER_RESPONSE" "$regx" else textInfo "$regx: Found instance $instance with public IP $eip on Security Group: $sg with Elasticsearch port $ES_API_PORT response $SERVER_RESPONSE" "$regx" fi # check for port $ES_DATA_PORT TCP, this is the communication port, not: - # test_tcp_connectivity is in include/os_detector + # test_tcp_connectivity is in include/os_detector # syntax is 'test_tcp_connectivity $HOST $PORT $TIMEOUT' (in seconds) CHECH_HTTP_ES_DATA=$(test_tcp_connectivity $eip $ES_DATA_PORT 2) - # Using HTTP error codes here as well to reuse httpStatus function + # Using HTTP error codes here as well to reuse httpStatus function # codes for better handling, so 200 is open and 000 is not responding httpStatus $CHECH_HTTP_ES_DATA if [[ $CHECH_HTTP_ES_DATA -eq "200" ]];then textFail "$regx: Found instance $instance with public IP $eip on Security Group: $sg with Elasticsearch port $ES_DATA_PORT response $SERVER_RESPONSE" "$regx" else textInfo "$regx: Found instance $instance with public IP $eip on Security Group: $sg with Elasticsearch port $ES_DATA_PORT response $SERVER_RESPONSE" "$regx" - fi + fi # check for Kibana on port $ES_KIBANA_PORT CHECH_HTTP_ES_KIBANA=$(curl -m 2 -s -w "%{http_code}" -o /dev/null -X GET "http://$eip:$ES_KIBANA_PORT/api/status") httpStatus $CHECH_HTTP_ES_KIBANA @@ -66,13 +67,13 @@ extra787(){ textFail "$regx: Found instance $instance with public IP $eip on Security Group: $sg with Kibana on port $ES_KIBANA_PORT response $SERVER_RESPONSE" "$regx" else textInfo "$regx: Found instance $instance with public IP $eip on Security Group: $sg with Kibana on port $ES_KIBANA_PORT response $SERVER_RESPONSE" "$regx" - fi - else + fi + else textInfo "$regx: Found instance $instance with private IP on Security Group: $sg" "$regx" - fi + fi done < <(cat $TEMP_EXTRA787_FILE) - fi - rm -rf $TEMP_EXTRA787_FILE + fi + rm -rf $TEMP_EXTRA787_FILE done else textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Elasticsearch/Kibana ports" "$regx" diff --git a/checks/check_extra788 b/checks/check_extra788 index f2258843516..6c3c9fd0abd 100644 --- a/checks/check_extra788 +++ b/checks/check_extra788 @@ -14,6 +14,7 @@ CHECK_ID_extra788="7.88" CHECK_TITLE_extra788="[extra788] Check connection and authentication for Internet exposed Amazon Elasticsearch Service (ES) domains" CHECK_SCORED_extra788="NOT_SCORED" CHECK_TYPE_extra788="EXTRA" +CHECK_ASFF_RESOURCE_TYPE_extra788="AwsElasticsearchDomain" CHECK_ALTERNATE_check788="extra788" extra788(){ @@ -31,8 +32,8 @@ extra788(){ # If the endpoint starts with "vpc-" it is in a VPC then it is fine. if [[ "$ES_DOMAIN_ENDPOINT" =~ ^vpc-* ]];then ES_DOMAIN_VPC=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.VPCOptions.VPCId' --output text) - textInfo "$regx: Amazon ES domain $domain is in VPC $ES_DOMAIN_VPC run extra779 to make sure it is not exposed using custom proxy" "$regx" - else + textInfo "$regx: Amazon ES domain $domain is in VPC $ES_DOMAIN_VPC run extra779 to make sure it is not exposed using custom proxy" "$regx" + else $AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.AccessPolicies.Options --output text > $TEMP_POLICY_FILE 2> /dev/null CHECK_ES_DOMAIN_POLICY_OPEN=$(cat $TEMP_POLICY_FILE | jq -r '. | .Statement[] | select(.Effect == "Allow" and (((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and select(has("Condition") | not))') CHECK_ES_DOMAIN_POLICY_HAS_CONDITION=$(cat $TEMP_POLICY_FILE | jq -r '. | .Statement[] | select(.Effect == "Allow" and (((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and select(has("Condition")))' ) @@ -43,29 +44,29 @@ extra788(){ CONDITION_HAS_PRIVATE_IP=$(echo "${condition_ip}" | grep -E '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)') if [[ $CONDITION_HAS_PRIVATE_IP ]];then CONDITION_HAS_PRIVATE_IP_ARRAY+=($condition_ip) - fi + fi CONDITION_HAS_PUBLIC_IP=$(echo "${condition_ip}" | grep -vE '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|0\.0\.0\.0|\*)') if [[ $CONDITION_HAS_PUBLIC_IP ]];then CONDITION_HAS_PUBLIC_IP_ARRAY+=($condition_ip) fi CONDITION_HAS_ZERO_NET=$(echo "${condition_ip}" | grep -E '^(0\.0\.0\.0)') CONDITION_HAS_STAR=$(echo "${condition_ip}" | grep -E '^\*') - done + done CHECK_ES_DOMAIN_POLICY_CONDITION_PRIVATE_IP=${CONDITION_HAS_PRIVATE_IP_ARRAY[@]} CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP=${CONDITION_HAS_PUBLIC_IP_ARRAY[@]} CHECK_ES_DOMAIN_POLICY_CONDITION_ZERO=$CONDITION_HAS_ZERO_NET CHECK_ES_DOMAIN_POLICY_CONDITION_STAR=$CONDITION_HAS_STAR - fi + fi if [[ $CHECK_ES_DOMAIN_POLICY_OPEN || $CHECK_ES_DOMAIN_POLICY_CONDITION_ZERO || $CHECK_ES_DOMAIN_POLICY_CONDITION_STAR || ${CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP[@]} ]];then #Prowler will check to read indices or kibaba status if no conditions, condition IP is *, 0.0.0.0/0, 0.0.0.0/8 or any public IP. # check for REST API on port 443 CHECH_ES_HTTPS=$(curl -m 2 -s -w "%{http_code}" -o /dev/null -X GET "https://$ES_DOMAIN_ENDPOINT/_cat/indices") httpStatus $CHECH_ES_HTTPS - if [[ $CHECH_ES_HTTPS -eq "200" ]];then + if [[ $CHECH_ES_HTTPS -eq "200" ]];then textFail "$regx: Amazon ES domain $domain policy allows Anonymous access and ES service endpoint $ES_DOMAIN_ENDPOINT responded $SERVER_RESPONSE" "$regx" else textInfo "$regx: Amazon ES domain $domain policy allows Anonymous access but ES service endpoint $ES_DOMAIN_ENDPOINT responded $SERVER_RESPONSE" "$regx" - fi + fi # check for Kibana on port 443 CHECH_KIBANA_HTTPS=$(curl -m 2 -s -w "%{http_code}" -o /dev/null -X GET "https://$ES_DOMAIN_ENDPOINT/_plugin/kibana/api/status") httpStatus $CHECH_KIBANA_HTTPS @@ -73,13 +74,13 @@ extra788(){ textFail "$regx: Amazon ES domain $domain policy allows Anonymous access and Kibana service endpoint $ES_DOMAIN_ENDPOINT responded $SERVER_RESPONSE" "$regx" else textInfo "$regx: Amazon ES domain $domain policy allows Anonymous access but Kibana service endpoint $ES_DOMAIN_ENDPOINT responded $SERVER_RESPONSE" "$regx" - fi + fi else if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && ${CHECK_ES_DOMAIN_POLICY_CONDITION_PRIVATE_IP[@]} ]];then textInfo "$regx: Amazon ES domain $domain policy allows access from a Private IP or CIDR RFC1918 $(echo ${CONDITION_HAS_PRIVATE_IP_ARRAY[@]})" "$regx" - else - textPass "$regx: Amazon ES domain $domain does not allow Anonymous cross account access" "$regx" - fi + else + textPass "$regx: Amazon ES domain $domain does not allow Anonymous cross account access" "$regx" + fi fi rm -f $TEMP_POLICY_FILE fi @@ -88,4 +89,4 @@ extra788(){ textInfo "$regx: No Amazon ES domain found" "$regx" fi done -} +} diff --git a/checks/check_extra789 b/checks/check_extra789 index 964067cd3df..87f3a1a1797 100644 --- a/checks/check_extra789 +++ b/checks/check_extra789 @@ -15,11 +15,12 @@ CHECK_ID_extra789="7.89" CHECK_TITLE_extra789="[extra789] Find trust boundaries in VPC endpoint services connections" CHECK_SCORED_extra789="NOT_SCORED" CHECK_TYPE_extra789="EXTRA" +CHECK_ASFF_RESOURCE_TYPE_extra789="AwsEc2Vpc" CHECK_ALTERNATE_extra789="extra789" extra789(){ TRUSTED_ACCOUNT_IDS=$( echo "${ACCOUNT_NUM} ${GROUP_TRUSTBOUNDARIES_TRUSTED_ACCOUNT_IDS}" | xargs ) - + for regx in ${REGIONS}; do ENDPOINT_SERVICES_IDS=$(${AWSCLI} ec2 describe-vpc-endpoint-services \ ${PROFILE_OPT} \ @@ -29,19 +30,19 @@ extra789(){ ) for ENDPOINT_SERVICE_ID in ${ENDPOINT_SERVICES_IDS}; do - + ENDPOINT_CONNECTION_LIST=$(${AWSCLI} ec2 describe-vpc-endpoint-connections \ ${PROFILE_OPT} \ --query "VpcEndpointConnections[?VpcEndpointState=='available'].VpcEndpointOwner" \ --region ${regx} \ --output text | xargs ) - + for ENDPOINT_CONNECTION in ${ENDPOINT_CONNECTION_LIST}; do for ACCOUNT_ID in ${TRUSTED_ACCOUNT_IDS}; do if [[ "${ACCOUNT_ID}" == "${ENDPOINT_CONNECTION}" ]]; then textPass "${regx}: Found trusted account in VPC endpoint service connection ${ENDPOINT_CONNECTION}" "${regx}" - # Algorithm: + # Algorithm: # Remove all trusted ACCOUNT_IDs from ENDPOINT_CONNECTION_LIST. # As a result, the ENDPOINT_CONNECTION_LIST finally contains only unknown/untrusted account ids. ENDPOINT_CONNECTION_LIST=("${ENDPOINT_CONNECTION_LIST[@]/$ENDPOINT_CONNECTION}") # remove hit from whitelist @@ -52,6 +53,6 @@ extra789(){ for UNTRUSTED_CONNECTION in ${ENDPOINT_CONNECTION_LIST}; do textFail "${regx}: Found untrusted account in VPC endpoint service connection ${UNTRUSTED_CONNECTION}" "${regx}" done - done + done done } diff --git a/checks/check_extra790 b/checks/check_extra790 index 9a56cf173c0..6e9c2e80e6e 100644 --- a/checks/check_extra790 +++ b/checks/check_extra790 @@ -15,6 +15,7 @@ CHECK_ID_extra790="7.90" CHECK_TITLE_extra790="[extra790] Find trust boundaries in VPC endpoint services whitelisted principles" CHECK_SCORED_extra790="NOT_SCORED" CHECK_TYPE_extra790="EXTRA" +CHECK_ASFF_RESOURCE_TYPE_extra790="AwsEc2Vpc" CHECK_ALTERNATE_extra790="extra790" extra790(){ @@ -40,14 +41,14 @@ extra790(){ for ENDPOINT_PERMISSION in ${ENDPOINT_PERMISSIONS_LIST}; do # Take only account id from ENDPOINT_PERMISSION: arn:aws:iam::965406151242:root ENDPOINT_PERMISSION_ACCOUNT_ID=$(echo ${ENDPOINT_PERMISSION} | cut -d':' -f5 | xargs) - + for ACCOUNT_ID in ${TRUSTED_ACCOUNT_IDS}; do if [[ "${ACCOUNT_ID}" == "${ENDPOINT_PERMISSION_ACCOUNT_ID}" ]]; then textPass "${regx}: Found trusted account in VPC endpoint service permission ${ENDPOINT_PERMISSION}" "${regx}" - # Algorithm: + # Algorithm: # Remove all trusted ACCOUNT_IDs from ENDPOINT_PERMISSIONS_LIST. # As a result, the ENDPOINT_PERMISSIONS_LIST finally contains only unknown/untrusted account ids. - ENDPOINT_PERMISSIONS_LIST=("${ENDPOINT_PERMISSIONS_LIST[@]/$ENDPOINT_PERMISSION}") + ENDPOINT_PERMISSIONS_LIST=("${ENDPOINT_PERMISSIONS_LIST[@]/$ENDPOINT_PERMISSION}") fi done done @@ -55,6 +56,6 @@ extra790(){ for UNTRUSTED_PERMISSION in ${ENDPOINT_PERMISSIONS_LIST}; do textFail "${regx}: Found untrusted account in VPC endpoint service permission ${UNTRUSTED_PERMISSION}" "${regx}" done - done + done done -} +}