Set PAM''s Password Hashing Algorithm
Description
The PAM system service can be configured to only store encrypted
representations of passwords. In “/etc/pam.d/system-auth”, the
password
section of the file controls which PAM modules execute
during a password change. Set the pam_unix.so
module in the
password
section to include the argument sha512
, as shown
below:
password sufficient pam_unix.so sha512 other arguments...
This will help ensure when local users change their passwords, hashes for
the new passwords will be generated using the SHA-512 algorithm. This is
the default.
Rationale
Passwords need to be protected at all times, and encryption is the standard
method for protecting passwords. If passwords are not encrypted, they can
be plainly read (i.e., clear text) and easily compromised. Passwords that
are encrypted with a weak algorithm are no more protected than if they are
kepy in plain text.
This setting ensures user and group account administration utilities are
configured to store only encrypted representations of passwords.
Additionally, the crypt_style
configuration option ensures the use
of a strong hashing algorithm that makes password cracking attacks more
difficult.
Shell script
The following script can be run on the host to remediate the issue.
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then
if [ -e "/etc/pam.d/system-auth" ] ; then
PAM\_FILE\_PATH="/etc/pam.d/system-auth"
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 "/etc/pam.d/system-auth")
PAM\_FILE\_PATH="/etc/authselect/$CURRENT\_PROFILE/$PAM\_FILE\_NAME"
authselect apply-changes -b
fi
if ! grep -qP '^\s\*password\s+'"sufficient"'\s+pam\_unix.so\s\*.\*' "$PAM\_FILE\_PATH"; then
# Line matching group + control + module was not found. Check group + module.
if [ "$(grep -cP '^\s\*password\s+.\*\s+pam\_unix.so\s\*' "$PAM\_FILE\_PATH")" -eq 1 ]; then
# The control is updated only if one single line matches.
sed -i -E --follow-symlinks 's/^(\s\*password\s+).\*(\bpam\_unix.so.\*)/\1'"sufficient"' \2/' "$PAM\_FILE\_PATH"
else
echo 'password '"sufficient"' pam\_unix.so' >> "$PAM\_FILE\_PATH"
fi
fi
# Check the option
if ! grep -qP '^\s\*password\s+'"sufficient"'\s+pam\_unix.so\s\*.\*\ssha512\b' "$PAM\_FILE\_PATH"; then
sed -i -E --follow-symlinks '/\s\*password\s+'"sufficient"'\s+pam\_unix.so.\*/ s/$/ sha512/' "$PAM\_FILE\_PATH"
fi
if [ -f /usr/bin/authselect ]; then
authselect apply-changes -b
fi
else
echo "/etc/pam.d/system-auth was not found" >&2
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Ansible playbook
The following playbook can be run with Ansible to remediate the issue.
- name: Gather the package facts
package\_facts:
manager: auto
tags:
- CCE-82043-1
- CJIS-5.6.2.2
- DISA-STIG-RHEL-07-010200
- NIST-800-171-3.13.11
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(c)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.1
- PCI-DSSv4-8.3.2
- configure\_strategy
- low\_complexity
- medium\_disruption
- medium\_severity
- no\_reboot\_needed
- set\_password\_hashing\_algorithm\_systemauth
- name: Set PAM's Password Hashing Algorithm - Check if /etc/pam.d/system-auth file
is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result\_pam\_file\_present
when: '"pam" in ansible\_facts.packages'
tags:
- CCE-82043-1
- CJIS-5.6.2.2
- DISA-STIG-RHEL-07-010200
- NIST-800-171-3.13.11
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(c)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.1
- PCI-DSSv4-8.3.2
- configure\_strategy
- low\_complexity
- medium\_disruption
- medium\_severity
- no\_reboot\_needed
- set\_password\_hashing\_algorithm\_systemauth
- name: Set PAM's Password Hashing Algorithm - Check the proper remediation for the
system
block:
- name: Set PAM's Password Hashing Algorithm - Define the PAM file to be edited
as a local fact
ansible.builtin.set\_fact:
pam\_file\_path: /etc/pam.d/system-auth
- name: Set PAM's Password Hashing Algorithm - Check if system relies on authselect
tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result\_authselect\_present
- name: Set PAM's Password Hashing Algorithm - Ensure authselect custom profile
is used if authselect is present
block:
- name: Set PAM's Password Hashing Algorithm - Check integrity of authselect current
profile
ansible.builtin.command:
cmd: authselect check
register: result\_authselect\_check\_cmd
changed\_when: false
failed\_when: false
- name: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - Get authselect current profile
ansible.builtin.shell:
cmd: authselect current -r | awk '{ print $1 }'
register: result\_authselect\_profile
changed\_when: false
when:
- result\_authselect\_check\_cmd is success
- name: Set PAM's Password Hashing Algorithm - Define the current authselect profile
as a local fact
ansible.builtin.set\_fact:
authselect\_current\_profile: '{{ result\_authselect\_profile.stdout }}'
authselect\_custom\_profile: '{{ result\_authselect\_profile.stdout }}'
when:
- result\_authselect\_profile is not skipped
- result\_authselect\_profile.stdout is match("custom/")
- name: Set PAM's Password Hashing Algorithm - Define the new authselect custom
profile as a local fact
ansible.builtin.set\_fact:
authselect\_current\_profile: '{{ result\_authselect\_profile.stdout }}'
authselect\_custom\_profile: custom/hardening
when:
- result\_authselect\_profile is not skipped
- result\_authselect\_profile.stdout is not match("custom/")
- name: Set PAM's Password Hashing Algorithm - Get authselect current features
to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result\_authselect\_features
changed\_when: false
when:
- result\_authselect\_profile is not skipped
- authselect\_current\_profile is not match("custom/")
- name: Set PAM's Password Hashing Algorithm - Check if any custom profile with
the same name was already created
ansible.builtin.stat:
path: /etc/authselect/{{ authselect\_custom\_profile }}
register: result\_authselect\_custom\_profile\_present
changed\_when: false
when:
- authselect\_current\_profile is not match("custom/")
- name: Set PAM's Password Hashing Algorithm - Create an authselect custom profile
based on the current profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b {{ authselect\_current\_profile
}}
when:
- result\_authselect\_check\_cmd is success
- authselect\_current\_profile is not match("custom/")
- not result\_authselect\_custom\_profile\_present.stat.exists
- name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
when:
- result\_authselect\_check\_cmd is success
- result\_authselect\_profile is not skipped
- authselect\_current\_profile is not match("custom/")
- authselect\_custom\_profile is not match(authselect\_current\_profile)
- name: Set PAM's Password Hashing Algorithm - Ensure the authselect custom profile
is selected
ansible.builtin.command:
cmd: authselect select {{ authselect\_custom\_profile }}
register: result\_pam\_authselect\_select\_profile
when:
- result\_authselect\_check\_cmd is success
- result\_authselect\_profile is not skipped
- authselect\_current\_profile is not match("custom/")
- authselect\_custom\_profile is not match(authselect\_current\_profile)
- name: Set PAM's Password Hashing Algorithm - Restore the authselect features
in the custom profile
ansible.builtin.command:
cmd: authselect enable-feature {{ item }}
loop: '{{ result\_authselect\_features.stdout\_lines }}'
register: result\_pam\_authselect\_restore\_features
when:
- result\_authselect\_profile is not skipped
- result\_authselect\_features is not skipped
- result\_pam\_authselect\_select\_profile is not skipped
- name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
when:
- result\_authselect\_check\_cmd is success
- result\_authselect\_profile is not skipped
- result\_pam\_authselect\_restore\_features is not skipped
- name: Set PAM's Password Hashing Algorithm - Change the PAM file to be edited
according to the custom authselect profile
ansible.builtin.set\_fact:
pam\_file\_path: /etc/authselect/{{ authselect\_custom\_profile }}/{{ pam\_file\_path
| basename }}
when:
- result\_authselect\_present.stat.exists
- name: Set PAM's Password Hashing Algorithm - Check if expected PAM module line
is present in {{ pam\_file\_path }}
ansible.builtin.lineinfile:
path: '{{ pam\_file\_path }}'
regexp: ^\s\*password\s+sufficient\s+pam\_unix.so\s\*.\*
state: absent
check\_mode: true
changed\_when: false
register: result\_pam\_line\_present
- name: Set PAM's Password Hashing Algorithm - Include or update the PAM module
line in {{ pam\_file\_path }}
block:
- name: Set PAM's Password Hashing Algorithm - Check if required PAM module line
is present in {{ pam\_file\_path }} with different control
ansible.builtin.lineinfile:
path: '{{ pam\_file\_path }}'
regexp: ^\s\*password\s+.\*\s+pam\_unix.so\s\*
state: absent
check\_mode: true
changed\_when: false
register: result\_pam\_line\_other\_control\_present
- name: Set PAM's Password Hashing Algorithm - Ensure the correct control for
the required PAM module line in {{ pam\_file\_path }}
ansible.builtin.replace:
dest: '{{ pam\_file\_path }}'
regexp: ^(\s\*password\s+).\*(\bpam\_unix.so.\*)
replace: \1sufficient \2
register: result\_pam\_module\_edit
when:
- result\_pam\_line\_other\_control\_present.found == 1
- name: Set PAM's Password Hashing Algorithm - Ensure the required PAM module
line is included in {{ pam\_file\_path }}
ansible.builtin.lineinfile:
dest: '{{ pam\_file\_path }}'
line: password sufficient pam\_unix.so
register: result\_pam\_module\_add
when:
- result\_pam\_line\_other\_control\_present.found == 0 or result\_pam\_line\_other\_control\_present.found
> 1
- name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result\_authselect\_present is defined
- result\_authselect\_present.stat.exists
- |-
(result\_pam\_module\_add is defined and result\_pam\_module\_add.changed)
or (result\_pam\_module\_edit is defined and result\_pam\_module\_edit.changed)
when:
- result\_pam\_line\_present.found is defined
- result\_pam\_line\_present.found == 0
- name: Set PAM's Password Hashing Algorithm - Check if the required PAM module
option is present in {{ pam\_file\_path }}
ansible.builtin.lineinfile:
path: '{{ pam\_file\_path }}'
regexp: ^\s\*password\s+sufficient\s+pam\_unix.so\s\*.\*\ssha512\b
state: absent
check\_mode: true
changed\_when: false
register: result\_pam\_module\_sha512\_option\_present
- name: Set PAM's Password Hashing Algorithm - Ensure the "sha512" PAM option for
"pam\_unix.so" is included in {{ pam\_file\_path }}
ansible.builtin.lineinfile:
path: '{{ pam\_file\_path }}'
backrefs: true
regexp: ^(\s\*password\s+sufficient\s+pam\_unix.so.\*)
line: \1 sha512
state: present
register: result\_pam\_sha512\_add
when:
- result\_pam\_module\_sha512\_option\_present.found == 0
- name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result\_authselect\_present.stat.exists
- |-
(result\_pam\_sha512\_add is defined and result\_pam\_sha512\_add.changed)
or (result\_pam\_sha512\_edit is defined and result\_pam\_sha512\_edit.changed)
when:
- '"pam" in ansible\_facts.packages'
- result\_pam\_file\_present.stat.exists
tags:
- CCE-82043-1
- CJIS-5.6.2.2
- DISA-STIG-RHEL-07-010200
- NIST-800-171-3.13.11
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(c)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.1
- PCI-DSSv4-8.3.2
- configure\_strategy
- low\_complexity
- medium\_disruption
- medium\_severity
- no\_reboot\_needed
- set\_password\_hashing\_algorithm\_systemauth