The mention of setuid thing for storing personal secrets seemed a little odd, so I looked at the code. It seems the only thing that has been updated recently is the README and Makefile. scache.c has a few things that trip up new C programmers. A read of some resources on secure C programming is advised. A good place to start is:
The program checks to ensure it is running setuid. In that context the following are particularly dangerous:
- The path to the cache file is determined by looking at the HOME environment variable. Anyone that is calling that can set HOME to whatever they want, causing the cache file to be created in or deleted from any directory. It's better to use getpwuid(getuid()) to find the home directory of the running user.
- The use of stat() (instead of lstat()) and fopen() (instead of open() with O_CREAT|O_EXCL) opens the door to symlink attacks. This can allow creation of arbitrary files.
- popen() is used without clearing the environment. I think that most systems clear particularly dangerous environment variables from setuid programs (e.g. LD_PRELOAD, LD_LIBRARY_PATH) but there could be others (documented or not) that influence the behavior of the program called by popen() in a way that can be exploited by an attacker. Generally, a privileged program will drop privileges and sanitize the environment before calling subprocesses. popen() is not a rich enough interface to make that easy.
There are other smaller issues (e.g. memory leaks, unclear handling of buffer sizes, failure to check returns from functions that could fail, etc.). Additionally, if home directories are on NFS, it is quite unlikely that this program will be able to create the file with root ownership ("root squash"). I don't immediately see how these could be exploited.
Another comment mentions a bunch of prior art. Those are probably better things to be looking at than trying to invent something new in this space.
That being said, there are a number of interesting concepts that the author needed to explore to get to this point. Hopefully this comment is helpful in understanding some next steps to take in understanding some of the pitfalls of C programming and setuid.
As you might imagine, there is some prior art in this space.
In broadly portable Unix userspace, there is GNOME Keyring. It takes special caution to pin secrets in memory (prevent swapping them to disk) and to zero out secrets before freeing them. For session-lifetime password store, it never writes the secrets to disk at all. Keyrings are encrypted with a key derived from a master password for each ring. I don't know what key derivation algorithm is used. For persisted secrets, I imagine they are stored encrypted on disk using something derived from the keyring password.
In the Linux kernel, there is the infrastructure behind the user interface keyctl(1). I am basically unfamiliar with it aside from knowing it exists.
On MacOS, there is Keychain. Ditto.
On Windows, there is the CryptProtectData / CryptUnprotectData family of functions, which theoretically ties the encryption to the current user. Using that nice primitive, one can just encrypt and then write out to any old file on disk.
I'm a little confused here. The author compares S-Cache to 'sudo'. 'sudo' is a command that lets an unprivileged user run a privileged command. S-Cache lets a process access a secret without having to manage it. The process (in a sense) is not _privileged_ enough to see the secret but rather delegates this to S-Cache.
The author (as far as I can tell) does not mention the shadow passwords file. Can you explain more?
[+] [-] mgerdts|6 years ago|reply
https://security.web.cern.ch/security/recommendations/en/cod...
The program checks to ensure it is running setuid. In that context the following are particularly dangerous:
- The path to the cache file is determined by looking at the HOME environment variable. Anyone that is calling that can set HOME to whatever they want, causing the cache file to be created in or deleted from any directory. It's better to use getpwuid(getuid()) to find the home directory of the running user.
- The use of stat() (instead of lstat()) and fopen() (instead of open() with O_CREAT|O_EXCL) opens the door to symlink attacks. This can allow creation of arbitrary files.
- popen() is used without clearing the environment. I think that most systems clear particularly dangerous environment variables from setuid programs (e.g. LD_PRELOAD, LD_LIBRARY_PATH) but there could be others (documented or not) that influence the behavior of the program called by popen() in a way that can be exploited by an attacker. Generally, a privileged program will drop privileges and sanitize the environment before calling subprocesses. popen() is not a rich enough interface to make that easy.
There are other smaller issues (e.g. memory leaks, unclear handling of buffer sizes, failure to check returns from functions that could fail, etc.). Additionally, if home directories are on NFS, it is quite unlikely that this program will be able to create the file with root ownership ("root squash"). I don't immediately see how these could be exploited.
Another comment mentions a bunch of prior art. Those are probably better things to be looking at than trying to invent something new in this space. That being said, there are a number of interesting concepts that the author needed to explore to get to this point. Hopefully this comment is helpful in understanding some next steps to take in understanding some of the pitfalls of C programming and setuid.
(edited for formatting)
[+] [-] lisper|6 years ago|reply
[+] [-] loeg|6 years ago|reply
In broadly portable Unix userspace, there is GNOME Keyring. It takes special caution to pin secrets in memory (prevent swapping them to disk) and to zero out secrets before freeing them. For session-lifetime password store, it never writes the secrets to disk at all. Keyrings are encrypted with a key derived from a master password for each ring. I don't know what key derivation algorithm is used. For persisted secrets, I imagine they are stored encrypted on disk using something derived from the keyring password.
In the Linux kernel, there is the infrastructure behind the user interface keyctl(1). I am basically unfamiliar with it aside from knowing it exists.
On MacOS, there is Keychain. Ditto.
On Windows, there is the CryptProtectData / CryptUnprotectData family of functions, which theoretically ties the encryption to the current user. Using that nice primitive, one can just encrypt and then write out to any old file on disk.
[+] [-] mothershipper|6 years ago|reply
If someone steals the shadow password file, they still have quite a bit of computation to do to crack the credential.
[+] [-] blendergeek|6 years ago|reply
[+] [-] catlifeonmars|6 years ago|reply