Passwd -a sha256|sha512 less secure than default

NB: Behavior may have changed since 2018 - Please read remainder of thread

While this has been suggested by some as in improvement in security, it appears to actually significantly reduce security as the salt and hash is not saved in its entirety in /etc/shadow.

Even with adding

CONFIG_BUSYBOX_CONFIG_SHA512SUM=y
CONFIG_BUSYBOX_CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="sha512"

the entire salt and hash is not saved in /etc/shadow

MD5:

$1$tQp3Abnw$xXJ0GXdIyirluUOHLku9/.

SHA256:

$53zwFqmYUjxY

SHA512:

$66to3JK5RgZM

What it should look like for SHA512:

$6$IOBMqc5q$TwDyyW8TTy7KC7F4e49.lZvyIq58FcjFwavsYXdSQtIAn5dvc0O1RqJfC8PB1itwYyySt8R8CnAMlw2eoHdfs0

While was discussed some time ago on the openwrt-devel list, there is information on threads here that have suggested passwd -a sha512 or the like as a security improvement, which it apparently is not. It is not clear from the wiki that there is a significant security downgrade by requesting or even compiling in more modern password authentication hash.

1 Like

I have noticed that to, I was so concerned about it that I went checking both if it was an error in Musl (no, can still get a correct hash on Openwrt using a hashing program) or an error in Busybox (also no, the very same version of Busybox does not have that problem in TinyCore Linux).
So it is clearly some bug in Openwrt/Lede.

That dev post is somewhat concerning, if SHA has been disabled, it should be disabled properly, not half way so that it still outputs data that is wrong.

This http://lists.uclibc.org/pipermail/uclibc-cvs/2015-January/031368.html is meant to be a fix (for uClibc), so it might need the same applied for Musl (or it could just be unbroken, which would solve all the problems).

The various SHA* algorithms are disabled with
https://git.openwrt.org/?p=openwrt/openwrt.git;a=blob;f=toolchain/musl/patches/901-crypt_size_hack.patch

The main issue imho is that musl crypt() is not returning NULL, errno = ENOSYS/EINVAL when an unsupported hash (any salt starting with dollar + digit) is requested.

@jeff, @jow,

The behavior you describe in the original post is not correct anymore. The current version 19.07 rc2, with busybox 1.31.1 (as of December 2019), has a crypt() function that behaves as expected for a *nix system:
http://man7.org/linux/man-pages/man3/crypt.3.html
After disabling the hack and setting the default password algorithm to SHA256, the shadow file shows passwords correctly hashed and formatted. Luci, though, seems to have trouble checking passwords stored with the stronger hashing algorithms.

There is a significant increase in the security of password storage from MD5 to SHA256, and even more to SHA512. The latter is the current default in many systems today.

Given the current guidance for users to stop using routers with 4MB of flash memory, most, if not all routers should be able to handle either of the SHA algorithms, and it is really poor practice to keep an old and outdated hashing algorithm alive.

I created a separate post in the developer area, but we need to clear inaccurate information so that users don't get the wrong idea about password security.

This works as expected today and should be enabled by default. The SHA hack should be removed from the code, or at the very least, disabled by default.

2 Likes

I can confirm, works fine.

1 Like

On further inspection, the Luci issue is also shared by Dropbear, which leaves users unable to log in via SSH. However, the issue is not with either package above. The problem is due to uClibc not implementing SHA256/512, which both Luci and Dropbear depend on in order to verify logins.

Rebuilding the system with libc++ instead solved the issue, and surprisingly for me, did not increase the firmware size. My test was on a minimal system.

Thanks @shm0 for confirming this works in other routers.

I’m assuming you meant musl, as that is the standard C library used by OpenWrt at this time. So then it seems nothing of consequence has changed, correct?

I don't have the exact timeline, but I think that at some point busybox didn't have SHA implementations for password hashing. When they tried to implement them, they realized that their C library (uClibc) didn't have them either, so they built their own and forced their login routines to use the internal implementations. That works for logging in to busybox in a local terminal, but breaks SSH or any other remote login (i.e. Luci, in our case).

In the meantime, someone tried to implement the stronger passwords in OpenWrt, but realized that they did not work. They put in a patch that failed silently and downgraded security to DES, instead of MD5. I think that's the time when your first post in this thread was created. Later on, though, after some complaints, the patch was updated to fail, without downgrade. This the current state and a more graceful failure.

What I discovered now is that, if one disables the SHA patch and rebuilds busybox with libc++, everything works. Since I had a minimal system, with a bunch of disabled stuff, even in busybox, the final binaries are not bigger than the uClibc. I can't say that this will be the case for a fully blown system, where libc++ implementations might make a big difference in size.

So, to answer your question, I think something did change since the first post, and it is the default behavior now. The other change is that we now have evidence that it is possible to implement stronger password security, but may involve serious changes for a system with default configuration. It doesn't seem to be the case for a minimalistic system.

