Flare-On 2020: 05 - TKApp
Challenge 5 - TKApp
Now you can play Flare-On on your watch! As long as you still have an arm left to put a watch on, or emulate the watch’s operating system with sophisticated developer tools.
Ok, all we’re given for this challenge is a .tpk file. A quick search in Google tells us this is related to smart watch software. A hex editor (and Wikipedia) tells us that this is simply a ZIP file given the file magic of 50 4b 03 04
. Our zip extraction with 7zip reveals a bunch of files, the most interesting of which (given the name) is TKApp/bin/TKApp.dll
Let’s try to get some information about this binary by using PEiD
PEiD tells us that this dll was written in C#. This means we can throw it into ILSpy and have it decompile it for us!
After searching around for a while, learning the interface, and understanding the code, the function GetImage()
seems of interest.
private bool GetImage(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(App.Password) || string.IsNullOrEmpty(App.Note) || string.IsNullOrEmpty(App.Step) || string.IsNullOrEmpty(App.Desc))
{
btn.Source = "img/tiger1.png";
btn.Clicked -= Clicked;
return false;
}
string text = new string(new char[45]
{
App.Desc[2],
App.Password[6],
App.Password[4],
App.Note[4],
App.Note[0],
App.Note[17],
App.Note[18],
App.Note[16],
App.Note[11],
App.Note[13],
App.Note[12],
App.Note[15],
App.Step[4],
App.Password[6],
App.Desc[1],
App.Password[2],
App.Password[2],
App.Password[4],
App.Note[18],
App.Step[2],
App.Password[4],
App.Note[5],
App.Note[4],
App.Desc[0],
App.Desc[3],
App.Note[15],
App.Note[8],
App.Desc[4],
App.Desc[3],
App.Note[4],
App.Step[2],
App.Note[13],
App.Note[18],
App.Note[18],
App.Note[8],
App.Note[4],
App.Password[0],
App.Password[7],
App.Note[0],
App.Password[4],
App.Note[11],
App.Password[6],
App.Password[4],
App.Desc[4],
App.Desc[3]
});
byte[] key = SHA256.Create().ComputeHash(Encoding.get_ASCII().GetBytes(text));
byte[] bytes = Encoding.get_ASCII().GetBytes("NoSaltOfTheEarth");
try
{
App.ImgData = Convert.FromBase64String(Util.GetString(Runtime.Runtime_dll, key, bytes));
return true;
}
catch (Exception ex)
{
Toast.DisplayText("Failed: " + ex.Message, 1000);
}
return false;
}
To create the image, we’ll need to find out how App.Desc
, App.Password
, App.Step
, and App.Note
are generated
App.Desc
For each of these variables, the process will be fairly similar. ILSpy provides us with an “Analyze” function that can track where a particular variable is used or set.
In the case of the Desc variable, let’s follow this to IndexPage_CurrentPageChanged()
.
private void IndexPage_CurrentPageChanged(object sender, EventArgs e)
{
if (base.Children.IndexOf(base.CurrentPage) == 4)
{
using (ExifReader exifReader = new ExifReader(Path.Combine(Application.get_Current().get_DirectoryInfo().get_Resource(), "gallery", "05.jpg")))
{
if (exifReader.GetTagValue(ExifTags.ImageDescription, out string result))
{
App.Desc = result;
}
}
}
else
{
App.Desc = "";
}
}
Looks like this function reads the ImageDescription tag on the image TKApp/res/gallery/05.jpg and stores the result in Desc. In less than a minute, we have our first variable assigned a value: “water”
App.Password
We see password is set in OnLoginButtonClicked()
. Below is that function:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
if (IsPasswordCorrect(passwordEntry.Text))
{
App.IsLoggedIn = true;
App.Password = passwordEntry.Text;
base.Navigation.InsertPageBefore(new MainPage(), this);
await base.Navigation.PopAsync();
}
else
{
Toast.DisplayText("Unlock failed!", 2000);
passwordEntry.Text = string.Empty;
}
}
IsPasswordCorrect()
returns true if the input matches Util.Decode(TKData.Password)
. TKData.Password
is statically set to a byte array and Util.Decode()
simply XORs each byte with a key of 0x53
. We can use CyberChef to extract the expected password of “mullethat”
App.Step
Step is set in PedDataUpdate()
. The following snippet of the function shows how it’s set:
if (e.get_StepCount() > 50 && string.IsNullOrEmpty(App.Step))
{
App.Step = Application.get_Current().get_ApplicationInfo().get_Metadata()["its"];
}
After searching for a while, the metadata can be found in tizen-manifest.xml in the root of the TKApp directory. The value of the key of “its” is “magic”
App.Note
ILSpy tells us that Note is set in SetupList()
private void SetupList()
{
List<Todo> list = new List<Todo>();
if (!isHome)
{
list.Add(new Todo("go home", "and enable GPS", Done: false));
}
else
{
Todo[] collection = new Todo[5]
{
new Todo("hang out in tiger cage", "and survive", Done: true),
new Todo("unload Walmart truck", "keep steaks for dinner", Done: false),
new Todo("yell at staff", "maybe fire someone", Done: false),
new Todo("say no to drugs", "unless it's a drinking day", Done: false),
new Todo("listen to some tunes", "https://youtu.be/kTmZnQOfAF8", Done: true)
};
list.AddRange(collection);
}
List<Todo> list2 = new List<Todo>();
foreach (Todo item in list)
{
if (!item.Done)
{
list2.Add(item);
}
}
mylist.ItemsSource = list2;
App.Note = list2[0].Note;
}
Reading through the code, Note ends up being set to the second string of the second Todo object in the list: “keep steaks for dinner”
Wrapping it all up
Now that we’ve finished our side quests, we return to GetImage()
. Using the strings we obtained in the last 4 sections, the text
variable ends up being “the kind of challenges we are gonna make here”, our key
is the SHA256 hash of text
(248E9D7323A1A3C5D5B3283DCB2B40211A14415B6DCD2A86181721FD74B4BEFD
) and our bytes
(IV) is 4e 6f 53 61 6c 74 4f 66 54 68 65 45 61 72 74 68
(or “NoSaltOfTheEarth”). These variables are passed to GetString()
, which simply AES decrypts data with a key and an initialization vector - key
is the key and bytes
is the IV. The ciphertext is obtained from Runtime.Runtime_dll. After searching for a bit in ILSpy, I found Runtime.Runtime_dll file here:
We can right click –> save code on this item in ILSpy, upload it to CyberChef’s input and use CyberChef’s AES decrypt routine, along with the key and IV we found previously, CyberChef gives us a suggestion to use FromBase64 and RenderImage on the result which gives us the flag:
Flag: n3ver_go1ng_to_recov3r@flare-on.com
Side note
If you reverse The Init()
function, the Latitude and Longitude are set to 34.6252, -97.2117 based off of the coordinates embedded in the metadata of res/gallery/04.jpg. I haven’t seen Tiger King, but my guess is that this the location of the park owned by Joe Exotic in the show.
Click here to return to the Flare-On 2020 overview page.
Leave a comment