I was surfing on the Web a few days ago looking at various homepages for security
professionals to see if there were any interesting links. I discovered nothing
too interesting, so, being bored, I hit a link to a page with various network
utilities available through cgi interfaces.
One did catch my interest, a DNS zone transfer utility online, so I plugged
in one of my domains. It tried to transfer it and failed. Being somewhat disappointed,
I went to get a delicious, refreshing Diet Pepsi . Coming
back to the computer, I thought "Hmm. Well since I won’t be able to transfer
domains that are properly secured, and transferring domains that aren’t secure
isn’t really interesting either, what can I do?"
It occurred to me to ask which domains might the server this cgi is hosted
on be allowed to transfer (since it was a WWW server at a major European ISP).
So, I tried to transfer the DNS zone for the ISP, which worked. Interesting,
I thought, but not too interesting, so I wrote a script to use their CGI script
to grab all their subdomains. Now this was interesting: 90+ subdomains, quite
a few of which were very "interesting" (noc.*). Also, you could transfer
any domain they hosted, which is an interesting fact, considering they host
several tens of thousands of domains. I then emailed the company to tell them
about the problem, and haven’t yet heard back from them.
So what is the moral of the story, if any?
Well the most obvious lesson is that unless you really need a cgi script, you
shouldn’t put it up on a publicly available Web server. This lesson is extremely
important, as many Web servers come with a set of default cgi scripts, for example
"printenv.cgi" which prints out all the available environmental variables
such as Web server name, version, path to files, etc. Many of these cgi’s have
security flaws and can be used to compromise a server, so remove them unless
you absolutely need them.
The next lesson would be to restrict cgi programs to only those who need them.
The DNS zone transfer cgi could, for example, have been restricted to a certain
set of IP addresses or hostnames, which would have greatly reduced the exposure
and risk. This isn’t foolproof, but the mere fact that search engines are unable
to index it will keep it away from many curious people.
Of course, checking user input goes a long way. Restricting users from putting
in certain values (i.e. your DNS zones, extremely long strings, etc.) will prevent
many problems. Just because the text box on your webpage is limited to 50 characters
validation is also basically useless as avoiding it is relatively trivial. Validation
of user input must be done as the very first thing in your cgi programs.
This is not a trivial task, unfortunately. If you decide to go with a "default
allow" policy and try to block all potentially dangerous input, your task
is Herculean. Attackers can use Unicode encoding for example, where many characters
have dozens of ways they can be encoded. Other obfuscation methods such as using
ASCII values, hex and octal numbers instead of normal decimal, and mangled escape/quoting
characters can be used. Of course you can never be fully sure that a given input
is not "dangerous", because there may be some undiscovered technique
or flaw that results in a new attack being possible.
If you go with a "default deny" policy your job will be considerably
easier. Several assumptions can be made, one of which is that legitimate input
will be entered "sanely", i.e. not using ASCII values or hex numbers.
Even then, it may be possible for attackers to enter hostile input. For example
if your CGI only allows a-z, A-Z, 0-9 and some "safe" characters,
such as "/" and "" it might still be possible for an attacker
to use ASCII values or Unicode, so always test your program.
Checking a program’s output is another way to prevent various problems. For
example, you may restrict the number of responses a program will give to 5 listings
of whatever. If an attacker discovers some way to insert a wildcard into a search,
for example, they would not be able to get as many responses as quickly (thus
giving you a better chance of detecting the problem). Alternatively, if you
have a program that looks up user information and returns it, you may wish to
censor parts of that data. For example, if the user has a credit card number
registered with you, you might only return the sum of all the digits, or the
last 4 digits so that the user can verify which card they registered.
Do not load CGI programs on systems that serve other functions, if possible.
For example the DNS zone transfer program would have been relatively harmless
if it had been loaded onto a webserver that was not allowed to do DNS zone transfers
from the ISP’s servers. Software can have strange interactions that cannot be
fully anticipated. This is how the Apache Web server was compromised for example:
multiple services were loaded onto one machine, and a small error in one allowed
another to be exploited to ultimately gain control of the Web server. Had there
been multiple servers for WWW and FTP, or a better configuration of the existing
server, it would probably not have been possible to compromise it as easily
as they did. The average server already has several hundred software packages
ranging from the OS kernel to text editors and so forth, so there is a wealth
of potential problems.
Isolating CGI’s from the system is also a good idea. Chrooting the entire webserver,
or the CGI alone will greatly restrict the access it has on the system. No CGI
should ever be run as root, or any other user with privileges (i.e. normal users).
Ideally CGI programs should run with almost no privilege, and if they must do
tasks that require higher access, it is recommended to use external programs
(or wrappers) that have a very well defined structure and are strict on what
input they will take, and what actions they can perform. Calling a stock command
line program directly from a CGI is often a bad idea as there are usually dangerous
options, or even potential buffer overflows in the command being used.
There are, of course, many other issues and potential solutions, but I’ll save
those for a later article. As always, basic secure programming principles apply
here. Have a design — do not simply create it on the fly, if possible. Minimize
the capabilities of the program. If it needs multiple functions consider creating
several (hopefully simpler) programs. Isolate the programs as much as possible
from the system, since an attacker will be able to get at them (via the Web)
and potentially abuse them. Where possible, apply these concepts at higher levels.
For example if you need a variety of network utilities available via the WWW,
consider creating a dedicated server for these, and then strip down the OS install
and stick it behind a firewall. Remember, from little security flaws grow large
Kurt Seifried (firstname.lastname@example.org)
is a security analyst and the author of more security articles than you can
shake a stick at. Please do not send him mean email as it makes his email server
sad. He’s also a glutton for punishment and sushi.
SecurityPortal is the world’s foremost on-line resource and services
provider for companies and individuals concerned about protecting their
information systems and networks.
The Focal Point for Security on the Net ™