From 16b77cada2b34a627d76d72c4baba09dee21b54e Mon Sep 17 00:00:00 2001 From: Damien Cavagnini Date: Wed, 9 Jul 2025 17:36:05 +0200 Subject: [PATCH] chore: add new scripts for debian 12 - package_manager_is_configured -> 1.2.1.2 - ptrace_scope_is_restricted -> 1.5.2 - gdm_is_removed.sh -> 1.7.1 - dnsmasq_is_disabled.sh -> 2.1.5 --- bin/hardening/dnsmasq_is_disabled.sh | 91 +++++++++++++++++++ bin/hardening/gdm_is_removed.sh | 66 ++++++++++++++ .../package_manager_is_configured.sh | 66 ++++++++++++++ bin/hardening/ptrace_scope_is_restricted.sh | 81 +++++++++++++++++ tests/hardening/dnsmasq_is_disabled.sh | 36 ++++++++ tests/hardening/gdm_is_removed.sh | 16 ++++ .../package_manager_is_configured.sh | 9 ++ tests/hardening/ptrace_scope_is_restricted.sh | 30 ++++++ 8 files changed, 395 insertions(+) create mode 100755 bin/hardening/dnsmasq_is_disabled.sh create mode 100755 bin/hardening/gdm_is_removed.sh create mode 100755 bin/hardening/package_manager_is_configured.sh create mode 100755 bin/hardening/ptrace_scope_is_restricted.sh create mode 100644 tests/hardening/dnsmasq_is_disabled.sh create mode 100644 tests/hardening/gdm_is_removed.sh create mode 100644 tests/hardening/package_manager_is_configured.sh create mode 100644 tests/hardening/ptrace_scope_is_restricted.sh diff --git a/bin/hardening/dnsmasq_is_disabled.sh b/bin/hardening/dnsmasq_is_disabled.sh new file mode 100755 index 0000000..badeb07 --- /dev/null +++ b/bin/hardening/dnsmasq_is_disabled.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure dnsmasq services are not in use (Automated) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=3 +# shellcheck disable=2034 +DESCRIPTION="Ensure dnsmasq services are not in use." +PACKAGE='dnsmasq' +SERVICE="dnsmasq.service" + +# 2 scenario here: +# - dnsmasq is a dependency for another package -> disable the service +# - dnsmasq is not a dependency for another package -> remove the package + +# This function will be called if the script status is on enabled / audit mode +audit() { + # 0 means true in bash + PACKAGE_INSTALLED=1 + PACKAGE_IS_DEPENDENCY=1 + SERVICE_ENABLED=1 + + is_pkg_installed "$PACKAGE" + [ "$FNRET" = 0 ] && PACKAGE_INSTALLED=0 # 0 means true in bash + + is_pkg_a_dependency "$PACKAGE" + # dnsmasq is installed with dnsmasq-base, which + [ "$FNRET" = 0 ] && PACKAGE_IS_DEPENDENCY=0 + + is_service_enabled "$SERVICE" + [ "$FNRET" = 0 ] && SERVICE_ENABLED=0 + + if [ "$PACKAGE_INSTALLED" -eq 0 ] && [ "$PACKAGE_IS_DEPENDENCY" -eq 1 ]; then + crit "$PACKAGE is installed and not a dependency" + elif [ "$PACKAGE_INSTALLED" -eq 0 ] && [ "$PACKAGE_IS_DEPENDENCY" -eq 0 ] && [ "$SERVICE_ENABLED" -eq 0 ]; then + crit "$SERVICE is enabled" + else + ok "$PACKAGE is not in use" + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + audit + if [ "$PACKAGE_INSTALLED" -eq 0 ] && [ "$PACKAGE_IS_DEPENDENCY" -eq 1 ]; then + crit "$PACKAGE is installed and not a dependency, removing it" + apt-get purge "$PACKAGE" -y + apt-get autoremove -y + elif [ "$PACKAGE_INSTALLED" -eq 0 ] && [ "$PACKAGE_IS_DEPENDENCY" -eq 0 ] && [ "$SERVICE_ENABLED" -eq 0 ] && [ "$IS_CONTAINER" -eq 1 ]; then + crit "$SERVICE is enabled, i'm going to stop and mask it" + systemctl stop "$SERVICE" + systemctl mask "$SERVICE" + else + ok "$PACKAGE is not in use" + 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/gdm_is_removed.sh b/bin/hardening/gdm_is_removed.sh new file mode 100755 index 0000000..2b4d930 --- /dev/null +++ b/bin/hardening/gdm_is_removed.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure GDM is removed (Automated) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=3 +# shellcheck disable=2034 +DESCRIPTION="Ensure GDM is removed." +PACKAGE='gdm3' + +# This function will be called if the script status is on enabled / audit mode +audit() { + is_pkg_installed "$PACKAGE" + if [ "$FNRET" = 0 ]; then + crit "$PACKAGE is installed!" + else + ok "$PACKAGE is absent" + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + is_pkg_installed "$PACKAGE" + if [ "$FNRET" = 0 ]; then + crit "$PACKAGE is installed, purging it" + apt-get purge "$PACKAGE" -y + apt-get autoremove -y + else + ok "$PACKAGE is absent" + 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/package_manager_is_configured.sh b/bin/hardening/package_manager_is_configured.sh new file mode 100755 index 0000000..b86d643 --- /dev/null +++ b/bin/hardening/package_manager_is_configured.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure package manager repositories are configured (Manual) +# + +set -e # One error, it's over +set -u # One variable unset, it's over + +# shellcheck disable=2034 +HARDENING_LEVEL=1 +# shellcheck disable=2034 +DESCRIPTION="Ensure apt has source list" + +# CIS recommends to execute "apt-cache policy" to ensure the configuration is correct +# this is not convenient to test, we check the presence of sources list in /var/lib/apt/lists/ +APT_LIB_PATH="/var/lib/apt/lists/" +# files that are going to be present anyway +MANDATORY_FILES="lock auxfiles partial" + +# This function will be called if the script status is on enabled / audit mode +audit() { + apt update >/dev/null 2>&1 || true + + # shellcheck disable=2012 + if [ "$(ls "$APT_LIB_PATH" | wc -l)" -ne "$(wc -w <<<"$MANDATORY_FILES")" ]; then + ok "apt package manager is configured" + else + crit "there is no source file, apt is not configured" + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + warn "This recommendation can only be resolved manually" +} + +# 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/ptrace_scope_is_restricted.sh b/bin/hardening/ptrace_scope_is_restricted.sh new file mode 100755 index 0000000..90b5416 --- /dev/null +++ b/bin/hardening/ptrace_scope_is_restricted.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure ptrace_scope is restricted (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 ptrace_scope is restricted" + +SYSCTL_PARAMS='kernel.yama.ptrace_scope=1' + +# This function will be called if the script status is on enabled / audit mode +audit() { + for SYSCTL_VALUES in $SYSCTL_PARAMS; do + SYSCTL_PARAM=$(echo "$SYSCTL_VALUES" | cut -d= -f 1) + SYSCTL_EXP_RESULT=$(echo "$SYSCTL_VALUES" | cut -d= -f 2) + debug "$SYSCTL_PARAM should be set to $SYSCTL_EXP_RESULT" + has_sysctl_param_expected_result "$SYSCTL_PARAM" "$SYSCTL_EXP_RESULT" + if [ "$FNRET" != 0 ]; then + crit "$SYSCTL_PARAM was not set to $SYSCTL_EXP_RESULT" + elif [ "$FNRET" = 255 ]; then + warn "$SYSCTL_PARAM does not exist -- Typo?" + else + ok "$SYSCTL_PARAM correctly set to $SYSCTL_EXP_RESULT" + fi + done +} + +# This function will be called if the script status is on enabled mode +apply() { + for SYSCTL_VALUES in $SYSCTL_PARAMS; do + SYSCTL_PARAM=$(echo "$SYSCTL_VALUES" | cut -d= -f 1) + SYSCTL_EXP_RESULT=$(echo "$SYSCTL_VALUES" | cut -d= -f 2) + debug "$SYSCTL_PARAM should be set to $SYSCTL_EXP_RESULT" + has_sysctl_param_expected_result "$SYSCTL_PARAM" "$SYSCTL_EXP_RESULT" + if [ "$FNRET" != 0 ]; then + warn "$SYSCTL_PARAM was not set to $SYSCTL_EXP_RESULT -- Fixing" + set_sysctl_param "$SYSCTL_PARAM" "$SYSCTL_EXP_RESULT" + sysctl -w net.ipv4.route.flush=1 >/dev/null + elif [ "$FNRET" = 255 ]; then + warn "$SYSCTL_PARAM does not exist -- Typo?" + else + ok "$SYSCTL_PARAM correctly set to $SYSCTL_EXP_RESULT" + fi + done +} + +# 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/dnsmasq_is_disabled.sh b/tests/hardening/dnsmasq_is_disabled.sh new file mode 100644 index 0000000..7b0b983 --- /dev/null +++ b/tests/hardening/dnsmasq_is_disabled.sh @@ -0,0 +1,36 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + + describe Prepare on purpose failed test + apt install -y dnsmasq + # running on a container, will can only test the package installation, not the service management + + describe Running on purpose failed test + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe correcting situation + sed -i 's/audit/enabled/' "${CIS_CONF_DIR}/conf.d/${script}.cfg" + "${CIS_CHECKS_DIR}/${script}.sh" --apply || true + + describe Checking resolved state + register_test retvalshouldbe 0 + run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe Prepare test package dependencies + # try to install a package with not much dependencies + apt install -y ocserv + # running on a container, will can only test the package installation, not the service management + + describe Running successfull test + register_test retvalshouldbe 0 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe clean installation + apt remove -y ocserv + apt autoremove -y + +} diff --git a/tests/hardening/gdm_is_removed.sh b/tests/hardening/gdm_is_removed.sh new file mode 100644 index 0000000..4ad9ef8 --- /dev/null +++ b/tests/hardening/gdm_is_removed.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Running on blank host + register_test retvalshouldbe 0 + dismiss_count_for_test + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + ################################################################## + # For this test, we only check that it runs properly on a blank # + # host, and we check root/sudo consistency. But, we don't test # + # the apply function because it can't be automated or it is very # + # long to test and not very useful. # + ################################################################## +} diff --git a/tests/hardening/package_manager_is_configured.sh b/tests/hardening/package_manager_is_configured.sh new file mode 100644 index 0000000..011c7ab --- /dev/null +++ b/tests/hardening/package_manager_is_configured.sh @@ -0,0 +1,9 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Running on blank host + # chance to not have any souces list on a blank host are close to null + register_test retvalshouldbe 0 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all +} diff --git a/tests/hardening/ptrace_scope_is_restricted.sh b/tests/hardening/ptrace_scope_is_restricted.sh new file mode 100644 index 0000000..84ef780 --- /dev/null +++ b/tests/hardening/ptrace_scope_is_restricted.sh @@ -0,0 +1,30 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Running on blank host + register_test retvalshouldbe 0 + dismiss_count_for_test + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + if [ -f "/.dockerenv" ]; then + skip "SKIPPED on docker" + else + describe Tests purposely failing + sysctl -w kernel.yama.ptrace_scope=0 2>/dev/null + register_test retvalshouldbe 1 + register_test contain "kernel.yama.ptrace_scope was not set to 1" + + run noncompliant "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe correcting situation + sed -i 's/audit/enabled/' "${CIS_CONF_DIR}/conf.d/${script}.cfg" + "${CIS_CHECKS_DIR}/${script}.sh" --apply || true + + describe Checking resolved state + register_test retvalshouldbe 0 + register_test contain "correctly set to 1" + register_test contain "kernel.yama.ptrace_scope correctly set to 1" + run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + fi +}