Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

Using exec() for executing shell scripts in CGI

by stumbler (Acolyte)
on Dec 13, 2006 at 23:18 UTC ( #589693=perlquestion: print w/replies, xml ) Need Help??

stumbler has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks

I want to execute some programs from a CGI script. After browsing in perlmonks and reading perlsec, I found that I can use the following approach:-

die "Can't fork: $!" unless defined $pid = open(KID, "-|"); if ($pid) { # parent while (<KID>) { # do something } close KID; } else { exec 'myprog', 'arg1', 'arg2' or die "can't exec myprog: $!"; }

I have a shell script whose arguments are the path and the executable

Shell Script: #!/bin/ksh # print the arguments for checking # $1 is the directory # $2 is the executable echo $1 echo $2 # change dir to $1 cd $1 # execute $2 $2 echo "Exit"

and I execute that using 'exec' as shown

... ... $dir = 'some path'; # untainted $exe = 'some executable'; # untainted ... ... exec '', $dir, $exe ... ...

I am wondering if it is a good idea to execute unix shell scripts with some arguments as shown? I want to use this approach in CGI scripts to run executables from the web. ( Note that the 'executable' is preset inside the CGI script and IS NOT an user input.) Are there any security issues with this approach?

Replies are listed 'Best First'.
Re: Using exec() for executing shell scripts in CGI
by jarich (Curate) on Dec 14, 2006 at 12:17 UTC

    I think your solution may be verging on over-kill. You should be able to achieve the same effect with a direct call to system() or exec():

    my %commands = ( opt1 => "exe1", opt2 => "exe2", opt3 => "exe3", ); my $runmode = $cgi->param("runmode"); if(exists $commands{$runmode} ) { system( $commands{$runmode}, $arg1, $arg2 ); if($?) { handle_error(); } } else { handle_error(); # invalid $runmode }

    If you don't need to wait until the program returns, then replace system with exec.

    The important thing to be aware of here is that calls to system()/exec() make your code unportable. If you're trying to remove a file, make a directory, run "find", get a directory listing or other things like that, then you should be using Perl's built ins or appropriate modules (for example unlink, mkdir or File::Path, File::Find, opendir and readdir or glob).

    As far as security goes, you need to consider the following things:

    • Where you pass data from the web (for example the arguments) is that data properly untainted? (Can you think of any data options which will make it do the wrong thing?)
    • Can your executables survive being called out of order, or having multiple invocations running at the same time? (What happens if I hit reload 10 times? Or if I start something before you do?)
    • Is there a better way to achieve the same effect?

    I hope this helps.


    Update Sorry I should have been checking $? not $@ in my second if statement.

Re: Using exec() for executing shell scripts in CGI
by leocharre (Priest) on Dec 14, 2006 at 06:10 UTC

    I would be asking myself a few things.. For example; is there any chance that someone will run your bash/whatever script from the command line? What if you fed your executable script some bogus info, will it blow up, ruin something? I don't know that you have to make an executable any less secure then a regular cgi script. It *is* easier to debug though then stinkin' cgi.. ack.. ugh. *cough*.. excuse me.

    I'm not sure how far along you are in this venture- but i'll risk sounding obvious just in case and mention that: you have to remember that the script will not be run by *you*- it will be run by apache, or whatever user the web server is running as. Unless of course, you are running su exec- it lets scripts run with *your* permissions- super useful- but.. it means your scripts have the power to destroy any data that *you* can.

    Also, if you need your script to do some freaky business like add or take out real users fromthe machine, i would look into sudo, which let's regular users (maybe a safer *you* or apache) do things to the machine that only root regularly can.

    Personally, I have faced this kind of thing with making modules that have interface independent code/methods/subs- so.. it's really convenient for testing. And then your interface - be it cgi or cli- is almost (almost!) an afterthought.

    Your module code would check all the parameters to make sure they are not crud- and then after something happens, it can check that it really did happen- etc. If your cli or your cgi calls the stuff- the meat is the same.

    It's amazing how much the web can complicate a trivial task. sigh. Hope any of that helps.

      Thanks for the responses

      As mentioned in original post, I preset the executables I need to run using the following approach:-

      I have a hash which has the list of commands that can only be used. Something like..

      my %commands = ( opt1 => exe1, opt2 => exe2, opt3 => exe3, );

      In the CGI script, I have a variable , $runmode, which can take a value of 'opt1' or 'opt2' or 'opt3'. I retrieve the executable by $commands{ 'opt1' } and pass it on to the shell script.

      I don't do any admin activities such as adding new user, deleting or modifying existing user accounts, etc.. using CGI scripts.

A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://589693]
Approved by ikegami
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (5)
As of 2022-12-07 19:45 GMT
Find Nodes?
    Voting Booth?

    No recent polls found