From fbd26ceefa92c1e99a8d1e17dcbbb6ce1649e3ac Mon Sep 17 00:00:00 2001 From: Thibault Ayanides Date: Mon, 16 Nov 2020 14:09:12 +0100 Subject: [PATCH] Fix race condition on /etc/passwd, /etc/shadow and /etc/group --- bin/hardening/6.2.10_check_user_dot_file_perm.sh | 4 ++-- bin/hardening/6.2.11_find_user_forward_files.sh | 2 +- bin/hardening/6.2.12_find_user_netrc_files.sh | 2 +- bin/hardening/6.2.13_set_perm_on_user_netrc.sh | 2 +- bin/hardening/6.2.14_find_user_rhosts_files.sh | 2 +- bin/hardening/6.2.16_check_duplicate_uid.sh | 2 +- bin/hardening/6.2.17_check_duplicate_gid.sh | 2 +- bin/hardening/6.2.18_check_duplicate_username.sh | 2 +- bin/hardening/6.2.19_check_duplicate_groupname.sh | 2 +- bin/hardening/6.2.1_remove_empty_password_field.sh | 5 ++--- bin/hardening/6.2.7_users_valid_homedir.sh | 2 +- bin/hardening/6.2.8_check_user_dir_perm.sh | 4 ++-- bin/hardening/6.2.9_users_valid_homedir.sh | 2 +- lib/utils.sh | 5 +++++ 14 files changed, 21 insertions(+), 17 deletions(-) diff --git a/bin/hardening/6.2.10_check_user_dot_file_perm.sh b/bin/hardening/6.2.10_check_user_dot_file_perm.sh index 6aac5d5..bbd4020 100755 --- a/bin/hardening/6.2.10_check_user_dot_file_perm.sh +++ b/bin/hardening/6.2.10_check_user_dot_file_perm.sh @@ -18,7 +18,7 @@ ERRORS=0 # This function will be called if the script status is on enabled / audit mode audit () { - for DIR in $(cat /etc/passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do + for DIR in $(get_db passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do debug "Working on $DIR" for FILE in $DIR/.[A-Za-z0-9]*; do if [ ! -h "$FILE" -a -f "$FILE" ]; then @@ -42,7 +42,7 @@ audit () { # This function will be called if the script status is on enabled mode apply () { - for DIR in $(cat /etc/passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do + for DIR in $(get_db passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do for FILE in $DIR/.[A-Za-z0-9]*; do if [ ! -h "$FILE" -a -f "$FILE" ]; then FILEPERM=$(ls -ld $FILE | cut -f1 -d" ") diff --git a/bin/hardening/6.2.11_find_user_forward_files.sh b/bin/hardening/6.2.11_find_user_forward_files.sh index f14af16..c964cbf 100755 --- a/bin/hardening/6.2.11_find_user_forward_files.sh +++ b/bin/hardening/6.2.11_find_user_forward_files.sh @@ -19,7 +19,7 @@ FILENAME='.forward' # This function will be called if the script status is on enabled / audit mode audit () { - for DIR in $(cat /etc/passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do + for DIR in $(get_db passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do debug "Working on $DIR" for FILE in $DIR/$FILENAME; do if [ ! -h "$FILE" -a -f "$FILE" ]; then diff --git a/bin/hardening/6.2.12_find_user_netrc_files.sh b/bin/hardening/6.2.12_find_user_netrc_files.sh index 6a59b08..3d6dae0 100755 --- a/bin/hardening/6.2.12_find_user_netrc_files.sh +++ b/bin/hardening/6.2.12_find_user_netrc_files.sh @@ -19,7 +19,7 @@ FILENAME='.netrc' # This function will be called if the script status is on enabled / audit mode audit () { - for DIR in $(cat /etc/passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do + for DIR in $(get_db passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do debug "Working on $DIR" for FILE in $DIR/$FILENAME; do if [ ! -h "$FILE" -a -f "$FILE" ]; then diff --git a/bin/hardening/6.2.13_set_perm_on_user_netrc.sh b/bin/hardening/6.2.13_set_perm_on_user_netrc.sh index 3c271db..4789a70 100755 --- a/bin/hardening/6.2.13_set_perm_on_user_netrc.sh +++ b/bin/hardening/6.2.13_set_perm_on_user_netrc.sh @@ -19,7 +19,7 @@ ERRORS=0 # This function will be called if the script status is on enabled / audit mode audit () { - for DIR in $(cat /etc/passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do + for DIR in $(get_db passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do debug "Working on $DIR" for FILE in $DIR/.netrc; do if [ ! -h "$FILE" -a -f "$FILE" ]; then diff --git a/bin/hardening/6.2.14_find_user_rhosts_files.sh b/bin/hardening/6.2.14_find_user_rhosts_files.sh index a131747..a10daa5 100755 --- a/bin/hardening/6.2.14_find_user_rhosts_files.sh +++ b/bin/hardening/6.2.14_find_user_rhosts_files.sh @@ -19,7 +19,7 @@ FILENAME=".rhosts" # This function will be called if the script status is on enabled / audit mode audit () { - for DIR in $(cat /etc/passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do + for DIR in $(get_db passwd | egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do debug "Working on $DIR" for FILE in $DIR/$FILENAME; do if [ ! -h "$FILE" -a -f "$FILE" ]; then diff --git a/bin/hardening/6.2.16_check_duplicate_uid.sh b/bin/hardening/6.2.16_check_duplicate_uid.sh index 891b75d..0f0fee8 100755 --- a/bin/hardening/6.2.16_check_duplicate_uid.sh +++ b/bin/hardening/6.2.16_check_duplicate_uid.sh @@ -21,7 +21,7 @@ ERRORS=0 # This function will be called if the script status is on enabled / audit mode audit () { - RESULT=$(cut -f3 -d":" < /etc/passwd | sort -n | uniq -c | awk '{print $1":"$2}' ) + RESULT=$(get_db passwd | cut -f3 -d":" | sort -n | uniq -c | awk '{print $1":"$2}' ) FOUND_EXCEPTIONS="" for LINE in $RESULT; do debug "Working on line $LINE" diff --git a/bin/hardening/6.2.17_check_duplicate_gid.sh b/bin/hardening/6.2.17_check_duplicate_gid.sh index 8212da2..cc8fa73 100755 --- a/bin/hardening/6.2.17_check_duplicate_gid.sh +++ b/bin/hardening/6.2.17_check_duplicate_gid.sh @@ -20,7 +20,7 @@ ERRORS=0 # This function will be called if the script status is on enabled / audit mode audit () { - RESULT=$(cut -f3 -d":" /etc/group | sort -n | uniq -c | awk '{print $1":"$2}' ) + RESULT=$(get_db group | cut -f3 -d":" | sort -n | uniq -c | awk '{print $1":"$2}' ) for LINE in $RESULT; do debug "Working on line $LINE" OCC_NUMBER=$(awk -F: '{print $1}' <<< "$LINE") diff --git a/bin/hardening/6.2.18_check_duplicate_username.sh b/bin/hardening/6.2.18_check_duplicate_username.sh index 27a8743..36f0dcf 100755 --- a/bin/hardening/6.2.18_check_duplicate_username.sh +++ b/bin/hardening/6.2.18_check_duplicate_username.sh @@ -18,7 +18,7 @@ ERRORS=0 # This function will be called if the script status is on enabled / audit mode audit () { - RESULT=$(cat /etc/passwd | cut -f1 -d":" | sort -n | uniq -c | awk {'print $1":"$2'} ) + RESULT=$(get_db passwd | cut -f1 -d":" | sort -n | uniq -c | awk {'print $1":"$2'} ) for LINE in $RESULT; do debug "Working on line $LINE" OCC_NUMBER=$(awk -F: {'print $1'} <<< $LINE) diff --git a/bin/hardening/6.2.19_check_duplicate_groupname.sh b/bin/hardening/6.2.19_check_duplicate_groupname.sh index 94a8ab5..1d397f3 100755 --- a/bin/hardening/6.2.19_check_duplicate_groupname.sh +++ b/bin/hardening/6.2.19_check_duplicate_groupname.sh @@ -18,7 +18,7 @@ ERRORS=0 # This function will be called if the script status is on enabled / audit mode audit () { - RESULT=$(cat /etc/group | cut -f1 -d":" | sort -n | uniq -c | awk {'print $1":"$2'} ) + RESULT=$(get_db group | cut -f1 -d":" | sort -n | uniq -c | awk {'print $1":"$2'} ) for LINE in $RESULT; do debug "Working on line $LINE" OCC_NUMBER=$(awk -F: {'print $1'} <<< $LINE) diff --git a/bin/hardening/6.2.1_remove_empty_password_field.sh b/bin/hardening/6.2.1_remove_empty_password_field.sh index c378e6c..8ec02d7 100755 --- a/bin/hardening/6.2.1_remove_empty_password_field.sh +++ b/bin/hardening/6.2.1_remove_empty_password_field.sh @@ -14,12 +14,11 @@ set -u # One variable unset, it's over HARDENING_LEVEL=1 DESCRIPTION="Ensure password fields are not empty in /etc/shadow." -FILE='/etc/shadow' # This function will be called if the script status is on enabled / audit mode audit () { info "Checking if accounts have an empty password" - RESULT=$($SUDO_CMD cat $FILE | awk -F: '($2 == "" ) { print $1 }') + RESULT=$(get_db shadow | awk -F: '($2 == "" ) { print $1 }') if [ ! -z "$RESULT" ]; then crit "Some accounts have an empty password" crit $RESULT @@ -30,7 +29,7 @@ audit () { # This function will be called if the script status is on enabled mode apply () { - RESULT=$(cat $FILE | awk -F: '($2 == "" ) { print $1 }') + RESULT=$(get_db shadow | awk -F: '($2 == "" ) { print $1 }') if [ ! -z "$RESULT" ]; then warn "Some accounts have an empty password" for ACCOUNT in $RESULT; do diff --git a/bin/hardening/6.2.7_users_valid_homedir.sh b/bin/hardening/6.2.7_users_valid_homedir.sh index a29c798..3b16833 100755 --- a/bin/hardening/6.2.7_users_valid_homedir.sh +++ b/bin/hardening/6.2.7_users_valid_homedir.sh @@ -18,7 +18,7 @@ ERRORS=0 # This function will be called if the script status is on enabled / audit mode audit () { - RESULT=$(cat /etc/passwd | awk -F: '{ print $1 ":" $3 ":" $6 }') + RESULT=$(get_db passwd | awk -F: '{ print $1 ":" $3 ":" $6 }') for LINE in $RESULT; do debug "Working on $LINE" USER=$(awk -F: {'print $1'} <<< $LINE) diff --git a/bin/hardening/6.2.8_check_user_dir_perm.sh b/bin/hardening/6.2.8_check_user_dir_perm.sh index 5b9f3b9..d57768c 100755 --- a/bin/hardening/6.2.8_check_user_dir_perm.sh +++ b/bin/hardening/6.2.8_check_user_dir_perm.sh @@ -18,7 +18,7 @@ ERRORS=0 # This function will be called if the script status is on enabled / audit mode audit () { - for dir in $(cat /etc/passwd | /bin/egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do + for dir in $(get_db passwd | /bin/egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do debug "Working on $dir" debug "Exceptions : $EXCEPTIONS" debug "echo \"$EXCEPTIONS\" | grep -q $dir" @@ -57,7 +57,7 @@ audit () { # This function will be called if the script status is on enabled mode apply () { - for dir in $(cat /etc/passwd | /bin/egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do + for dir in $(get_db passwd | /bin/egrep -v '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do debug "Working on $dir" debug "Exceptions : $EXCEPTIONS" debug "echo \"$EXCEPTIONS\" | grep -q $dir" diff --git a/bin/hardening/6.2.9_users_valid_homedir.sh b/bin/hardening/6.2.9_users_valid_homedir.sh index cb3b5e9..bb48843 100755 --- a/bin/hardening/6.2.9_users_valid_homedir.sh +++ b/bin/hardening/6.2.9_users_valid_homedir.sh @@ -21,7 +21,7 @@ ERRORS=0 # This function will be called if the script status is on enabled / audit mode audit () { debug "Checking homedir exists" - RESULT=$(cat /etc/passwd | awk -F: '{ print $1 ":" $3 ":" $6 }') + RESULT=$(get_db passwd | awk -F: '{ print $1 ":" $3 ":" $6 }') for LINE in $RESULT; do debug "Working on $LINE" USER=$(awk -F: {'print $1'} <<< $LINE) diff --git a/lib/utils.sh b/lib/utils.sh index 57afc62..dc4ec00 100644 --- a/lib/utils.sh +++ b/lib/utils.sh @@ -126,6 +126,11 @@ _does_pattern_exist_in_file() { fi } +get_db() { + local DB="$1" + $SUDO_CMD getent --service files "$DB" +} + # 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.