Troopers 23 Badge Challenges
Troopers conference is known for its fabulous hardware badges. This year, we were given an ESP32-base badge. In an workshop, we could solder a Shitty-Addon with colored LEDs and a connector for a remote control.
In addition, the badge was featuring 2 challenges. Similar to CTF-challenges, when solved, the challenges would give you a token, you’d submit the token on a local troopers website, and get raffle tickets after a given number of points.
- Battleship: an exploit challenge
- U-Boot: a serial port challenge
Battleship
The badge featured a battleship game. You play the game against the computer, select where to hide ships, and try to find computer ships before computer finds yours.
Battleship game splash page*
Fire at guessed locations, and try to sink your opponent’s ships
The source code of the game is given to participants.
I solved this challenge with the help of Kev, thanks!
Locating the flag
We quickly spot where the flag should be (but of course, it is not provided):
|
|
We need to get in this case GAMESTATE_HIDDEN_FLAG
. We also learn that this is not reverse engineering challenge: we need not dump the firmware, but an exploit that can be triggered from the game itself.
So, how do we get in this state? The switch is on the game status. The possible game states are defined as an enumeration at the beginning of the file.
|
|
There is no place where we can explicitly state the gamestate to GAMESTATE_HIDDEN_FLAG
. We have a look at the type of gamestate
:
|
|
The state is an integer. Before that we have a couple of arrays such as computer_hits
or player_hits
, with a fixed size of MAX_SHIP_FIELDS
.
|
|
Finding the overflow
Is there a possible overflow? We spot those lines which happen when we hit a ship of the computer:
|
|
Can we have the index gamestate->player_hits_idx++
be bigger than the allocated size for the player_hits
table? Yes! Actually, there is no control on the limit of this index. So, for instance, if we keep hitting the same location on the map, player_hits_idx
will increment and we can get it to overflow the next values.
As we have an integer round
between the player_hits
table and our target state
integer, we’ll have to hit the same location 14+4=18 times to start overflow the state.
Exploiting to get to the desired state
Recall we need to get to state 7. So, we need to overflow state and write value 7 in it. How can we control the values we overflow the memory with?
|
|
With the position of the cursor!
So, we need to find what corresponds to cursor=7
. The code is nicely commented for that.
|
|
Exploit
The methodology is the following:
- We start a game and randomly place our ships (we don’t care where they are located).
- We fire at the 2nd column of the 2nd row. If there is no ship there, we won’t be able to get to the desired stage, and we restart the game.
- If there is a computer ship at that location, we repeatedly fire at that location. After more than 14 hits at the same location, you should see the round overflow:
Notice the round overflow: exploit under progress!
- We continue to hit the same location, and at some point (after 18th hit), we should finally overflow the state and get in the desired FLAG state and get our flag!
We got the token!
Conclusion
I loved this challenge! The fact it can be solved directly from the badge is an added bonus. You just need to read the code with attention.
U-Boot
Another challenge suggested “have you tried to restart the badge?” The name of the challenge suggested there would be something to see during the boot phase.
I connected to the serial port of the badge with picocom -b 112500 /dev/ttyUSB0
, and re-started the badge.
The hexadecimal value didn’t work - as a matter of fact badge tokens were only integers. So, Kev and I simply converted the values to decimal ;-)
8932-5861-1530-4735-6252
is the correct flag!
Easy! An introduction challenge to connecting to the serial port.