Open source software security

Web Hacking Lesson 1

14 December 2011
This is the first in a series of training articles that goes hand in hand with a test site that should be downloaded and installed by the reader. The training is designed to help you gain experience with methods used by attackers to compromise web applications so you can build better applications and learn to defend your applications more successfully. This initial lesson covers Cross Site Scripting (XSS) attacks and includes instructions on downloading and installing the test application. Future lessons will cover other attack methods such as remote file injection, SQL injection, malicious file upload, authentication bypass, and other topics.
by Justin C. Klein Keane
April 17, 2008

This exercise is designed to expose you to several of the top threat vectors facing web based applications, specifically PHP/MySQL applications. 'Threat vector' is a common term used in computer security to connote ways in which an attacker will attempt to compromise a system. System is used in a broad sense here because a compromised web application can easily lead to a compromised web server which in term could lead to a compromised operating system.

Defending web based application is of critical importance because they are some of the most common targets of attackers. When web application security is defeated it can lead to any number of outcomes, largely determined by the motives of the attacker. Because we can never fully predict motives of an attacker web based applications must be defended against all threats, regardless of how small they seem. What may at first seem like an inconsequential threat may turn out to be the linchpin of a complex attack. Developers must defend against not only existing attacks but also emerging ones and future vectors that have not yet been considered. While this may at first seem to be an insurmountable task, it is in fact possible using best practices and insuring that an application may only behave as it was intended. Enforcement of design becomes the key to preventing many web application vulnerabilities.

During this first exercise we will look at several common attack routes from the perspective of an attacker (i.e. without the source code of the application available). Once familiar with these attacks we will look at source code an examine strategies to foil such attacks.

