0

I am trying to create a file when a user submits a form, using
exec("sudo touch a.cpp") or die("Unable to create file)";
Output: Unable to create file

I have checked following answers:
1: sudo in php exec()
2: https://askubuntu.com/questions/139723/sudo-does-not-ask-for-password/139733#139733
3: https://askubuntu.com/questions/810462/nopasswd-option-not-working-in-sudo?noredirect=1&lq=1
4: also tried exec("echo <password> | sudo -S touch a.cpp");

Added www-data ALL=(ALL) NOPASSWD: /var/www/html/<project-folder> in visudo

Nothing seems to work.

Update: As mentioned in comment by @Rolfie using fopen() resolves this issue but still i am unable to use any command using exec(), for example compiling a file again shows same error.

9
  • 1
    I don't think you should ever use sudo in an exec() function. Just make sure the directory is owned by the same user php uses. And make sure it has the rights to be edited. Commented Oct 8, 2018 at 12:07
  • I think you should use fopen() to create the file in stead of exec(). Once again the right of the directory should be correct. chmod and chown the directory in linux to the correct user. Commented Oct 8, 2018 at 12:12
  • @Rolfie using exec('fopen("a.cpp", "w")') or die("Unable to create file!"); doesn't work also, file has rights to be edited but is there a way to check and change ? Commented Oct 8, 2018 at 12:18
  • 1
    fopen() is a php function and not a linux function. So there is no need for exec. Just fopen("a.cpp", "w"); check php.net/manual/en/function.fopen.php. Commented Oct 8, 2018 at 12:23
  • Also touch() is a php function, check php.net/manual/en/function.touch.php . This should also do what you want to do. fopen is mostly used when you want to write something in the file, like a txt file. So maby touch() is the better option for you. Commented Oct 8, 2018 at 12:24

1 Answer 1

1

You don't have to run as root! My answer below does not require you to give root permissions to www-data.

This works - I tested on Ubuntu 20.04 LTS Server August 2021.

Let's begin:

Create a "sudocmds.txt" and "results.txt" text files outside of the web root path i.e.

If your webroot is /var/www/html/ then place your text files in /var/www/cmds/

Set permissions on the files to www-data:

sudo chown www-data /var/www/cmds/sudocmds.txt
sudo chown www-data /var/www/cmds/results.txt

I'll use iptables as an example to show "iptables -L" via a button press:

Create a form:

<form method="post">
<input type="hidden" name="cmd"> <br>
<input type="submit" name="cmd" value="CMD";">
</form>

Use PHP code to write a "1" to the sudocmds.txt file when the 'CMD' button is pressed:

<?php 
  if(isset($_POST['cmd']))
      {
       $data=$_POST['cmd'];
       file_put_contents("../cmds/sudocmds.txt", "1");
       sleep(1);
       echo nl2br( file_get_contents('../cmds/results.txt') );
      }
?>

Now create a service to run on your host that will monitor the file and look for that 1 to appear then exec a command.

For this I will use inotify-tools as an example:

sudo apt install inotify-tools -y

Create the script:

sudo nano /opt/cmd-watcher.sh

#!/bin/bash

inotifywait -mqr -e close_write "/var/www/cmds/sudocmds.txt" | while read line
do
if grep -q 1 "/var/www/cmds/sudocmds.txt"; then
  sudo iptables -L > /var/www/cmds/results.txt
fi
done

Make the script executable

sudo chmod +x /opt/cmd-watcher.sh

Run the script in the background

sudo sh /opt/cmd-watcher.sh &

Now go to your webpage refresh it and press the button, you will see the results of the command appear after 1 second :)

I know it's a bit of a process but it means that you don't have to have the security risk of running commands as root with www-data.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.