in reply to Re^2: Taint and Shellshock
in thread Taint and Shellshock

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


Replies are listed 'Best First'.
Re^4: Taint and Shellshock
by kennethk (Abbot) on Sep 27, 2014 at 20:33 UTC
    I think you misapprehended my point (or I misapprehend yours). Suppose the client request to a Perl script sets the environmental variable BAD_VAR. In Perl, $ENV{BAD_VAR} is tainted. Suppose your CGI script is
    #!/usr/bin/perl -wT print "Content-type: text/plain\n\n"; local $ENV{PATH} = '/usr/local/bin'; print `my_prog 12345`;
    From my understanding, Perl will not raise any issue in the scenario where my_prog accesses BAD_VAR, and hence %ENV can be used to bypass taint. Is this not correct?

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

      First problem: HOW does the client set "the environmental variable BAD_VAR" (and assuming the worst, let's use your earlier suggestion that BAD_VAR be set to rm rm -rf /) and where does the script you've shown us access BAD_VAR?

      Somehow, that value has to get passed in to the script... not just to the params packaged up by CGI, but from the params to the script. Taint won't allow that except to allow the 'bad' params to be passed to a part of the script that purports to scrub the input; the untaint function. Of course, if the scrubbing is done badly, that's a failure on the programmer's part; not Perl's and not taint's.

      Second (or, more of the same): if the script allows rm -rf / to pass an untaint function, the script's author hasn't done an adequate job. The script should have been designed to ensure that outside data conforms to a (reasonably) testable format... and should (with taint's help) block execution, eval or anything else dangerous, if the data doesn't conform.


      ++$anecdote ne $data


        kennethk's analysis is entirely correct.

        First problem: HOW does the client set "the environmental variable BAD_VAR"

        Firstly, one of the key factors in exploiting shellshock is that it's not just a single environment variable that is vulnerable. Any environment variable will do. So it doesn't need to be called "BAD_VAR". It could be called, say, HTTP_BAD_BAR.

        Make a request to a CGI script like this:

        GET /test.cgi HTTP/1.1 Host: example.com Bad-Var: foo

        You'll see that the environment contains a variable called HTTP_BAD_VAR.

        Somehow, that value has to get passed in to the script... not just to the params packaged up by CGI, but from the params to the script.

        No. Forget the script. The script doesn't do anything insecure. Let's imagine a simple script that doesn't even look at environment variables:

        #!/usr/bin/perl print "Content-Type: text/plain\n\n"; print "Here's the entire book...\n\n"; system("cat chapter-*.txt");

        Yes $ENV{HTTP_BAD_VAR} is tainted, but the script doesn't actually touch that hash value, so no error is raised about it.

        The one-argument form of system(), if it contains shell characters (in this case, the asterisk) doesn't spawn the given command directly, but runs it via the system shell (which will usually be bash).

        So bash gets spawned. Bash inherits all of %ENV because child processes inherit their parent's environment. Thus bash gets the HTTP_BAD_VAR verbatim from the HTTP request header.

        And bash will eval any environment variable that starts with () {.

        First problem: HOW does the client set "the environmental variable BAD_VAR"
        The classic example Shellshock is having HTTP_USER_AGENT be your bad variable
        wget -U "() { test;};echo \"Content-type: text/plain\"; echo; echo; /b +in/cat /etc/passwd" http://10.248.2.15/cgi-bin/test.cgi
        and more generally, the whole point of tainting the whole of %ENV is that you shouldn't be playing catch-up; whole thing is potentially suspect.
        where does the script you've shown us access BAD_VAR?
        This is exactly my point. The Perl script never accesses BAD_VAR, only the child process. Perhaps this updated case would make my vector more obvious:
        #!/usr/bin/perl -wT print "Content-type: text/plain\n\n"; local $ENV{PATH} = '/usr/local/bin'; print `eval \$BAD_VAR`;
        The horror with Shellshock is that unless you wipe all potentially corrupted values out of %ENV, it doesn't matter what you call. Thus my original question, should I be updating that script to read
        #!/usr/bin/perl -wT print "Content-type: text/plain\n\n"; local %ENV = (PATH => '/usr/local/bin'); print `eval \$BAD_VAR`;

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