Home Buckeye CTF 2022 - pong - Writeup
Post
Cancel

Buckeye CTF 2022 - pong - Writeup

challenge-description

Playing by the rules?

Let’s take a look at the website:

picture-2

The website lets us play a classic game of pong. We can begin the match by pressing P to serve and then move the left paddle up and down with W and S. As simple as it is, pong is a pretty cool game. However, the challenege description was kind of right - you cannot really beat AI controlled paddle. At least not the intended way.

We do a little cheating

This version of pong is mostly a client-side rendering game. We can see the code responsible for playing the game in index.html file. When you open the webpage, draw() function draws the game canvas and from this time on setInterval(tick, 13) makes sure that every 13 milliseconds tick() function is triggered to update the state of the game which then re-draws the whole canvas at the end with draw() .

The reason you cannot beat the AI is because the right paddle y position will always match position of the ball (p2 = by):

1
2
3
4
5
// tick() function
// controls
if(p1 - up * .01 > pl / 2) p1 -= up * .01;
if(p1 + down * .01 < 1 - pl / 2) p1 += down * .01;
p2 = by;

Okay, so we know there is no way to beat the AI in a fair game. But what if we wanted to cheat a little? Let’s take a look at how the game awards points for scoring.

1
2
3
4
// tick() function
if(bx < -.1 || bx > 1.1) {
    socket.emit("score", bx);
}

The game takes horizontal position of the ball (bx) and checks if it exceeded the boundaries of the game. If bx is less that -0.1 then the ball flew off the left side of the screen (point for AI) and if bx is more than 1.1 then the ball flew off the right side of the screen (we scored a point). However, point scoring happens server side - the client only informs the server with socket.emit("score", bx) that the ball was in either of scoring positions.

Right, so what would happen if we triggered socket.emit("score", 1.2) manually, from developer console? This would make server believe that we actually scored a point.

picture-3

Yep! That’s exactly what happened. Just for the sake of testing, let’s call socket.emit("score", -0.2) to see if AI will be awarded the point.

picture-4

Point for AI, just as expected. So now we can either call socket.emit("score", 1.2) a bunch of times or just put it in a for loop to win the game and get the flag.

picture-5

This post is licensed under CC BY 4.0 by the author.