michael orlitzky

CVE-2017-11747: Tinyproxy privilege escalation via PID file manipulation​

Product
Tinyproxy
Versions affected
1.8.4 and earlier
Published on
2017-07-30
Author
Michael Orlitzky
Bug report
https://github.com/tinyproxy/tinyproxy/issues/106
MITRE
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11747

Summary

The tinyproxy daemon creates its PID file 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 the daemon is stopped, root usually sends a SIGTERM to the contents of the PID file (which are under the control of the runtime user).

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

Exploitation

There is only a risk of exploitation when some other user relies on the data in the PID file. However, the point of the PID file is to provide a daemon's PID to other users (mainly root). Therefore any use of the PID file is suspect.

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

  1. I run /etc/init.d/tinyproxy start to start the daemon.
  2. tinyproxy drops to the tinyproxy user.
  3. tinyproxy writes its PID file, now owned by the tinyproxy 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/tinyproxy 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).

Workaround

Tinyproxy can be run in the foreground with the -d flag 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.

However, Tinyproxy will still attempt to create the PID file specified in its configuration file, even when running in the foreground. You must therefore specify a dummy PID file in the Tinyproxy configuration—at a path writable by its unprivileged user—and ensure that no one attempts to use it for signaling the process. Something like,

1
PidFile "/var/lib/tinyproxy/dont-use-me-bad-bad-bad.pid"

is probably clear enough.