Description
After login, pam_motd shows /etc/motd and a dynamic message built by running the executable
scripts of /etc/update-motd.d/ with run-parts. On Ubuntu, 00-header prints the full
distribution version and the kernel name, release and architecture
(Welcome to Ubuntu 24.04.5 LTS (GNU/Linux 6.8.0-147-generic x86_64)), and some other scripts
can repeat the version (on 20.04, the ESM notice of 91-contract-ua-esm-status).
This control runs the dynamic message as pam_motd does and checks that its output names
neither the running kernel release nor the Ubuntu <version> of the system.
The fix records the new mode with dpkg-statoverride, so a package upgrade (for example of
base-files, which owns 00-header) does not make the script executable again. Ubuntu ships no
/etc/motd; its check only applies when an administrator created one.
Rationale
The kernel release and the exact distribution version tell an attacker who reached a shell, or who only watches a session, which local privilege escalation exploits apply. There is no need to show them to every user at every login.
Impact
Users no longer see the welcome line with the version and kernel at login, nor any other
script that printed them. They can still run uname -a or lsb_release -a. The other parts of
the message (help links, system load, pending updates) are kept.
Setting
| Location | /etc/motd, /etc/update-motd.d/00-header |
| Default | 00-header executable, no /etc/motd |
| Recommended | Scripts that print the version or kernel not executable, /etc/motd without OS details |
Audit
- If
/etc/motdexists, it must not contain the escape sequences\m,\r,\s,\vorUbuntufollowed by a version. - Run
run-parts --lsbsysinit /etc/update-motd.das root. The output must not contain the result ofuname -r, norUbuntufollowed by theVERSION_IDof/etc/os-release.
Automated: every check must pass. Scanners report each check by its id.
motd-no-os
/etc/motd does not reveal the system version (not applicable when absent).
path: /etc/motd
pattern: \\[mrsv]|Ubuntu [0-9]
expect: no_match
dynamic-motd
Output of the dynamic MOTD scripts, as built by pam_motd.
script: |
[ -d /etc/update-motd.d ] || { echo "no /etc/update-motd.d"; exit 2; }
v=$(. /etc/os-release && printf '%s' "$VERSION_ID")
k=$(uname -r)
hits=$(timeout 120 run-parts --lsbsysinit /etc/update-motd.d 2>/dev/null | grep -F -e "$k" -e "Ubuntu $v")
if [ -n "$hits" ]; then printf '%s\n' "$hits" | head -n 3; exit 1; fi
echo "no kernel release or Ubuntu $v in the dynamic MOTD"
Remediation
- For each script of
/etc/update-motd.d/whose output shows the version or the kernel (00-headerby default), remove the execute bit in a way that survives upgrades:dpkg-statoverride --update --add root root 0644 /etc/update-motd.d/00-header. - Remove OS names, versions and escape sequences from
/etc/motd, if it exists.
| Restart | none |
| Disruption | none |
Rollback
For each changed script: dpkg-statoverride --remove /etc/update-motd.d/<script> then
chmod 755 /etc/update-motd.d/<script>.
scripts
#!/bin/sh
# CB-UBU-AUTH-002 / scripts - stop the dynamic MOTD scripts that print the OS version or the kernel release.
# The mode is recorded with dpkg-statoverride so package upgrades keep it. Idempotent.
# SPDX-License-Identifier: Apache-2.0
set -eu
d=/etc/update-motd.d
[ -d "$d" ] || exit 0
v=$(. /etc/os-release && printf '%s' "$VERSION_ID")
k=$(uname -r)
for f in "$d"/*; do
[ -f "$f" ] && [ -x "$f" ] || continue
timeout 60 "$f" 2>/dev/null | grep -qF -e "$k" -e "Ubuntu $v" || continue
if [ -L "$f" ]; then
echo "$f is a symbolic link and prints system details: review it by hand" >&2
exit 1
fi
dpkg-statoverride --list "$f" >/dev/null 2>&1 || dpkg-statoverride --update --add root root 0644 "$f"
chmod 0644 "$f"
echo "disabled $f"
done
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_motd(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- motd(5), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- update-motd(5), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- Ubuntu Server documentation - pam_motd Canonical, vendor-doc, accessed 2026-10-19
- dpkg-statoverride(1), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
Mappings
| Framework | ID | Relation | Note |
|---|---|---|---|
| NIST SP 800-53 Rev. 55.1.1 | AC-8 | related |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
| Taxonomy | ID |
|---|---|
| MITRE ATT&CK | T1082 |
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. Fails on a fresh install (00-header prints the version and kernel, the ESM notice repeats Ubuntu 20.04); fix sets both scripts to 0644 through dpkg-statoverride; kept after reboot; fix idempotent. |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic. Fails on a fresh install (00-header prints the version and kernel); fix sets it to 0644 through dpkg-statoverride; kept after reboot; fix idempotent. |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic. Fails on a fresh install (00-header prints the version and kernel); fix sets it to 0644 through dpkg-statoverride; kept after reboot; fix idempotent. |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic. Fails on a fresh install (00-header prints the version and kernel); fix sets it to 0644 through dpkg-statoverride; kept after reboot; fix idempotent. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |