Cyber Talents Mini CTF Week 3

Feb 21, 2021 • 9 minutes to read


This was the third one of the Cyber Talents February weekly mini CTFs. Link here

There were 5 challenges:




is an open-source, free and lightweight network intrusion detection system (NIDS) software for Linux and Windows to detect emerging threats.

A Google search shows “Snort”. Tried it and it’s the correct answer.


At the start, we were given a hyper link to an audio file

By the file name and the sound in the audio file we can guess that it’s morse code.

With an audio processing software (e.g. Audacity), we can easily transcript the morse code:


Transcripted below (“/” denoting word separation, since space is used for letter separation):

- .... . / ..-. .-.. .- --. / .. ... / .. / .- -- / ... .--. . .- -.- .. -. --. / .-.. --- ..- -.. . .-. / - .... .- -. / -... . ..-. --- .-. .

Translate the code above on we can get the following text:


After trying several times of submission, I figured out the flag is


Find the map

We were given a Windows executable file.

This challenged was marked “Easy”. But according to my observation, this was the last challenge everyone who solved it solved :D

Running the program

Running the program gave us the following output:

find the map

Hmm. Not much information.

A bird eye view

Running string Find_the_map.exe to extract strings from the file, something quite noticable showed up:


The word “MAP” corresponds to the output of the program and hints in the description. So this must be some clue. And the following part looks like a base64 string.

So base64 decode it:


We got:


Looks like 6 instruction addresses chained by arrows.


It’s time to the real “Reverse Engineering” part.

First of all, let’s look at the main function of this program:


By examining data 0x40410c, 0x4040d8 and 0x4040a4 we can guess that function sub_401040 is somehow a printing function.

Followed by that is 6 functions being called. And hey, those functions are the addresses from the “Map” we found above!

6 functions


So I guessed that the “Map” might be indicating the sequence of those functions should be executed, instead of the sequence they are arranged in the original program.

The value of the arguments passed to those 6 functions can be found in this memory segment:

data arguments segment

Let’s make it a table for later use:

Function Name Arg. Address Arg. Value Hex
sub_401bc0 0x404074 21 48 73 63 20 6d 00 00
sub_401500 0x40407c 22 29 4a 22 22 4a 00 00
sub_401080 0x404084 61 6f 3a 49 3d 79 00 00
sub_4012c0 0x40408c 2e 77 2e 7d 42 20 00 00
sub_401740 0x40409c 3d 74 54 61 66 56 00 00
sub_401980 0x404094 77 6d 47 3a 22 36 00 00

We can see that all of these parameter values are composed of 6 bytes terminated by 2 0x00 bytes. This is another aspect of similarity of these 6 functions.

But what does those functions do?

Function analysis

Having a quick glance of those 6 functions, they look extremely similar. So I guessed that they all do similar things. Below is a comparison of the decompile code of the functions (Only 3 listed, but you got the idea):

functions compare

So I decided to give the first function in the “Map” (i.e. sub_401740) a detialed look and try to figure out what it does.

The argument passed to sub_401740 is the data at 0x40409c, according to what we found in the main function:

call 401740

Now let’s look into function sub_401740 with assembly graph view for better understanding:

sub_401740 1

We can see that this function takes 1 argument. And in the case in the main function, the argument passed to this function is address 0x40409c.

In block 1, the program save a copy of arg1 in variable var_24 (@ebp-0x20), then saved the byte address after arg1 into variable var_30(@ebp-0x2c). Now those 3 pointers looks like this:

			   var_2c = 0x40409d
0x40409c	3d 74 54 61 66 56 00 00
			var_24 = 0x40409c

Block 2 is a loop. It reads the byte to which var_24 is pointing into al, increases var_24 by 1 to point to the next byte, and examine the value of al, until the value of al is 0x00. When the loop is done, var_24 and var_2c would be like this:

			   var_2c = 0x40409d
			   |              al = 0x00
			   |              ^
			   V              |
0x40409c	3d 74 54 61 66 56 00 00
			                     var_24 = 0x4040a3

At the beginning of block 3, the program substracts var_30 from var_24, and stored it into var_34. This value is equal to the length of the array before 0x00 element, or the string length. And we know this length would be 6.

The value of var_34 is then saved to another variable var_14. By examining the following part of this function, we can find that var_14 is never written again, only read. So we can rename var_14 as STR_LEN to make it easier to read.

Next let’s take a further look at block 3:

sub_401740 2

After calculating the string length, the program calls malloc 3 times and save the heap addresses into variables var_10, var_20 and var_28. By debugging this function and setting breakpoints, we can see that the memory allocated for var_10 and var_20 are 6 bytes long, and for var_28 is 7 bytes long.

