Setuid on scripts

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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s