Help Brain conquer the world

Funny story. Awhile back I was fixing a friends code (who's a novice programmer at best), and he did something very similar. He'd just check to see whether or not a cookie was set for authentication. He didn't compare it to anything else in his database, either.

I believe it was something like:
Code:
session_start();
if(isset($_COOKIE['admin'])){
    require_once("admin_stuff.php");
}

So me, being the douche that I am of course, just opened up Firebug and set a cookie with the key "admin" and the value to "wat", did a request to his administration panel, and left a note in the admin bulletins section. After teaching him how to implement several layers of authentication security I had to explain and show to him what an SQLi was, since his site was full of them. ~_~


For those of you that are wondering what he did wrong (oh god please don't let this apply to anyone!), you should always sanitize your request variables (GET, POST, etc) when interacting with a database to prevent SQL injections, check the content-type on file uploads (try not to disclose temp paths either) and rename the files in case the "attacker" slipped by your file suffix check (*.jpg/*.txt, etc) and got a shell on your server named something like "lol_hacked.jpg.php".


If you're still not entirely certain that your webapp is secure, check out HackThisSite. It's a fun little "hacker game environment" where you exploit pre-written vulnerabilities in each "mission" that hopefully will result in making you more aware of network security. If you're interested in the topic itself (whether in practice or theory), check out Reddit's /r/netsec subreddit and the corresponding IRC channel on freenode. We have a bunch of discussions on recent happenings, and I've even spoken to other BHW members in the channel before, so you won't be alone.


Ooops. I think I typed too much. Ruh roh.
 
My apologies, I totally forgot about it. Will post the solution later today.
 
Last edited:
OH MY GOD, I LOVE THIS! I'm not very good at programming but love the spirit and will give this a try :)
 
Postponing the solution for 1 day to provide AlexaR with some time :)
 
Postponing the solution for 1 day to provide AlexaR with some time :)
Awww thank you! Very nice of you :') however, I am drawing a blank here haha. I hope to learn a lot from this thread XD
 
The solution

There are 2 problems with the authorisation script - the reason the script is vulnerable is because both problems exist at the same time.

We 'll see them one by one.

Not correctly comparing values

PHP:
$cachedCredentials['username'] == $user

When is the above comparison true? Obviously when you have "admin" on the left and "admin" on the right (or any other string on both sides).

But what happens if you have "admin" (string) on the left and 5 (an integer) on the right? Well, 5 and and "admin" are obviously not the same and it should fail (and it does - live example: http://codepad.org/ZhSVay6y )

Ok, no problem so far - but what happens if you have "admin" on the left and 0 (integer) on the right? Well, they are different so we expect the equality comparison to fail. Wrong! The comparison is true! (live example: http://codepad.org/Y41y6Zey)

What did just happen here? Why does PHP think that "admin" and 0 are equal? Is it stupid? :o As usually, we should read the f*cking manual: http://www.php.net/manual/en/language.operators.comparison.php


$a == $b | Equal | TRUE if $a is equal to $b after type juggling

Type juggling? Yes - PHP assumes we are intelligent people and when we compare apples ("strings") with oranges ("integers"), we do it on purpose. And since we do it on purpose, PHP does the casting of oranges to apples for us transparently.

Reading about type juggling in the manual, it says that "a variable's type is determined by the context in which the variable is used". In other words, if I have apples on the left and oranges on the right, PHP will convert apples to oranges first and THEN perform the comparison between the two bags of oranges.

Indeed, we can see that "admin" when cast to integer, it returns 0 (
http://codepad.org/xQ9OH9ak)

So, all we need to bypass the authentication, is to fill the $user and $pass variables with 0. Which leads us to the second issue...

serialize/unserialize is evil

Serialize() is a simple way of transforming an object to a string in a way that the object can be "rebuilt" later, in order to save it somewhere (a file, a db, a cookie). When you want to get the object back, you retrieve the string, pass it to unserialize() and voila - your object as you left it.

When you retrieve a value stored in a cookie, it is always a string. Given this fact, we could never exploit the problem described above by simply putting "0" value in the cookie. But because the script used the serialize/unserialize method, we now can!

Reading the manual, we see that unserialize() takes a string and returns mixed (i.e. various valid language types). Now, we can construct a string that after being read from the cookie, it will hold integer values instead of strings.

So, Brain only need to hack his cookie to have this string:
Code:
a:2:{s:8:"username";i:0;s:8:"password";i:0;}

Indeed, we can see it 's working: http://codepad.org/kw1pOpHV

How do we construct that funky string? We can ask PHP to do it for us :)
PHP:
$z = array(    'username' => 0,    'password' => 0);echo serialize($z);

Prevention

Since the script uses the serialize/unserialize method, the programmer should have used the === operator instead of the == . The === does not do type casting, so if you compare apples with oranges, the comparison will always fail.
 
@jazzc
What about some new challenges ? It's good fun solving these! Reminds me of the challenge on hack this site!!
 
Back
Top