SANS Holiday Hack Challenge 2019 Postmortem — Part 2

Tan Kee Hock
CSG @ GovTech
Published in
9 min readApr 17, 2020

We hope you enjoyed Part 1 of this two part series that covered how the team used an SQL injection to uncover a mystery! If you haven’t already, read the article for interesting learning points such as how the “UpdateXML” function can be used to perform unauthorised information disclosure.

In Part 2, we’d like to share more about a web terminal challenge called the “Holiday Hack Trail”. In this game, your aim is to move your character over a certain distance before Christmas Day! The game contains some common vulnerabilities seen in today’s web applications. If you think you have a flair for white-hat hacking, give it a go before reading on!

The Holiday Hack Trail — Try it without referring to this post. No cheating! 😊

Know Thy Enemy

Cyber Tip #1: A cybersecurity specialist must gain a thorough understanding of the matter at hand before starting the exercise.

Let’s examine how the game works:

First, select the difficulty level: “EASY”, “MEDIUM” or “HARD”. The higher the difficulty, the less money and time that you have to complete the quest. Let’s not be too ambitious and start with the “EASY” mode.

Step 1 — Select Difficulty

Next, you can purchase some equipment to help you in your quest, and click “BUY” to proceed.

Step 2 — Purchase Supplies

Let’s Play!

Step 3: Play the game

The game begins. To complete the quest, your reindeer must drag the sleigh over an 8000-unit distance. Clicking on the “GO” button moves the sleigh by a small random distance. Playing the game this way will take a few thousand clicks on the “GO” button. This takes too long!

There must be a way to “GAME” the system!

Hack, this is way faster!

Now, let’s see how we can complete the game in this seemly impossible setting!

Reload the game in “EASY” mode. When you reach the game screen, pay attention to the in-game URL bar. The parameters (e.g. distance, money) in the in-game URL bar look familiar — these same variables appear in the game. Clicking on the “GO” button increases the value of the “distance” parameter by a random number. The in-game “Distance Remaining” field, which started at 8000 units, sees a reduction by the same value.

Pay attention to the parameters in the in-game URL
The value corresponds with each other!

This implies that the “distance” parameter in the in-game URL bar stores the value of the distance travelled by the character! Some quick thinking leads us to manipulate the “distance” parameter in the in-game URL bar to trick the game into recognising that the character has travelled an arbitrary amount of distance.

Since the character will cover a distance of more than 10 units (based on our observations) when we click “GO”, we then change the “distance” parameter to 7990, which indicates that the character has travelled 7990 units. By choosing a value close to 8000, we can ensure that the character is able to cross the finishing line in one turn when we click “GO”.

Simply edit the parameter and click “GO”

Voila! We cleared the “EASY” level simply by manipulating the “distance” parameter.

This scenario mimics a common issue we see in today’s web applications. To deliver dynamic and user-rich experience, some web application’s response or behaviour may be modified based on user-supplied inputs. Sometimes, these inputs are consumed directly by the web application, without being validated. As a result, unexpected values may cause the web applications to behave in ways they are not supposed to.

In this case, the “distance” parameter found in the in-game URL bar defines the in-game value of the distance travelled by your character. We can therefore change the distance travelled with our input and complete the game in just one turn.

There are risks that can arise from the lack of proper validations of user inputs, e.g. Cross Site Scripting (XSS) attacks, SQL Injections, Server-Side Request Forgery (SSRF), to name a few.

Cyber Tip #2: Developers should not trust user inputs to the application and must always validate the inputs to ensure that the incoming data conforms to the application’s requirements.

Too easy? Try something tougher!

Next, let’s attempt the “MEDIUM” difficulty level. This time, the in-game URL bar no longer contains the vulnerable parameter that we manipulated in the “EASY” level.

How about the HTTP requests? Could the exploit vector lies in one of the HTTP requests? To examine the HTTP requests fired when navigating the game, we configured the browser to redirect all HTTP traffic through a popular security tool, BurpSuite (I am using the community edition for this demonstration), before they go out to the internet. We want to examine the HTTP requests fired since the start of the game, and spot suspicious parameters that can potentially be misused to rig the game.

A couple of HTTP GET and POST requests were fired when loading the game, selecting the difficulty and buying equipment. In fact, the HTTP POST request to the “/trail/” URL looks fishy…

Expanding the HTTP POST request to “/trail/”, we see the “distance” parameter again. From the “EASY” mode, we now know that the “distance” parameter defines the distance covered by the character and we can complete the game immediately by modifying the value of the “distance” parameter. Now, how do we do that when the HTTP POST request is fired immediately by the game without our knowledge?

This is where BurpSuite’s “Intercept” feature comes into play. It allows us to intercept the request sent by the application, modify it and forward it to the target. At the equipment purchase screen, we turn on the “Intercept” feature of BurpSuite, change the value of the “distance” parameter to “7990” and forward the traffic out. The in-game value of the “distance travelled” is now set to the value “7990” and clicking on the “BUY” button will complete the game.

Intercepting the HTTP POST request and modifying it

TADA! We’ve completed “MEDIUM” mode in a few clicks!

Here, we exploit the vulnerable “distance” parameter again. The challenge is spotting the HTTP request that contains this parameter. Attack-proxy tools help us better identify these parameters and modify them to test for vulnerabilities. Similar to the “EASY” mode, the vulnerability is the acceptance of an unverified user input to the value of the “distance” parameter, which defines the in-game value of “distance remaining”.

It’s common for web applications to fire requests to a backend server to retrieve values or perform certain tasks. With more web applications adopting an API-driven architecture, the front-end application is responsible solely for rich user experience, leaving the backend server to perform the processing. To ensure a seamless user experience, there’s constant interaction between the front-end web application and the backend application.

While browsers come with “developer” features for visibility of the network traffic from the web application, they do not contain features available in tools like BurpSuite to facilitate the testing. Security professionals (like us!) use these Attack-Proxy tools, like BurpSuite, to assist in testing of these parameters.

Difficulty Level: Hard. Challenge Accepted!

This is “MEDIUM” mode, with a twist. A similar set of parameters are sent to the same endpoint (“/trail/”), except that the request comes with an additional “hash” parameter.

New “hash” parameter

This prevents us from using the same technique in “MEDIUM” mode, as it returns a “badHash” error message. The server is detecting tampering attempts with the use of the new “hash” parameter.

“badHash” message

How do we “crack” the “hash” parameter to bypass the system’s anti-tampering mechanism?

First, use a use a tool (like BlackPloit’s “hash-dentifier”) to ascertain the type of hash algorithm. You can also check out this website that does the same thing.

Output from hash-identifier

MD5 hash is obsolete by today’s cryptographic standards. In fact, you can easily find the corresponding plaintext value of an MD5 hash online. Sites like hashes.org allows the community to perform MD5 hash lookups to search for the corresponding plaintext value.

Plaintext found

Our simple search tells us that the MD5 hash has a plaintext value of “1626”. What does this value mean? After spending much time studying the POST request parameters, we observe that the values of certain parameters add up to “1626”. To put that theory to test, we will proceed to modify the parameter value to identify the parameters that affect the hash computation. If the website returns a “badHash” error, the modified parameter is used in its anti-tampering checks.

Let’s test this out with the “distance” parameter. Modifying its value caused the web application to return a “badHash” error, hence the “distance” parameter is used in the calculation:

“distance” parameter is used in the MD5 calculation

From this, we infer that when the server receives the request, it computes the hash value based on the sum of these parameters. When the newly computed hash value differs from the original in the HTTP POST request, the server detects a tampering attempt and returns a “badHash” error message. We’ve figured out the server’s anti-tampering mechanism!

Further testing showed that these parameters are used in the calculation of the MD5 hash:

1. curmonth (9)

2. curday (1)

3. money (1500)

4. distance (0)

5. ammo (10)

6. food (100)

7. runners (2)

8. reindeer (2)

9. meds (2)

You need only identify one vulnerable parameter (“distance”) to complete the exploit, not all. Since we already know that “distance” defines the distance travelled in the game, we can simply modify its value and update the hash value accordingly. Let’s exploit!

Modify the “distance” parameter to “7990” (the magic number explained earlier), then use an open source tool, e.g. md5sum (a common utility found in most Linux distributions), to generate a new MD5 hash based on the new total value of “9619” (7990 + 1626 = 9616).

Calculating the new MD5 hash value

Upon changing the distance parameter and modifying the hash value, we bypass the system’s anti-tampering mechanism. The in-game value can now be modified:

Intercepting and modify both the “distance” and “hash” parameters

We won the game!

Despite the anti-tampering mechanism in place, we manage to work around it! The underlying vulnerability was the use of a user-supplied input for the anti-tampering checks. To improve this anti-tampering safeguard, the “hash” parameter should not be exposed.

In this case, there is no need for the web application to send the hash value back to the server since the server already knows the default starting values and hash computation can be done entirely on the server’s end. The server is able to detect any deviation from the expected and return a response accordingly. In fact, there is no need to expose the “distance” parameter at all.

(Download these) Learning Points

We touched on techniques to manipulate the HTTP GET and POST parameters, which are common injection points that malicious actors exploit when attacking web applications. We’ve also seen how manipulation of parameters sent to the server has allowed us to “game” the system, all because the server trusted the user inputs without proper validation.

The key takeaway is — from a developer’s perspective — it’s never a good idea to trust user inputs. Developers should always validate user inputs and never let the user control important parameters!

Participating in Capture-The-Flag competitions like these are not only fun, but allows us to explore new techniques / tools and build a stronger foundation in cybersecurity. Find out more about the challenge and our submission.

We hope this article has helped to spur the inner “hacker” in you! Taking the first step into “hacking” is difficult, but it’s also what defines us.

So “hack on”! 😊

--

--