SSH allows root login with a password, and there is no non-root account #2

Closed
opened 2026-08-27 23:22:23 +00:00 by tiagoagueda · 2 comments
Owner

Effective sshd -T on the board:

permitrootlogin yes
passwordauthentication yes
pubkeyauthentication yes
permitemptypasswords no

root has a password set, and there are no non-root users at all. Only port 22 is listening,
which is the one good thing here.

Done when

  • a non-root admin user exists, with an authorized key and sudo
  • PermitRootLogin prohibit-password
  • PasswordAuthentication no
  • verified from a second session before the first is closed

⚠️ Do this with WiFi (192.168.27.45) or the serial console open as a fallback. Locking
yourself out of a headless board with no remote power control means a physical trip.

Effective `sshd -T` on the board: ``` permitrootlogin yes passwordauthentication yes pubkeyauthentication yes permitemptypasswords no ``` `root` has a password set, and there are no non-root users at all. Only port 22 is listening, which is the one good thing here. **Done when** - [ ] a non-root admin user exists, with an authorized key and sudo - [ ] `PermitRootLogin prohibit-password` - [ ] `PasswordAuthentication no` - [ ] verified from a *second* session before the first is closed ⚠️ Do this with WiFi (`192.168.27.45`) or the serial console open as a fallback. Locking yourself out of a headless board with no remote power control means a physical trip.
Author
Owner

Most of the checklist done 2026-08-29, verified from fresh sessions on both network paths.
Not closed
- the passwords are the owner's to set, and that is the last step.

  • a non-root admin user exists, with an authorized key and sudo - draco, uid 1000, in
    sudo, carrying the key root already trusted
  • PermitRootLogin prohibit-password
  • PasswordAuthentication no (plus KbdInteractiveAuthentication no, or PAM's
    keyboard-interactive route stays open)
  • verified from a second session before the first was closed
  • draco needs a password - for sudo and for the serial console
$ ssh draco@192.168.27.44 'echo ok'      -> ok
$ ssh draco@192.168.27.45 'echo ok'      -> ok      (wlan0, second path)
$ ssh -o PubkeyAuthentication=no root@…  -> Permission denied (publickey).

Applied as a drop-in. sshd_config has its Include at line 12, above its own
PermitRootLogin yes, and sshd keeps the first value it obtains for a keyword - so the
drop-in wins rather than being overridden by the line below. Validated with sshd -t before
reloading, and reloaded rather than restarted.

prohibit-password rather than no deliberately: root key login is how the deploy and probe
tooling reaches this board, and removing it would mean rebuilding all of that for no security
gain, since the key is the only credential either way.

⚠️ The serial console is not covered. serial-getty@ttyS0 authenticates through PAM
against /etc/shadow, so accounts still need real passwords for physical recovery - which is
exactly why this cannot be finished without you.

⚠️ The rescue SD card is a clone made before all of this and still accepts root with a
password. tools/sync-rescue-sd.sh now carries the hardening drop-in and the admin key, but
the card is not safe until it is re-synced.

And something worse turned up on the way

/ was owned by uid 1000 and group-writable, as were /usr/lib/modules and six files
under it - an orphaned uid from however this rootfs was built, harmless only because no
account had that uid.

Creating the admin account as uid 1000 would have handed it write access to / and to a
kernel modules directory
- a privilege-escalation path introduced by the act of fixing a
password problem. Caught because apt warned about an unsafe path transition while installing
sudo.

Fixed: root:root 755, draco verified refused write access to /, and nothing outside
/home is uid or gid 1000. Worth re-checking after any rootfs restore:

