From 80a1146af743eac2bc829e5f718958b06ac365f2 Mon Sep 17 00:00:00 2001 From: Charles Herlin Date: Fri, 22 Feb 2019 12:39:41 +0100 Subject: [PATCH] IMP(8.2.5): find multiline pattern in files (syslog) Add func to find pattern in file that spreads over multiple lines The func will remove commented lines (that begin with '#') and consider the file as one long line. Thus, this is not possible to look for pattern at beginning of line with this func ('^' and '$') Improved pattern in 8.2.5 Add syslog-ng to installed dependencies in Dockerfiles Fixed multifile arguments when looking for pattern that got broken in d2bbf754 due to "nocase" and _does_pattern_exist_in_file wrapper Please note that you can only look for pattern in ONE FILE at once Fixed 8.2.5 and 8.3.2 with for loop on files and 'FOUND' flag You now need to specify each and every file to look for or embed a 'find' command as follow : `FILES="$SYSLOG_BASEDIR/syslog-ng.conf $(find $SYSLOG_BASEDIR/conf.d/)"` Improved test files Applied shellcheck recommendations --- bin/hardening/8.2.5_syslog-ng_remote_host.sh | 39 ++++++++++------ bin/hardening/8.3.2_tripwire_cron.sh | 26 +++++++---- lib/utils.sh | 27 +++++++++++ tests/docker/Dockerfile.debian10_20181226 | 2 +- tests/docker/Dockerfile.debian8 | 2 +- tests/docker/Dockerfile.debian9 | 2 +- .../hardening/8.2.5_syslog-ng_remote_host.sh | 45 +++++++++++++++++-- tests/hardening/8.3.2_tripwire_cron.sh | 10 +++-- 8 files changed, 123 insertions(+), 30 deletions(-) diff --git a/bin/hardening/8.2.5_syslog-ng_remote_host.sh b/bin/hardening/8.2.5_syslog-ng_remote_host.sh index 03ca7f3..9ef0cfa 100755 --- a/bin/hardening/8.2.5_syslog-ng_remote_host.sh +++ b/bin/hardening/8.2.5_syslog-ng_remote_host.sh @@ -14,27 +14,40 @@ set -u # One variable unset, it's over HARDENING_LEVEL=3 DESCRIPTION="Configure syslog-ng to send logs to a remote log host." -PATTERN='^destination.*(tcp|udp)[[:space:]]*\([[:space:]]*\".*\"[[:space:]]*\)' +PATTERN='destination[[:alnum:][:space:]*{]+(tcp|udp)[[:space:]]*\(\"[[:alnum:].]+\".' # This function will be called if the script status is on enabled / audit mode audit () { - FILES="$SYSLOG_BASEDIR/syslog-ng.conf $SYSLOG_BASEDIR/conf.d/*" - does_pattern_exist_in_file "$FILES" "$PATTERN" - if [ $FNRET != 0 ]; then - crit "$PATTERN is not present in $FILES" - else + FOUND=0 + FILES="$SYSLOG_BASEDIR/syslog-ng.conf $(find $SYSLOG_BASEDIR/conf.d/)" + for FILE in $FILES; do + does_pattern_exist_in_file_multiline "$FILE" "$PATTERN" + if [ $FNRET == 0 ]; then + FOUND=1 + fi + done + + if [ $FOUND == 1 ]; then ok "$PATTERN is present in $FILES" - fi + else + crit "$PATTERN is not present in $FILES" + fi } # This function will be called if the script status is on enabled mode apply () { - FILES="$SYSLOG_BASEDIR/syslog-ng.conf $SYSLOG_BASEDIR/conf.d/*" - does_pattern_exist_in_file "$FILES" "$PATTERN" - if [ $FNRET != 0 ]; then - crit "$PATTERN is not present in $FILES, please set a remote host to send your logs" - else + FOUND=0 + FILES="$SYSLOG_BASEDIR/syslog-ng.conf $(find $SYSLOG_BASEDIR/conf.d/ -type f)" + for FILE in $FILES; do + does_pattern_exist_in_file_multiline "$FILE" "$PATTERN" + if [ $FNRET == 0 ]; then + FOUND=1 + fi + done + if [ $FOUND == 1 ]; then ok "$PATTERN is present in $FILES" + else + crit "$PATTERN is not present in $FILES, please set a remote host to send your logs" fi } @@ -48,7 +61,7 @@ EOF # This function will check config parameters required check_config() { - : + : } # Source Root Dir Parameter diff --git a/bin/hardening/8.3.2_tripwire_cron.sh b/bin/hardening/8.3.2_tripwire_cron.sh index ab9c539..190d8fd 100755 --- a/bin/hardening/8.3.2_tripwire_cron.sh +++ b/bin/hardening/8.3.2_tripwire_cron.sh @@ -1,5 +1,6 @@ #!/bin/bash +# run-shellcheck # # CIS Debian Hardening # @@ -11,26 +12,34 @@ set -e # One error, it's over set -u # One variable unset, it's over +# shellcheck disable=2034 HARDENING_LEVEL=4 +# shellcheck disable=2034 DESCRIPTION="Implemet periodic execution of file integrity." -FILES='/etc/crontab /etc/cron.d/*' +FILES="/etc/crontab $(find /etc/cron.d/ -type f)" PATTERN='tripwire --check' # This function will be called if the script status is on enabled / audit mode audit () { - does_pattern_exist_in_file "$FILES" "$PATTERN" - if [ $FNRET != 0 ]; then - crit "$PATTERN is not present in $FILES" - else + FOUND=0 + for FILE in $FILES; do + does_pattern_exist_in_file "$FILE" "$PATTERN" + if [ "$FNRET" == 0 ]; then + FOUND=1 + fi + done + if [ $FOUND == 1 ]; then ok "$PATTERN is present in $FILES" + else + crit "$PATTERN is not present in $FILES" fi } # This function will be called if the script status is on enabled mode apply () { does_pattern_exist_in_file "$FILES" "$PATTERN" - if [ $FNRET != 0 ]; then + if [ "$FNRET" != 0 ]; then warn "$PATTERN is not present in $FILES, setting tripwire cron" echo "0 10 * * * root /usr/sbin/tripwire --check > /dev/shm/tripwire_check 2>&1 " > /etc/cron.d/CIS_8.3.2_tripwire else @@ -54,8 +63,9 @@ if [ -z "$CIS_ROOT_DIR" ]; then fi # Main function, will call the proper functions given the configuration (audit, enabled, disabled) -if [ -r $CIS_ROOT_DIR/lib/main.sh ]; then - . $CIS_ROOT_DIR/lib/main.sh +if [ -r "$CIS_ROOT_DIR"/lib/main.sh ]; then + # shellcheck source=/opt/debian-cis/lib/main.sh + . "$CIS_ROOT_DIR"/lib/main.sh else echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_ROOT_DIR in /etc/default/cis-hardening" exit 128 diff --git a/lib/utils.sh b/lib/utils.sh index 6f67cef..f488909 100644 --- a/lib/utils.sh +++ b/lib/utils.sh @@ -114,15 +114,42 @@ _does_pattern_exist_in_file() { if $SUDO_CMD [ -r "$FILE" ] ; then debug "$SUDO_CMD grep -q $OPTIONS -- '$PATTERN' $FILE" if $($SUDO_CMD grep -q $OPTIONS -- "$PATTERN" $FILE); then + debug "Pattern found in $FILE" FNRET=0 else + debug "Pattern NOT found in $FILE" FNRET=1 fi else debug "File $FILE is not readable!" FNRET=2 fi +} +# Look for pattern in file that can spread over multiple lines +# The func will remove commented lines (that begin with '#') +# and consider the file as one long line. +# Thus, this is not possible to look for pattern at beginning of line +# with this func ('^' and '$') +does_pattern_exist_in_file_multiline() { + local FILE="$1" + shift + local PATTERN="$*" + + debug "Checking if multiline pattern: $PATTERN is present in $FILE" + if $SUDO_CMD [ -r "$FILE" ] ; then + debug "$SUDO_CMD grep -v '^[[:space:]]*#' $FILE | tr '\n' ' ' | grep -Pq -- "$PATTERN"" + if $($SUDO_CMD grep -v '^[[:space:]]*#' $FILE | tr '\n' ' ' | grep -Pq -- "$PATTERN" ); then + debug "Pattern found in $FILE" + FNRET=0 + else + debug "Pattern NOT found in $FILE" + FNRET=1 + fi + else + debug "File $FILE is not readable!" + FNRET=2 + fi } add_end_of_file() { diff --git a/tests/docker/Dockerfile.debian10_20181226 b/tests/docker/Dockerfile.debian10_20181226 index 368bb58..657417c 100644 --- a/tests/docker/Dockerfile.debian10_20181226 +++ b/tests/docker/Dockerfile.debian10_20181226 @@ -2,7 +2,7 @@ FROM debian:buster-20181226 RUN groupadd -g 500 secaudit && useradd -u 500 -g 500 -s /bin/bash secaudit && mkdir -m 700 /home/secaudit && chown secaudit:secaudit /home/secaudit -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y bc openssh-server sudo +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y bc openssh-server sudo syslog-ng COPY --chown=500:500 . /opt/debian-cis/ diff --git a/tests/docker/Dockerfile.debian8 b/tests/docker/Dockerfile.debian8 index c91b51c..ee66040 100644 --- a/tests/docker/Dockerfile.debian8 +++ b/tests/docker/Dockerfile.debian8 @@ -2,7 +2,7 @@ FROM debian:jessie RUN groupadd -g 500 secaudit && useradd -u 500 -g 500 -s /bin/bash secaudit && mkdir -m 700 /home/secaudit && chown secaudit:secaudit /home/secaudit -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y bc openssh-server sudo +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y bc openssh-server sudo syslog-ng COPY --chown=500:500 . /opt/debian-cis/ diff --git a/tests/docker/Dockerfile.debian9 b/tests/docker/Dockerfile.debian9 index 14e7271..7badd43 100644 --- a/tests/docker/Dockerfile.debian9 +++ b/tests/docker/Dockerfile.debian9 @@ -2,7 +2,7 @@ FROM debian:stretch RUN groupadd -g 500 secaudit && useradd -u 500 -g 500 -s /bin/bash secaudit && mkdir -m 700 /home/secaudit && chown secaudit:secaudit /home/secaudit -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y bc openssh-server sudo +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y bc openssh-server sudo syslog-ng COPY --chown=500:500 . /opt/debian-cis/ diff --git a/tests/hardening/8.2.5_syslog-ng_remote_host.sh b/tests/hardening/8.2.5_syslog-ng_remote_host.sh index b333419..a8d3846 100644 --- a/tests/hardening/8.2.5_syslog-ng_remote_host.sh +++ b/tests/hardening/8.2.5_syslog-ng_remote_host.sh @@ -1,10 +1,49 @@ # run-shellcheck test_audit() { +#set -x + describe Running on blank host - register_test retvalshouldbe 0 - dismiss_count_for_test + register_test retvalshouldbe 1 # shellcheck disable=2154 run blank /opt/debian-cis/bin/hardening/"${script}".sh --audit-all - # TODO fill comprehensive tests + cp -a /etc/syslog-ng/syslog-ng.conf /tmp/syslog-ng.conf.bak + + echo "destination mySyslog tcp (\"syslog.example.tld\")" >> /etc/syslog-ng/syslog-ng.conf + grep syslog.example.tld /etc/syslog-ng/syslog-ng.conf + + describe Checking one line conf + register_test retvalshouldbe 0 + run oneline /opt/debian-cis/bin/hardening/"${script}".sh --audit-all + + + cp -a /tmp/syslog-ng.conf.bak /etc/syslog-ng/syslog-ng.conf + cat >> /etc/syslog-ng/syslog-ng.conf </etc/syslog-ng/conf.d/1_tcp_destination + echo "destination mySyslog tcp (\"syslog.example.tld\")" >> /etc/syslog-ng/conf.d/1_tcp_destination + cat /etc/syslog-ng/conf.d/1_tcp_destination + + + describe Checking file in subdirectory + register_test retvalshouldbe 0 + run subfile /opt/debian-cis/bin/hardening/"${script}".sh --audit-all + + + + # Cleanup + #mv /tmp/syslog-ng.conf.bak /etc/syslog-ng/syslog-ng.conf + + rm /etc/syslog-ng/conf.d/1_tcp_destination + } diff --git a/tests/hardening/8.3.2_tripwire_cron.sh b/tests/hardening/8.3.2_tripwire_cron.sh index b333419..3b3af16 100644 --- a/tests/hardening/8.3.2_tripwire_cron.sh +++ b/tests/hardening/8.3.2_tripwire_cron.sh @@ -1,10 +1,14 @@ # run-shellcheck test_audit() { describe Running on blank host - register_test retvalshouldbe 0 - dismiss_count_for_test + register_test retvalshouldbe 1 # shellcheck disable=2154 run blank /opt/debian-cis/bin/hardening/"${script}".sh --audit-all - # TODO fill comprehensive tests + sed -i 's/audit/enabled/' /opt/debian-cis/etc/conf.d/"${script}".cfg + /opt/debian-cis/bin/hardening/"${script}".sh || true + + describe Checking auto resolved state + register_test retvalshouldbe 0 + run resolved /opt/debian-cis/bin/hardening/"${script}".sh --audit-all }