You will have noticed that the very first statement in the
execute_viewer function above calls a function named
sane_url that isn't shown in the listing. Before we actually write
that function, let's talk about the potential damage an attacker can do
through command line arguments.
Assume the user configures his application to use a different viewer,
say lynx, this is invoked as "lynx %s". Probably the first
thing that comes to mind are, what about local files as arguments? Well,
just specifying /etc/passwd will cause no grief; all that
happens is that the intended ``victim´´ is shown his own password file. A
somewhat nastier variant though is to make lynx display special files
like /dev/zero, which will cause lynx to sit there reading
zero bytes from the device until it dies of memory exhaustion. Which
is not a real problem either. On some Unix or Linux systems, however,
the mouse device is readable by the user running the X Windows session,
and telling lynx to read from the mouse device will seriously hose the
victim's session.
There are worse things that can happen, however. Among other things,
lynx supports special URL schemes such as
lynxexec:command. If enabled,8.3 lynxexec URLs will cause the specified command
to be executed. The advantage to a potential attacker is obvious.
However, there is even more havoc an attacker can cause. Think about
command line arguments! lynx supports a huge number of them,
and one of them is -cfg which lets you specify an alternative
configuration file. And you can do interesting things with this file! One
of them is defining what program to use in order to display images. Now
imagine a nasty person manages to If the attacher manages to upload a fake
configuration file on the victim's computer, say /tmp/nasty.cfg.
this fake configuration file specifies the command rm -rf
as the image file viewer. Now all he needs to do is make the victim
visit the URL -cfg=/tmp/nasty.cfg http://foo.com/blah.jpg
and lynx will execute what it thinks is the program to view the
downloaded JPEG file...wiping the victim's home directory instead.
Of course, there are other things you can do here...you get the idea.
Now, there's a big IF in the scenario above; which is the attacker's
ability to upload a file to the victim's machine. Contrary to popular
belief, this is a lot easier than many people think. For instance, you can
mail it to the victim, and for most Unix and Linux flavors it will wind
up in /var/mail/login or similar. And guess what -
most parsers, including lynx' config file parser, are robust
enough to skip all mail headers and other gunk they're unable to parse.
So what do we learn from this? You need to be extremely paranoid
about what you accept as command line arguments. First, never
allow arguments starting with a dash. It could be a deadly command line
option. And don't think that the lynx example above is contrived!
There have been attacks on FTP daemons and telnetd that exploited
this type of problem successfully.
Second, if you run powerful programs like lynx with untrusted
command line options, try to be really anal about what you accept.
It's better to make one or two people unhappy because you're too
anal, than putting your entire user base at risk through e.g. a
mail virus or worm. In the case of lynx, the right check would
be to accept only HTTP and FTP URLs, for instance.
Here's some sample code:
int
sane_url(const char *url)
{
int n;
if (strncasecmp(url, "http:", 5)
&& strncasecmp(url, "https:", 6)
&& strncasecmp(url, "ftp:", 4))
return 0;
/* Be extra nasty: restrict the set of characters we accept.
* Note that we can accept shell meta characters because we
* use exec() rather than system() to run the command. */
while (*url) {
if (!isalpha(*url)
&& !isdigit(*url)
&& !strchr(".,?=;", *url))
return 0;
}
return 1;
}
XXX: As a special case, mention sendmail which can take its list of addresses from the mail message itself (-t option).