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.
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 security incidents.
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 (tm)