How to Execute Shell Commands as Another User in PHP (Bypassing www-data Limitations)


4 views

When working with PHP scripts executed via HTTP (not CLI), you'll encounter permission constraints because the web server typically runs under the www-data user. Here's why standard sudo approaches fail:

<?php
// These won't work as expected:
echo shell_exec('sudo -u targetuser command'); // Silent failure
echo shell_exec('whoami'); // Outputs: www-data

Three primary reasons:

  • PHP's shell_exec() doesn't provide an interactive terminal
  • Web server users are often restricted in sudoers configuration
  • Password prompts can't be handled in non-interactive environments

1. Sudoers File Configuration (Recommended)

Edit /etc/sudoers using visudo:

www-data ALL=(targetuser) NOPASSWD: /path/to/command
www-data ALL=(targetuser) NOPASSWD: /usr/bin/whoami

PHP implementation:

<?php
$output = shell_exec('sudo -u targetuser /path/to/command 2>&1');
echo $output;

2. Setuid Wrapper (Advanced)

Create a C wrapper:

#include <unistd.h>
#include <stdlib.h>

int main() {
    setuid(1000); // Target user's UID
    system("/path/to/command");
    return 0;
}

Compile and set permissions:

gcc wrapper.c -o wrapper
sudo chown root:root wrapper
sudo chmod 4755 wrapper

3. SSH Alternative

For remote commands:

<?php
$connection = ssh2_connect('localhost', 22);
ssh2_auth_pubkey_file(
    $connection,
    'targetuser',
    '/home/targetuser/.ssh/id_rsa.pub',
    '/home/targetuser/.ssh/id_rsa'
);
$stream = ssh2_exec($connection, '/path/to/command');
stream_set_blocking($stream, true);
echo stream_get_contents($stream);
  • Always specify exact commands in sudoers (no wildcards)
  • Regularly audit setuid binaries
  • Use SSH keys with restricted commands when possible
  • Consider creating a dedicated restricted user instead of using sudo

Check system logs when commands fail:

tail -f /var/log/auth.log

Test command execution flow:

<?php
echo "Attempting raw command:\n";
echo shell_exec('whoami 2>&1');

echo "\nTesting sudo:\n";
echo shell_exec('sudo -u targetuser whoami 2>&1');

echo "\nTesting with full path:\n";
echo shell_exec('sudo -u targetuser /usr/bin/whoami 2>&1');

When trying to run shell commands as a different user from PHP using shell_exec(), developers often encounter silent failures. The core issue stems from how PHP (running as www-data) interacts with sudo:

<?php
// These common approaches fail:
echo shell_exec('sudo -u myusername -S /usr/bin/whoami'); // Empty output
echo shell_exec('echo "mypass" | sudo -u myusername -S /usr/bin/whoami'); // Also empty
?>

Modern Linux systems implement several security measures that prevent this from working out of the box:

  • sudo requires TTY by default (disabled in PHP)
  • Password prompting doesn't work in non-interactive shells
  • Web server processes are heavily restricted by SELinux/apparmor

The most secure approach is to configure passwordless sudo access for specific commands:

# In /etc/sudoers.d/php_commands
www-data ALL=(myusername) NOPASSWD: /usr/bin/whoami
www-data ALL=(myusername) NOPASSWD: /path/to/your/script.sh

Now your PHP code can work without passwords:

<?php
echo shell_exec('sudo -u myusername /usr/bin/whoami'); // Success!
?>

For more complex scenarios, create a setuid wrapper:

#!/bin/bash
# /usr/local/bin/run_as_user.sh
su - myusername -c "$@"

Set permissions:

sudo chown root:root /usr/local/bin/run_as_user.sh
sudo chmod 4755 /usr/local/bin/run_as_user.sh

PHP usage:

<?php
echo shell_exec('/usr/local/bin/run_as_user.sh "whoami"');
?>

If using PHP-FPM, you can run the pool as your target user:

; /etc/php/7.4/fpm/pool.d/myuser.conf
[myuser]
user = myusername
group = myusername
listen = /run/php/php7.4-fpm-myuser.sock

Then route specific PHP scripts to this pool.

Always follow security best practices:

  • Restrict sudo permissions to specific commands only
  • Never expose password in PHP code
  • Consider using SSH with key authentication instead of sudo
  • Audit all commands run through these methods

For remote commands or better security:

<?php
$command = escapeshellarg('whoami');
echo shell_exec("ssh myusername@localhost {$command}");
?>

Configure SSH key authentication first for passwordless access.