This rule ensures the system prevents informative messages from being presented to the user
pertaining to logon information 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 errors when manually editing these files, it is
recommended to use the appropriate tools, such as authselect or authconfig,
depending on the OS version.
warning alert:
Warning
If the system relies on authselect tool to manage PAM settings, the remediation
will also use authselect tool. However, if any manual modification was made in
PAM files, the authselect integrity check will fail and the remediation will be
aborted in order to preserve intentional changes. In this case, an informative message will
be shown in the remediation report.
If the system supports the /etc/security/faillock.conf file, the pam_faillock
parameters should be defined in faillock.conf file.
Rationale
The pam_faillock module without the silent option will leak information about the existence or
non-existence of a user account in the system because the failures are not recorded for unknown
users. The message about the user account being locked is never displayed for non-existing user
accounts allowing the adversary to infer that a particular account exists or not on the system.
- name: Gather the package facts
package_facts:
manager: auto
tags:
- DISA-STIG-UBTU-20-010072
- accounts_passwords_pam_faillock_silent
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
when: '"libpam-runtime" in ansible_facts.packages'
tags:
- DISA-STIG-UBTU-20-010072
- accounts_passwords_pam_faillock_silent
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Remediation
where authselect tool is present
block:
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
failed_when: false
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Informative
message based on the authselect integrity check result
ansible.builtin.assert:
that:
- result_authselect_check_cmd.rc == 0
fail_msg:
- 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.
success_msg:
- authselect integrity check passed
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Get
authselect current features
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
when:
- result_authselect_check_cmd is success
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
"with-faillock" feature is enabled using authselect tool
ansible.builtin.command:
cmd: authselect enable-feature with-faillock
register: result_authselect_enable_feature_cmd
when:
- result_authselect_check_cmd is success
- result_authselect_features.stdout is not search("with-faillock")
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
authselect changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_enable_feature_cmd is not skipped
- result_authselect_enable_feature_cmd is success
when:
- '"libpam-runtime" in ansible_facts.packages'
- result_authselect_present.stat.exists
tags:
- DISA-STIG-UBTU-20-010072
- accounts_passwords_pam_faillock_silent
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Remediation
where authselect tool is not present
block:
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
if pam_faillock.so is already enabled
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: .*auth.*pam_faillock\.so (preauth|authfail)
state: absent
check_mode: true
changed_when: false
register: result_pam_faillock_is_enabled
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Enable
pam_faillock.so preauth editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so preauth
insertbefore: ^auth.*sufficient.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Enable
pam_faillock.so authfail editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so authfail
insertbefore: ^auth.*required.*pam_deny\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Enable
pam_faillock.so account section editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: account required pam_faillock.so
insertbefore: ^account.*required.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
when:
- '"libpam-runtime" in ansible_facts.packages'
- not result_authselect_present.stat.exists
tags:
- DISA-STIG-UBTU-20-010072
- accounts_passwords_pam_faillock_silent
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
the presence of /etc/security/faillock.conf file
ansible.builtin.stat:
path: /etc/security/faillock.conf
register: result_faillock_conf_check
when: '"libpam-runtime" in ansible_facts.packages'
tags:
- DISA-STIG-UBTU-20-010072
- accounts_passwords_pam_faillock_silent
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
the pam_faillock.so silent parameter in /etc/security/faillock.conf
ansible.builtin.lineinfile:
path: /etc/security/faillock.conf
regexp: ^\s*silent
line: silent
state: present
when:
- '"libpam-runtime" in ansible_facts.packages'
- result_faillock_conf_check.stat.exists
tags:
- DISA-STIG-UBTU-20-010072
- accounts_passwords_pam_faillock_silent
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
the pam_faillock.so silent parameter in PAM files
block:
- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
the inclusion of pam_faillock.so preauth silent parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth(:?(?!silent).)*)
line: \1required\3 silent
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- '"libpam-runtime" in ansible_facts.packages'
- not result_faillock_conf_check.stat.exists
tags:
- DISA-STIG-UBTU-20-010072
- accounts_passwords_pam_faillock_silent
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
Remediation - Shell Script
# 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
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
# insert at the top
sed -i --follow-symlinks '/^# here are the per-package modules/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
num_lines=$(sed -n 's/^\s*auth.*success=\([1-9]\).*pam_unix\.so.*/\1/p' "$pam_file")
if [ ! -z "$num_lines" ]; then
# Add pam_faillock (authfail) module below pam_unix, skipping N-1 lines, where N is
# the number of jumps in the pam_unix success=N statement. Ignore commented and empty lines.
append_position=$(cat -n "${pam_file}" \
| grep -P "^\s+\d+\s+auth\s+.*$" \
| grep -w "pam_unix.so" -A $(( num_lines - 1 )) \
| tail -n 1 | cut -f 1 | tr -d ' '
)
sed -i --follow-symlinks ''${append_position}'a auth [default=die] pam_faillock.so authfail' "$pam_file"
else
sed -i --follow-symlinks '/^auth.*pam_unix\.so.*/a auth [default=die] pam_faillock.so authfail' "$pam_file"
fi
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")
FAILLOCK_CONF="/etc/security/faillock.conf"
if [ -f $FAILLOCK_CONF ]; then
regex="^\s*silent"
line="silent"
if ! grep -q $regex $FAILLOCK_CONF; then
echo $line >> $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.*\bsilent\b" "$PAM_FILE_PATH"; then
sed -i -E --follow-symlinks "s/(.*auth.*pam_faillock.so.*)\bsilent\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).*silent' "$pam_file"; then
sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ silent/' "$pam_file"
fi
done
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi