Journal: FlareOn7 (Part 1)

asuna amawaka
insomniacs
Published in
14 min readOct 24, 2020

(edit: I’m sorry that some of the screencaptures for the solution python scripts are really low resolution. Go to my GitHub repo to download them! https://github.com/asuna-amawaka/Flareon7-2020)

This year marks my 4th participation in FlareOn challenges :) I’ve learnt so much from other participants every year, and I think it’s good time I try to write my own post this time. Ok, let’s go!

(Python) 1_-_fidler

The first challenge has always been straightforward — judging from how the first blood was always drawn in minutes. No surprises from this one too. Unzip the challenge and go straight for the .py file.

Anything that has a name with the word “flag” in it is interesting — this function “decode_flag” looks to be super interesting. If this challenge is in the 10th or 11th stage, I wouldn’t be so sure, but hey this is the first one, so let’s go after it.

Tracing back, we find a “victory_screen” function that takes in a token which is to be decoded to form the flag. So…

Well then, this looks like it’s the end of our hunt — some hardcoded numbers and leads up to victory_screen(). Shortening the python, we get:

I feel bad that I didn’t see the kitty when I was solving this.

(UPX, Fixing PE Header) 2_-_garbage

First, try to run the file:

Signs of a corrupted file *sigh*. Now whip out your hex viewers, everyone..

Wonderful. Looks like the file is truncated. Looking at what is available within the file, what’s missing appears to be the import table. And.. the file is UPX-packed. But the UPX tool was not able to unpack it because the file is “broken”, too bad.

Ok so, fix the missing import table, yes? I’m not sure if I’ll be successful with that since I don’t even know what should be in the import table. How about write my own executable, UPX-pack it, then use it to patch this binary so that UPX unpacker can at least be able to act on it, so I may statically analyze the code? Yes, let’s do that.

I went on to Microsoft documents, randomly picked a function and took their example code like this one here: https://docs.microsoft.com/en-us/windows/win32/api/winhttp/nf-winhttp-winhttpconnect, compile and UPX-pack it. Then copy the bottom part of the file over to our challenge binary. Voila?

Ok, IDA Pro opens the file without complaining, good. One of the first things I’ve always done as a malware analyst was to look at the strings in the binary. Habits die hard, and here looking at strings has proven to be fruitful.

Yes, covid-19 sucks indeed. Also, there are two very long encrypted(?) strings. Let’s see how they are used.

Ok, looks like they went into sub_401000 to be decoded? Follow it!

That’s a simple loop. Solve it now!

Unfortunately, I don’t see any tankers.. Think my approach for these flags is too crude, but a flag is a flag. Next!

(Binary data, Debugging) 3_-_wednesday

Ah yes, the frog game. I heard some folks won this level purely by playing — so amazing! My fingers and brain will never coordinate well together to be able to hit the right button 296 times. Oh well, back to doing this the “traditional” RE way.

This binary looks like it is written in Nim, with the Nimgame2 engine. But when I was reversing this binary, it didn’t really matter to me which language it was originally written in. The disassembled instructions were pretty easy to follow with all the descriptive names. Anyway, I went straight in to look for the “success path” — which function leads to winning the game?

Poking around the main module, we can see this variable “_winScene_” that suggested that this is what will be displayed after winning, and probably contains the flag. So let’s follow it and see where it’s used.

One of the xref leads us to this code snippet that does a comparison, and if the comparison is true, the winscene is given to a function to be rendered.

Tracing through the function above, the value in [eax] seems to be the current score — so if the score is 0x128, we get to load the winscene. Ok, but before we get excited, let’s see what happens to the winscene to confirm if this is the “success path” we are looking for. Diving into the function @sceneeq, we come to this show function that retrieves a player text, and sets it on the scene. Ooh.. is that our flag?

Within this @getPlayerText function, there is a loop that looks like it is converting something to a character, and this loop is expected to be executed 7 times before the character is formed… hmmm… could that be ASCII in binary form?

The debugger can help us from here forth J Let’s get to it.

So I patched [eax] to be 0x128, continue execution. The binary crashed :<

Tracing the crash, it looks like it originated from that loop we saw earlier, when trying to convert binary to char (my unverified hypothesis at this point). Let’s see which value it was trying to read.

It was trying to read 8 bytes from where the value 0x128 was found. Not sure what this value is supposed to be… since this 0x128 is supposed to be a score, maybe try to watch this memory address for changes when playing the game? Sounds like a plan.

I edited the breakpoint at 0x433FAD to break when the score hits 8.

Ok, after pressing the correct button for 8 times, the breakpoint hit. Now look at the memory space 8 bytes after the score: 00 00 01 01 00 00 00 01. Looks very binary to me…

Let’s try breakpoint on [eax]==0x10 instead, to confirm that we are indeed dealing with some binary values. The result of that is…

Yes, still binary! And that series of binary values looks like the button that was pressed i.e. duck or jump. Repeat this a few times, and we would notice that these values do not change! Which means that all 0x128 steps/obstacles the frog has to overcome could be found statically somewhere in the binary (hopefully!) or in the memory (I supposed if the author is sneaky he can make this 0x128 be decoded/decrypted into memory at runtime). Let’s try searching in the binary first.

Here it is! 0x128 bytes of 0s and 1s.

Nice! Now try to get the result string that is returned from @getPlayerText.

Patch the memory again, this time with all 0x128 “expected moves” and put a breakpoint on 0x4349C0 to view the result_text that is formed from the binary values.

And that’s it. We are done :)

(OLE, VBA, Data packing) 04_-_report

Malicious documents are always a hassle to analyze, but they’re still one of my favorites. Let’s dip right in!

Using olevba tool, we are able to extract all the macros in report.xls

The next step would be to analyze the functions and make it produce the flag for us.

The starting point is the function “folderol”. Here’s the python reimplementation of the functions:

The file “F.L” in my script above refers to the content extracted from F/o

The strings decoded are:

rigmarole(onzo[1]) = AppData
rigmarole(onzo[2]) = \Microsoft\stomp.mp3
rigmarole(onzo[3]) = play
rigmarole(onzo[4]) = FLARE-ON
rigmarole(onzo[5]) = Sorry, this machine is not supported.
rigmarole(onzo[6]) = FLARE-ON
rigmarole(onzo[7]) = Error
rigmarole(onzo[8]) = winmgmts:\\.\root\CIMV2
rigmarole(onzo[9]) = SELECT Name FROM Win32_Process
rigmarole(onzo[10]) = vbox
rigmarole(onzo[11]) = WScript.Network
rigmarole(onzo[12]) = \Microsoft\v.png

From the strings, we can deduce there are going to be 2 files being created — one of them should hold the flag, or clues to the flag. Within the folderol function, stomp.mp3 is created from contents read from “F.T.Text”, which came from second part of F/o.

But sadly..

This is not what I should be looking at, huh. What about v.png? Here comes the question: what should be decrypted into v.png? There seems to be no more code in the vba that does this..

Hmmm, it looks like when stomp.mp3 is created, not all of F.T.Text is used (only the first 0xA4B6C bytes. 0xA4B6C/4 = 168667). So what about the rest?

Let’s take a closer look at the decrypting function “canoodle”.

for cattywampus in range(0, len(panjandrum)-1, 4):
kerfuffle[quean] = int(Mid(panjandrum, cattywampus+ardylo, 2),16) ^ bibble[quean % len(bibble)]

It looks like 4 bytes are taken at once (step of 4 each loop), but only 2 bytes are used in the XOR decrypting. There’s also this ardylo variable that is given as 0 when canoodle is called.

Taking another look at the data in F.T.Text, notice how the remaining unused data starts with 00. My guess is, there are 2 files being “packed” within 4 bytes — the first 2 bytes are used to decrypt into the first file, and the other 2 bytes make up the second file. We can test this to see where it brings us.

canoodle(fttext, 2, 468336, xertz)

Nope, nothing good came out of this.

There are now two possibilities: the key used to XOR-decrypt is different for v.png, or I’m wrong about the 2 files being packed into blocks of 4 bytes. My instincts tell me to check on the key.

Assuming I’m expecting to see a real .png file, then it must begin with a valid .png 8-byte magic header: 89 50 4E 47 0D 0A 1A 0A

Since it is only a XOR operation, we can retrieve the key if we XOR the ciphertext (the second set of 2 bytes in the 4-byte block) with this 8-byte value.

Now, that looks like something… FLARE-ON? Yes!

And we are done.

(dotNet) 5_-_TKApp

I know, this is supposed to be a Tizen challenge but… I cant get the emulator working :< so, back to static analysis.

Unzip the .tpk file and we can see TKApp.dll within.

Nice, it’s a .NET executable. This will be easy.. *coughs* hopefully.

I guess the intuitive thing would be to start the analysis from the dll’s entrypoint, which is TKApp.Program.Main

