CSCG 2020 reversing intro challenges writeup (easy level)

Hello everyone, I hope all of you are safe out there, before we start I have to mention that I don’t have a good experience in this field yet, so if you spot any mistakes or think of better methods of doing this, please let me know in the comments

CSCG 2020 is a German Cyber Security Challenge Qualification CTF which has some entry level challenges in couple fields, today we will be looking at the first 3 reverse engineering challenges

This write-up is targeting beginners like my self, so I will be demonstrating some easy ways to solve each challenge

PREREQUISITE

In order to understand this write-up right, it’s recommended to have a basic idea about the following subjects
• how C language code is structured
• assembly language knowledge and debugging
• XOR
• some familiarity with Linux

first challenge

so let’s begin. After setting up an account in the CTF website, downloading the first challenge and unzipping it, you get two files, flag and rev1, the latter appears to be executable
now we need to get an idea about what those files might be, file is a great utility to get couple information about files, file * gives the following result :

flag: ASCII text
rev1: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=c26549fbcc84a4199635818d97bd48b69eea5fb2, not stripped

this might seem a bit overwhelming but in an entry level challenge we’re only interested in 2 peaces of information, ELF 64-bit executable, and not stripped, meaning rev1 is an executable that runs under Linux 64 bits systems, and contains some strings that will help us debugging/reversing it if we had to

the first file is obviously just a text file with the content : CSCG{real_flag_is_on_the_server}, as it was mentioned on the website that we should send the password we get from the executable to a server to get the actual flag

So how would we approach this ?

Trying to execute rev1 gives the following result
1-asking_for_password

“password is not password” hmm okay

“asking for a password” means that rev1 takes your input and compare it with some string that may or may not be hard-coded in the binary

strings is a great command to get all hard-coded strings in an executable

strings rev1 gives the following result :

We can ignore most of it, but if you look close enough, you’ll see “give me your password” which is what we got earlier, and right underneath it, this weird string “ y0u_5h3ll_p455”, (from the Lord of the Rings series :stuck_out_tongue:) let’s try throwing that string at rev1 and …

3-voila

now sending that string to the server gives the following result

4-nc

Voilà! Easy 40 points earned without trying to debug anything

if you don’t like working with terminals that much, there is this nice tool called Binary Ninja , which is great when it comes to static analysis, running it with rev1 gives us a nice graphical interface explains the executable branches (this where some assembly knowledge comes handy) there are also 3 ways of displaying code, from pure assembly to human-friendy-code, however I won’t be using that as I prefer reading the former :stuck_out_tongue:

after jumping to main() (which the tools detect the address of, automatically, thanks to the binary not being stripped), we get this view

even if you have no idea about what’s going on, you can easily spot the password, and strcmp() which is used to compare it with your input

there also the command ltrace which you can use to trace system calls, after executing it with rev1,and throwing a random string at it, you can see it being compared just like in the following picture

note : we see the same string in both read() and strcmp() because rev1 compares our input with the password directly without changing it
and those where couple way of how you can approach this binary

second challenge

the second challenges, gives the same files, same prompt, unless there is no hard-coded string this time, try running strings and you won’t see any password

running it with binary ninja, we get the following view

hmm, this time rev2 is not comparing our input string directly, but rather using a loop (denoted by the green and the blue lines) to change it byte by byte (subtracting 0x77 from each byte to be specific hence the sub eax, 0x77), and that explains why we couldn’t find any useful strings with the strings command, because all the bytes are non-ascii values

now we know that each byte is decreased by 0x77 and compared to something else, so to retrieve the password we should know that “something else” and increase each byte of it by 0x77

The easiest way to figure it out would be using ltrace command again, which shows us the following

now we see some weird characters which are just an encoding to represent non ascii characters I believe, we need to add 0x77 to each byte to get the password, for that I wrote something like this

#include<stdio.h>

