Zyxel hardcoded admin password found – patch now!


Towards the end of 2020, a researcher at Dutch cybersecurity company EYE was taking a look at the firmware of a Zyxel network router.

RELATED POSTS

He examined the password database that shipped in the firmware and noticed an unusual username of zyfwp.

That name didn’t show up in the official list of usernames shown in the router’s user interface…

…yet it did have a password hash in the database itself, which was interesting all on its own.

To explain.

Zyxel products are Linux-based, and Linux usernames and passwords are typically split between two files for security reasons.

The file /etc/passwd is usually world-readable and contains a list of known users, e.g.


root:x:0:0::/root:/bin/slash
bin:x:1:1::/bin:/bin/false
nobody:x:999:999::/nowhere:/bin/false
duck:x:1000:1000::/home/duck:/bin/fish

For reference: the first field on each line is the username; the third is the user’s numeric ID or UID (the root account is always UID zero); the sixth field is the user’s home directory; and the last one denotes the program to run when the user logs in, typically a command shell for regular accounts and /bin/false, a program that exits immediately with an error code, for other accounts.

The second field, intriguingly, is the user’s password.

Or, to be more precise, it used to be where Unix passwords were stored, thus keeping usernames and passwords together in one file for consistency and convenience.

But storing passwords, hashed or not, in a world-readable file was quickly found to be a terrible idea.

Even in the 1970s, hackers would routinely collect /etc/password files so they could crack them offline.

The early passwords of several Unix pioneers were cracked for fun in 2019 based on ancient password files embedded in the BSD-3 source code. Ken Thompson’s password, for example, turned out to be the chess move p/q2-q4!. Thompson himself rather nicely chimed in with congratulations to the finder.

So the “passwords” in /etc/passwd are now set to the letter x, acting merely as a placeholder, and the hashed passwords themselves are stored elsewhere, typically in a locked-down file called /etc/shadow, which might look like this:


root:$1$trymenow$loO18cesIqNfnT1c66lRV/:::::::
bin:*:::::::
nobody:*:::::::
duck:$1$trymetoo$8a7wRlziGi4YMvlmVy23V/:::::::

Accounts with “passwords” starting with a * character don’t have a password, so you can’t login interactively to those accounts (after all, there is no valid reply you could give at the password prompt that would hash to an asterisk character).

In the example above, the root and duck accounts do have passwords set, using hashing method $1$ (the no-longer-fit-for-purpose md5crypt algorithm – never use this in real life!), with salts trymemow and trymetoo respectively.

If, for instance, you can find the input that hashes via md5crypt to r0NTYRppwVIrSnk6OjqPI0 with salt trymenow (and why not try it now?), you just cracked the root password.

However, even if you can’t crack the password, the presence of a password hash in /etc/shadow nevertheless gives you a hint that the account concerned is intended for remote logins.