But I’ll always try to click around to see if there’s any clue towards the flag that can “shortcut” our way there. Here’s what I found:

There’s a “flag” as well as “IsPasswordCorrect”, “Decode”, “GetString” functions. Looks interesting. Let’s start here!

Here, password is expected to be “mullethat”.

This function performs an AES-decryption. Let’s see where it is used.

Now this function looks very interesting and fulfilling all conditions expected within this function seems to produce an image file — maybe the flag is in the image?

if (string.IsNullOrEmpty(App.Password) || string.IsNullOrEmpty(App.Note) || string.IsNullOrEmpty(App.Step) || string.IsNullOrEmpty(App.Desc))

Previously we have retrieved the Password. Next is to figure out the values for Note, Step and Desc.

The “SetupList” function tells us that Note will be “keep steaks for dinner”.

Step will take the value of the metadata named “its”. This is found in the tizen-manifest.xml file:

The last required variable, Desc, is set in the function IndexPage_CurrentPageChanged, and its value is taken from the exif data of “05.jpg”.

So we have collected the following values:

Password = “mullethat”
Note = “keep steaks for dinner”
Step = “magic”
Desc = “water”

Now we can proceed to figure out what is the image created from these values.

I’ve reimplemented the above code snippet in Python:

The string that is formed from the 4 values collected is “the kind of challenges we are gonna make here”, and the SHA256 hash of this string is used as the key to decrypt the ciphertext in the resource named “runtime.dll”.

And…that’s it! :)

(Autoit) 6_-_codeit

This one created a little bit of frustration for me when I was solving it. But hey, now that I think back on it, it wasn’t that bad as compared to 10 and 11 :P

So the challenge asks us to make the binary give us a QR code, which shall be the flag. First thing would be to recognise what language is the binary coded in, before we can analyze it.

It’s UPX-packed, so unpack it first.

Then “AutoIt v3 GUI” came up in the strings of the unpacked binary. Maybe then try to decompile as an AutoIt exe?

I used this decompiler tool “Exe2Aut” to help, and got a perfect Autoit v3 script, along with two files: “sprite.bmp” and “qr_encoder.dll”.

Opening the AutoItv3 script in SciTE, we can see that the script is very, very heavily obfuscated. Let’s start de-obfuscating it to make it more readable.

Other than automatically getting rid of some of the obfuscation, I also renamed some of the functions based on the API calls being made within them. Now we can start analysing the code. The entrypoint is this function named “areialbhuyt”.

It looks like a structure is being built that affects the QR code generated, and the input string did not seem to matter. Hmm, let’s check out the function “decrypt_something” (originally “areyzotafnf”).

In gist, the function takes a “ComputerName” value, performs some kind of decoding on it via the function “aregtfdcyni”. The SHA256 hash of the output is then calculated as used as the key to AES-decrypt some data. What is the expected “ComputerName” value we should feed in here? Let’s look at function “aregtfdcyni” closely.

Within “aregtfdcyni”, sprite.bmp is read from the 54th byte onwards, for a length of 7*length_of_computername. The relevant data within sprite.bmp looks like it has something to do with binary numbers.

Each byte read is then transformed with AND and SHL operations, with each char within computername added to the value. Then a string is built using the results from each transformed byte. I’ve re-implemented this logic with Python, and hopefully be able to tell what is going on. I gave computername a value of 0s as a test.

And then I see this output:

It looks like the bmp file contains 91 bytes of data (starting from the 54th byte, as seen in the screenshot above) that makes up the string “aut01tfan1999”.

At this point, I got stuck for 1 day… I didn’t know what is the expected “computername” value that can interact with this string such that the output’s hash value is to be used towards decrypting the correct data to generate the QR code with the flag.

After some sleep, I decided to just use the string “aut01tfan1999” directly as the output of function “aregtfdcyni” and see what happens.

Within the decryption function, there are checks to ensure that the decryption is correct — if at any point along the way the wrong parameters are used, then CryptDecrypt will not succeed. After CryptDecrypt succeeds, and if the decrypted data starts with “FLARE” and ends with “ERALF”, we are done.

Tada?

Amazingly that worked. But I don’t know why.. I felt that I just got lucky with this one. Perhaps we may find the explanation from someone else’s write up. But here’s the flag, nonetheless.

:D That’s all for now. I’m still tidying up my notes for the rest of the challenges. Will post part 2 when I am done!

~~

https://twitter.com/AsunaAmawaka

--

--