int main(void){
        unsigned int i;
        int pass[] = {'\374', '\375', '\352', '\300', '\272', '\354', '\350', '\375', '\373', '\275', '\367', '\276', '\357', '\271', '\373', '\366', '\275', '\300', '\272', '\271', '\367', '\350', '\362', '\375', '\350', '\362', '\374'};

        for(i = 0 ; i < sizeof(pass) / sizeof(pass[0]) ; i++)
                putchar(pass[i] + 0x77);
        puts("");
        return 0;
}

running this programs gives : “sta71c_tr4n5f0rm4710n_it_is” which I’m positive that it’s another movie’s quote that I don’t know about

9-second_password

submitting it to the server we get

10-second_challenge_solved
another not-so-hard 47 points !

Third challenge

this is very similar to the second one, except this time we get a password with file and ltrace, just one little problem, it’s not the same!

string’s output :
12-strings_output

ltrace’s output :

strings gives us 2 lines, when ltrace show one long line only, with more characters than strings's output, well … this is because strings by definition are a sequence of bytes followed by and null byte (‘\0’ byte), we can see that our password in second picture contains 3 of them, so strings sees that password as 4 separate strings, as for why the second one has more character than the first, strings only shows strings above a certain length, so “17” and “5J” are ignored because they’re too short (are you tired of the word “strings” yet ? :stuck_out_tongue:

Now we know the password, now we just have to figure out exactly what input we should throw at rev3 so it can match that (remember that rev3 modifies our input before comparing it)

and for that we need to take a look at the assembly code, opening binaryninja, we get this view

we’re only focusing on the left box cause that’s where the magic happens, if you can’t figure out what’s happening there, I advise you to use the other human-friendly displaying mode I talked about earlier, or just learn some assembly if you’re interested in this field :stuck_out_tongue:

basically the codes loops over each byte of the input, xor it with (its index in the input string + 0xa) add subtract two from it

so if your input is “hey”

the code will do the following

pass[0] = (‘h’ ^ (0 + 0xa) ) -2

pass[1] = (‘e’ ^ (1 + 0xa) ) - 2

so to reverse this algorithm we should add 2 to each byte of the password we got earlier, then Xor it with (it’s index + 0xa)

and for that I wrote this code


#include<stdio.h>
#include<string.h>

int main(void){
        char ptr[] = {'l', 'p', '`', '7', 'a', '<', 'q', 'L', 'w', '\036', 'k', 'H', 'o', 'p', 't', '(', 'f', '-', 'f', '*', ',', 'o','}', 'V', '\017', '\025', 'J'};
        unsigned int i = 0;

        for(i = 0;i < sizeof(ptr)/sizeof(ptr[0]); i++)
                printf("%c", (ptr[i] + 2) ^ (0xa + i));
        puts("");
        return 0;
}

After running this code we get the following flag : “dyn4m1c_k3y_gen3r4t10n_y34h” which all I can say about is “lol!”

14-last_flag

One last thing we need to do …

And there is our last laughable flag that gets us another 51 points !
I really hopped I could explain this so even beginners can understand and not find it boring

as this my first write up, I would like to thank @dtm and @leeky so much for putting up with my most-of-the-time-stupid questions, as well as other people who put me on track, like yeni, ayoub and hammadi

if anything unclear or fuzzy don’t hesitate to ask about it, Jeff’s out

10 Likes

Nice writeup! :slightly_smiling_face:

1 Like

Your explaination is so good. I mean, i don’t know much about CTF but after reading your writeup, i understands everything and now i am also gets interested in CTF exercies. I will practice these exercises now. Just want to ask you can you please suggest some free Reverse engineering tool other than Binary ninja because its too expensive for me. And i don’t like ghidra also because it’s not that much user friendly. if you have any suggestions for free reverese engineering tool then please tell me about that.

Thanks againg for great writeup.

1 Like

glad you liked it!
for now I only use binary ninja for static analysis and keep firing it up every 30 minutes, and gdb for dynamic analysis, but I’m sure the guys on discord can give more help, you should check it out if you haven’t already!

can OLY DBG work for these CTFs…?

Given that OllyDbg is for Windows executables and these are Linux binaries, it shouldn’t work. If there are any Windows binaries in the CTF, they might work (OllyDbg is quite outdated).

2 Likes

This is a dream come true for me

2 Likes