posted 2017-12-29
UNIX daemons are long-running processes. They run in the background, and are usually started or stopped when the computer is started or stopped. The thing that starts and stops them is called a “service manager.”
A few popular service managers are OpenRC, systemd,
and SysV-init.
OpenRC and SysV-init start and stop daemons with what are basically
shell scripts, while systemd interprets and executes a
declarative configuration file innocent children,
presumably. They are all supposed to set up the temporary paths and
permissions that the daemon needs.
For increased security, daemons will do as much work as possible as an unprivileged, non-root user. OpenRC and systemd have the ability to launch the daemon as that unprivileged user. SysV-init, being mostly shell script, does not. To fake it, you would need to litter every init script with su calls.
Many daemons are designed to be launched as root but then drop privileges afterwards. This is done for two reasons:
If your daemon is launched as root and if its configuration file is writable by its unprivileged, runtime user, then you are probably screwed in one of two ways.
Most UNIX users own their own shit. If you don't think too hard about the little ballet that your service manager performs, then it can sound like a good idea to let the daemon users own their own shit, too. Whatever, I don't know, people just do it.
Often, the amount and type of shit that will be done as root is contained in the configuration file; the first way is for the unprivileged to simply change that shit.
Example: if port = 58008
is set in the configuration
file, and if the unprivileged user can edit that to say port =
80
, then he can cause a denial of service by stealing port 80
from your web server and a denial of boredom by redirecting your
visitors to 4chan.
Another example: suppose that keyfile =
/path/to/secret.key
is configurable and points to a private
key that needs to be read as root (because it's private).
The unprivileged user might change that path to trick root into
reading any file on the system. If the unprivileged user can see the
“private key data” at runtime, then he can read any file
on the system that way.
Another common practice is to specify the unprivileged user's name
inside the configuration file itself. Suppose the daemon is
running as the butthead user, because its configuration
file says username = butthead
. If butthead can
write to that configuration file, then he can change it to say
username = root
. The next time the daemon is started,
it won't drop privileges, and will instead do everything as root.
So why is that a problem? Well, the configuration file almost always lets you specify some kind of action; for example
mail_command = /usr/sbin/sendmail -f butthead@example.com
If butthead can change that, he can make it say,
mail_command = /home/butthead/lol_you_is_fucked.sh
The next time the daemon is started, it will do everything as root, including when it invokes that “mail command.” In cases like these, the unprivileged user can almost always gain full root privileges himself.
Are you even listening? Configuration should be owned and writable only by root. Pay special attention to the directories that contain your configuration files. Those need to be owned and writable only by root, too; otherwise the files can simply be replaced.
A related, but much stupider vulnerability exists when the daemon executable itself (as opposed to its configuration file) is writable or owned by a non-root user. That user can change the executable to do bad things, and then root will unwittingly run the modified code the next time that he starts the daemon.
Obviously, anything that might be run by root should be owned and writable only by root. This is obvious. This is obvious? This is obvious.