diff --git a/bin/hardening/chrony_is_enabled_and_running.sh b/bin/hardening/chrony_is_enabled_and_running.sh new file mode 100755 index 0000000..084b21a --- /dev/null +++ b/bin/hardening/chrony_is_enabled_and_running.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure chrony is enabled and running (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 chrony is enabled and running." +PACKAGE="chrony" +SERVICE="chrony" + +# This function will be called if the script status is on enabled / audit mode +audit() { + CHRONY_INSTALLED=0 + CHRONY_ENABLED=0 + CHRONY_RUNNING=0 + + is_pkg_installed "$PACKAGE" + if [ "$FNRET" -ne 0 ]; then + CHRONY_INSTALLED=1 + crit "chrony is not installed" + fi + # no package, no need to check further + return + + is_service_enabled "$SERVICE" + if [ "$FNRET" -ne 0 ]; then + CHRONY_INSTALLED=1 + crit "chrony is not enabled" + fi + + is_service_active "$SERVICE" + if [ "$FNRET" -ne 0 ]; then + CHRONY_RUNNING=1 + crit "chrony is not running" + fi +} + +# This function will be called if the script status is on enabled mode +apply() { + audit + if [ "$CHRONY_INSTALLED" -eq 1 ]; then + warn "Please install chrony manually to ensure only one time synchronization system is installed" + fi + + if [ "$CHRONY_ENABLED" -eq 1 ]; then + info "Enablign chrony service" + manage_service "enable" "$SERVICE" + fi + + if [ "$CHRONY_RUNNING" -eq 1 ]; then + info "Starting chrony service" + manage_service "start" "$SERVICE" + 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/network_services _listening.sh b/bin/hardening/network_services _listening.sh new file mode 100644 index 0000000..6a1c19b --- /dev/null +++ b/bin/hardening/network_services _listening.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure only approved services are listening on a network interface (Manual) +# + +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 only approved services are listening on a network interface" + +# This function will be called if the script status is on enabled / audit mode +audit() { + ss -plntuH | while read i ; + do socket=$(echo "$i" | awk '{print $5}') ; + proc=$(echo "$i" | awk '{print $7}' | awk -F ',' '{print $1}' | sed 's/users:((//') ; + info -e "$proc listening on \t$socket" ; + done + + # output example : + # "ntpd" listening on 127.0.0.1:123 + # "ntpd" listening on 0.0.0.0:123 +} + +# This function will be called if the script status is on enabled mode +apply() { + info "This recommendation has to be reviewed and applied 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 \ No newline at end of file diff --git a/bin/hardening/tftp_is_disabled.sh b/bin/hardening/tftp_is_disabled.sh new file mode 100644 index 0000000..65b7daa --- /dev/null +++ b/bin/hardening/tftp_is_disabled.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +# run-shellcheck +# +# CIS Debian Hardening +# + +# +# Ensure tftp 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 tftp services are not in use." +PACKAGE='tftpd-hpa' +SERVICE="tftpd-hpa.service" + +# 2 scenario here: +# - tftp is a dependency for another package -> disable the service +# - tftp 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 \ No newline at end of file diff --git a/bin/hardening/use_time_sync.sh b/bin/hardening/use_time_sync.sh index 6adb0f9..05ea72c 100755 --- a/bin/hardening/use_time_sync.sh +++ b/bin/hardening/use_time_sync.sh @@ -6,7 +6,7 @@ # # -# Ensure time synchronization is in use (Not Scored) +# Ensure a single time synchronization daemon is in use (Automated) # set -e # One error, it's over @@ -15,28 +15,31 @@ set -u # One variable unset, it's over # shellcheck disable=2034 HARDENING_LEVEL=3 # shellcheck disable=2034 -DESCRIPTION="Ensure time synchronization is in use" +DESCRIPTION="Ensure a single time synchronization is in use" PACKAGES="systemd-timesyncd ntp chrony" # This function will be called if the script status is on enabled / audit mode audit() { - FOUND=false + local count=0 for PACKAGE in $PACKAGES; do is_pkg_installed "$PACKAGE" - if [ "$FNRET" = 0 ]; then - ok "Time synchronization is available through $PACKAGE" - FOUND=true + if [ "$FNRET" -eq 0 ]; then + let count=$((count+1)) fi done - if [ "$FOUND" = false ]; then + if [ "$count" -eq 0 ]; then crit "None of the following time sync packages are installed: $PACKAGES" + elif [ "$count" -gt 1 ]; then + crit "Multiple time sync packages are installed, from $PACKAGES. Pick one and remove the others" + else + info "A single time sync package from $PACKAGES is installed" fi } # This function will be called if the script status is on enabled mode apply() { - : + info "This recommendation has to be reviewed and applied manually" } # This function will check config parameters required diff --git a/tests/hardening/chrony_is_enabled_and_running.sh b/tests/hardening/chrony_is_enabled_and_running.sh new file mode 100644 index 0000000..118a757 --- /dev/null +++ b/tests/hardening/chrony_is_enabled_and_running.sh @@ -0,0 +1,18 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + + describe Ensure package is installed + + # install dependencies + apt update + apt install -y chrony + + # not much to test here, we are running in a container, we wont check service state + describe Checking blank host + register_test retvalshouldbe 0 + run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + apt remove -y chrony + +} \ No newline at end of file diff --git a/tests/hardening/network_services _listening.sh b/tests/hardening/network_services _listening.sh new file mode 100644 index 0000000..00ec662 --- /dev/null +++ b/tests/hardening/network_services _listening.sh @@ -0,0 +1,10 @@ +# 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 + +} diff --git a/tests/hardening/tftp_is_disabled.sh b/tests/hardening/tftp_is_disabled.sh new file mode 100644 index 0000000..6169859 --- /dev/null +++ b/tests/hardening/tftp_is_disabled.sh @@ -0,0 +1,36 @@ +# shellcheck shell=bash +# run-shellcheck +test_audit() { + + describe Prepare on purpose failed test + apt install -y tftp + # 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 that depends on 'tftp-hpa' + apt install -y tfpt-hpa-dbg + # running on a container, we 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 tfpt-hpa-dbg + apt autoremove -y + +} \ No newline at end of file diff --git a/tests/hardening/use_time_sync.sh b/tests/hardening/use_time_sync.sh index dc32b03..92897f4 100644 --- a/tests/hardening/use_time_sync.sh +++ b/tests/hardening/use_time_sync.sh @@ -3,7 +3,6 @@ test_audit() { describe Running on blank host register_test retvalshouldbe 1 - dismiss_count_for_test # shellcheck disable=2154 run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all @@ -14,6 +13,13 @@ test_audit() { # Finally assess that your corrective actions end up with a compliant system describe Checking resolved state register_test retvalshouldbe 0 - register_test contain "Time synchronization is available through" run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all + + describe Break things + apt-get update + apt-get install -y chrony + + describe Checking broken state + register_test retvalshouldbe 1 + run broken "${CIS_CHECKS_DIR}/${script}.sh" --audit-all }