diff --git a/bin/hardening/dnsmasq_is_disabled.sh b/bin/hardening/dnsmasq_is_disabled.sh new file mode 100755 index 0000000..8eead4d --- /dev/null +++ b/bin/hardening/dnsmasq_is_disabled.sh @@ -0,0 +1,96 @@ +#!/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' +KNOWN_DEPS="dnsmasq-base" +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" + if [ "$FNRET" -eq 0 ]; then + PACKAGE_INSTALLED=0 # 0 means true in bash + fi + + is_pkg_a_dependency "$PACKAGE" "$KNOWN_DEPS" + if [ "$FNRET" -eq 0 ]; then + PACKAGE_IS_DEPENDENCY=0 + fi + + is_service_enabled "$SERVICE" + if [ "$FNRET" -eq 0 ]; then + SERVICE_ENABLED=0 + fi + + 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() { + 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 ]; 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..f1faf4e --- /dev/null +++ b/bin/hardening/gdm_is_removed.sh @@ -0,0 +1,67 @@ +#!/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() { + PACKAGE_INSTALLED=1 + is_pkg_installed "$PACKAGE" + if [ "$FNRET" = 0 ]; then + crit "$PACKAGE is installed!" + PACKAGE_INSTALLED=0 + else + ok "$PACKAGE is absent" + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + if [ "$PACKAGE_INSTALLED" -eq 0 ]; then + info "$PACKAGE is installed, purging it" + apt-get purge "$PACKAGE" -y + apt-get autoremove -y + else + info "$PACKAGE is not installed, nothing to do" + 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..0b115d8 --- /dev/null +++ b/bin/hardening/ptrace_scope_is_restricted.sh @@ -0,0 +1,66 @@ +#!/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_PARAM='kernel.yama.ptrace_scope' +SYSCTL_VALUE=1 + +# This function will be called if the script status is on enabled / audit mode +audit() { + SYSCTL_VALID=1 + has_sysctl_param_expected_result "$SYSCTL_PARAM" "$SYSCTL_VALUE" + if [ "$FNRET" -ne 0 ]; then + crit "$SYSCTL_PARAM is not set to $SYSCTL_VALUE" + else + ok "$SYSCTL_PARAM correctly set to $SYSCTL_VALUE" + SYSCTL_VALID=0 + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + if [ "$SYSCTL_VALID" -ne 0 ]; then + info "setting $SYSCTL_PARAM=$SYSCTL_VALUE" + set_sysctl_param "$SYSCTL_PARAM" "$SYSCTL_VALUE" + 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/dnsmasq_is_disabled.sh b/tests/hardening/dnsmasq_is_disabled.sh new file mode 100644 index 0000000..f51260d --- /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 failed test + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run failed "${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..feaa424 --- /dev/null +++ b/tests/hardening/gdm_is_removed.sh @@ -0,0 +1,12 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe Prepare test + apt remove -y gdm3 + + describe Running resolved test + register_test retvalshouldbe 0 + # shellcheck disable=2154 + run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + +} diff --git a/tests/hardening/package_manager_is_configured.sh b/tests/hardening/package_manager_is_configured.sh new file mode 100644 index 0000000..233e178 --- /dev/null +++ b/tests/hardening/package_manager_is_configured.sh @@ -0,0 +1,28 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + describe prepare failing test + # we'll have to bring back the sources after the test + find /etc/apt -name '*.list' -exec cat {} \; -exec rm -f {} \; >>/tmp/sources.list + find /etc/apt -name '*.sources' -exec cat {} \; -exec rm -f {} \; >>/tmp/sources.sources + + describe Running failed test + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run failed "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe fix situation + if [ -s /tmp/sources.list ]; then + mv /tmp/sources.list /etc/apt/ + fi + + if [ -s /tmp/sources.sources ]; then + mv /tmp/sources.sources /etc/apt/sources.list.d/ + fi + + describe Running resolved test + register_test retvalshouldbe 0 + # shellcheck disable=2154 + run resolved "${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..4b482e0 --- /dev/null +++ b/tests/hardening/ptrace_scope_is_restricted.sh @@ -0,0 +1,21 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + # current value may differ among the OS + local current_value + current_value=$(sysctl kernel.yama.ptrace_scope | awk -F '=' '{print $2}' | sed 's/\ //g') + + if [ "$current_value" -eq 1 ]; then + # can only test audit here, unless running on a privileged container + describe Running successfull test + register_test retvalshouldbe 0 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + else + # can only test audit here, unless running on a privileged container + describe Running failed test + register_test retvalshouldbe 1 + # shellcheck disable=2154 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + fi +}