From 4be1a9d9e401ac3669d18ffdbef28216bd266d77 Mon Sep 17 00:00:00 2001 From: damien cavagnini Date: Tue, 5 Aug 2025 16:23:52 +0200 Subject: [PATCH] feat: add debian12 scripts - iptables_loopback.sh -> 4.3.2.2 - iptables_rule_them_all.sh -> 4.3.2.4 - iptables_outbound_established.sh -> 4.3.2.3 - ip6tables_loopback.sh -> 4.3.3.2 - ip6tables_outbound_established.sh -> 4.3.3.3 - ip6tables_rule_them_all.sh -> 4.3.3.4 - ip6tables_default_deny_policy.sh -> 4.3.3.1 --- .../ip6tables_default_deny_policy.sh | 97 +++++++++++++++ bin/hardening/ip6tables_loopback.sh | 114 ++++++++++++++++++ .../ip6tables_outbound_established.sh | 92 ++++++++++++++ bin/hardening/ip6tables_rule_them_all.sh | 108 +++++++++++++++++ bin/hardening/iptables_loopback.sh | 108 +++++++++++++++++ .../iptables_outbound_established.sh | 86 +++++++++++++ bin/hardening/iptables_rule_them_all.sh | 102 ++++++++++++++++ .../ip6tables_default_deny_policy.sh | 16 +++ tests/hardening/ip6tables_loopback.sh | 16 +++ .../ip6tables_outbound_established.sh | 16 +++ tests/hardening/ip6tables_rule_them_all.sh | 16 +++ tests/hardening/iptables_loopback.sh | 16 +++ .../iptables_outbound_established.sh | 16 +++ tests/hardening/iptables_rule_them_all.sh | 16 +++ 14 files changed, 819 insertions(+) create mode 100644 bin/hardening/ip6tables_default_deny_policy.sh create mode 100755 bin/hardening/ip6tables_loopback.sh create mode 100755 bin/hardening/ip6tables_outbound_established.sh create mode 100755 bin/hardening/ip6tables_rule_them_all.sh create mode 100755 bin/hardening/iptables_loopback.sh create mode 100755 bin/hardening/iptables_outbound_established.sh create mode 100755 bin/hardening/iptables_rule_them_all.sh create mode 100644 tests/hardening/ip6tables_default_deny_policy.sh create mode 100644 tests/hardening/ip6tables_loopback.sh create mode 100644 tests/hardening/ip6tables_outbound_established.sh create mode 100644 tests/hardening/ip6tables_rule_them_all.sh create mode 100644 tests/hardening/iptables_loopback.sh create mode 100644 tests/hardening/iptables_outbound_established.sh create mode 100644 tests/hardening/iptables_rule_them_all.sh diff --git a/bin/hardening/ip6tables_default_deny_policy.sh b/bin/hardening/ip6tables_default_deny_policy.sh new file mode 100644 index 0000000..dfea79d --- /dev/null +++ b/bin/hardening/ip6tables_default_deny_policy.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure ip6tables default deny firewall policy (Manual) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=2 +# shellcheck disable=2034 +DESCRIPTION="Ensure ip6tables default deny firewall policy" + +# This function will be called if the script status is on enabled / audit mode +audit() { + INPUT_CHAIN_DROP=1 + OUTPUT_CHAIN_DROP=1 + FORWARD_CHAIN_DROP=1 + + local input_default="" + local output_default="" + local forward_default="" + input_default=$($SUDO_CMD ip6tables -S INPUT | awk '/^-P/ {print $3}') + output_default=$($SUDO_CMD ip6tables -S OUTPUT | awk '/^-P/ {print $3}') + forward_default=$($SUDO_CMD ip6tables -S FORWARD | awk '/^-P/ {print $3}') + + if [ "$input_default" != "DROP" ]; then + crit "ip6tables 'INPUT' chain does not have 'DROP' has default policy" + else + ok "ip6tables 'input' chain has 'DROP' has default policy" + INPUT_CHAIN_DROP=0 + fi + + if [ "$output_default" != "DROP" ]; then + crit "ip6tables 'OUTPUT' chain does not have 'DROP' has default policy" + else + ok "ip6tables 'OUTPUT' chain has 'DROP' has default policy" + OUTPUT_CHAIN_DROP=0 + fi + + if [ "$forward_default" != "DROP" ]; then + crit "ip6tables 'FORWARD' chain does not have 'DROP' has default policy" + else + ok "ip6tables 'FORWARD' chain has 'DROP' has default policy" + FORWARD_CHAIN_DROP=0 + fi + +} + +# This function will be called if the script status is on enabled mode +apply() { + audit + if [ "$INPUT_CHAIN_DROP" -ne 0 ]; then + info "Please review your ip6tables default 'INPUT' policy. We wont apply it for you to avoid cutting the branch you are sitting on" + fi + + if [ "$OUTPUT_CHAIN_DROP" -ne 0 ]; then + info "Please review your ip6tables default 'OUTPUT' policy. We wont apply it for you to avoid cutting the branch you are sitting on" + fi + + if [ "$FORWARD_CHAIN_DROP" -ne 0 ]; then + info "Please review your ip6tables default 'FORWARD' policy. We wont apply it for you to avoid cutting the branch you are sitting on" + fi + +} + +# This function will check config parameters required +check_config() { + : +} + +# Source Root Dir Parameter +if [ -r /etc/default/cis-hardening ]; then + # shellcheck source=../../debian/default + . /etc/default/cis-hardening +fi + +if [ -z "$CIS_LIB_DIR" ]; then + echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment." + echo "Cannot source CIS_LIB_DIR variable, aborting." + exit 128 +fi + +# Main function, will call the proper functions given the configuration (audit, enabled, disabled) +if [ -r "${CIS_LIB_DIR}"/main.sh ]; then + # shellcheck source=../../lib/main.sh + . "${CIS_LIB_DIR}"/main.sh +else + echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening" + exit 128 +fi diff --git a/bin/hardening/ip6tables_loopback.sh b/bin/hardening/ip6tables_loopback.sh new file mode 100755 index 0000000..346e6e1 --- /dev/null +++ b/bin/hardening/ip6tables_loopback.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure ip6tables loopback traffic is configured (Automated) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=2 +# shellcheck disable=2034 +DESCRIPTION="Ensure ip6tables loopback traffic is configured" +PACKAGE="iptables" + +# This function will be called if the script status is on enabled / audit mode +audit() { + is_pkg_installed "$PACKAGE" + if [ "$FNRET" -ne 0 ]; then + crit "$PACKAGE is not installed" + return + fi + + is_ipv6_enabled + if [ "$NFRET" -ne 0 ]; then + ok "ipv6 is not enabled" + return + fi + + IPTABLES_LOOPBACK_INPUT=1 + IPTABLES_LOOPBACK_OUTPUT=1 + IPTABLES_LOOPBACK_DENY=1 + + local input_rules + local output_rules + input_rules=$($SUDO_CMD ip6tables -S INPUT 2>/dev/null) + output_rules=$($SUDO_CMD ip6tables -S OUTPUT 2>/dev/null) + + # the '.*' below is in case of comments + # shellcheck disable=2086 + if grep "\-A INPUT -i lo.*-j ACCEPT" <<<$input_rules >/dev/null; then + ok "loopback is configured in ip6tables input rules" + IPTABLES_LOOPBACK_INPUT=0 + else + crit "loopback is not configured in ip6tables input rules" + fi + + # shellcheck disable=2086 + if grep "\-A INPUT -s ::1 .*-j DROP" <<<$input_rules >/dev/null; then + ok "::1 is dropped in ip6tables input rules" + IPTABLES_LOOPBACK_DENY=0 + else + crit "::1 is not dropped in ip6tables input rules" + fi + + # shellcheck disable=2086 + if grep "\-A OUTPUT -o lo.*-j ACCEPT" <<<$output_rules >/dev/null; then + ok "loopback is configured in ip6tables output rules" + IPTABLES_LOOPBACK_OUTPUT=0 + else + crit "loopback is not configured in ip6tables output rules" + fi + +} + +# This function will be called if the script status is on enabled mode +apply() { + audit + if [ "$IPTABLES_LOOPBACK_INPUT" -ne 0 ]; then + info "update ip6tables rules to allow loopback input" + ip6tables -A INPUT -i lo -j ACCEPT + fi + + if [ "$IPTABLES_LOOPBACK_OUTPUT" -ne 0 ]; then + info "update ip6tables rules to allow loopback" output + ip6tables -A OUTPUT -o lo -j ACCEPT + fi + + if [ "$IPTABLES_LOOPBACK_DENY" -ne 0 ]; then + info "update ip6tables rules to drop ::1 input" + ip6tables -A INPUT -s ::1 -j DROP + fi +} + +# This function will check config parameters required +check_config() { + : +} + +# Source Root Dir Parameter +if [ -r /etc/default/cis-hardening ]; then + # shellcheck source=../../debian/default + . /etc/default/cis-hardening +fi + +if [ -z "$CIS_LIB_DIR" ]; then + echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment." + echo "Cannot source CIS_LIB_DIR variable, aborting." + exit 128 +fi + +# Main function, will call the proper functions given the configuration (audit, enabled, disabled) +if [ -r "${CIS_LIB_DIR}"/main.sh ]; then + # shellcheck source=../../lib/main.sh + . "${CIS_LIB_DIR}"/main.sh +else + echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening" + exit 128 +fi diff --git a/bin/hardening/ip6tables_outbound_established.sh b/bin/hardening/ip6tables_outbound_established.sh new file mode 100755 index 0000000..b509680 --- /dev/null +++ b/bin/hardening/ip6tables_outbound_established.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure ip6tables outbound and established connections are configured (Manual) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=2 +# shellcheck disable=2034 +DESCRIPTION="Ensure ip6tables outbound and established connections are configured" +PACKAGE="iptables" + +# This function will be called if the script status is on enabled / audit mode +audit() { + is_pkg_installed "$PACKAGE" + if [ "$FNRET" -ne 0 ]; then + crit "$PACKAGE is not installed" + return + fi + + is_ipv6_enabled + if [ "$NFRET" -ne 0 ]; then + ok "ipv6 is not enabled" + return + fi + + INPUT_ESTABLISHED=1 + OUTPUT_ESTABLISHED=1 + + local output_established_rules + + if $SUDO_CMD ip6tables -S INPUT | grep ESTABLISHED >/dev/null 2>&1; then + INPUT_ESTABLISHED=0 + ok "INPUT ESTABLISHED connections are allowed" + else + crit "INPUT ESTABLISHED connections are not allowed" + fi + + if $SUDO_CMD ip6tables -S OUTPUT | grep state >/dev/null 2>&1; then + output_established_rules=$($SUDO_CMD ip6tables -S OUTPUT | grep state) + # shellcheck disable=2086 + if grep ESTABLISHED <<<$output_established_rules >/dev/null && grep NEW <<<$output_established_rules >/dev/null; then + OUTPUT_ESTABLISHED=0 + ok "OUTPUT NEW and ESTABLISHED connections are allowed" + else + crit "OUTPUT NEW and ESTABLISHED connections are not allowed" + fi + else + crit "OUTPUT NEW and ESTABLISHED connections are not allowed" + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + if [ "$INPUT_ESTABLISHED" -ne 0 ] || [ "$OUTPUT_ESTABLISHED" -ne 0 ]; then + info "Please review manually your outbound and established connection, and update them accordingly to your site policies" + fi +} + +# This function will check config parameters required +check_config() { + : +} + +# Source Root Dir Parameter +if [ -r /etc/default/cis-hardening ]; then + # shellcheck source=../../debian/default + . /etc/default/cis-hardening +fi + +if [ -z "$CIS_LIB_DIR" ]; then + echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment." + echo "Cannot source CIS_LIB_DIR variable, aborting." + exit 128 +fi + +# Main function, will call the proper functions given the configuration (audit, enabled, disabled) +if [ -r "${CIS_LIB_DIR}"/main.sh ]; then + # shellcheck source=../../lib/main.sh + . "${CIS_LIB_DIR}"/main.sh +else + echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening" + exit 128 +fi diff --git a/bin/hardening/ip6tables_rule_them_all.sh b/bin/hardening/ip6tables_rule_them_all.sh new file mode 100755 index 0000000..649ed54 --- /dev/null +++ b/bin/hardening/ip6tables_rule_them_all.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure ip6tables firewall rules exist for all open ports (Manual) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=2 +# shellcheck disable=2034 +DESCRIPTION="Ensure ip6tables firewall rules exist for all open ports" +PACKAGE="iptables" + +# we are going to +# - list listening ports +# - list ip6tables rules using dport +# - compare both + +# This function will be called if the script status is on enabled / audit mode +audit() { + is_pkg_installed "$PACKAGE" + if [ "$FNRET" -ne 0 ]; then + crit "$PACKAGE is not installed" + return + fi + + is_ipv6_enabled + if [ "$NFRET" -ne 0 ]; then + ok "ipv6 is not enabled" + return + fi + + IPTABLES_IS_VALID=0 + local iptables_ports_rules="" + local listening_ports + # we may have configured some custom chains in INPUT, that need to be checked too. + local custom_chains="" + local builtin_targets="ACCEPT DROP QUEUE RETURN" + + for target in $($SUDO_CMD ip6tables -L INPUT | awk '{print $1}' | sed '1,2d'); do + if ! grep "$target" <<<"$builtin_targets" >/dev/null; then + custom_chains="$custom_chains $target" + fi + done + + for chain in INPUT $custom_chains; do + # number of fields is not fixed, there may be some comments before and after + # ex: + # udp spt:68 dpt:67 /* DHCP Request */ + # /* ssh connection */ tcp dpt:22 + iptables_ports_rules="$iptables_ports_rules $($SUDO_CMD ip6tables -nL "$chain" | grep 'dpt:' | sed 's/^.*dpt://g' | awk '{print $1}' | sort -u)" + done + listening_ports=$($SUDO_CMD ss -tuln | awk '($5!~/%lo:/ && $5!~/127.0.0.1:/ && $5!~/\[?::1\]?:/) {split($5, a, ":"); print a[2]}' | sort -u) + + for port in $listening_ports; do + if ! grep "$port" <<<"$iptables_ports_rules" >/dev/null; then + crit "$port does not have an ip6tables rule" + IPTABLES_IS_VALID=1 + fi + done + + if [ "$IPTABLES_IS_VALID" -eq 0 ]; then + ok "all listening ports have a corresponding rule in ufw" + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + audit + if [ "$IPTABLES_IS_VALID" -ne 0 ]; then + # Debian 12 CIS marks this script as "Automated", but we wont do it + # How can we know if a rule should be allowed or denied ? From everywhere ? A specific range ? + warn "Please review the ip6tables rules and update them accordingly. We wont do it in an automated way, as we don't know if it should be allowed or denied" + fi + +} + +# This function will check config parameters required +check_config() { + : +} + +# Source Root Dir Parameter +if [ -r /etc/default/cis-hardening ]; then + # shellcheck source=../../debian/default + . /etc/default/cis-hardening +fi +if [ -z "$CIS_LIB_DIR" ]; then + echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment." + echo "Cannot source CIS_LIB_DIR variable, aborting." + exit 128 +fi + +# Main function, will call the proper functions given the configuration (audit, enabled, disabled) +if [ -r "${CIS_LIB_DIR}"/main.sh ]; then + # shellcheck source=../../lib/main.sh + . "${CIS_LIB_DIR}"/main.sh +else + echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening" + exit 128 +fi diff --git a/bin/hardening/iptables_loopback.sh b/bin/hardening/iptables_loopback.sh new file mode 100755 index 0000000..8c475ad --- /dev/null +++ b/bin/hardening/iptables_loopback.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure iptables loopback traffic is configured (Automated) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=2 +# shellcheck disable=2034 +DESCRIPTION="Ensure iptables loopback traffic is configured" +PACKAGE="iptables" + +# This function will be called if the script status is on enabled / audit mode +audit() { + is_pkg_installed "$PACKAGE" + if [ "$FNRET" -ne 0 ]; then + crit "$PACKAGE is not installed" + return + fi + + IPTABLES_LOOPBACK_INPUT=1 + IPTABLES_LOOPBACK_OUTPUT=1 + IPTABLES_LOOPBACK_DENY=1 + + local input_rules + local output_rules + input_rules=$($SUDO_CMD iptables -S INPUT 2>/dev/null) + output_rules=$($SUDO_CMD iptables -S OUTPUT 2>/dev/null) + + # the '.*' below is in case of comments + # shellcheck disable=2086 + if grep "\-A INPUT -i lo.*-j ACCEPT" <<<$input_rules >/dev/null; then + ok "loopback is configured in iptables input rules" + IPTABLES_LOOPBACK_INPUT=0 + else + crit "loopback is not configured in iptables input rules" + fi + + # shellcheck disable=2086 + if grep "\-A INPUT -s 127.0.0.0/8.*-j DROP" <<<$input_rules >/dev/null; then + ok "127.0.0.0/8 is dropped in iptables input rules" + IPTABLES_LOOPBACK_DENY=0 + else + crit "127.0.0.0/8 is not dropped in iptables input rules" + fi + + # shellcheck disable=2086 + if grep "\-A OUTPUT -o lo.*-j ACCEPT" <<<$output_rules >/dev/null; then + ok "loopback is configured in iptables output rules" + IPTABLES_LOOPBACK_OUTPUT=0 + else + crit "loopback is not configured in iptables output rules" + fi + +} + +# This function will be called if the script status is on enabled mode +apply() { + audit + if [ "$IPTABLES_LOOPBACK_INPUT" -ne 0 ]; then + info "update iptables rules to allow loopback input" + iptables -A INPUT -i lo -j ACCEPT + fi + + if [ "$IPTABLES_LOOPBACK_OUTPUT" -ne 0 ]; then + info "update iptables rules to allow loopback" output + iptables -A OUTPUT -o lo -j ACCEPT + fi + + if [ "$IPTABLES_LOOPBACK_DENY" -ne 0 ]; then + info "update iptables rules to drop 127.0.0.0/8 input" + iptables -A INPUT -s 127.0.0.0/8 -j DROP + fi +} + +# This function will check config parameters required +check_config() { + : +} + +# Source Root Dir Parameter +if [ -r /etc/default/cis-hardening ]; then + # shellcheck source=../../debian/default + . /etc/default/cis-hardening +fi + +if [ -z "$CIS_LIB_DIR" ]; then + echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment." + echo "Cannot source CIS_LIB_DIR variable, aborting." + exit 128 +fi + +# Main function, will call the proper functions given the configuration (audit, enabled, disabled) +if [ -r "${CIS_LIB_DIR}"/main.sh ]; then + # shellcheck source=../../lib/main.sh + . "${CIS_LIB_DIR}"/main.sh +else + echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening" + exit 128 +fi diff --git a/bin/hardening/iptables_outbound_established.sh b/bin/hardening/iptables_outbound_established.sh new file mode 100755 index 0000000..fcdc97f --- /dev/null +++ b/bin/hardening/iptables_outbound_established.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure iptables outbound and established connections are configured (Manual) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=2 +# shellcheck disable=2034 +DESCRIPTION="Ensure iptables outbound and established connections are configured" +PACKAGE="iptables" + +# This function will be called if the script status is on enabled / audit mode +audit() { + is_pkg_installed "$PACKAGE" + if [ "$FNRET" -ne 0 ]; then + crit "$PACKAGE is not installed" + return + fi + + INPUT_ESTABLISHED=1 + OUTPUT_ESTABLISHED=1 + + local output_established_rules + + if $SUDO_CMD iptables -S INPUT | grep ESTABLISHED >/dev/null 2>&1; then + INPUT_ESTABLISHED=0 + ok "INPUT ESTABLISHED connections are allowed" + else + crit "INPUT ESTABLISHED connections are not allowed" + fi + + if $SUDO_CMD iptables -S OUTPUT | grep state >/dev/null 2>&1; then + output_established_rules=$($SUDO_CMD iptables -S OUTPUT | grep state) + # shellcheck disable=2086 + if grep ESTABLISHED <<<$output_established_rules >/dev/null && grep NEW <<<$output_established_rules >/dev/null; then + OUTPUT_ESTABLISHED=0 + ok "OUTPUT NEW and ESTABLISHED connections are allowed" + else + crit "OUTPUT NEW and ESTABLISHED connections are not allowed" + fi + else + crit "OUTPUT NEW and ESTABLISHED connections are not allowed" + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + if [ "$INPUT_ESTABLISHED" -ne 0 ] || [ "$OUTPUT_ESTABLISHED" -ne 0 ]; then + info "Please review manually your outbound and established connection, and update them accordingly to your site policies" + fi +} + +# This function will check config parameters required +check_config() { + : +} + +# Source Root Dir Parameter +if [ -r /etc/default/cis-hardening ]; then + # shellcheck source=../../debian/default + . /etc/default/cis-hardening +fi + +if [ -z "$CIS_LIB_DIR" ]; then + echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment." + echo "Cannot source CIS_LIB_DIR variable, aborting." + exit 128 +fi + +# Main function, will call the proper functions given the configuration (audit, enabled, disabled) +if [ -r "${CIS_LIB_DIR}"/main.sh ]; then + # shellcheck source=../../lib/main.sh + . "${CIS_LIB_DIR}"/main.sh +else + echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening" + exit 128 +fi diff --git a/bin/hardening/iptables_rule_them_all.sh b/bin/hardening/iptables_rule_them_all.sh new file mode 100755 index 0000000..8f2a91d --- /dev/null +++ b/bin/hardening/iptables_rule_them_all.sh @@ -0,0 +1,102 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure iptables firewall rules exist for all open ports (Manual) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=2 +# shellcheck disable=2034 +DESCRIPTION="Ensure iptables firewall rules exist for all open ports" +PACKAGE="iptables" + +# we are going to +# - list listening ports +# - list iptables rules using dport +# - compare both + +# This function will be called if the script status is on enabled / audit mode +audit() { + is_pkg_installed "$PACKAGE" + if [ "$FNRET" -ne 0 ]; then + crit "$PACKAGE is not installed" + return + fi + + IPTABLES_IS_VALID=0 + local iptables_ports_rules="" + local listening_ports + # we may have configured some custom chains in INPUT, that need to be checked too. + local custom_chains="" + local builtin_targets="ACCEPT DROP QUEUE RETURN" + + for target in $($SUDO_CMD iptables -L INPUT | awk '{print $1}' | sed '1,2d'); do + if ! grep "$target" <<<"$builtin_targets" >/dev/null; then + custom_chains="$custom_chains $target" + fi + done + + for chain in INPUT $custom_chains; do + # number of fields is not fixed, there may be some comments before and after + # ex: + # udp spt:68 dpt:67 /* DHCP Request */ + # /* ssh connection */ tcp dpt:22 + iptables_ports_rules="$iptables_ports_rules $($SUDO_CMD iptables -nL "$chain" | grep 'dpt:' | sed 's/^.*dpt://g' | awk '{print $1}' | sort -u)" + done + listening_ports=$($SUDO_CMD ss -tuln | awk '($5!~/%lo:/ && $5!~/127.0.0.1:/ && $5!~/\[?::1\]?:/) {split($5, a, ":"); print a[2]}' | sort -u) + + for port in $listening_ports; do + if ! grep "$port" <<<"$iptables_ports_rules" >/dev/null; then + crit "$port does not have an iptables rule" + IPTABLES_IS_VALID=1 + fi + done + + if [ "$IPTABLES_IS_VALID" -eq 0 ]; then + ok "all listening ports have a corresponding rule in ufw" + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + audit + if [ "$IPTABLES_IS_VALID" -ne 0 ]; then + # Debian 12 CIS marks this script as "Automated", but we wont do it + # How can we know if a rule should be allowed or denied ? From everywhere ? A specific range ? + warn "Please review the iptables rules and update them accordingly. We wont do it in an automated way, as we don't know if it should be allowed or denied" + fi + +} + +# This function will check config parameters required +check_config() { + : +} + +# Source Root Dir Parameter +if [ -r /etc/default/cis-hardening ]; then + # shellcheck source=../../debian/default + . /etc/default/cis-hardening +fi +if [ -z "$CIS_LIB_DIR" ]; then + echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment." + echo "Cannot source CIS_LIB_DIR variable, aborting." + exit 128 +fi + +# Main function, will call the proper functions given the configuration (audit, enabled, disabled) +if [ -r "${CIS_LIB_DIR}"/main.sh ]; then + # shellcheck source=../../lib/main.sh + . "${CIS_LIB_DIR}"/main.sh +else + echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening" + exit 128 +fi diff --git a/tests/hardening/ip6tables_default_deny_policy.sh b/tests/hardening/ip6tables_default_deny_policy.sh new file mode 100644 index 0000000..6fc0baa --- /dev/null +++ b/tests/hardening/ip6tables_default_deny_policy.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Prepare test + apt install -y iptables + + # not much to test here, unless working on a privileged container + describe Running on blank host + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe clean test + apt remove -y iptables + +} diff --git a/tests/hardening/ip6tables_loopback.sh b/tests/hardening/ip6tables_loopback.sh new file mode 100644 index 0000000..6fc0baa --- /dev/null +++ b/tests/hardening/ip6tables_loopback.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Prepare test + apt install -y iptables + + # not much to test here, unless working on a privileged container + describe Running on blank host + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe clean test + apt remove -y iptables + +} diff --git a/tests/hardening/ip6tables_outbound_established.sh b/tests/hardening/ip6tables_outbound_established.sh new file mode 100644 index 0000000..6fc0baa --- /dev/null +++ b/tests/hardening/ip6tables_outbound_established.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Prepare test + apt install -y iptables + + # not much to test here, unless working on a privileged container + describe Running on blank host + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe clean test + apt remove -y iptables + +} diff --git a/tests/hardening/ip6tables_rule_them_all.sh b/tests/hardening/ip6tables_rule_them_all.sh new file mode 100644 index 0000000..6fc0baa --- /dev/null +++ b/tests/hardening/ip6tables_rule_them_all.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Prepare test + apt install -y iptables + + # not much to test here, unless working on a privileged container + describe Running on blank host + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe clean test + apt remove -y iptables + +} diff --git a/tests/hardening/iptables_loopback.sh b/tests/hardening/iptables_loopback.sh new file mode 100644 index 0000000..6fc0baa --- /dev/null +++ b/tests/hardening/iptables_loopback.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Prepare test + apt install -y iptables + + # not much to test here, unless working on a privileged container + describe Running on blank host + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe clean test + apt remove -y iptables + +} diff --git a/tests/hardening/iptables_outbound_established.sh b/tests/hardening/iptables_outbound_established.sh new file mode 100644 index 0000000..6fc0baa --- /dev/null +++ b/tests/hardening/iptables_outbound_established.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Prepare test + apt install -y iptables + + # not much to test here, unless working on a privileged container + describe Running on blank host + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe clean test + apt remove -y iptables + +} diff --git a/tests/hardening/iptables_rule_them_all.sh b/tests/hardening/iptables_rule_them_all.sh new file mode 100644 index 0000000..6fc0baa --- /dev/null +++ b/tests/hardening/iptables_rule_them_all.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Prepare test + apt install -y iptables + + # not much to test here, unless working on a privileged container + describe Running on blank host + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe clean test + apt remove -y iptables + +}