6 - System Maintenance#

6.1 - System File Permissions#

6.1.1 - Audit package permissions#

Running dpkg --list or apt list --installed shows a list of all installed packages on the system.

Note: apt list --installed likely will output too many lines to view, in the terminal, so apt list --installed > packages.txt will output it to a file named packages.txt.

Running dpkg --verify PACKAGE_NAME verifies the files in a package. The errors it returns are:

Code Meaning
S    File size differs.
M    File mode differs (includes permissions and file type).
5    The MD5 checksum differs.
D    The major and minor version numbers differ on a device file.
L    A mismatch occurs in a link.
U    The file ownership differs.
G    The file group owner differs.
T    The file time (mtime) differs.

Verifying all packages can reveal security vulnerabilities, but is extremely time-consuming.

6.1.2 - 6.1.9 - Configure important file permissions#

To ensure that the file permissions are set properly on important files and directories, run:

sudo chown root:root /etc/passwd
sudo chmod u-x,go-wx /etc/passwd
sudo chown root:root /etc/passwd~
sudo chmod u-x,go-wx /etc/passwd~
sudo chown root:root /etc/group
sudo chmod u-x,go-wx /etc/group
sudo chown root:root /etc/group~
sudo chmod u-x,go-wx /etc/group~
sudo chown root:root /etc/shadow
sudo chmod u-x,go-wx /etc/shadow
sudo chown root:root /etc/shadow~
sudo chmod u-x,go-wx /etc/shadow~
sudo chown root:root /etc/gshadow
sudo chmod u-x,go-wx /etc/gshadow
sudo chown root:root /etc/gshadow~
sudo chmod u-x,go-wx /etc/gshadow~

Note

To run all of these commands at once, paste them into a .sh file and run it with bash.

Ex: sudo bash script.sh

6.1.10 - Ensure no world writable files exist#

To scan for world-writable files in local directories, run:

df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -0002

To search on individual partitions, run:

find PARTITION_NAME -xdev -type f -perm -0002

If a world-writable file is found, remove miscellaneous write access on it by running chmod o-w FILENAME.

6.1.11 - 6.1.12 - Check for unowned/ungrouped files#

To scan for unowned files in local directories, run:

df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -nouser

To scan for ungrouped files in local directories, run:

df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -nogroup

To search for unowned files in individual partitions, run:

find PARTITION_NAME -xdev -nouser

To search for ungrouped files in individual partitions, run:

find PARTITION_NAME -xdev -nogroup

If any files are found, assign them an owner or group by using chown. See man chown for more information.

6.1.13 - 6.1.14 - Audit SUID and SGID executables#

To scan for SUID files locally, run:

df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev
-type f -perm -4000

To scan for SGID files locally, run:

df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev
-type f -perm -2000

To scan on individual partitions, run:

# SUID:
find PARTITION_NAME -xdev -type f -perm 4000

# SGID:
find PARTITION_NAME -xdev -type f -perm 2000

For files that are found, review them, and either revoke the permissions of or delete rogue files.

6.2 - User and Group Settings#

6.2.1 - 6.2.2 - Ensure password integrity#

Find accounts without shadowed passwords by running:

awk -F: '($2 != "x" ) { print $1 " is not set to shadowed passwords "}'
/etc/passwd

Set all accounts to use shadowed passwords by running:

sed -e 's/^\([a-zA-Z0-9_]*\):[^:]*:/\1:x:/' -i /etc/passwd

Search for accounts with empty passwords by running:

awk -F: '($2 == "" ) { print $1 " does not have a password "}' /etc/shadow

If an account has an empty password, change it or lock the account using the passwd command or the user settings GUI.

6.2.3 - Ensure all groups in /etc/passwd exist in /etc/group#

Make sure that all groups in /etc/passwd are in /etc/group by running the following script:

#!/bin/bash

for i in $(cut -s -d: -f4 /etc/passwd | sort -u ); do
    grep -q -P "^.*?:[^:]*:$i:" /etc/group
    if [ $? -ne 0 ]; then
        echo "Group $i is referenced by /etc/passwd but does not exist in /etc/group"
    fi
done
source <(curl -s https://raw.githubusercontent.com/CAMSCSC/CIS-Breakdown/main/scripts/6.2.3.sh)

6.2.4 - 6.2.6 - Configure home directories#

Create a home directory for users with an interactive shell without a home directory and ensure that users own their home directory by running the following script

#!/bin/bash

awk -F: '($1!~/(halt|sync|shutdown)/ && $7!~/^(\/usr)?\/sbin\/nologin(\/)?$/
&& $7!~/(\/usr)?\/bin\/false(\/)?$/) { print $1 " " $6 }' | while
    read -r
    user dir
do
    if [ ! -d "$dir" ]; then
        echo "User: \"$user\" home directory: \"$dir\" does not exist, creating
home directory"
        mkdir "$dir"
        chmod g-w,o-rwx "$dir"
        chown "$user" "$dir"
    else
        owner=$(stat -L -c "%U" "$dir")
        if [ "$owner" != "$user" ]; then
            chmod g-w,o-rwx "$dir"
            chown "$user" "$dir"
        fi
    fi
