Running scripts as another user might sound like a trivial task, as this is what setuid is supposed to solve. However, if you create a bash script, a php script or another type of script you will soon discover that they do not respond to the setuid flag. This is mainly because of security and the fact that the scripting languages usually have not implemented the setuid functionality at all.
The easiest way of accomplishing this is to create a wrapper program that runs your script for you. C is a good language for this. The following file is an example on how to run a php as setuid.
Wrapper.c
#include #include #include int main(void) { system("/usr/bin/php /home/www-config/bin/createConfig.php"); return 0; }
The script can be compiled with cc Wrapper.c -o Wrapper, if you have gcc installed. After compiling, you will need to set the setuid flag on the executable by issuing the chmod u+s Wrapper command. Now you can issue ./Wrapper to run the php script given.
Let’s pretend we have a Linux system with two users good and workaround. Log onto the system as user workaround and create compile Wrapper.c. After issuing chmod u+s Wrapper, do a ls -al and you should see something like the following:
total 40 drwxr-xr-x 4 workaround workaround 136 Sep 21 11:04 . drwxr-xr-x 22 workaround workaround 748 Sep 21 11:03 .. -rwsr-xr-x 1 workaround workaround 12588 Sep 21 11:04 Wrapper -rw-r--r-- 1 workaround workaround 195 Sep 21 11:04 Wrapper.c
Note the highlighted s in the permissions of the Wrapper file, this is the setuid flag. Now log into the good user and run this script. This will now be run as the workaround user, since the setuid flag is set and the file is owned by the workaround user.
You might be tempted to take the script name as an argument. Do not do this, as this severly decreases the security! If you really want to do simething like this, please use predefined commands and give the command line argument as the “command number 3”. This way no malicious user can execute all commands through this script.
For more information, I would recommend this article.
Privilege separation from the www-data user
So, I got a question down in the comment section and will respond to it here for better formatting š I have the following 3 files.
/home/www-config/bin/createConfig.php
<?php mkdir("/home/www-config/mytestfolder"); ?>
/home/www-config/bin/createConfig.c
#include #include #include int main(void) { system("/usr/bin/php /home/www-config/bin/createConfig.php"); return 0; }
/home/marius/public_html/test/index.php
<?php exec("/home/www-config/bin/createConfig"); ?>
I have compiled the createConfig.c file and set the setuid bit, as explained in the guide.
ls -al
marius@debiansrv:~/public_html/test$ ls -al /home/www-config/bin/ drwxr-xr-x 2 www-config www-config 4096 Oct 11 11:14 . drwxr-xr-x 3 www-config www-config 4096 Oct 11 11:14 .. -rwsr-xr-x 1 www-config www-config 6618 Sep 20 23:08 createConfig -rwx------ 1 www-config www-config 163 Sep 20 23:08 createConfig.c -rwx------ 1 www-config www-config 51 Oct 11 11:09 createConfig.php
Here is the output of ls -l before and after I use my browser to visit ~/marius/test/.
ls -l /home/www-config
# Before going to the url drwxr-xr-x 2 www-config www-config 4096 Oct 11 11:14 bin # After drwxr-xr-x 2 www-config www-config 4096 Oct 11 11:14 bin drwxr-xr-x 2 www-config www-data 4096 Oct 11 11:18 mytestfolder
I also tested this with the root user, which also worked.