Skip to content

Latest commit

 

History

History
68 lines (42 loc) · 2.73 KB

File metadata and controls

68 lines (42 loc) · 2.73 KB

babygame02

Overview

200 points

Category: Binary Exploitation

Tags : #picoCTF 2023 Binary Exploitation game

Description

Break the game and get the flag. Additional details will be available after launching your challenge instance.

Solution

Let's download .exe. Start Ghidra

Decompiling. Arrange the local variable names, so that the code is easier to read. Note the win function that outputs the flag - there is not reference to it, it is not called anywhere.

Inside the move_player function we can see a hidden command l<symbol> - it changes the symbol, that represents the player.

So we can use it as follows:

  1. player:@
  2. command:l3
  3. player: 3

It means, that we can change one byte inside the array of chars, that represents a map.

The following line is responsible for placing player character on the map:(undefined size is 1 byte):

*(undefined *)(*playerCoordY * 0x5a + map + playerCoordY[1]) = player_tile;

It means, that we can travel across the memory byte by byte, because int value (*playerCoordY * 0x5a + map + playerCoordY[1]) was casted to a pointer on value of size 1 byte. And we can change one byte anywhere in the stack. It's not much we can do - and the first (and it is right) thought would be about changing the return address.

We can see, that return address of move_player inside main is 08049704 and start address of the win function is 0804975d. They differ by one byte. Now we, what we need to do.

5d is equal to char ']'.

Run a debugger you're comfortable with - I was using gdb+gef. Place breakpoint on move_player and inspect the stack.

Offset from the beginning of the array to the first byte of the return address from move_player is equal to 39. It means, that we need to make 39 steps to the left from the top left corner.

But program will crush, if you do like that. So we need to move up from top left conner (because with that we will move by 90 bytes in one step, and will not overwrite something important on the stack with our player-char).

So we need to make one step up. Then we make 39 steps to the left. And finally - make one step down (it eliminates out +90 bytes offset from the beginning) - and it's done.

Locally it will work just fune. Yay!

Then you will run that remote and it will not work.

I don't know why, but buffer will not flush, if you jump exactly to 0804975d - the beginning of the win. So we just try addresses of next instructions until it works.

It worked with 08049779, and 0x79 == 'y'


So, here is the input for the task:

ly
aaaa
wwwww
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
s