20 Sep, 2015

CSAW Qualifiers: Lawn Care Simulator Walkthrough

by John Poulin

For those who aren’t familiar, CSAW is an annual Capture the Flag (CTF) event hosted by NYU Polytechnic School of Engineering. It is a CTF intended for undergraduate students, but the qualifiers are open to anyone.

This post will walk you through one of the medium-difficulty web-application challenges.

Step 0: Load the Page

The first rule of web application testing is: PROXY EVERYTHING. Proxying played a huge role in the ability to solve this challenge quickly, without even having to parse through HTML source code.

Upon loading the page you could quickly discern that there was a login and user registration function, as well as some client-side JavaScript logic to “grow grass.” Running the app through a proxy indicated several interesting requests:

The .git folder in particular caught my attention. In the industry we see a decent amount of new developers that include their .git folder within their webapp, and that is a HUGE flaw. The other file worth noticing was the md5.js file, which may indicate that the site is leveraging client-side hashing.

Step 1: Download all the Things

Exposing a .git directory allows anyone to “pillage” the repository, using tools to recreate the source code from object files. DVCS-Pillage is a tool that will allow us to pillage their repository, hopefully allowing us to gain access to their source code.

Run the script on the target and you’ll see that it wants to make 8 requests. Allow it. After the script is complete you will have access to (some of) the site’s PHP code.

Step 2: Analyze all the Things 

One of the first things I noticed was the obvious ___HINT___ file. Taking a quick look, it didn’t appear overly helpful:

Before planting grass, add compost or other soil amendment to the soil to improve its ability to hold water.

Starting with the sign_up.php file I noticed that there was an obvious case of username enumeration. Because of their use of mysql_real_escape_string, SQL Injection was unlikely. The SQL query, however, was constructed with the use of the LIKE operator, rather than = operator. This allowed us to use the wildcard '%' to match any user within the application.

Step 3: Username Enumeration

I attempted to sign up with the user ‘%’, which resulted in a unique error message, thanks to the username enumeration vulnerability:

This response indicates that there is a user named _ FLAG _ in the system – if that couldn’t be more obvious ;)

Step 4: Bypass the Authentication Logic

Now, with access to a username we still needed to discover how we can authenticate. First instinct is to try to login with the known username and a common password such as ‘1234.’

The response simply indicated: “Not Authorized,” which wasn’t really helpful. With access to the source code it made sense to determine what was occurring behind the scenes.

The authentication portion included the flag.php file, which was not contained within the downloaded source code. Essentially, there is a validate function, which if bypassed, would provide the flag.

There were a few things worth noticing. The password provided needed to be the same length as the user’s hash. Since we saw that they were leveraging JavaScript to generate MD5 hashes, we assumed that the validate function was expecting $pass to be an MD5 hash, not a plaintext password.

If the password length matches, the script proceeded to a character-by-character comparison of the password and the users hash. In the event that the character matched, the script slept for 300,000 microseconds. This is a timing condition we could use to enumerate the password hash.

Step 5: Enumerating the Hash

Leveraging Burp Suite we captured a sign in request and replayed it via Repeater. Because we were dealing with a timing condition, it was important to take notice of the response time.

The normal response indicated a time of approximately 1,000 milliseconds. We proceeded to change the first character of the hash, iterating through all hexadecimal values until one had a noticeably different time.

The response time appeared to increase by about 300 milliseconds, which indicated that the first character of the hash was ‘6’. We continued to do this for the next character, too.

Eventually we discovered that the next character again, was 6. The current response time was about 600 milliseconds larger than normal, which is what we expected. We continued this approach for each character in the hash, until we received the flag.

Eventually the system responded with the flag gr0wth__h4ck!nG!1!1!