Is it safe to allow www-data to execute privileged commands?

Information Security Asked by UserK on December 26, 2020

I have noticed several questions on Stack Overflow, like this one, about executing commands with root privileges using PHP. The answer proposed to add the line


to the /etc/sudoers.d file.

Is it a safe approach to solve the problem? Does it create a vulnerability?

4 Answers

This... is atrocious. The whole point of running Web things as a non-root user is damage containment: in case the Web server process gets hijacked through some vulnerability, at least the attacker won't obtain full control of the machine, since he will be constrained by the limitations of the non-root account www-data. But if you give www-data a way to run every command it wishes to, with the rights of any user (including root), and without any further authentication, then you just lost that damage containment feature.

To be fair, www-data + sudo is slightly better than simply running everything as root, because the going-to-root has to be explicit; therefore, common flaws like a PHP script writing files in improper locations would be harder to exploit. But still, making www-data a member of the sudoers looks like a poor idea.

Correct answer by Tom Leek on December 26, 2020

I did some recent research and found some ways to do this, but as said by @tom-leek, it would in no way be 100% consistent, just a less unsafe method.

But there is a way that I believe is easy even for professionals with little experience like me!

The best secure method is to use the crontab.

  1. Save all your commands in a database (mysql whateaver)

  2. Create a cronjob to read these mysql entries and execute via exec() or shell_exec();

  3. Add these lines to cron

    crontab -e

            • killProcess.php

I prefer to check every 5s but you can check each 10 minutes, as you prefer.

  1. The PHP put values in db table, a simple table with 1 value worked for me and just it! $domain_name kkk

  2. The root user checks the table and get records, generate certificates and remove $domain_name of table.

You can use, I prefer Lego, but whatever.

  1. Create cron job and a basic script to renew certificates (most letsencrypt ways to deploy certificates have this ready and easy to deploy)
  2. Update nginx file with certificate files

If your system is hacked you never will lose your root access and can fix it quickly!

I found this good idea in this article:

Where killProcess.php fetches the process IDs from the database and execute the kill linux command(or any other linux commands as per your requirement) through the php function shell_exec().

Since the cronjob entry is configured as the root user, the specified script has all the same set of privileges as the root user.

Answered by felipecalil on December 26, 2020

Every time, with no exception, when you see ALL=(ALL) NOPASSWD: ALL in the /etc/sudoers file, someone deserves to be fired. Basically, you have a second root user.

Is it safe? Hell no. Does it create a vulnerability? Hell yes.

You can use sudo to safely grant a non-root user (including www-data) a privileged execution, but it should always be as specific as possible. If you need to run /usr/bin/my_system_tool +x /var/cache/my_cache as root for whatever reason, that exact command, including parameters should be in the /etc/sudoers file.

Answered by Tom on December 26, 2020

When considering how secure something is, you should assume the attacker is able to log in as your www-data user, and have a shell. This does not mean your attacker really can get a shell, but there can be plenty of ways how the attacker can execute arbitrary shell commands; they could be results of library bugs like shellshock, or oversights in your code.

The safest way

The best way of doing this is, like @AlexeyVesnin said, to use a specialized process to do the work. Have this process listen on a (unix domain, so it isn't reachable from the network) socket, read its input from said socket, sanitize the input(!), do the work, and return some result to the socket, from where the web server script reads results. Any authorization (user needs to enter some password on the web site to be allowed to do this) should be handled in that process, and the www-data user should not be able to read any of that authorization data.

The mostly-safe sudo way

In case your budget, or your skill, doesn't make this best approach feasible, using the sudo approach isn't completely wrong, but you should restrict sudo permissions to the minimum you actually need. For example, let's assume you want to show current disk I/O data on your web site, for which you need to call iotop:

  • make a script, in this example /var/www/bin/get-disk-io, that extracts the data you need:

    /usr/sbin/iotop -b -n 1 | /usr/bin/head -2

  • Do not allow the caller of the script to pass any parameters, i.e. the script shouldn't access $1, $2, ... , $*, $@
  • In case you absolutely have to use parameters, sanitize them in your script first. Especially pay attention to whitespace or any unusual characters that might be hidden in parameters.
  • Make sure to state the full path to every command in that script, so attackers can't replace any of those commands with their own
  • Allow access to this script, and only this script, in /etc/sudoers
  • Make sure env_reset is in the defaults policy in your sudoers file

Note that this is still safer than a suid program, since (a) you can restrict who can execute it, so an attacker who gains the ability to execute a program under a different user won't be able to use it, (b) you can't pass arbitrary parameters to it, (c) the environment is sanitized by sudo, and (d) you can make sudo log when the command gets executed, so you have an audit trail that a suid program doesn't give you.

The suid way

Note: Do not do this unless you know what you're doing. If you're asking, or reading, this question on stackexchange, you probably don't. So don't do this.

If you set the owner of an executable to a certain user (chown user /my/executable/file), then set the suid bit (chmod u+s /my/executable/file), then that program will run under the permissions of that user every time it is executed. So, for example, chown root /bin/cat; chmod u+s /bin/cat will run every invocation of cat with root rights, which means you can read every file on the system independent of its access rights. Do not try this on a system that is connected to a network, not even for 5 minutes to "check if it works".

  • On many unix systems, this works for compiled programs only, not for scripts that need an interpreter
  • In some configurations, for example if you run the program under strace, the s bit has no effect
  • In NFS configurations, root often doesn't have access to files on the NFS server, so this might even reduce what you're able to do.

The restricted-suid-Linux way

Linux has a capabilities system, that works almost like suid, but a much finer granularity. For example, if you need a process to be able to use port numbers below 1024, in classical unix systems, you need to run the command as root, often meaning you need to do the above chown/chmod u+s stuff, which allows using those port numbers, but also grants access to the filesystem. Linux allows you to give the port capability without everything else that comes with root:

setcap cap_net_bind_service+EP /path/to/my/program

Do man 7 capabilities to learn more. If you seriously consider giving suid to a program, think twice if setting a capability isn't a better idea.

Answered by Guntram Blohm on December 26, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP