Breaking Ente's 404 page

Introduction

Recently, Aswin Asok of Ente added a chrome-dino like game to their 404 page with a leaderboard. Shortly after this was released someone changed their score to 999999

The leaderboard was implemented initially by just sending the score to an endpoint which only validated that the score was less than 999999 so that it fit on the score pill in the UI, however no other anti cheat.

A few minutes later I saw Aswin Asok post a meme about making it harder for cheaters to cheat the leaderboard. Challenge accepted.

strong doge vs weak doge meme, where the weak doge is showing a json payload of just sending the score directly, and the strong doge is showing an encrypted payload

The updated system has a few different parts

  1. The score is now sent as an encrypted blob to the server instead of just plain JSON
  2. Server side validation

The server side validation starts the second you press the play button by notifying the server that you have started a run and getting a runId that can be used to track the run throughout back. When you end the run, this will let the server compare if you lied about the duration of your run. The second part of the server side validation is to collect metrics client side and report it in the final blob when completing a run. This currently collects

These are compared against eachother and against reasonable limits to see if you have cheated, which invalidates your run. For example, if you tried to set the comboDuration really high your run would get rejected.

Breaking it

While the individual apps of ente is open source like Ente Photos, the Ente marketing pages are not open source, which is the only place the minigame is present. However thankfully Ente ships source maps so we can read and debug the frontend code quite easily, however not modify it.

My first attempt was to set a breakpoint at the top of the death function and manually type return every time. Sadly however you cannot use return while in a breakpoint

error showing "Uncaught SyntaxError: return not in function"

My second attempt was to give myself invincibility through the ingame shield powerups. I did this by putting a breakpoint at the top of the hitObstacle function and setting state.activePower to shield and state.shieldCharges to some high number every time I hit an obstacle.

Unfortunately however, I am quite bad at the game. This means that I end up hitting the breakpoint often and needing to manually re-enable shields again. This can be solved by abusing log points. Log points work somewhat similar to console.log(logpoint contents here), and since setting a variable also returns it, putting state.activePower = "shield" in the logpoint both sets the activePower attribute but also logs "shield" when encountered.

The results

Leaderboard showing a link to this post in first place with 12802 points

Thanks you Aswin Asok for the fun challenge!