Then I got a feeling. Those 3 buffers might be used to store data towards the final answer.

In debugger

So I jumped to the end of the function, set a breakpoint right before the function prepares to return, and examined the values of the 3 buffers when the program gets there. Here’s we’re paused at:


Here’s what I found:


Buffer Value
var_10 x3mZZh
var_20 x3mZZh
var_28 ZmxhZ3\x00

The value of buffer var_28 looks more like something ready to output, because it’s a string ending with 0x00. Plus, if you look at the ending part of this function, you can see that the value of var_28 is set as the return value of this function (saved to eax):

sub_401740 3

So I looked at the string ZmxhZ3 and thought: Hey, this looks like a base64 string. So I tried to base64 decode it, and I got:

base64 -d

Hey! It decoded as “flag”! It must be the beginning of “flag{blablabla}”. We’re on the right track!

So I repeated the process above steps, and here are the buffer var_28 values I found in all 6 functions:

Function Buffer var_28 value
sub_401bc0 cmF0c1
sub_401500 Z290X0
sub_401080 tDb25n
sub_4012c0 1lfQ==
sub_401740 ZmxhZ3
sub_401980 95b3Vf

And I concatenated those strings in the order of the “Map”, i.e. 0x401740=>0x401080=>0x401BC0=>0x401980=>0x401500=>0x4012C0. And I got:


Base64 decode it, we got:



We were given a RAR archive file.

After extracting this archive, we get a directory:


Whoa. That’s, a lot.

After exploring around the sub-directories, this looks like a user data directory of some browser to me.

The Cookies file caught my attention. This might contain user credentials of user session info.

cat cookies

Looks like it’s a SQLite database file. Let’s try:


Now we’ve got ourselves some cookies :)

Next I tried to find clues in other files. First I tried looking for the word “flag” in all the files:

for i in $(find . -type f); do grep -l -i 'flag' "$i"; done

Some file names showed up:

flag files

Upon checking all these files, the ./IndexedDB/https_app.slack.com_0.indexeddb.blob/1/00/3 was most interesting. It seems to contain some data from a Slack chat:


Very messy, but still there’s something readable in it. We can read something about the flag and a Pastbin account.

I spent very long time trying to restore the chat messages from this file, with no luck.

Then I thought, what else could be interesting inside this file? Maybe URLs.

So next, I searched for “http” inside this file. Many things came up: Slack icon files, announcement for new Slack features, etc.

But finally I spotted this one:

This is a link to a slack team chat. Then I tried to login to this Slack in browser:

ask login

I was asked to login! (Yeah of course, what do you expect?)

But remember the cookies we found before? Very likely we can use those cookies to steal a session. So I opened the developer’s console and filled in the cookies we found just now:

fill cookies

I tried to create a cookie named “x” and fill in the value. But somehow every time I hit enter, the entry is gone. So I left it alone and tried logging in again anyway. And we got:


Voila! In we are.

Here we confirmed the chat messages we read in the messy file. And there is a base64 string:


(%3D is URL-encoded “=”)

Decode the base64 string:

password: GShekxW7Ra

We got a password. But what for?

The chat mentioned a Pastbin account. But what would be the user name of the account?

Since the Slack user we are impersonating now is “c8540731”, I decided to try this user name on Pastebin. The user profile URLs on Pastebin are in format:<username>. So I put in my browser’s address box.

And guess what:


Then I clicked the “Flag” file. It asked me for a password:

password asked

I entered the password we found in the Slack chat (GShekxW7Ra), and got the file:



We were given a link to a website

The website index looks like this:


There’s no link to other paths in this page. Only the “Home” link on the top left corner, which links to this page itself.

On some further trials, I found that whatever path I go to, it’s always the same page:

giber page

But if you check the source of this page, you can find that it’s not quite the same. The URL path is reflected in the “Home” link:

path reflect

Meanwhile, I also tried to wfuzz the paths, and got some intresting results:

500 on non ascii

I found that the server returns 500 status when the path contians non-ASCII characters. Also, from the response headers we can see that the backgroud is running Python, probably Flask:

response header

Thus I guessed that the URL path is somehow programmaticaly processed in the backend.

Very likely it’s populating a template. This gives us the chance for SSTI.

Therefore, I tried to do some simple injection to confirm my guess. I gave the server {{ 1+1 }} in the path:

template eval

We can see the expression we passed in the path is evaluated.

Next I tried this payload:


And I got:

cmd exec

This confirms that we can run shell commands.

Then I tried to read /etc/passwd file:


And there the flag is.

Plus, I also grab the backend source code.

CTFCyberTalentsMini CTF
comments powered by Disqus