Monday, August 07, 2006

Authentication bypass.

This is an example of a far too common problem. Developers have a tendency to assume that client applications will always act how they were designed to act. This is fine if you're depending on them for functionality, but NOT if you're depending on them for security.

Recently I was asked to take a peek at a content management system currently in developement. A lot of it seemed relatively stable, except for this one short snippet of code. Whenever a protected page is loaded, one that you have to be logged in to view, a function containing this code is called:

if(!isset($_SESSION['session']["privLvl"])) {
header("Location: login.php");
}

It grabs a variable called 'privLvl' registered to the users session. If the user is not logged in, this variable is unset and the browser is redirected to the login page. So then, what is the problem? The problem exists, because our developer is putting his trust in a function that depends on the browsers response. header("Location: login.php"); will force a browser to redirect to login.php, but only because that is how a browser is programmed to react. watch what happens when I load this page in ie, then in netcat:

first, here is the code for admin.php:

<?

if(!isset($_SESSION['session']["privLvl"])) {
header("Location: login.php");
}

echo "BIG SECRET!";

?>

Here is an image of what loads in IE:





that form is what is stored in login.php, we've been happily redirected, as intended. And now, in netcat:






Whoops. Netcat has no idea what to do with the Location: header, its not a browser. A secure way to implement this would be as follows:


<?

if(!isset($_SESSION['session']["privLvl"])) {
header("Location: login.php");
exit();
}

echo "BIG SECRET!";

?>


Here we force exit of the script after redirect, incase the client doesn't listen.
There are plenty of other vulnerabilities based on this same flawed thinking. Using javascript to sanatize input is a common one. As a developer you should always be concious of what your functions depend on, and whether or not those dependencies are under your control.

2 comments:

Didier Stevens said...

Good point! Another classic example is a browser cookie.

Browser cookies are stored on the client computer and are under the control of the user. In the case of IE, they are just text files stored in the cookies folder. The user can edit them and send whatever he wants to your web app.

Firefox stores all cookies in one file called cookies.txt

Alexandre said...

A content location header should be followed by some content with a link to the new location. So header() followed by exit() is not a fully compliant solution.

From RFC 2616 about HTTP 1.1:
"The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s)".