Description
pam_unix checks local passwords against /etc/shadow. Three options matter here:
nulloklets accounts with an empty password field authenticate with no password. Ubuntu sets it in the defaultunixprofile;- the hashing method used when a password is changed:
yescryptfrom Ubuntu 22.04,sha512on 20.04, whosepam_unix(PAM 1.3.1) does not support yescrypt. Older methods (md5,bigcrypt, DES) are fast to crack; use_authtokin the password stack:pam_unixstores the new password that the modules before it (quality check, history) accepted, instead of asking for it again unchecked.
The packaged unix profile is replaced by a copy without nullok, so package upgrades do not
bring the option back. Passwords keep their current hash until they are changed.
pam-auth-update writes use_authtok on the pam_unix.so password line only when another
password module runs before it. On a default system pam_unix is first and the option is
absent: it appears once pam_pwquality (CB-UBU-AUTH-010) or pam_pwhistory
(CB-UBU-AUTH-012) is enabled. Adding it by hand while pam_unix is first would break password
changes.
Rationale
An empty password field, created by mistake or by a tool, becomes an open account as long as
nullok is present. A weak hashing method lets an attacker who copies /etc/shadow recover
passwords quickly.
Impact
Accounts with an empty password can no longer log in with a password. Give them a password, or
lock them with passwd -l.
Setting
| Location | /usr/share/pam-configs/cirsec_unix |
| Default | nullok; yescrypt (sha512 on 20.04); no use_authtok |
| Recommended | No nullok, yescrypt or sha512, use_authtok |
Audit
- No
pam_unix.soline in/etc/pam.d/common-author/etc/pam.d/common-passwordcontainsnullok. - The
pam_unix.soline of/etc/pam.d/common-passwordcontainsyescryptorsha512, anduse_authtok.
Automated: every check must pass. Scanners report each check by its id.
no-nullok-auth
path: /etc/pam.d/common-auth
pattern: pam_unix\.so.*\bnullok\b
expect: no_match
no-nullok-password
path: /etc/pam.d/common-password
pattern: pam_unix\.so.*\bnullok\b
expect: no_match
strong-hash
path: /etc/pam.d/common-password
pattern: ^\s*password\s+.*pam_unix\.so.*\b(yescrypt|sha512)\b
use-authtok
pam_unix stores the password accepted by the modules before it.
path: /etc/pam.d/common-password
pattern: ^\s*password\s+.*pam_unix\.so.*\buse_authtok\b
Remediation
- Lock or set a password for every account with an empty field:
awk -F: '$2==""' /etc/shadow. - Copy
/usr/share/pam-configs/unixto/usr/share/pam-configs/cirsec_unix, remove everynullok, changeName:and make sure thePassword:lines carryyescrypt(sha512on 20.04). - Run
pam-auth-update --enable cirsec_unix --disable unix. On Ubuntu 20.04 and 22.04, whosepam-auth-updatehas no--disable, runpam-auth-update --enable cirsec_unix --remove unix, then add aunixline to/var/lib/pam/seenso that later runs do not enable the profile again. - Enable a password quality or history module (CB-UBU-AUTH-010, CB-UBU-AUTH-012) so that
use_authtokis written on thepam_unix.sopassword line. - Check that a new login still works before closing your session.
| Restart | none |
| Disruption | low |
| Lockout risk | yes: can cut off administrative access. Off by default in generated scripts and playbooks, opt in through a tailoring file. |
Rollback
Run pam-auth-update --enable unix --remove cirsec_unix and delete the profile file.
profile
p=/usr/share/pam-configs/cirsec_unix
sed -e '/^Name:/!s/[[:space:]]nullok\b//g' \
-e 's/^Name: .*/Name: CIRSEC - Unix authentication without nullok/' /usr/share/pam-configs/unix >"$p"
h=yescrypt
[ "$(. /etc/os-release && printf '%s' "$VERSION_ID")" != 20.04 ] || h=sha512
grep -q yescrypt "$p" || grep -q sha512 "$p" || sed -i "s/\(pam_unix\.so obscure\)/\1 $h/" "$p"
for f in /etc/pam.d/common-auth /etc/pam.d/common-password /etc/pam.d/common-account /etc/pam.d/common-session; do cb_backup "$f"; done
if grep -q -- '--disable' /usr/sbin/pam-auth-update; then
DEBIAN_FRONTEND=noninteractive pam-auth-update --enable cirsec_unix --disable unix
else
# Ubuntu 20.04 and 22.04: no --disable. Remove the profile, then mark it as seen so later
# runs (package upgrades, other profiles) do not enable it again as a new default.
DEBIAN_FRONTEND=noninteractive pam-auth-update --enable cirsec_unix --remove unix
grep -qx unix /var/lib/pam/seen || echo unix >>/var/lib/pam/seen
fi
Handwritten code reads parameters from CB_<NAME> environment variables. Each release turns these fixes into remediate.sh and an Ansible role per profile: dry run by default, a fix runs only when its check fails.
References
- pam_unix(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- pam-auth-update(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R68) ANSSI, guide, accessed 2026-10-19
Mappings
| Framework | ID | Relation | Note |
|---|---|---|---|
| ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0 | R68 | partial | R68 is about protecting stored passwords; this control covers the hashing method. |
| NIST SP 800-53 Rev. 55.1.1 | IA-5(1) | partial |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
Related controls
- related
CB-UBU-AUTH-010Enforce password quality with pam_pwquality - related
CB-UBU-AUTH-012Prevent reuse of recent passwords
People and lifecycle
| Authors |
|
| Verified | 2026-10-19 by Sn0wAlice on 20.04, Proxmox VM, Ubuntu 20.04 cloud image, kernel 5.4.0-216-generic. nullok removed through the cirsec_unix profile (--remove unix and seen entry, no --disable on this release), sha512 kept, use_authtok present; password login works with pamtester (login, sshd, sudo); unchanged after dpkg-reconfigure libpam-runtime and reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic. nullok removed through the cirsec_unix profile (--remove unix and seen entry, no --disable on this release), use_authtok present; password login works with pamtester (login, sshd, sudo); unchanged after dpkg-reconfigure libpam-runtime and reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic. nullok removed through the cirsec_unix profile (--disable unix), use_authtok present; password login works with pamtester (login, sshd, sudo); unchanged after dpkg-reconfigure libpam-runtime and reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic. nullok removed through the cirsec_unix profile (--disable unix), use_authtok present; password login works with pamtester (login, sshd, sudo); unchanged after dpkg-reconfigure libpam-runtime and reboot. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |