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
This commit is contained in:
Charles Herlin 2019-02-22 12:39:41 +01:00
parent 4e1d897a64
commit da6acb0b0c
8 changed files with 123 additions and 30 deletions

View File

@ -14,27 +14,40 @@ set -u # One variable unset, it's over
HARDENING_LEVEL=3 HARDENING_LEVEL=3
DESCRIPTION="Configure syslog-ng to send logs to a remote log host." 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 # This function will be called if the script status is on enabled / audit mode
audit () { audit () {
FILES="$SYSLOG_BASEDIR/syslog-ng.conf $SYSLOG_BASEDIR/conf.d/*" FOUND=0
does_pattern_exist_in_file "$FILES" "$PATTERN" FILES="$SYSLOG_BASEDIR/syslog-ng.conf $(find $SYSLOG_BASEDIR/conf.d/)"
if [ $FNRET != 0 ]; then for FILE in $FILES; do
crit "$PATTERN is not present in $FILES" does_pattern_exist_in_file_multiline "$FILE" "$PATTERN"
else if [ $FNRET == 0 ]; then
FOUND=1
fi
done
if [ $FOUND == 1 ]; then
ok "$PATTERN is present in $FILES" 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 # This function will be called if the script status is on enabled mode
apply () { apply () {
FILES="$SYSLOG_BASEDIR/syslog-ng.conf $SYSLOG_BASEDIR/conf.d/*" FOUND=0
does_pattern_exist_in_file "$FILES" "$PATTERN" FILES="$SYSLOG_BASEDIR/syslog-ng.conf $(find $SYSLOG_BASEDIR/conf.d/ -type f)"
if [ $FNRET != 0 ]; then for FILE in $FILES; do
crit "$PATTERN is not present in $FILES, please set a remote host to send your logs" does_pattern_exist_in_file_multiline "$FILE" "$PATTERN"
else if [ $FNRET == 0 ]; then
FOUND=1
fi
done
if [ $FOUND == 1 ]; then
ok "$PATTERN is present in $FILES" ok "$PATTERN is present in $FILES"
else
crit "$PATTERN is not present in $FILES, please set a remote host to send your logs"
fi fi
} }
@ -48,7 +61,7 @@ EOF
# This function will check config parameters required # This function will check config parameters required
check_config() { check_config() {
: :
} }
# Source Root Dir Parameter # Source Root Dir Parameter

View File

@ -1,5 +1,6 @@
#!/bin/bash #!/bin/bash
# run-shellcheck
# #
# CIS Debian Hardening # CIS Debian Hardening
# #
@ -11,26 +12,34 @@
set -e # One error, it's over set -e # One error, it's over
set -u # One variable unset, it's over set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=4 HARDENING_LEVEL=4
# shellcheck disable=2034
DESCRIPTION="Implemet periodic execution of file integrity." 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' PATTERN='tripwire --check'
# This function will be called if the script status is on enabled / audit mode # This function will be called if the script status is on enabled / audit mode
audit () { audit () {
does_pattern_exist_in_file "$FILES" "$PATTERN" FOUND=0
if [ $FNRET != 0 ]; then for FILE in $FILES; do
crit "$PATTERN is not present in $FILES" does_pattern_exist_in_file "$FILE" "$PATTERN"
else if [ "$FNRET" == 0 ]; then
FOUND=1
fi
done
if [ $FOUND == 1 ]; then
ok "$PATTERN is present in $FILES" ok "$PATTERN is present in $FILES"
else
crit "$PATTERN is not present in $FILES"
fi fi
} }
# This function will be called if the script status is on enabled mode # This function will be called if the script status is on enabled mode
apply () { apply () {
does_pattern_exist_in_file "$FILES" "$PATTERN" 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" 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 echo "0 10 * * * root /usr/sbin/tripwire --check > /dev/shm/tripwire_check 2>&1 " > /etc/cron.d/CIS_8.3.2_tripwire
else else
@ -54,8 +63,9 @@ if [ -z "$CIS_ROOT_DIR" ]; then
fi fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled) # Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r $CIS_ROOT_DIR/lib/main.sh ]; then if [ -r "$CIS_ROOT_DIR"/lib/main.sh ]; then
. $CIS_ROOT_DIR/lib/main.sh # shellcheck source=/opt/debian-cis/lib/main.sh
. "$CIS_ROOT_DIR"/lib/main.sh
else else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_ROOT_DIR in /etc/default/cis-hardening" 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 exit 128

View File

@ -114,15 +114,42 @@ _does_pattern_exist_in_file() {
if $SUDO_CMD [ -r "$FILE" ] ; then if $SUDO_CMD [ -r "$FILE" ] ; then
debug "$SUDO_CMD grep -q $OPTIONS -- '$PATTERN' $FILE" debug "$SUDO_CMD grep -q $OPTIONS -- '$PATTERN' $FILE"
if $($SUDO_CMD grep -q $OPTIONS -- "$PATTERN" $FILE); then if $($SUDO_CMD grep -q $OPTIONS -- "$PATTERN" $FILE); then
debug "Pattern found in $FILE"
FNRET=0 FNRET=0
else else
debug "Pattern NOT found in $FILE"
FNRET=1 FNRET=1
fi fi
else else
debug "File $FILE is not readable!" debug "File $FILE is not readable!"
FNRET=2 FNRET=2
fi 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() { add_end_of_file() {

View File

@ -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 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/ COPY --chown=500:500 . /opt/debian-cis/

View File

@ -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 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/ COPY --chown=500:500 . /opt/debian-cis/

View File

@ -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 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/ COPY --chown=500:500 . /opt/debian-cis/

View File

@ -1,10 +1,49 @@
# run-shellcheck # run-shellcheck
test_audit() { test_audit() {
#set -x
describe Running on blank host describe Running on blank host
register_test retvalshouldbe 0 register_test retvalshouldbe 1
dismiss_count_for_test
# shellcheck disable=2154 # shellcheck disable=2154
run blank /opt/debian-cis/bin/hardening/"${script}".sh --audit-all 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 <<EOF
destination mySyslog {
tcp ("syslog.example.tld"),
port(1234),
EOF
describe Checking mutliline conf
register_test retvalshouldbe 0
run multiline /opt/debian-cis/bin/hardening/"${script}".sh --audit-all
mv /tmp/syslog-ng.conf.bak /etc/syslog-ng/syslog-ng.conf
#echo "#Sample 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
} }

View File

@ -1,10 +1,14 @@
# run-shellcheck # run-shellcheck
test_audit() { test_audit() {
describe Running on blank host describe Running on blank host
register_test retvalshouldbe 0 register_test retvalshouldbe 1
dismiss_count_for_test
# shellcheck disable=2154 # shellcheck disable=2154
run blank /opt/debian-cis/bin/hardening/"${script}".sh --audit-all 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
} }