Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Trojan Horse? (taint mode)

by IraTarball (Monk)
on Nov 25, 2001 at 10:44 UTC ( #127370=perlquestion: print w/ replies, xml ) Need Help??
IraTarball has asked for the wisdom of the Perl Monks concerning the following question:

I was reading Advanced Perl Programming and came across this little warning about double quote interpolation. The author warns that a string like "$a" does variable interpolation. No surprise there. Then he say's "But you now know that "a" can be replaced ba a block as long as it returns a reference to a scalar..." and so we should be worried about someone filling a variable with {system('/bin/rm -rf /*')} and maybe doing 'bad things' to us.

Now for the question.

Isn't a variable only interpolated once? I mean, when I try the following...

perl -swe 'while (<STDIN>) {print "$_"}'
and I type in {system('rm -rf *')} it just prints {system('rm -rf *')} without executing the system call. This is just what I would have expected before reading the quoted material. Am I missing something though?

Along these lines, I'm under the impression that tainted data is mainly a concern if you're going to eval it, or pass it to system or backticks, are there any really sneaky situations that I'm missing?

The reason the above caught my attention was that it implied that every program where I echo user input would need to be run in taint mode. I think that would suck.

What do you think?

Ira,

"So... What do all these little arrows mean?"
~unknown

Comment on Trojan Horse? (taint mode)
Select or Download Code
Re: Trojan Horse? (taint mode)
by dws (Chancellor) on Nov 25, 2001 at 10:53 UTC

    I'm under the impression that tainted data is mainly a concern if you're going to eval it, or pass it to system or backticks, are there any really sneaky situations that I'm missing?

      open(IN, $file);

    can really spoil your day if $file contains   "| rm -f *"

      The author warns that a string like "$a" does variable interpolation. No surprise there. Then he say's "But you now know that "a" can be replaced ba a block as long as it returns a reference to a scalar..." and so we should be worried about someone filling a variable with {system('/bin/rm -rf /*')} and maybe doing 'bad things' to us.

      In my humble opinion, by his statement, "a" can be replaced, the original author may be discussing literally replacing the letter 'a' in the expression, "$a", with an actual (curly brace-delimited) block of code; in other words, changing the expression (quotes and all), "$a" to the different other expression, "${system('/bin/rm -rf /*')}", not necessarily assigning such a string as "{system('/bin/rm -rf /*')}", to the variable, $a and interpolating that.

      I by no means intend, by posting this reply, to minimize the importance of the interpolation discussions. Nor is it my purpose to cast a pall on any of the extemely pertinant, valid points made in any of those threads.

      However, the questions being discussed do not seem to me to be addressing the behavior described (as I read it) by the original author (not that it was especially well written). Perhaps all is right with the world and interpolation is, in fact, predictable.

      dmm

      
      You can give a man a fish and feed him for a day ...
      Or, you can teach him to fish and feed him for a lifetime
      
        The only problem with that interpretation is that it doesn't match the "Moral of the Story" (which is "Be very careful of strings that you get from untrusted sources.") Shooting yourself in the foot that way has nothing to do with strings from untrusted sources. The disconnect is as strong as if it had said:
        Look at this troublesome code:
        1 while fork();

        Moral of the Story: Don't trust external data sources.

        Both pieces are true (fork bombs are bad, external data shouldn't be trusted) but the jump from one to the other is unclear and misleading. It implies that external data can cause unexpected fork bombs, but it doesn't actually demonstrating how such a thing might happen.

        -Blake

Re: Trojan Horse? (taint mode)
by jarich (Curate) on Nov 25, 2001 at 13:06 UTC
    Perl interpolates variables in double quoted strings safely. Everything in the variable is considered to be a literal. So
    my $a = q#${system('rm -rf /')}#; print "The command in \$a is $a\n";
    will print out:
    The command in $a is ${system('rm -rf /')}
    and not even attempt to remove my files. Likewise this
    my $b = "The command in \$a is $a\n";
    sets $b to the string we printed out. Printing $b does exactly the same as the above. The only way this is going to come and cause us grief is if we eval $a - as you've suggested.

    Perhaps the author is mistaken or you've misunderstood the reference, can you post the paragraph or two? I've checked the book errata and it's not mentioned anywhere there, but it's a pretty big mistake if you haven't misunderstood it.

    Even authors make mistakes. :)

      The only way this is going to come and cause us grief is if we eval $a ?

      But pause to consider that someone playing with your CGI script has managed to get output redirected to an executable shell script.... Which is often the aim of a malicious hack. If you don't want naughty words appearing in, for example, your system initialisation scripts, it might be a good idea to untaint everything input.
Re: Trojan Horse? (taint mode)
by blakem (Monsignor) on Nov 25, 2001 at 15:37 UTC
    Here is the relevant portion of the text from page 13: (I believe this is fair use)

    Trojan horses
    While we are talking about obfuscation, it is worth talking about a very insidious way of including executable code within strings. Normally, when Perl sees a string such as "$a", it does variable interpolation. But you now know that "a" can be replaced by a block as long as it returns a reference to a scalar, so something like this is perfectly acceptable, even within a string:
    print "${foo()}";
    Replace foo() by system ('/bin/rm *') and you have an unpleasant Trojan Horse.
    print "${system('/bin/rm *')}"
    Perl treats it like any other function and trusts system to return a reference to a scalar. The parameters given to system do their damage before Perl has a chance to figure out that system doesn't return a scalar reference.

    Moral of the story: Be very careful of strings that you get from untrusted sources. Use the taint-mode option (invoke Perl as perl -T) or the Safe module that comes with the Perl distribution. Please see the Perl documentation for taing checking, and see the index for som pointers to the Safe module.

    At the very best this is correct but unclear... at the worst it is just plain wrong. The above implies (but doesn't exactly state) that this would wreak havoc on your machine:
    $a = q|{system('/bin/rm -rf *')}|; print "$a";
    but, as has been stated above, the output of this snippet is simply the value of $a.... no external commands are executed.

    Unless I'm overlooking something, this looks like an Errata to me.

    -Blake

      I think its very clear... I decided to try it as the author stated above. I used echo because well - I like my system the way it is. And its a good thing I did too because the command executed. This is what I have:
      #!/usr/bin/perl $a ="${system(\"echo 'hello from system'\")}\n"; print "$a";
      And this is the output:
      hello from system stupid.pl

      I think this is what the author is talking about. Now when I use the q or qq it responds as you said so I guess that perl treats qq differently than an actual double quote. Something I didn't know. Interestingly enough it prints the name of the script out as well when this command executes... not sure why.

        I see no difference in the behavior of the following two lines:
        $a = qq|${system("echo 'hello from system'")}\n|; $a = "${system(\"echo 'hello from system'\")}\n";
        They both execute the 'echo' command which sends a message to your terminal and returns 0. My perl (5.00503 and 5.6.1 on unix) then complains that 0 is not a scalar ref and dies. Apparently your perl is casting the return value of 0 into a scalar ref to 0, and $a is assigned the value of $0, which happens to be the name of the script.

        The book seems to imply that this behavior emulates what would happen if $a had come from user input. Fortunately that is not the case. If $a had come from STDIN, none of the above caveats would apply. Try it:

        #!/usr/bin/perl -wT use strict; my $a = <STDIN>; chomp($a); print "$a";
        </code>

        -Blake

Re: Trojan Horse? (taint mode)
by IraTarball (Monk) on Nov 25, 2001 at 20:27 UTC
    Thank you gents. I thought this was an especially unclear passage, as blakem pointed out. It might be correct if the author means  print "${system('rm -rf')}"; is bad but that would be your own dumb fault wouldn't it? And what would that have to do with taint?

    Well, any way, thanks for your clarity and wisdom.

    Ira,

    "So... What do all these little arrows mean?"
    ~unknown

Re: Trojan Horse? (taint mode)
by chromatic (Archbishop) on Nov 25, 2001 at 23:15 UTC
    ph3@r:

    print "$\{system('echo \"hello\"')}";

    Yet fear not so much:

    chomp(my $input = <STDIN>); print "$input\n";
    Feed this one the shell command above (a nice variable dereferencing scheme) and it'll print out literally.

    Unless you're doing hazardous things with string eval, you're probably safe.

Re: Trojan Horse? (taint mode)
by BrentDax (Hermit) on Nov 26, 2001 at 11:46 UTC
    There are some pretty dangerous possibilities:
    $a=" (?{system('rm -rf *')})"; $b=~/foo($a)bar/;
    That will ruin your whole day.

    =cut
    --Brent Dax
    There is no sig.

      For this to ruin your day, you would have to explicitly permit the execution of code within interpolated variables with use re 'eval'; So, like the example in the book, it looks scary on the surface, but isn't that bad in practice.

      -Blake

        Boy am I glad I pushed for use re 'eval'. It's at times like this when paranoia pays off...

            -- Chip Salzenberg, Free-Floating Agent of Chaos

Re: Trojan Horse? (taint mode)
by mattr (Curate) on Nov 26, 2001 at 12:56 UTC
    I can't figure out why you would ever want to execute/eval untainted CGI input as-is. And I don't know if I'd trust Perl's CGI tainting to keep my evals safe from those curly brackets.. paranoia is good there.

    As far as standard input, you are worried about a user maliciously erasing all their own files? Or are you allowing users to run suid? Context?

    update 2002.1.26 sorry I missed your/blakem's quotation.

      The context is general knowledge. This all started when I read the passage I tersely quoted and blakem included in full. It's not to solve a specific implementation problem, but rather to ensure understanding so that I can avoid specific implementation problems.

      I can't figure out why you would ever want to execute/eval untainted CGI input as-is

      Yeah, that does sound dangerous. That's why the quoted material caught my attention. It seemes to imply that code could be evaluated without my express permission but instead simply because I put it in double quotes. That kinda freaked me out.

      Thanks,

      Ira,

      "So... What do all these little arrows mean?"
      ~unknown

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://127370]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (9)
As of 2014-10-25 11:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (143 votes), past polls