It is important that when simulating an attacker that we have the best tools available to exploit web based applications. Such tools will allow us to send malformed URL requests, intercept and alter form submissions, and examine, alter, and even create our own cookies. The Firefox web browser has many extensions that will allow us to do all of these things. Once Firefox is installed download and install the web developer extension (https://addons.mozilla.org/en-US/firefox/addon/60) as well as the tamper data extension (https://addons.mozilla.org/en-US/firefox/addon/966). These extensions will allow you greater ease in exploiting web applications.

Installing the Test Site

In order run through the exercises in this series you'll need to download and install the test site (which is a very simple blogging application). The test site (madirish_training.zip) is distributed as a zipped directory that you should be able to unzip with pretty much any archiving program.

The site is a PHP (http://www.php.net) and MySQL (http://www.mysql.com) application that should be able to run on pretty much any web server. If you don't have a web server, PHP or MySQL installed don't worry. The easiest way to get them installed is to check out XAMPP (http://sourceforge.net/projects/xampp/). You can download and install XAMPP and get Apache (http://www.apache.org), PHP and MySQL installed. Alternatively you can install each component on your own. All three can run on Windows or Linux so you can use whatever hardware you have right now. I won't go into specifics of installation since each piece has pretty good documentation on the installation process on their website.

One you've got these prerequisite software pieces installed you need to install the test site. Go ahead and unzip the test site in your htdocs directory (or whatever web root you're using). You can then point your web browser to your site name and add 'madirish/install.php' to the URL. For instance, if everything is installed on your local machine, point your browser to 'http://localhost/madirish/install.php'. This page will ask you some questions about your database and install the mysql database (called hack_test) and make sure that your web server can write to the necessary directories for the application to work.

Note that if you don't feel comfortable using the install page you can install the database quite easily using the script db.sql found in the sql directory in the training. To install this way simply open a command prompt, navigate to the unzipped training directory and type:

mysql -u root - p < sql/db.sql

Once you've completed the exercises you may want to see if you can 'fix' the test site so that it's no longer vulnerable to the exploits described below. Be sure to delete the test site when you're done or keep it behind a firewall, since it's deliberately designed to be insecure and could be used to compromise your computer!

You can start the exercise by pointing your browser at your install URL with "index.php" added to it. In my case this URL is "http://localhost/madirish/index.php".

Cross Site Scripting

Cross site scripting (CSS or XSS) is a common web application vulnerability that can allow a malicious user to abuse an application in many ways. The test site has several XSS vulnerabilities. The first of these is presented by the way the application handles failed logins. Pull up the application page and attempt to log in using any made up username and password. You'll note that the application correctly handles the error message by not revealing whether or not the user exists. For instance, some applications may respond to a failed login with a message such as 'password incorrect' or 'user account does not exist'. These types of messages leak information about the failed login that can be useful for an attacker. For instance, if an attacker is trying to brute force an account they must correctly guess the account name and password. Brute forcing is an attack based on guessing. For instance, the attacker could simply try one username with every password they could think of, then move on. Computers are quite good at brute forcing, with automated attack programs that can tirelessly guess usernames and passwords. Given enough time any username and password combination can be guessed by a computer. Giving the attacker clues as to whether an account exists reduces the time it takes to brute force that account because the attacker does not have to guess at account names, merely passwords.

The sample application correctly alerts the users that their login attempt failed, but does not hint as to whether or not it was the username or password that did not match. However, there is a critical flaw in how the application alerts the user to this fact. Can you spot the flaw? Can you exploit this flaw to cause the page to redirect to "http://www.MadIrish.net"?

Try logging in with an incorrect username and password. You'll notice that a Javascript prompt shows up telling you that you failed to log in. Now, examine the URL for the page. Next examine the source code for the page. You'll see there is a URL "get" variable that is included as part of the page. The URL "index.php?msg=Sorry,%20could%20not%20log%20in%20with%20those%20credentials." includes the message that is included as part of the alert. Looking at the source we can see:

<script>alert('Sorry, could not log in with those credentials.');</script>

Try changing the URL so that it reads something else, for instance, try going to the URL "index.php?msg=foo" and observe what happens, view the resulting page source code. Can you spot the flaw yet?

Now let's try exploiting this get variable's inclusion into the javascript. Try going to the URL "index.php?msg=foo');alert('bar" and observe what happens. This time you see two alert messages, and if you view the source you can see:

<script>alert('foo');alert('bar');</script>

You can see that the URL variable is being included directly in the page source. Now try going to the URL "index.php?msg=One moment');location.href=('http://www.sas.upenn.edu" and observe what happens.

Now, this may seem innocuous enough, but lets take the attack one step forward and URL encode the entire query string. To do this we simply craft the URL using the hexidecimal values for each character that the browser will properly interpret, but which a user won't be able to understand. Try going to the URL:

index.php?msg=%27%29%3b%6c%6f%63%61%74%69%6f%6e%2e%68%72%65%66%3d%28%27%68%74%74%70%3a%2f%2f%77%77%77%2e%73%61%73%2e%75%70%65%6e%6e%2e%65%64%75

Notice what happened? Now, an end user certainly won't understand what this URL is up to, but you can clearly see the hidden redirect. What if instead of the University of Pennsylvania web site this redirect pointed to a malicious phishing site that harvested usernames and passwords then redirected the user right back to the URL "http://localhost/madirish/?msg=Account confirmed, pleas log in". Many users would never notice they had ever visited the phishing page. This type of error could be exploited to harvest usernames and passwords from our application by sending an e-mail to users that said the user needed to log into the site using the above URL to confirm their account.

This example clearly demonstrates that a vulnerability exists that might be overlooked by a developer. After all, who cares if a user could craft the JavaScript alert on the index page? Obviously a clever attacker would care very much and could exploit this subtle flaw to their advantage.

How can this attack be prevented? The easiest way is to enforce that the application behaves exactly as it was intended. The actual PHP code used reads:

if ($_GET["msg"]) {
	$msg = $_GET["msg"];
	echo "<!-- JavaScript error messages -->\n<script>alert('$msg');</script>\n\n";
}

Now, if the code was altered so that it read:

if ($_GET["msg"]) {
	$msg = urlencode($_GET["msg"]);
	echo "<!-- JavaScript error messages -->\n<script>alert('$msg');</script>\n\n";
}

The message string could be altered, but it would never affect how the application functioned. In essence we want to restrict the URL variable from escaping out of the single quotes in the alert. It is tempting to simply do a string replace and replace all single quotes with an escaped single quote, so that the URL:

?msg='alert);alert('foo

was converted into the string:

?msg=\'alert;alert(\'foo

which would effectively foil this attack. However, this approach fails if the attacker enters the URL:

?msg=\'alert);alert(\'foo

because escaping the single quote converts the string into the value:

?msg=\\'alert);alert(\\'foo

which in fact escapes the back slash, rather than the single quote. Trying to plan for variances in URL crafting will ultimately fail. The only safe way to enforce the parameter is correctly interpreted is to use PHP's native functionality (rather than "rolling your own" solution).

See if you can find other cross site scripting attacks in the site. Try to only use XSS attacks that will pop up Javascript alerts since these will be minimally invasive to the actual functionality of the site.

Once you realize that a XSS attack is possible you can begin to imagine the possibilities. One particularly evil XSS attack is to inject code (Javascript or otherwise) that actually includes an iframe into the page. If the iframe is merely 1 pixel by 1 pixel it is invisible to the user, but could allow new content to be included in the page. There are several browser attacks that can be performed using the iframe, not the least of which could be to prompt the user to download and execute malicious code. The possibilities are endless.