done
source <(curl -s https://raw.githubusercontent.com/CAMSCSC/CIS-Breakdown/main/scripts/6.2.4.sh)

Then ensure that the home directories have permissions of 750 by running the following script:

#!/bin/bash

awk -F: '($1!~/(halt|sync|shutdown)/ && $7!~/^(\/usr)?\/sbin\/nologin(\/)?$/
&& $7!~/(\/usr)?\/bin\/false(\/)?$/) {print $6}' /etc/passwd | while
    read -r
    dir
do
    if [ -d "$dir" ]; then
        dirperm=$(stat -L -c "%A" "$dir")
        if [ "$(echo "$dirperm" | cut -c6)" != "-" ] || [ "$(echo "$dirperm" |
            cut -c8)" != "-" ] || [ "$(echo "$dirperm" | cut -c9)" != "-" ] || [ "$(
            echo
            "$dirperm" | cut -c10
        )" != "-" ]; then
            chmod g-w,o-rwx "$dir"
        fi
    fi
done
source <(curl -s https://raw.githubusercontent.com/CAMSCSC/CIS-Breakdown/main/scripts/6.2.6.sh)

6.2.7 - 6.2.10 - Configure dot files#

Configure the dot files in every home directory by running the following script:

#!/bin/bash

awk -F: '($1!~/(halt|sync|shutdown)/ && $7!~/^(\/usr)?\/sbin\/nologin(\/)?$/ && $7!~/(\/usr)?\/bin\/false(\/)?$/) { print $1 " " $6 }' /etc/passwd | while read -r user dir
do
    if [ -d "$dir" ]; then
        for file in "$dir"/.*; do
            if [ ! -h "$file" ] && [ -f "$file" ]; then
                fileperm=$(stat -L -c "%A" "$file")
                if [ "$(echo "$fileperm" | cut -c6)" != "-" ] || [ "$(echo "$fileperm" | cut -c9)" != "-" ]; then
                    echo "User: \"$user\" file: \"$file\" has permissions:\"$fileperm\""
                    chmod go-w "$file"
                fi
            fi
        done
        file="$dir/.netrc"
        if [ ! -h "$file" ] && [ -f "$file" ]; then
            rm -f "$file"
            echo ".netrc file found and removed in $user\'s home directory."
        fi
        file="$dir/.forward"
        if [ ! -h "$file" ] && [ -f "$file" ]; then
            rm -r "$file"
            echo ".forward file found and removed in $user\'s home directory."
        fi
        file="$dir/.rhosts"
        if [ ! -h "$file" ] && [ -f "$file" ]; then 
            rm -r "$file"
            echo ".rhosts file found and removed in $user\'s home directory."
        fi
    fi
done
source <(curl -s https://raw.githubusercontent.com/CAMSCSC/CIS-Breakdown/main/scripts/6.2.7.sh)

6.2.11 - 6.2.12 - Validate root account integrity#

Ensure that root is the only account with UID 0 by running:

awk -F: '($3 == 0) { print $1 }' /etc/passwd

If anything other than root is returned, assign those accounts a new UID or remove them.

Check for the integrity of the root PATH by running the following script:

#!/bin/bash

RPCV="$(sudo -Hiu root env | grep '^PATH' | cut -d= -f2)"
echo "$RPCV" | grep -q "::" && echo "root's path contains a empty directory (::)"
echo "$RPCV" | grep -q ":$" && echo "root's path contains a trailing (:)"
for x in $(echo "$RPCV" | tr ":" " "); do
    if [ -d "$x" ]; then
        ls -ldH "$x" | awk '$9 == "." {print "PATH contains current working directory (.)"}
        $3 != "root" {print $9, "is not owned by root"}
        substr($1,6,1) != "-" {print $9, "is group writable"}
        substr($1,9,1) != "-" {print $9, "is world writable"}'
    else
        echo "$x is not a directory"
    fi
done
source <(curl -s https://raw.githubusercontent.com/CAMSCSC/CIS-Breakdown/main/scripts/6.2.7.sh)

6.2.13 - 6.2.16 - Remove duplicate groups and users#

Check for duplicates by scanning /etc/passwd and /etc/group with the following script:

#!/bin/bash

cut -f3 -d":" /etc/passwd | sort -n | uniq -c | while read x; do
    [ -z "$x" ] && break
    set - $x
    if [ $1 -gt 1 ]; then
        users=$(awk -F: '($3 == n) { print $1 }' n=$2 /etc/passwd | xargs)
        echo "Duplicate UID ($2): $users"
    fi
done

cut -d: -f1 /etc/passwd | sort | uniq -d | while read -r x; do
    echo "Duplicate login name $x in /etc/passwd"
done

cut -d: -f3 /etc/group | sort | uniq -d | while read x; do
    echo "Duplicate GID ($x) in /etc/group"
done

cut -d: -f1 /etc/group | sort | uniq -d | while read -r x; do
    echo "Duplicate group name $x in /etc/group"
done
source <(curl -s https://raw.githubusercontent.com/CAMSCSC/CIS-Breakdown/main/scripts/6.2.13.sh)

If any results are returned, edit /etc/passwd or /etc/group to fix the discrepancy.

The grpck command can also be used to scan for other discrepancies in /etc/group.

6.2.17 - Ensure shadow group is empty#

Ensure that no users are in the shadow group by running:

grep ^shadow:[^:]*:[^:]*:[^:]+ /etc/group
awk -F: -v GID="$(awk -F: '($1=="shadow") {print $3}' /etc/group)" '($4==GID) {print}' /etc/passwd

If any groups are returned, remove them from the shadow group.