PHP/CGI Vulnerabilities and Abuses
by L14
PHP is a scripted language primarily used with HTTP servers to create websites with dynamic, or changing, content. PHP has many similarities to C and Perl, although it is simplified a bit. This makes PHP a nice language with which to work, since many of the complexities that do not concern website development are removed.
This article will focus on some of the security issues that I encountered while writing a PHP mailing list and helping people on IRC. Most people I talked to did not even realize that security was an issue, and that how their scripts were constructed could change how secure/tamperproof their sites were.
The major problem is how variables are passed to PHP from the web browser. Variables and their values are appended to the URL, resulting in something that looks like this:
http://example.com/dir/script.php?variable1=somevalueBecause the variable names and their values are passed in plain text from the location bar of the browser, the values can easily be changed by the end user to perform different tasks than what the developer originally intended. Some of the possible abuses of this are described below.
Since many sites are quite complex, and contain scripts that reuse functions, those functions are often put into a standard include file. This means that only one file need be changed to update the entire site.
User authentication functions can (and often do) fall into this category. The user is verified once, and thereafter a value is passed to tell further scripts that secure content can be accessed.
However in sites with both secure and insecure areas, there needs to be a way of deciding whom to authorize. An easy solution is to just pass a variable that specifies either a secure or insecure mode, depending on what is being linked to. The same things may get executed in both modes but that probably doesn't matter.
If the mode is secure and the login fails, the script just bails. If the mode is insecure (or the login is valid), the same core features get executed. The problem of course is that after looking through the site for a few minutes, a user may realize that they could avoid having to login by just changing the value of the mode variable.
They can find out what it should be by simply checking a section that does not require authorization, and find out what the mode value is. Then all they have to do is change it in the location bar of the previous page and reload.
For a company that has a large audience for its website or mailing list, this can pose a severe problem: Anyone could change their site with no tools and very little knowledge:
http://example.com/dir/page.php?var1=val1&var2=val2&mode=sec (User has to login) http://example.com/dir/page.php?var1=val1&var2=val2&mode=ins (User doesn't have to login, it's magic!)This can be solved by moving code related to authentication to a separate file. This file is included instead of the standard include file in documents considered secure, and if the login is valid, the standard file is included as well. This removes the need for a mode variable; removing control is removed from the end-user.
Another problem, identical in its root, is that users can change the values being submitted to make the page work differently.
Consider a mailing list: A user visits the page, fills in a form, clicks submit, immediately receives an e-mail with a link in it, clicks the link, and is added to the list.
If that user is malicious, they may realize that they can fool with the system by changing the URL in the link, perhaps adding someone else to the list. While this is not much of a problem if they do it once, if they write a simple JavaScript and the mailing list only checks to see if users exist before sending the confirmation e-mail, they can potentially add someone hundreds or thousands of times.
If the mailing list only checks to see if users exists before adding them, then the confirmation portion can be abused. The confirmation section, since it sends emails immediately, also has more potential as a mail-bombing utility. While trying to abuse my own mailing list software, I managed to send 500 e-mails per minute to my account at university, from a remote computer, using an HTML/JavaScript file that I wrote at that remote computer and opened in IE.
If several sites that were vulnerable in this way were found, quite an effective attack could be launched against major servers, with almost no chance of being caught.
This is also easily fixed.
It should be checked both before confirmation and before adding the user whether a given user already exists. There should also be a database of temporary users, which the user subscribing gets added to until they subscribe. This list can be erased periodically, as people may opt to sign up later, but that time should be at least a week.
Alternatively, indexes generated from the e-mail addresses themselves could be included in the URL of the confirmation link, so that the address variable and the index variable must match before the user gets added, or a confirmation message sent. This removes the need for a temporary database but can still be tampered with, so in my software I just added the extra database.
I have found this problem in every PHP based mailing list I have looked at, plus several ASP and Perl ones as well. To find vulnerable lists I simply searched for "mail lists" on Yahoo!, and if I could manipulate the URL and send my test e-mail account more than one e-mail, I considered it to be vulnerable to attack.
To find and test approximately ten, all on reasonably fast servers, took less than 15 minutes, which I feel makes this a legitimate oversight of PHP developers in particular (and CGI developers in general) to look at how program structure can be exploited.