CSAW 2013 WidgetCorp Writeup, with bonus coolness
The “WidgetCorp” challenge for the 2013 CSAW CTF was a really neat web exploitation problem. It was a challenge where I was super excited to work through the whole thing (not always the case for sure!)
It’s a light blue because I solved it but you get the gist. No information/comments are provided about what to expect so you’re going in blind here.
Here is a picture of the homepage for this site:
Interesting, looks like a very well put together site eh?
On our main page once we’ve logged in we have options to:
- Check our widgets
- Make a new widget
- Check out the new feature (a link to the logout page, also an attempt at humor)
Great, so let’s make a widget!
Alright, looks good. Once we submit this page we get:
So we made a new widget with ID 7574 – let’s check it out now.
Great, so we have options to view/edit our newly created widget. Let’s view it:
As expected we have a page were we can view our widget details. The URL for this page looks like:
Obviously the id=7574 is showing that we are viewing a widget with the ID of 7574 (as we saw the website tell us earlier).
Now any good hacker would try to go to this URL next:
Which sadly yields us a:
Well, what were you expecting?
So they are checking if we own the widget before displaying the information. But how do they do that?
Cookies should always be checked during any sort of web auditing, they are often forgotten about or not coded securely.
Great so we have the following cookies:
- PHPSESSID, which is PHP’s way of doing cookies.
- widget_tracker, an interesting field which I immediately recognized as being a base64 encoded value
- widget_validate, some seemingly long string of characters (128 characters in length – nudge nudge)
Let’s checkout that widget_tracker value first shall we?
YToxOntpOjA7aTo3NTc0O30%3D
**So we decode the url encoded string:
YToxOntpOjA7aTo3NTc0O30==
Oh my, that double equal sign makes me smile every time! (Almost always means base64 encoding!)
Base64 decoding that value gives us:
a:1:{i:0;i:7574;}
What is that?! Did someone screw up JSON? Nope, actually it’s the PHP serialize function. I got it right away because I do far to much programming in PHP. Basically it’s like JSON encoding where you take an array and turn it into a string.
So let’s script this:
This will allow us to better understand what is going on.
Interesting, so we see it’s an array of the widgets we’ve created! So we can simply reverse this function to create a valid cookie value, bypassing the authentication.
Not done yet! What about that other value widget_validate?
Now this one I knew right away from experience that it was a SHA-1 hash (based off it’s length/character set, if you ever need to figure out a hash type see https://code.google.com/p/hash-identifier/)
But what is being hashed? My username? Our PHP session ID?
So I figured this out by simply monitoring the cookies being used. Hacking is really just like being a scientist…
So all I did was watch when the widget_validate cookie value changed, in this way I could see patterns and hopefully determine how they do their authorization.
So I had multiple theories of how they did it but I noticed basically that anytime I added a widget the cookie value would change (after I viewed the new widget).
In this way I knew that the widget_validate cookie was changing based on the widgets that I had created.
After a bit of testing I found that the value was simple a SHA-1 hash of the serialized widget array (a:1:{i:0;i:7574;}).
Great, now lets translate that into some code:
So this code will generate a valid cookie to view any widget that we want. Basically you call it with the wanted widget ID and a valid PHP session ID and it will auto-build the cookie for you.
So here is a simple function that gets any page I give it, this function also has the “generate_legit_cookies” function in it so it will auto make the appropriate cookies, etc.
I ended up make a script that views everyone’s widgets and outputs their values and that was a BIG mistake. So much script kiddy input values (people running Acunetix, automated tools).
Here’s a funny screenshot of that output:
So big mistake, luckily I screwed up my code at some point when I put in a null value for the ID and got an SQL error from the website.
So I got that as an output and it immediately clicked for me, we’re doing SQL injection via cookies. This is something I’ve always wanted to do (security nerds have different dreams I suppose).
Now, I did this manually step-by-step but I’m going to show a better method in this blog post. The better idea I had after I won is what I’ll continue with here because it’ll convey a good idea for future problems like this.
The idea I had was to simply make my script this:
So basically I made a PHP script that acts as a psuedo proxy for any SQL injection tool I want. I just tell my tool that the site I’m injection is http://127.0.0.1/widget_wut.php?id=1. That PHP script just returns the output from the http://128.238.66.224/widget_list.php I guess you would call this being a “hybrid script kiddy” because the PHP script simply does all the cookie crazyness for the SQL tool you’re using.
So here is the PHP script in action:
So hopefully this makes it more clear what I’m doing here but I’ll continue regardless (my brain is fried from constant CTF playing, maybe I’ll come back later and clean this up).
So after this I pointed sqlmap towards this local page:
My output:
So it’s working alright, let’s get the databases to ensure it’s all good:
Great everything works well, the next steps are pretty straightforward.
So hopefully this conveys everything that I’ve done correctly 😉 I’m pretty burned out so I’ll come back later and edit things that I screwed up.
-mandatory