The commit history of that "SHA patch" shows three commits with messages explaining the changes. The first ones date to 2015, long before this thread, and the latest one to this year. So, something has indeed changed...
https://git.openwrt.org/?p=openwrt/openwrt.git;a=history;f=toolchain/musl/patches/901-crypt_size_hack.patch;h=75f196abca5f44c3d17400d83f9eef30057bdff7;hb=HEAD

After the last change (in Jan 2019), there is also a menuconfig config option in master (and 19.07) to enable the SHA256 and SHA512 support with the standard musl libc.

https://git.openwrt.org/?p=openwrt/openwrt.git;a=commitdiff;h=ceb625439a84c7ea4ab1e39f126b6baffc48d1cd;hp=1211832977b98c491d1198ab66c4f8ffc0886a87

So, I am not sure if one needs currently to do anything else than just toggle the config option for musl, select the desired hash option for busybox and re-compile everything. (Note that musl is in the toolchain, so make sure to recompile also it.) Using the correctly configured musl should also reflect to dropbox etc., I think.

Ps.

Master branch has busybox 1.31.1, but unlike you say, 19.07 has busybox 1.30.1.

Pps.
uClibc has not been used for several years.

2 Likes

Thanks for clarifying the timeline. And the master vs rc2 bit too. I never installed rc2, I've always started by cloning the master branch, [re]configuring and then [re]building. Shouldn't have assumed that master and rc2 were the same.

I am confused, though, about uClibc not being used for years. When I first run make menuconfig right after downloading the source, uClibc appears as the default C library. It was only until after I changed that to libc++ and rebuilt the toolchain that my OpenWrt started working as expected with SHA256. Is this just an out of sync config option in the master branch?

PS. Yes, the rebuilt toolchain fixed all my problems at once, Luci and Dropbear didn't have any issues handling stronger hashes.

The default C library was switched from uclibc to musl in 2015:
https://git.openwrt.org/?p=openwrt/openwrt.git;a=commitdiff;h=a7780603923fddec225c9f4b0990fede4c2695a9;hp=aaf4aea141a6c0b33d6f4261e90151a51ef02a78

Currently the available choices for the main C library are musl and glibc.

 .config - OpenWrt Configuration
 > Advanced configuration options (for developers) > Toolchain Options ────────
...
  │ │          *** C Library ***                                          │ │  
  │ │          C Library implementation (Use musl)  --->                  │ │  
  │ │    [ ]   Include crypt() support for SHA256, SHA512 and Blowfish cip│ │  

You are probably mixing C++ libraries (like libc++) to the main C library in your analysis. The C++ libraries have a minor role in things. (And there the uClibc++ is still is use).

2 Likes

Thank you.

Yes, I must have not done a proper clean up between builds and then drew the wrong conclusions. This makes sense to me.

I'll start from scratch and only make the changes you suggest to confirm that's the proper way to enable stronger password hashing.

Thanks for your patience, this is very helpful :+1:

1 Like

I would think that this should be a 'default' I didn't know I had to go to the 'advanced' to enable the checksums. Thanks for the heads up though. Honestly, from a security perspective, if you they have your password file (physical access) its game over anyways.

Luci was broken with the 'defconfig' for x86_64. Hopefully someone will catch this and 'fix' in the next revision. Maybe sha256 should be a WORKING default?

I can confirm that sha256 indeed works if you choose 'advanced config' and 'enable crypt' as mentioned. I do think it should be a 'default' since the non-modifed config results in a brain-dead luci. Oh well.

From that discourse

All password hash algorithms except for MD5 (default) and DES (for
compatibility reasons) have been stripped from libc to cut down on
useless bloat.

If you care about password storage security, it's better to use a
function that was intentionally designed NOT to be fast, e.g. PBKDF2 or
bcrypt.

It does not make sense however to refer to bcrypt and then even compile it into the shadow package https://github.com/openwrt/packages/blob/master/utils/shadow/Makefile#L44 when at same time crypt_blowfish being stripped in the toolchain (in the same patch as SHA256|512).


Further from that discourse

I think switching from MD5 to SHA256/SHA512 is rather pointless.
It slows down password cracking by a small factor, but not by real
orders of magnitude,

That seems rather debatable as MD5 comes with fixed 64 rounds whilst SHA256|512 rounds are adjustable and even with the default of 5,000 rounds provides reasonable resistance. Increasing it to 15 <> 20 k makes it even difficult for quantum computing power.


Which leaves

been stripped from libc to cut down on useless bloat.

How much bloat?

14KB after LZMA on MIPS.

1 Like

Thank you for the input. Though it seems small probably every byte counts in the scheme of things.

Reconsider though

Either crypt_blowfish should be reinstated or bcrypt not compiled into shadow or else this setup makes no sense.

I have a PR in the works that switches shadow-utils to use libxcrypt and not the one in the libc.

1 Like

That would be splendid if accepted into the distro.