This is the third part of the Flare-On 6 CTF WriteUp series.
3 - Flarebear
The challenge reads
We at Flare have created our own Tamagotchi pet, the flarebear. He is very fussy. Keep him alive and happy and he will give you the flag.
Different from previous, this is an Android challenge. We are provided with an APK - flarebear.apk. Let's install and run this in an Android Emulator. I prefer Genymotion but you can use any other emulator or even a real physical device.
The game prompts us to create a "New Flare Bear". Let's create one and give it a name.
At the bottom, we have three buttons - Feed, Play & Clean. Keeping the bear inactive makes it unhappy and it starts to cry.
Our objective is thus to keep the bear happy by feeding, playing and cleaning at regular intervals. However we have no idea the order in which we do this. To understand the core logic of the game we need to study its code. We can use JADX to decompile the APK to its Java source.
The FlareBearActivity
class implements the game logic and resides in the com.fireeye.flarebear
package. The presence of import kotlin.text.StringsKt;
suggests that the game was most likely developed in Kotlin as opposed to Java.
Corresponding to the three actions - feed, play and clean we have three methods.
Each of the methods in turn call other methods to change some internal state variables. The changeMass
, changeHappy
and changeClean
changes the mass, happiness and cleanliness by a given amount respectiviely.
- Feeding increases mass and happiness by 10 and 2 units respectively while reducing cleanliness by 1 unit.
- Playing decreases the mass and cleanliness by 2 and 1 unit respectively while increasing happiness by 4 units.
- Cleaning increases cleanliness by 6 units while decreasing happiness by 1 unit. It doesn't change mass.
Internally, these methods make the changes and store the updated value using the setState
method.
The setState
method uses Android PreferenceManager to store the state values as a key-value pair.
In each of the feed
, play
and clean
methods there was a saveActivity
call with character f
, p
, and c
passed as argument respectively. Lets look at its code.
All saveActivity
does is to fetch a state variable named activity
and append the character to it.
We have also seen a call to setMood
from the clean
method. The decompiled code looks interesting.
If both isHappy
and isEcstatic
return true it calls danceWithFlag
. This is what we want. Let's have a look at both of the methods.
isEcstatic
returns true only if the mass, happiness and cleanliness state variables are 72, 30 and 0 respectively.
isHappy
returns true if result of getStat('f') / getStat('p')
lies in the range 2.0 to 2.5. The getStat
method counts the occurrences of the character in the state variable named activity
. We have seen before that the saveActivity
method appends a character to this state variable.
In other words, isHappy
will return true if the number of times we feed divided by the number of times we play lies in the aforementioned range.
Armed with the above information, we can form some equations. Let us denote the number of times to feed, play and clean be f
, p
, and c
respectively. Initially, mass, happiness and cleanliness are all zero.
Final Mass = 10f - 2p
Final Happiness = 2f + 4p - c
Final Cleanliness = -f -p +6c
Thus we have these system of equations,
Putting these system of equations in Wolfram Alpha, we get,
Thus, we need to clean 2 times, feed 8 times and play 4 times in order to make it happy and ecstatic which should gives us the flag. Let's try it out. There is no specific order in which we should feed, play and clean, but we should make sure that the number of times we execute each action equals the equation results.
Executing the required actions, make the bear happy and it gives us the flag.
Flag: th4t_was_be4rly_a_chall3nge@flare-on.com
Finally, its worth mentioning what if we patch isHappy
and isEcstatic
to return true instead of finding correct the number of times to execute each action. Will that gives us the flag too?
Unfortunately, this approach won't work. The number of times is used to derive a password which is used as a key to decrypt an encrypted resource using the AES crypto algorithm. Without the correct key we will not be able to decrypt the resource.