find / -xdev \( -uid 1000 -o -gid 1000 \) -not -path "/home/*"
**Most of the checklist done 2026-08-29, verified from fresh sessions on both network paths. Not closed** - the passwords are the owner's to set, and that is the last step. - [x] a non-root admin user exists, with an authorized key and sudo - `draco`, uid 1000, in `sudo`, carrying the key root already trusted - [x] `PermitRootLogin prohibit-password` - [x] `PasswordAuthentication no` (plus `KbdInteractiveAuthentication no`, or PAM's keyboard-interactive route stays open) - [x] verified from a second session before the first was closed - [ ] `draco` needs a password - for `sudo` and for the serial console ``` $ ssh draco@192.168.27.44 'echo ok' -> ok $ ssh draco@192.168.27.45 'echo ok' -> ok (wlan0, second path) $ ssh -o PubkeyAuthentication=no root@… -> Permission denied (publickey). ``` Applied as a drop-in. `sshd_config` has its `Include` at line 12, **above** its own `PermitRootLogin yes`, and sshd keeps the first value it obtains for a keyword - so the drop-in wins rather than being overridden by the line below. Validated with `sshd -t` before reloading, and reloaded rather than restarted. `prohibit-password` rather than `no` deliberately: root key login is how the deploy and probe tooling reaches this board, and removing it would mean rebuilding all of that for no security gain, since the key is the only credential either way. ⚠️ **The serial console is not covered.** `serial-getty@ttyS0` authenticates through PAM against `/etc/shadow`, so accounts still need real passwords for physical recovery - which is exactly why this cannot be finished without you. ⚠️ **The rescue SD card is a clone made before all of this** and still accepts root with a password. `tools/sync-rescue-sd.sh` now carries the hardening drop-in and the admin key, but the card is not safe until it is re-synced. ### And something worse turned up on the way `/` was owned by **uid 1000** and group-writable, as were `/usr/lib/modules` and six files under it - an orphaned uid from however this rootfs was built, harmless only because no account had that uid. **Creating the admin account as uid 1000 would have handed it write access to `/` and to a kernel modules directory** - a privilege-escalation path introduced by the act of fixing a password problem. Caught because `apt` warned about an unsafe path transition while installing sudo. Fixed: `root:root 755`, `draco` verified refused write access to `/`, and nothing outside `/home` is uid or gid 1000. Worth re-checking after any rootfs restore: ```sh find / -xdev \( -uid 1000 -o -gid 1000 \) -not -path "/home/*" ```
Author
Owner

Done 2026-08-29. Every box ticked and each one verified from a fresh session.

  • a non-root admin user exists, with an authorized key and sudo - draco, uid 1000
  • PermitRootLogin prohibit-password
  • PasswordAuthentication no (and KbdInteractiveAuthentication no, or PAM's
    keyboard-interactive route would stay open)
  • verified from a second session before the first was closed
ssh draco@192.168.27.44        -> ok
ssh draco@192.168.27.45        -> ok        (wlan0, independent path)
ssh -o PubkeyAuthentication=no -> Permission denied (publickey).
sudo -S -k id -un as draco     -> root
serial console, root + new pw  -> root@a80-debian:~#   (then logged out)

The serial console test matters because serial-getty@ttyS0 authenticates through PAM and is
not covered by any sshd setting - it is the physical recovery path, and it now works with the
new credential rather than the published one.

prohibit-password rather than no deliberately: root key login is how the deploy and probe
tooling reaches this board. The key is the only credential either way, so refusing it would
have cost a lot and bought nothing.

The part that was not in the plan

Installing sudo produced an odd apt warning about an unsafe path transition. Following it
up: / was owned by uid 1000 and group-writable, as were /usr/lib/modules and six files
under it - an orphaned uid from however this rootfs was built, harmless only because no
account had that uid.

Creating this admin account as uid 1000 would have handed it write access to / and to a
kernel modules directory.
A privilege-escalation path introduced by the act of closing a
password issue, and it would have been easy to close this ticket without noticing.

Fixed to root:root 755, draco verified refused write access to /, and nothing outside
/home is uid or gid 1000. Worth re-running after any rootfs restore:

find / -xdev \( -uid 1000 -o -gid 1000 \) -not -path "/home/*"
**Done 2026-08-29.** Every box ticked and each one verified from a fresh session. - [x] a non-root admin user exists, with an authorized key and sudo - `draco`, uid 1000 - [x] `PermitRootLogin prohibit-password` - [x] `PasswordAuthentication no` (and `KbdInteractiveAuthentication no`, or PAM's keyboard-interactive route would stay open) - [x] verified from a second session before the first was closed ``` ssh draco@192.168.27.44 -> ok ssh draco@192.168.27.45 -> ok (wlan0, independent path) ssh -o PubkeyAuthentication=no -> Permission denied (publickey). sudo -S -k id -un as draco -> root serial console, root + new pw -> root@a80-debian:~# (then logged out) ``` The serial console test matters because `serial-getty@ttyS0` authenticates through PAM and is not covered by any sshd setting - it is the physical recovery path, and it now works with the new credential rather than the published one. `prohibit-password` rather than `no` deliberately: root key login is how the deploy and probe tooling reaches this board. The key is the only credential either way, so refusing it would have cost a lot and bought nothing. ### The part that was not in the plan Installing `sudo` produced an odd apt warning about an unsafe path transition. Following it up: **`/` was owned by uid 1000 and group-writable**, as were `/usr/lib/modules` and six files under it - an orphaned uid from however this rootfs was built, harmless only because no account had that uid. **Creating this admin account as uid 1000 would have handed it write access to `/` and to a kernel modules directory.** A privilege-escalation path introduced by the act of closing a password issue, and it would have been easy to close this ticket without noticing. Fixed to `root:root 755`, `draco` verified refused write access to `/`, and nothing outside `/home` is uid or gid 1000. Worth re-running after any rootfs restore: ```sh find / -xdev \( -uid 1000 -o -gid 1000 \) -not -path "/home/*" ```
Sign in to join this conversation.
No description provided.