Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can we force perl always use three argument form of open when running from command line?

Tags:

security

perl

Running perl one-liners from command line has security implications.

The problem is that options -n/-p trigger the diamond operator <>, which use two arguments form of open, so with files name contain special characters, perl doesn't work as expected:

$ perl -pe '' 'uname|'
Linux

Or more dangerous when files name starting with >, like >file. In this case, file will be truncated.

For work around with this issue, we can:

  • Use ARGV::readonly module from CPAN.
  • Implement feature like ARGV::readonly module by ourself:

perl -pe 'BEGIN{$_.="\0" for @ARGV} ...' ./*

  • Use -i option, as perl will check for file existed before processing it.
  • Use -T option to enable taint mode.

I think all solutions can fix this issue, but also have their side effects. If we can force perl always use thee argument form of open, it'll be a better solution.

I wonder can we do it, force perl always use thee argument form of open?

Note

The question only apply for the case when running perl one liners from command line, because (of course) we can always use three argument form of open in Perl script.

like image 547
cuonglm Avatar asked Nov 29 '14 03:11

cuonglm


1 Answers

You probably only want to do this for one-liners (using the -e switch), so you'll want to customize ARGV::readonly for that purpose.

package Sanitize::ARGV;
if ($0 eq '-e') {
    @ARGV = map {  # from ARGV::readonly
        s/^(\s+)/.\/$1/;
        s/^/< /;
        $_.qq/\0/;
    } @ARGV;
}
1;

To force this package to be used system-wide, you can use an alias as Patrick J.S. suggests

alias perl='perl -MSanitize::ARGV'

or set a system-wide PERL5OPT variable

PERL5OPT="-MSanitize::ARGV"

And if you want to be more paranoid, hide your system perl (rename it to something unintelligible) and replace it with a wrapper

#!/bin/bash
THE_REAL_PERL=/usr/bin/glorbqweroinuerqwer
$THE_REAL_PERL -MSanitize::ARGV "$@"

The shell wrapper will still respect any user customizations to PERL5OPT


In the general case, you can use the CORE::GLOBAL mechanism to override the builtin open function, e.g.

package SafeOpen;
use Carp;
BEGIN {
    *CORE::GLOBAL::open = sub (*;$@) {
        goto &CORE::open if @_ > 2;
        Carp::cluck("OH MY GOD USING THE TWO-ARG open ARE YOU LIKE INSANE?");
        return CORE::open($_[0], '<', $_[1] // $_[0]);
    };
}
1;

and when this module is in use you will catch anyone in the act of using a 2-arg open call. Unfortunately, I think the mechanism of the ARGV filehandle magic bypasses this, so it still doesn't help with goofy filenames on the command line in a one-liner.

like image 84
mob Avatar answered Nov 15 '22 16:11

mob