michael orlitzky

CVE-2017-14609: Kannel privilege escalation via PID file manipulation

posted 2017-09-20

Kannel (open source WAP and SMS gateway)
Versions affected
Published on
Bug report


The Kannel daemons create their PID files after dropping privileges to a non-root user. That may be exploited (through init scripts or other management tools) by the unprivileged user to kill root processes, since when a daemon is stopped, root usually sends a SIGTERM to the contents of its PID file (which are under the control of the runtime user).


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 signaled (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.

This is commonly exploitable through init scripts that are run as root and which blindly trust the contents of their PID files. Kannel itself ships a few such a init scripts as debian/*.init.


There is only a risk of exploitation when some other user relies on the data in the PID file.

An example scenario involving an init script would be,

  1. I run /etc/init.d/bearerbox start to start the daemon.
  2. bearerbox drops to the kannel user.
  3. bearerbox writes its PID file, now owned by the kannel 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/bearerbox stop to stop the daemon while I investigate.
  7. The machine reboots, because I killed PID 1 (this is normally restricted to root).


The Kannel daemons can be run in the foreground (by omitting the --daemonize, --pid-file, and --user flags) under a modern init system like systemd or OpenRC. Those init systems create the PID file as root, and it can be relocated to a root-owned directory like /run to avoid the vulnerability.

A SysV-style init script can mitigate the risk by verifying the PID data. You can get the user of the process whose PID you find with

root # ps -p <pid> -o user=

and you can get the name of the command with

root # ps -p <pid> -o comm=

Init script authors should check the output of those two command against the expected values before sending a signal to a running process. That will eliminate the most serious risks.