Set Lockout Time for Failed Password Attempts

Classification:

compliance

Framework:

Control:

Description

This rule configures the system to lock out accounts during a specified time period after a number of incorrect login attempts using pam_faillock.so.

pam_faillock.so module requires multiple entries in pam files. These entries must be carefully defined to work as expected. In order to avoid any errors when manually editing these files, it is recommended to use the appropriate tools, such as authselect or authconfig, depending on the OS version.

If unlock_time is set to 0, manual intervention by an administrator is required to unlock a user. This should be done using the faillock tool.

Rationale

By limiting the number of failed logon attempts the risk of unauthorized system access via user password guessing, otherwise known as brute-forcing, is reduced. Limits are imposed by locking the account.

Remediation

Shell script

The following script can be run on the host to remediate the issue.

# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}\n' 'libpam-runtime' 2>/dev/null | grep -q installed; then

var\_accounts\_passwords\_pam\_faillock\_unlock\_time='600'


if [ -f /usr/bin/authselect ]; then
 if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
It is not recommended to manually edit the PAM files when authselect tool is available.
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
authselect enable-feature with-faillock

authselect apply-changes -b
else
 
pam\_file="/etc/pam.d/common-auth"
if ! grep -qE '^\s\*auth\s+required\s+pam\_faillock\.so\s+preauth.\*$' "$pam\_file" ; then
 sed -i --follow-symlinks '/^auth.\*pam\_unix\.so.\*/i auth required pam\_faillock.so preauth' "$pam\_file"
fi
if ! grep -qE '^\s\*auth\s+\[default=die\]\s+pam\_faillock\.so\s+authfail.\*$' "$pam\_file" ; then
 sed -i --follow-symlinks '/^auth.\*pam\_unix\.so.\*/a auth [default=die] pam\_faillock.so authfail' "$pam\_file"
fi
if ! grep -qE '^\s\*auth\s+sufficient\s+pam\_faillock\.so\s+authsucc.\*$' "$pam\_file" ; then
 sed -i --follow-symlinks '/^auth.\*pam\_faillock\.so.\*authfail.\*/a auth sufficient pam\_faillock.so authsucc' "$pam\_file"
fi

pam\_file="/etc/pam.d/common-account"
if ! grep -qE '^\s\*account\s+required\s+pam\_faillock\.so.\*$' "$pam\_file" ; then
 echo 'account required pam\_faillock.so' >> "$pam\_file"
fi

fi

AUTH\_FILES=("/etc/pam.d/common-auth" "/etc/pam.d/password-auth")

FAILLOCK\_CONF="/etc/security/faillock.conf"
if [ -f $FAILLOCK\_CONF ]; then
 regex="^\s\*unlock\_time\s\*="
 line="unlock\_time = $var\_accounts\_passwords\_pam\_faillock\_unlock\_time"
 if ! grep -q $regex $FAILLOCK\_CONF; then
 echo $line >> $FAILLOCK\_CONF
 else
 sed -i --follow-symlinks 's|^\s\*\(unlock\_time\s\*=\s\*\)\(\S\+\)|\1'"$var\_accounts\_passwords\_pam\_faillock\_unlock\_time"'|g' $FAILLOCK\_CONF
 fi
 for pam\_file in "${AUTH\_FILES[@]}"
 do
 if [ -e "$pam\_file" ] ; then
 PAM\_FILE\_PATH="$pam\_file"
 if [ -f /usr/bin/authselect ]; then
 
 if ! authselect check; then
 echo "
 authselect integrity check failed. Remediation aborted!
 This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
 It is not recommended to manually edit the PAM files when authselect tool is available.
 In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
 exit 1
 fi

 CURRENT\_PROFILE=$(authselect current -r | awk '{ print $1 }')
 # If not already in use, a custom profile is created preserving the enabled features.
 if [[ ! $CURRENT\_PROFILE == custom/\* ]]; then
 ENABLED\_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
 authselect create-profile hardening -b $CURRENT\_PROFILE
 CURRENT\_PROFILE="custom/hardening"
 
 authselect apply-changes -b --backup=before-hardening-custom-profile
 authselect select $CURRENT\_PROFILE
 for feature in $ENABLED\_FEATURES; do
 authselect enable-feature $feature;
 done
 
 authselect apply-changes -b --backup=after-hardening-custom-profile
 fi
 PAM\_FILE\_NAME=$(basename "$pam\_file")
 PAM\_FILE\_PATH="/etc/authselect/$CURRENT\_PROFILE/$PAM\_FILE\_NAME"

 authselect apply-changes -b
 fi
 
 if grep -qP '^\s\*auth\s.\*\bpam\_faillock.so\s.\*\bunlock\_time\b' "$PAM\_FILE\_PATH"; then
 sed -i -E --follow-symlinks 's/(.\*auth.\*pam\_faillock.so.\*)\bunlock\_time\b=?[[:alnum:]]\*(.\*)/\1\2/g' "$PAM\_FILE\_PATH"
 fi
 if [ -f /usr/bin/authselect ]; then
 
 authselect apply-changes -b
 fi
 else
 echo "$pam\_file was not found" >&2
 fi
 done
else
 for pam\_file in "${AUTH\_FILES[@]}"
 do
 if ! grep -qE '^\s\*auth.\*pam\_faillock\.so (preauth|authfail).\*unlock\_time' "$pam\_file"; then
 sed -i --follow-symlinks '/^auth.\*required.\*pam\_faillock\.so.\*preauth.\*silent.\*/ s/$/ unlock\_time='"$var\_accounts\_passwords\_pam\_faillock\_unlock\_time"'/' "$pam\_file"
 sed -i --follow-symlinks '/^auth.\*required.\*pam\_faillock\.so.\*authfail.\*/ s/$/ unlock\_time='"$var\_accounts\_passwords\_pam\_faillock\_unlock\_time"'/' "$pam\_file"
 else
 sed -i --follow-symlinks 's/\(^auth.\*required.\*pam\_faillock\.so.\*preauth.\*silent.\*\)\('"unlock\_time"'=\)[0-9]\+\(.\*\)/\1\2'"$var\_accounts\_passwords\_pam\_faillock\_unlock\_time"'\3/' "$pam\_file"
 sed -i --follow-symlinks 's/\(^auth.\*required.\*pam\_faillock\.so.\*authfail.\*\)\('"unlock\_time"'=\)[0-9]\+\(.\*\)/\1\2'"$var\_accounts\_passwords\_pam\_faillock\_unlock\_time"'\3/' "$pam\_file"
 fi
 done
fi

else
 >&2 echo 'Remediation is not applicable, nothing was done'
fi

Warning

If the system supports the new /etc/security/faillock.conf file but the pam_faillock.so parameters are defined directly in /etc/pam.d/system-auth and /etc/pam.d/password-auth, the remediation will migrate the unlock_time parameter to /etc/security/faillock.conf to ensure compatibility with authselect tool. The parameters deny and fail_interval, if used, also have to be migrated by their respective remediation.