diff --git a/checks/check_extra716 b/checks/check_extra716 index afdb8dd4..d1615857 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -17,10 +17,6 @@ CHECK_TYPE_extra716="EXTRA" CHECK_ALTERNATE_check716="extra716" extra716(){ - # if TEST_AUTHENTICATION has a value Prowler will try to access each ElasticSearch server to the public URI endpoint. - # That is from the host where Prowler is running and will try to read indices or get kibana status - TEST_ES_AUTHENTICATION= - # "Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" for regx in $REGIONS; do LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) @@ -40,17 +36,17 @@ extra716(){ if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION ]]; then # get content of IpAddress."aws:SourceIp" and get a clean list LIST_CONDITION_IPS=$(cat $TEMP_POLICY_FILE | jq '.Statement[0] .Condition.IpAddress."aws:SourceIp"'| awk -F'"' '{print $2}' | tr -d '",^$' | sed '/^$/d') - for condition_ip in $LIST_CONDITION_IPS;do - CONDITION_HAS_PRIVATE_IP=$(echo $condition_ip | grep -E '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)') + for condition_ip in "${LIST_CONDITION_IPS}";do + 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 - 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|\*)') + 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 '^\*') + CONDITION_HAS_ZERO_NET=$(echo "${condition_ip}" | grep -E '^(0\.0\.0\.0)') + CONDITION_HAS_STAR=$(echo "${condition_ip}" | grep -E '^\*') 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[@]} @@ -58,38 +54,18 @@ extra716(){ CHECK_ES_DOMAIN_POLICY_CONDITION_STAR=$CONDITION_HAS_STAR 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. - if [[ $TEST_ES_AUTHENTICATION ]];then - # 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 - 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 - # 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 - if [[ $CHECH_KIBANA_HTTPS -eq "200" ]];then - 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 - else - if [[ $CHECK_ES_DOMAIN_POLICY_OPEN ]];then - textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\") AUTH NOT TESTED" "$regx" - fi - if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && $CHECK_ES_DOMAIN_POLICY_CONDITION_ZERO ]];then - textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network 0.0.0.0) AUTH NOT TESTED" "$regx" - fi - if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && $CHECK_ES_DOMAIN_POLICY_CONDITION_STAR ]];then - textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network \"*\") AUTH NOT TESTED" "$regx" - fi - if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && ${CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP[@]} ]];then - textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and Public IP or Network $(echo ${CONDITION_HAS_PUBLIC_IP_ARRAY[@]})) AUTH NOT TESTED" "$regx" - fi + if [[ $CHECK_ES_DOMAIN_POLICY_OPEN ]];then + textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\") - use extra788 to test AUTH" "$regx" fi + if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && $CHECK_ES_DOMAIN_POLICY_CONDITION_ZERO ]];then + textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network 0.0.0.0) - use extra788 to test AUTH" "$regx" + fi + if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && $CHECK_ES_DOMAIN_POLICY_CONDITION_STAR ]];then + textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network \"*\") - use extra788 to test AUTH" "$regx" + fi + if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && ${CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP[@]} ]];then + textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and Public IP or Network $(echo ${CONDITION_HAS_PUBLIC_IP_ARRAY[@]})) - use extra788 to test AUTH" "$regx" + 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" diff --git a/checks/check_extra779 b/checks/check_extra779 index 627bc51a..468b127d 100644 --- a/checks/check_extra779 +++ b/checks/check_extra779 @@ -17,14 +17,10 @@ CHECK_TYPE_extra779="EXTRA" CHECK_ALTERNATE_check779="extra779" extra779(){ - # if TEST_AUTHENTICATION has a value Prowler will try to access each ElasticSearch server to port: - # 9200 API, 9300 Communcation and 5601 Kibana to figure out if authentication is enabled. - # That is from the host where Prowler is running and will try to read indices or get kibana status - TEST_ES_AUTHENTICATION= ES_API_PORT="9200" ES_DATA_PORT="9300" ES_KIBANA_PORT="5601" - + # Test connectivity and authentication is performed by check extra787 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 SG_LIST=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --output text \ @@ -38,58 +34,15 @@ extra779(){ $AWSCLI $PROFILE_OPT --region $regx ec2 describe-instances --filters Name=instance.group-id,Values=$sg --query 'Reservations[*].Instances[*].[InstanceId,PublicIpAddress]' --output text > $TEMP_EXTRA779_FILE # in case of exposed instances it does access checks if [[ -s "$TEMP_EXTRA779_FILE" ]];then - while read instance eip ; do - if [[ $TEST_ES_AUTHENTICATION ]];then - 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 - 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 - # 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 - # 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 - - # 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 - if [[ $CHECH_AUTH_5601 -eq "200" ]];then - 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 - fi - else - if [[ "$eip" == "None" ]];then - textInfo "$regx: Found instance $instance with private IP on Security Group: $sg" "$regx" - else - textFail "$regx: Found instance $instance with public IP $eip on Security Group: $sg open to 0.0.0.0/0 on for Elasticsearch/Kibana ports $ES_API_PORT/$ES_DATA_PORT/$ES_KIBANA_PORT" "$regx" - fi - fi + while read instance eip ; do if [[ "$eip" == "None" ]];then textInfo "$regx: Found instance $instance with private IP on Security Group: $sg" "$regx" + else + textFail "$regx: Found instance $instance with public IP $eip on Security Group: $sg open to 0.0.0.0/0 on for Elasticsearch/Kibana ports - use extra787 to test AUTH" "$regx" fi - # done < <(cat $TEMP_EXTRA779_FILE | grep -v None$) done < <(cat $TEMP_EXTRA779_FILE) - # while read instance eip ; do - # textInfo "$regx: Found instance $instance with private IP on Security Group: $sg" "$regx" - # done < <(cat $TEMP_EXTRA779_FILE | grep None$) fi rm -rf $TEMP_EXTRA779_FILE - #textFail "$regx: Found Security Group: $sg open to 0.0.0.0/0 on for Elasticsearch ports" "$regx" 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_extra786 b/checks/check_extra786 index 95b709a7..dd9f378e 100644 --- a/checks/check_extra786 +++ b/checks/check_extra786 @@ -18,7 +18,7 @@ CHECK_ALTERNATE_check786="extra786" extra786(){ for regx in $REGIONS; do - TEMP_EXTRA786_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.EXTRA779.XXXXXXXXXX) + 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 diff --git a/checks/check_extra787 b/checks/check_extra787 new file mode 100644 index 00000000..085d424e --- /dev/null +++ b/checks/check_extra787 @@ -0,0 +1,81 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2020) 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_extra787="7.87" +CHECK_TITLE_extra787="[extra787] Check connection and authentication for public exposed Elasticsearch/Kibana ports" +CHECK_SCORED_extra787="NOT_SCORED" +CHECK_TYPE_extra787="EXTRA" +CHECK_ALTERNATE_check787="extra787" + +extra787(){ + # Prowler will try to access each ElasticSearch server to port: + # 9200 API, 9300 Communcation and 5601 Kibana to figure out if authentication is enabled. + # That is from the host where Prowler is running and will try to read indices or get kibana status + ES_API_PORT="9200" + ES_DATA_PORT="9300" + 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 + 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 + if [[ $SG_LIST ]];then + for sg in $SG_LIST;do + # temp file store the list of instances IDs and public IP address if found + TEMP_EXTRA787_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.EXTRA787.XXXXXXXXXX) + # finds instances with that open security group attached and get its public ip address (if it has one) + $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 + # 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 + 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 + # 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 + # 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 + # 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 + if [[ $CHECH_AUTH_5601 -eq "200" ]];then + 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 + textInfo "$regx: Found instance $instance with private IP on Security Group: $sg" "$regx" + fi + done < <(cat $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" + fi + done +} diff --git a/checks/check_extra788 b/checks/check_extra788 new file mode 100644 index 00000000..c3f8c046 --- /dev/null +++ b/checks/check_extra788 @@ -0,0 +1,91 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +CHECK_ID_extra788="7.88" +CHECK_TITLE_extra788="[extra788] Check connection and authentication for publicly exposed Amazon Elasticsearch Service (ES) domains" +CHECK_SCORED_extra788="NOT_SCORED" +CHECK_TYPE_extra788="EXTRA" +CHECK_ALTERNATE_check788="extra788" + +extra788(){ + # Prowler will try to access each ElasticSearch server to the public URI endpoint. + # That is from the host where Prowler is running and will try to read indices or get kibana status + + # "Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" + for regx in $REGIONS; do + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + if [[ $LIST_OF_DOMAINS ]]; then + for domain in $LIST_OF_DOMAINS;do + TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.policy.XXXXXXXXXX) + # get endpoint or vpc endpoints + ES_DOMAIN_ENDPOINT=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.[Endpoint || Endpoints]' --output text) + # 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 + $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")))' ) + if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION ]]; then + # get content of IpAddress."aws:SourceIp" and get a clean list + LIST_CONDITION_IPS=$(cat $TEMP_POLICY_FILE | jq '.Statement[0] .Condition.IpAddress."aws:SourceIp"'| awk -F'"' '{print $2}' | tr -d '",^$' | sed '/^$/d') + for condition_ip in "${LIST_CONDITION_IPS}";do + 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 + 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 + 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 + 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 + 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 + # 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 + if [[ $CHECH_KIBANA_HTTPS -eq "200" ]];then + 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 + 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 + fi + rm -f $TEMP_POLICY_FILE + fi + done + else + textInfo "$regx: No Amazon ES domain found" "$regx" + fi + done +} diff --git a/groups/group14_elasticsearch b/groups/group14_elasticsearch index e046981f..22ffbb4c 100644 --- a/groups/group14_elasticsearch +++ b/groups/group14_elasticsearch @@ -13,6 +13,6 @@ GROUP_ID[14]='elasticsearch' GROUP_NUMBER[14]='14.0' -GROUP_TITLE[14]='Elasticsearch related security checks - [elasticsearch] ***************' +GROUP_TITLE[14]='Elasticsearch related security checks - [elasticsearch] *******' GROUP_RUN_BY_DEFAULT[14]='N' # run it when execute_all is called -GROUP_CHECKS[14]='extra715,extra716,extra779,extra780,extra781,extra782,extra783,extra784,extra785' +GROUP_CHECKS[14]='extra715,extra716,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra787,extra788' \ No newline at end of file diff --git a/include/connection_tests b/include/connection_tests index 632be16f..a34fb46c 100644 --- a/include/connection_tests +++ b/include/connection_tests @@ -12,9 +12,10 @@ # specific language governing permissions and limitations under the License. -# Functions to connection responses initially used for Elasticsearch related checks +# Function test_tcp_connectivity is in include/os_detector -httpStatus(){ +# Functions to connection responses initially used for Elasticsearch related checks +httpStatus(){ case $1 in 000) SERVER_RESPONSE="000 Not responding" ;; 200) SERVER_RESPONSE="200 Successful" ;;