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

Obviously, the correct way to deal with Shellshock is update bash. However, given that running under Taint mode already requires you to clean up pathing variables before external calls, would it be reasonable to shift best practice to invoking local %ENV = (PATH => '/usr/local/bin'); rather than piecemeal cleanup? Is there any good reason to not wipe the whole %ENV hash before an external call in web context?


#11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Replies are listed 'Best First'.
Re: Taint and Shellshock
by shmem (Chancellor) on Sep 27, 2014 at 08:08 UTC
    Is there any good reason to not wipe the whole %ENV hash before an external call in web context?

    Of course not. I'd localize %ENV and set it up with reasonable defaults before shelling out:

    { local %ENV = ( PATH => '/bin:/usr/bin:/usr/local/bin", IFS => " \t\n", LOGNAME => $ENV{LOGNAME}, # propagate values known to be secur +e ... } ... system( ... ) }

    update: corrected IFS} to IFS, addded propagation of secure ENV variables

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      Perhaps my choice of language was unclear - by 'wipe the whole %ENV hash' I meant localize the hash and set explicit values prior to shelling out. Perl is vulnerable to Shellshock because an environmental variable makes a side run and it's not in the set that Perl considers dangerous for an external call. In the perlsec docs, the only recommendations are regarding 5 specific variables which are the 5 that taint considers dangerous (please correct me if I'm mistaken). It seems like this issue might warrant increasing the scope of taint to consider any tainted value in %ENV dangerous to the shell (thus breaking billions of scripts worldwide....)


      #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: Taint and Shellshock
by LanX (Saint) on Sep 27, 2014 at 09:46 UTC
    Sometimes elements of the parent environment need to be passed through

    Shouldn't this line avoid all potential Shellshock exploits?

    s/^\(\) {.*// for values %ENV

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

    BTW: Couldn't fully test cause my Perl doesn't seem to be exploitable! (?)

      While in theory this seems sound, it still feels like the classic black-listing that always seems to fall prey to some clever escaping scheme. Perhaps I'm being paranoid, but it seems like best practice should have any spawned processes firewalled off from anything you didn't explicitly give it.


      #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

        While in theory you can whitelist keys which need to be passed thru from parents env to bash, you'll hardly be able to avoid dangerous values without some heuristics...

        Like forbidding anything which looks like an env-function.

        That's what my regex does in a generic way, ie erasing magic values starting with () { .

        You are free to combine it with further defense measures.°

        But I doubt you can efficiently realize an individual validation for each string format (like PATH, HOST, IP, USERNAME, ...)

        Cheers Rolf

        (addicted to the Perl Programming Language and ☆☆☆☆ :)

        °) something like (untested)

         local %ENV = map { $_ => kill_func $ENV{$_} } @whitelist

Re: Taint and Shellshock
by Don Coyote (Hermit) on Sep 27, 2014 at 10:18 UTC

    I have an example of a piecemeal solution. This is the sort of thing that you are suggesting to prevent doing by setting up a localised environment?

    Using File::Find I was having some warnings regarding insecure dependencies so I took to the debugger

    I solved untainting of directory paths by localising the environment variables such as PATH,CDPATH,IFS and using the hash argument form of the find subroutine.

    file( { wanted => \&wanted, untaint => 1 }, '.' );

    However I continued to get insecure PATH dependancy warnings through debugger and its use of Term::Cap Using the perl debugger (-d switch) Term::Cap shells out and gives me warnings. I fixed this by assigning a literal path right before the eval.

    Having localised the environment in my script, will I need to also localise for the debugger too? How do I do that?

    code excerpt Term::Cap version 1.16 lines 239 - 275 Term::Cap meta-source lines 251-254 being of particular interest. my workaround being commented '# op fix'

    DoC enlightenment is the true goal
    shellshock is a penalty shoot out
Re: Taint and Shellshock
by Anonymous Monk on Sep 27, 2014 at 02:12 UTC

    I take it above is just a basic example (or else you would lose values of QUERY_STRING, REMOTE_USER, etc.)?.

      Right; presumably, you'd properly scope your localization if you had interest in other environmental variables, and propagate any values of interest. For my own development, I rarely shell out to do something other than invoke a command line utility for heavy numerics, with validation performed at the script level. If you trust externally set environmental variables to pass information to your CLI, I don't understand why you'd bother with taint in the first place.


      #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: Taint and Shellshock
by parv (Parson) on Sep 27, 2014 at 10:51 UTC

    Regardless of the shell problem, is taint mode not the default in wide use due to the need to clean up things (certainly is the case for me)? If that is one of the argument, then what about the time spent on writing tests? Or, is the later more valuable than the former?

      …is taint mode not the default in wide use…

      Not in my experience. :( And when arguing against the practice, and discovering 100s of scripts have to be fixed (some in rather deep ways) with it on, the wide spread manager will say: “We can’t afford to do anything about that right now.”

      Taint has wide usage, but it only limits passing certain environmental variables through. If the CGI request sets BAD_VAR = rm -rf /, Perl will happily pass that through to your executable without untainting because it doesn't expect your child process will use it (in my understanding).


      #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

        Perhaps I don't understand the parent node as it was intended, but if I do correctly grok it, I think it's misleading, at best.

        Oversimplifying a bit, when the -T CLI option is on, anything that comes from outside the script is "tainted."

        Untainting data (be it ENV, $vars or anything else) can be fairly easy... but often is anything but 'easy' or simple. Consider, for example, data received as input from a form on a website.

        However, take a simple case, where login_data (an ID and yeah, this is old) was supposed to be five digits -- no more, no less, and nothing that's not an (arabic) digit. Since the user entry is tainted, the cgi in use untaints the login_data (to the site owner's satisfaction) by checking that the id received consists of exactly five digits:

        unless ( $value =~ /^\d{5}$/ ) # UNTAINT { out_badlog(); warn ("bad after UNTAINT\n"); exit; }

        Ascertaining that the five digits comprise a valid ID is a different topic and is performed in another part of the script.

        So, moving on to this from perlsec:

        "SECURITY MECHANISMS AND CONCERNS
        Taint mode
        Perl automatically enables a set of special security checks, called *taint mode*, when it detects its program running with differing real and effective user or group IDs. The setuid bit in Unix permissions is mode 04000, the setgid bit mode 02000; either or both may be set. You can also enable taint mode explicitly by using the -T command line flag. This flag is *strongly* suggested for server programs and any program run on behalf of someone else, such as a CGI script.
        "

        perlsec offers much more of relevance to the immediately previous comment from kennethk.

        There's more in perlfaq7.pod about determining "if a variable (emphasis supplied) is tainted" ...after which pf7 offers these gems:

        " You can use the tainted() function of the Scalar::Util module, ....See also 'Laundering and Detecting Tainted Data' in perlsec."

        Frankly, I (for just one, I hope) was unaware (because of far too cursory reading of its docs) that S:C offered capabilities there. I hope this belated epiphany is useful to others.

        Updated: Para 1 added and paras 2,3 and 4 edited for clarity


        ++$anecdote ne $data