Sep 12, 2012

Stripe’s Capture the Flag 2.0 – Level 5

Michael Tarantino

Michael Tarantino

Default image background

This article is part 6 of a 10 series blog detailing the approaches and solutions to hacking through Stripe’s 2012 CTF 2.0. To continue from the parent article, or see more hacks, please click here.

This blog entry details the approach used by Michael Tarantino in attacking the Stripe CTF 2.0 Challenge Level 7.


Thanks for hanging this far! My name is Michael and I am a consultant with Credera. I will be your Stripe guide for the next three levels, so let’s get rolling!

Level 5 is not exactly an attack with a fancy acronym like XSS or LFI; it is simply a failure to create a good authentication scheme. It is often easy to get caught up in the glamour of sanitizing your query params to avoid SQL injection and adding nonces to all your forms, but we can’t forget to fully vet our ideas to make sure they are not fundamentally flawed to begin with. Although Level 5 employs some of these “fancier” attacks, it has a fundamental weakness that would make it very difficult to secure no matter how careful the developers are.

Let’s get more specific. The scenario presented is as follows: A new centralized authentication system called DomainAuthenticator has been brought online. Its functionality is simple enough to understand. First, you provide a username, password, and a pingback URL. The DomainAuthenticator then posts your credentials to the pingback URL, which will respond with “DENIED” or “AUTHENTICATED.” A few closing notes [or, in my opinion, clues on how to go about attacking the thing] are given, namely that pingback URLs must be on the stripe-ctf domain, and that the internal firewall between Level 2 and Level 5 has been left wide open in the high ports.

I’m sure your gears are already turning on how this exploit is going to go, but I’ll start hitting some high notes and lead things in the right direction just in case. First, we know that Level 2 is almost certainly going to be involved, unless Stripe decided to just mislead us in an extremely overt way. Also, we know that the DomainAuthenticator is going to be looking for “AUTHENTICATED” from the pingback URL as its clue that your credentials were correct [the pingback URL being something we provide, MAJOR security flaw]. These two pieces are all we really need to get started.

The first step is to figure out where we can have the DomainAuthenticator make its auth request. This step more or less takes care of itself because of the clue about the Level 2 ports, as the local file inclusion attack we exploited back in Level 2 is clearly what we’ll want to do here. By providing a pingback URL that references a file of our making in the Level 2 environment, we can simply return “AUTHENTICATED” and we’re done…right? SWEET! Lets get hacking on some php.

The following php script will echo *AUTHENTICATED* which, according to the regex on line 110 of the sample code, will match what the DomainAuthenticator is looking for, and we’ll be auth’ed in no time. See code below in my file, yesMan.php:


<?php echo "*AUTHENTICATED**\n" ?>


Simple enough. Pushing this up to the Level 2 server the same way we did before gives us what we need, an “auth for anything” machine. Now we simply provide dummy credentials, and a pingback URL of and YAHOO! We’re authenticated!…as @level-2? Hmm…

So we’re not there yet. We’ve managed to authenticate, but not as the user with the password. For the password to be displayed, our auth host has to match the PASSWORD_HOST [see line 57 of the sample code], which in this case is level-5.

After some analysis, faking this is not really an option. We are going to have to get an auth message from level-5 servers. So are we back to square one? No, we’re not!

To understand the next step, we have to look at the code a bit. More specially, let’s look at how the pingback param is handled. Actually, “handled” is sort of an overstatement. This is just a run-of-the-mill query parameter, which is exactly why we are going to be able to use it to our advantage. The form we filled out earlier providing our credentials and a pingback URL is really just shoving these fields into query parameters, meaning we could just as easily hit this url directly: Clearly, this once again auth’s us as @level-2, which is still not what we want.

However, what if we passed this in as the pingback URL? That should cause Level 5 to ask itself for an auth, which in turn will ask Level 2 for an auth because of the pingback query param. Because the auth page actually shows the response from Level 2, we are effectively injecting the response into the Level 5 page! To review, DomainAuthenticator asks level 5 for authentication, but that request spurs an additional request for authentication to level 2 because of the additional pingback query param. Level 2 responds with *AUTHENTICATED**\n, which is put into a page “Pingback URL responded with “*AUTHENTICATED**” or something to that effect, which is then scanned again by the regex for the original auth request, and it once again matches, thus authenticating us again, but this time, as @level-5! Huzzah!

And what was that fatal flaw I spoke of in the beginning? Plainly put, allowing a user to provide their own pingback URL is likely not a good idea. Although a working firewall or better regex could have prevented this exploit, it is a fundamentally bad idea to allow a user to have such a high level of control over what authenticates them. A better idea would have been to expand the API to allow various trusted authentication URLs to be selected by the user rather than providing a URL themselves [or, something…maybe I’m trying to make a mansion out of popsicle sticks…] Enough asides, to Level 6!


These solutions are presented as a unique approach to a recent CTF hacking contest as an outreach of the Credera Security Team. All ‘hacking’ was performed in an ethical manner in accordance with Credera’s Core Values. For further information on Credera’s offerings in ethical hacking, security, compliance, and OWASP preparedness please contact us at

Conversation Icon

Contact Us

Ready to achieve your vision? We're here to help.

We'd love to start a conversation. Fill out the form and we'll connect you with the right person.

Searching for a new career?

View job openings