SMS Server Tools 3
 Menu
Basic information:
Additional information:
Support:
Get SMS Server Tools 3:
Additional Options

 Sponsored links

 Search
Custom Search

 Visitor locations
 
 SMS Server Tools 3 Community
Welcome, Guest. The forum is currently read-only, but will open soon. Sat Oct 12, 2024 09:16
SMSTools3 Community » Bug reports Bottom

Privilege escalation via PID file manipulation

Login and Post Reply

Page:  1

Author Post
Member
Registered:
Aug 2017
Location: United States of America
Hi, I've found a minor security issue in smsd.

Summary

The smsd daemon should create its PID file before dropping
privileges. This represents a minor security issue; additional factors
are needed to make it exploitable.

Details

The purpose of the PID file is to hold the PID of the running daemon,
so that later it can be stopped, restarted, or otherwise signalled
(many daemons reload their configurations in response to a SIGHUP).
To fulfil that purpose, the contents of the PID file need to be
trustworthy. If the PID file is writable by a non-root user, then he
can replace its contents with the PID of a root process. Afterwards,
any attempt to signal the PID contained in the PID file will instead
signal a root process chosen by the non-root user (a vulnerability).

This is commonly exploitable by init scripts that are run as root and
which blindly trust the contents of their PID files. The SMS Server
Tools themselves ship such an init script, scripts/sms3, which
contains e.g. the following:



In the above snippet, the contents of the $PID variable are controlled
by the smsd daemon user, while "kill" is run as root.

Exploitation

An example of a problematic scenario involving an init script would be,

1. I run "/etc/init.d/smsd start" to start the daemon.

2. smsd drops to the "smsd" user.

3. smsd writes its PID file, now owned by the "smsd" user.

4. Someone compromises the daemon.

5. The attacker is generally limited in what he can do because the
daemon doesn't run as root. However, he can write "1" into the
PID file, and he does.

6. I run "/etc/init.d/smsd stop" to stop the daemon while I investigate
the weird behavior resulting from the hack.

7. The machine reboots, because I killed PID 1 (this is normally restricted
to root).

Resolution

The problem is avoided by creating the PID file as root, before dropping
privileges.

Note however that currently, smsd tries to clean up its PID file if the
daemon terminates abnormally:



That will no longer be possible if the PID file is owned by root and the
daemon is running as a restricted user. Instead, the init system should
check to see if killing the daemon worked, and if it did, remove the PID
file.

Administrator
Registered:
May 2009
Location: Jyväskylä, Finland
Thanks for your report.

I think that I should at least fix the init script. After it does not blindly trust to the content of pid file, the major issue is gone, I believe. Like in some other daemons, pidof command could be used and the content of pid file could be just verified, or even ignored.

It would be easy change to create pid file before privileges are dropped, but as smsd is then unable to remove the file, other variations of init script may fail. However, this same happens when daemon is killed with SIGKILL. I still have to think about this and look at other variations of init scripts.

Member
Registered:
Aug 2017
Location: United States of America
Topic owner
I've tried to write a pure-POSIX init script that does this correctly, and it's a lot harder than it sounds. With `pidof`, the problem is that it can return more than one PID. With most init systems, it's possible to run multiple instances of a daemon with e.g. different config files. You wouldn't want to kill them both when you stop one, and there's no way to tell them apart. It's unlikely, but you also risk killing the processes of anyone who is running smsd interactively (say, to test a patch out of his home directory).

You could check that the PID contained in the PID file matches one of the PIDs returned by `pidof`, but even then, that could kill a second smsd running under a different user. And `pidof` is part of a third-party package that isn't guaranteed to be installed =)

I wouldn't swear that it can't be done, but it's not straightforward. And everyone who ships an init script would have to implement the same tricks.

The reason I suggested creating the PID file before dropping privileges is that, relatively at least, it's easy to write the PID file cleanup code. All I have to do in my init script is check if the process I tried to kill is gone, and rm the PID file if it is. That takes a line or two and is hard to get wrong -- many init systems (I have experience only with OpenRC) can even take care of it for you.

Administrator
Registered:
May 2009
Location: Jyväskylä, Finland
Actually, smsd is able to remove the pidfile even when it's owned by root and is not writable for smsd. That is because the directory /var/run/smstools is owned by smsd:smsd. This directory must be writable because the infofile is also created into this directory, and during that the smsd is running as a restricted user.

Both fixes will be done, and also in the init script there is a bug which causes too much killing in certain situations, when smsd is searched using grep without --word-regexp.

`pidof` will not be used, as the same functionality can be done using general commands. Basically it is verified that the pid from pidfile really belongs to smsd, and in this case only one process is terminated. That process takes care on the rest.

If pidfile is corrupted or missing, all smsd processes are killed softly by the name. Also if we are killing processes hardly, it's based on names. Therefore only single smsd is allowed to run at the same time. If more daemons are required, they should have unique names and configuration, like pidfile. For example we can run smsd_usa and smsd_finland, and they do not interfere with each other.

My script certainly is not POSIX compliant, I guess, but the requirements are also slightly different than usual. For example, when a process asked to terminate, it is not wanted that it's terminated right now. Kill -9 is for that, like argument force-stop in the init script is using. In the normal cases smsd will complete the job which was already started, and then stops without loosing messages or corrupting them.

Member
Registered:
Aug 2017
Location: United States of America
Topic owner
Quote
Actually, smsd is able to remove the pidfile even when it's owned by root and is not writable for smsd. That is because the directory /var/run/smstools is owned by smsd:smsd. This directory must be writable because the infofile is also created into this directory, and during that the smsd is running as a restricted user.

Once the PID file is created by root, you would store it directly in /var/run (which is owned by root) and not /var/run/smstools.


Quote
My script certainly is not POSIX compliant, I guess, but the requirements are also slightly different than usual.

The reason I'm harping on POSIX compliance is because, when I announce this, I'd like to be able to tell people how to fix it. Anyone who can use your init script might be OK, but for example, I discovered the issue on Gentoo. They have an official smstools package, and their init scripts might be run on Linux, FreeBSD, or even OSX. If your stop() function won't run on one of those systems, then I can't just say "copy and paste the upstream stop() function" to the Gentoo maintainer.

Login and Post Reply

Page:  1

SMSTools3 Community » Bug reports Top

 
Time in this board is UTC.  

Privacy Policy   SMS Server Tools 3 Copyright © Keijo Kasvi.