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

Hi monks,
If I may impose again on your wisdom. I get the following errror:
Insecure $ENV{PATH} while running with -T switch at /home/www/cgi-bin/xilogin.cgi line 166, <CONFIG> line 189.
With the following code:
elsif ($get eq "password") { # Get user's e-mail my $username = param('username'); if ($username) { my $sql = "SELECT * from $meta_configs{login_table} where $meta_co +nfigs{login_username} LIKE '$username'"; my $sth = $dbh->prepare("$sql") or &graceful_exit("Cannot prepare +SQL statement: $DBI::errstr",$sql); $sth->execute or graceful_exit("Cannot execute: $DBI::errstr",$sql +); my $rows = $sth->rows; my $email; my $db_username; my $password; while (my $hash_ref=$sth->fetchrow_hashref) { $email = $hash_ref->{email}; $db_username = $hash_ref->{"$meta_configs{login_username}"}; $password = $hash_ref->{password}; } $sth->finish; # send password: open (MAIL, "| /usr/lib/sendmail $email");
The last line is the offending one. The variable $email comes not from a CGI param, but from a database query.

And yes, I can (and will) simply pass it through a regexp, but I'm interested in the why here, not the immediate solution to my problem.

Thanks!

Replies are listed 'Best First'.
(ichimunki) Re: why is this tainted?
by ichimunki (Priest) on Dec 29, 2001 at 00:00 UTC
    The error message doesn't say $email is tainted. $ENV{PATH} is. You must do something like $ENV{PATH} = '' to fix this, and then (as you are correctly doing) rely on providing the full path to your external applications in your script.

    Also, $email, coming from an external source (the database) *should* be considered tainted (and once you fix the PATH variable, you may get a message for $email). It is tainted because it was not provided by your script, nor was it "cleaned" by your script. If someone can put a harmful string into your database, they've just fouled up your pipe. You will want to verify that $email is a conformant email address before sending it to sendmail.

    All that said, I would strongly advise against using this sort of pipe to sendmail in a taint protected CGI. You might want to take a look at the various email modules on CPAN, especially Mail::Sendmail.
      Thanks - that makes sense.

      As to why I'm not using the Mail::Sendmail module (or others) is that this project is designed to be very portable, and work on systems where there may not be many modules installed. I can, of course include these modules in the source, but this system already depends on about 6 modules, and I'm trying not to have too many modules unless there are really compelling reasons. If I can handle things w/o a module fairly easily, I'm choosing that route.

        For portable system I would not hard code path to sendmail binary. First of all most (I've seen) systems (several Linux distros and FreeBSD) use /usr/sbin/sendmail by default. Probably using SMTP would be more portable (it is quite safe to use Net::SMTP since libnet is popular enough to be installed on most systems).

        But of course it is better to put such things in config.

        --
        Ilya Martynov (http://martynov.org/)

        I understand your reasons, and they are commonly given as reasons why people are unwilling to use (certain) modules. But the modules don't necessarily have to be installed by the administrator and available site wide. They are often just Perl scripts themselves-- which means that you could potentially include them in your tarball as just another *.pm file. Or even easier for all involved: simply copy them right into your script in their own package space. (Again, assuming they are not dependent on being compiled and using a shared library or something).

        But more importantly in the case of Mail::Sendmail... this module purports in its POD to *improve* portability by lessening the dependence on an actual sendmail executable. That right there is a compelling reason to give it a closer look, imho. Not to mention that whatever you are trying to do related to email has probably already been encoded there, which takes enormous weight off your shoulders.

        Of course, unless you are likely to need email functionality every time this script loads, that may be overkill... but shell calls are vulnerable in lots of ways plain old Perl scripts aren't, which is a good reason to avoid them if at all possible, and where they must be done, why it is preferable to use established and tested interfaces, rather than rolling our own.
        I see ichimunki has essentially said what follows, but let me just reiterate as this seems to be a FAQ.

        Some of the mail sending modules will get you additional portability as they either implement their own SMTP server or rely upon a local or remote server. Mail::Sendmail is good for this, and some even have fallbacks down to a standard binary... (mailx, sendmail, etc.) You might also wish to consult this node.

        --
        perl -pe "s/\b;([st])/'\1/mg"

(Ovid) Re: why is this tainted?
by Ovid (Cardinal) on Dec 29, 2001 at 00:11 UTC

    You actually have a few issues here. The first one is that your PATH variable is tainted. This is to prevent a clever cracker from figuring out how to set the path and have your code execute his or her "sendmail" program.

    Further, though I haven't tested it, I'm pretty durned sure that $email will be tainted. If it's not, it should be. Remember, taint checking is to ensure that no data derived from outside your program can affect anything outside of your program. Because you didn't explitly set $email in your program, you have no guarantee of it's value, and therefore it's effect on the overall program. Once again, a clever cracker finding a way to alter the contents of your database could make your life miserable.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: why is this tainted?
by derby (Abbot) on Dec 29, 2001 at 00:51 UTC
    michellem,

    It's probably not coming from $email but from $ENV{PATH}. (When running under taint mode, all command-line arguments, environment variables, and file input are marked as tainted). You can check the taintedness of variables with Devel::Peek and see what the "magic" is set to.

    use Devel::Peek; ... my $username = param( username ); Dump( $username ); my $sql = "select ...... LIKE '$username'"; Dump( $sql ); ... Dump( $email ); Dump( $ENV{PATH} );

    You should see something like this for $username and $sql and $ENV{PATH}.

    SV = PVMG(0x81f8890) at 0x8159bec REFCNT = 1 FLAGS = (GMG,SMG,pPOK) IV = 0 NV = 0 PV = 0x81f3630 "scooby"\0 CUR = 6 LEN = 80 MAGIC = 0x81f3688 MG_VIRTUAL = &PL_vtbl_taint MG_TYPE = 't' MG_LEN = 1

    that MG_TYPE of 't' is showing this scalar is tainted. I would be suprised to see that $email is tainted.

    -derby

Re: why is this tainted?
by gav^ (Curate) on Dec 29, 2001 at 00:02 UTC
    I'm not sure why, but I have a couple of comments anyway. Why do you use quotes around something that is a string anyway? i.e.: $hash_ref->{"$meta_configs{login_username}"}; looks better as $hash_ref->{$meta_configs{login_username}}; and $dbh->prepare("$sql") makes more sense as $dbh->prepare($sql)

    Also, you could consider using a module such as Mail::Sendmail which means your code is a lot more portable, especially on systems where /usr/lib/sendmail doesn't exist, which I assume will be plentiful. It also should fix the problem with taint.

    Also why the convulted way to get the username and password, whats wrong with:

    my ($email, $user, $pass) = $sth->fetchrow_array;
      Because this is part of a much larger system, and the schema of the tables that hold the login information is not determined by my script, but by the user.

      .Michelle

Re: why is this tainted?
by Fastolfe (Vicar) on Dec 29, 2001 at 09:13 UTC
    In addition to the enormous security problems other posters have pointed out with $email, I'd also like to point out that what you're doing with $username in $sql is also very bad. Consider using bind variables here. As it's written now, I can put whatever I want into username and it will be interpreted as raw SQL, which means I can do some potentially nasty stuff with your database.
    $sth = $dbh->prepare('select x, y from z where username=?') or die "prepare: ". $dbh->errstr; $sth->execute($username) or die "execute: ". $dbh->errstr;
Re: why is this tainted?
by aspitzer (Initiate) on Dec 29, 2001 at 01:48 UTC
    # send password:
        $ENV{"PATH"} = "";
        open (MAIL, "| /usr/lib/sendmail $email"); 
    
    http://www.perl.org/troubleshooting_CGI.html
    --------------------------------------------------------
    
    Is the script complaining about insecure dependencies? 
    
    If your script complains about insecure dependencies, you
    are probably using the -T switch to turn on taint mode.
    
    Any data originating from outside of the program (i.e. the enviroment) is considered tainted.
    
    Environment variables such as PATH and LD_LIBRARY_PATH are particularly troublesome.
    
    You have to set these to a safe value or unset them completely, as I recommend.
    
    You should be using absolute paths anyway.
    
    If taint checking complains about something else, make sure that you have untainted the data.
    
    See the perlsec man page for details. 
    
    -ans
    
    
Re: (Not about the Taint, but another suggestion) - why is this tainted?
by buzzcutbuddha (Chaplain) on Dec 29, 2001 at 21:04 UTC
    Since everyone's answered the question about the taint, I figured I'd mention one thing that jumped out at me immediately: the fact that you are using the email address right from the Param in a SQL Query without sanity-checking it to ensure it's a valid email address.

    That's a potentially big security hole, especially when combined with using 'LIKE' in your SQL statement to return matching records. Queries with 'LIKE' perform wildcard matching. If I was Mr. Bad Cracker I could pass your script an email along the lines of *hotmail.com and get back all records for everyone with a Hotmail account.

    Granted you are sending the password to an email address, so it's not immediately insecure, but a determined cracker could use this to get a passwords from your site.

    Instead of using 'LIKE' (which is also a performance hit since it has to do the wildcard-matching), I would suggest that you canonicalize on uppercasing or lowercasing all entries in your database and do the same to each email address your given, and use '=' in your SQL query. That way, the database can only return one record, and wildcards are treated as literal characters. And as I said before, always always make sure that it's a valid email address you've been given before you even perform your query.

    Cheers, Maurice