Drew Chapin
Drew Chapin

Reputation: 7989

param does not work when setuid bit is on in perl cgi script

When the permissions of this script are u=rwx,g=rwx,o=r the scripts works just fine... However, I need the setuid bit to be turned on so the call to smartctl returns the desired data instead of an error.

#!/usr/bin/perl

use strict;
use warnings;
use CGI qw(:standard);

my $device = param("device") || "sda";

print header("text/plain");

print "device = $device\n\n";


$ENV{"PATH"} = "/usr/sbin";
open( PS, "smartctl -A /dev/$device |" );
while( <PS> )
{
    print $_ . "\n";
}
close( PS );

When I set the permission to u=rwxs,g=rwxs,o=r, the script works when the query does not specify device. But then when device is specified, nothing gets returned after print "device = $device\n\n";

Upvotes: 0

Views: 706

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754520

You need to look at the configuration of Perl.

perl -MConfig -e 'print "d_suidsafe = $Configu{d_suidsafe}\n"; }'

If it doesn't say anything (nothing visible after the =), then Perl was told to consider SUID scripts as unsafe. It treats them differently from regular scripts. Check the 'taint' system (-T command line option) too; it should warn about the 'script injection' problem mentioned below.


Coding suggestions:

  1. Use the three-argument form of open.
  2. Check that the open succeeded.

Like this:

open my $PS, "-|", "smartctl -A /dev/$device"
  or die "Could not popen smartctl: $!";

Well, probably not die, but report the error cleanly and don't use the unopened file handle.

if (open my $PS, "-|", "smartctl -A /dev/$device")
{
    while (<$PS>)
    {
        print "$_\n";
    }
    close $PS;
}
else
{
    print "Failed to open device: $!";
}

Note that you need to reject or sanitize the input of the person who wrote: sda; cp /bin/sh /tmp/...; chmod 6777 /tmp/... in the device parameter field. It's a bit like SQL injection, only this time, it is 'Perl script injection'. They might be more brutal than that: sda; rm -fr / 2>/dev/null & does a fairly good job of cleaning out the system of files and directories which the user to whom the script is setuid can modify. You can't trust users an inch at the best of times. In a setuid program, trusting the users at all is a serious problem. All of that doubly (if not multiply) so when the access is from a web browser.

Upvotes: 2

Related Questions