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

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.

Replies are listed 'Best First'.
Re^5: Taint and Shellshock
by ww (Archbishop) on Sep 28, 2014 at 03:47 UTC

    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 () {.

        Thank you both, tobyink and kennethk, for the explanations. I have definitely learned from your comments.

        UPDATE: Also instructive is an article -- cited in this (Mon, 2014-09-29) morning's Perlweekly -- by David Farrell. In essence, my view is both undermined and supported there:

        As I now understand it, a BAD_ENV can be injected into the params passed to the server's CGI script, and (more-or-less) easily. But getting the malware into the server's environment requires -- at least as I now understand it -- that the server's owner/CGI-writer has failed to use taint to force the server-side code to effectively assess each of the params being provided by the outside user and prevent passage of meta-characters which are (TBO our current knowledge) required to make bash execute the malware writer's payload.

        If I still have this wrong, pray continue my edumuckation....


        ++$anecdote ne $data


      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.