[Part 2] ACS-IXIA-CTF Write-up - Two face

Last weekend I participated at the CTF organized by IXIA and I wanted to showcase some of the challenges I solved that I found particularly interesting. (I think) there will be only 3-4 parts of this with 4-5 challenges. I'll try to present my thinking and all the pitfalls I've ran into.

Today I'm going to explain Two face from the Reverse category. It was a 150 (or 200) points challenge. Unfortunately I can't show you the prompt again because the challenges were made unavailable.

If you haven't checked out the first article, make sure to read it because I will use some intuition from the previous challenge to solve this one.


Analyzing

Once again, we are given a binary and some host and port to connect to. Let's do the usual stuff (strings, strace, ltrace). Running ltrace we get:

Looks like it's almost the same spiel like the previous challenge, it creates a file, reads 16536 bytes in this case, changes it's permissions and starts a process probably to check it's output later with banners. But let's also take a look in IDA.

Here we have the main function:

Some basic buffer handling, really common in ctfs.

The function which creates the file.

Checking the output.

Here we have some interesting function. We'll call it get_compute.

And a function which unlinks the file.

We see that the get_compute function calls dlopen and dlsym for to get the address of some compute function which later it calls to see if it prints to the standard output 'banners'. Dlopen expect a shared object. This means that this binary probably expects a shared library. But we also need it to output 'banners'.


Developing

Let's see if we can do that. We have plenty of space this time, so let's write a C program for it.

#include <stdio.h>

void compute()
{
    puts("banners");
}

int main(void)
{
    compute();
}

Okay. Let's compile it. And send it to the binary. Also let's pad it with the python script from the previous task.

Nothing happens. But it should work. Let's see what happens in GDB, after the dlsym call.

It calls another function, I might've missed it in IDA. Here is it:

It looks like it calls the compute function with some parameters and compares the return value with some array probably, every 3rd element. At this point, during the CTF, I've ran in several pitfalls:

  1. I haven't noticed that it calls the function with arguments, after analyzing in GDB, I saw the mov rdi, something instruction and then thought about adding a parameter to my compute function.
  2. It was a long time after i've saw the mov rdi, something and thought getting the local index variable from the function which compares our return value with some array, using C variable number of arguments. Which is bad, I know.

After some time and realizations, I've decided to first copy the array that it compares out return value with into my program. And my my compute function take a parameter.

Also notice from IDA, that it gives us the parameter from the array with 10 bytes behind. The parameter given to us is at offset 0x202020 + 3*i and it compares it with the one from the offset 0x202030 + 3 * i.

So let's code it now.

#include <stdio.h>

const long long get_idx[] = {0x000000000000002e, 0x0000000000000005, 0x0000000000012561, 0x0000000000000131, 0x0000000000000004, 0x0000000000001b5e, 0x000000000000031b, 0x0000000000000006, 0x000000000004dc83, 0x0000000000000107, 0x0000000000000002, 0x0000000000000003, 0x0000000000000213, 0x0000000000000006, 0x00000000000607d8, 0x0000000000000382, 0x0000000000000002, 0x0000000000000003, 0x00000000000000b8, 0x0000000000000001, 0x0000000000000002, 0x0000000000000391, 0x0000000000000006, 0x00000000000876bf, 0x00000000000001b1, 0x0000000000000006, 0x000000000004f9e5, 0x0000000000000217, 0x0000000000000003, 0x00000000000000f7, 0x0000000000000378, 0x0000000000000001, 0x0000000000000001, 0x00000000000002dd, 0x0000000000000001, 0x0000000000000001, 0x00000000000001cc, 0x0000000000000007, 0x00000000005fbf8c, 0x00000000000002b4, 0x0000000000000003, 0x000000000000039d, 0x0000000000000298, 0x0000000000000003, 0x0000000000000216, 0x00000000000002d8, 0x0000000000000003, 0x000000000000032f, 0x00000000000002a4, 0x0000000000000003, 0x0000000000000355, 0x000000000000023b, 0x0000000000000005, 0x0000000000016bf8, 0x00000000000002a1, 0x0000000000000002, 0x0000000000000031, 0x0000000000000329, 0x0000000000000004, 0x00000000000014e2, 0x00000000000001a2, 0x0000000000000006, 0x00000000000819e9, 0x0000000000000112, 0x0000000000000001, 0x0000000000000002, 0x00000000000002bd, 0x0000000000000007, 0x00000000001ed274, 0x00000000000000af, 0x0000000000000005, 0x00000000000015b7, 0x00000000000000aa, 0x0000000000000005, 0x0000000000014cdb, 0x0000000000000081, 0x0000000000000006, 0x00000000000866b6, 0x00000000000002ef, 0x0000000000000002, 0x0000000000000012, 0x0000000000000171, 0x0000000000000004, 0x0000000000001570, 0x0000000000000026, 0x0000000000000007, 0x00000000006d6577, 0x00000000000000bd, 0x0000000000000002, 0x000000000000005f, 0x0000000000000351, 0x0000000000000001, 0x0000000000000001, 0x0000000000000143, 0x0000000000000004, 0x00000000000005f0,
 0x00000000000001d2, 0x0000000000000003, 0x00000000000002a1, 0x00000000000000f2, 0x0000000000000007, 0x00000000001256f5, 0x00000000000001e7, 0x0000000000000003, 0x000000000000017d, 0x0000000000000039, 0x0000000000000001, 0x0000000000000009, 0x000000000000023f, 0x0000000000000001, 0x0000000000000006, 0x000000000000021e, 0x0000000000000005, 0x0000000000001b6d, 0x0000000000000045, 0x0000000000000007, 0x00000000003dfe8e, 0x00000000000000d2, 0x0000000000000007, 0x0000000000659d06, 0x000000000000025c, 0x0000000000000003, 0x00000000000002a9, 0x00000000000001ac, 0x0000000000000005, 0x000000000001205b, 0x00000000000002c5, 0x0000000000000003, 0x0000000000000079, 0x00000000000002e7, 0x0000000000000002, 0x000000000000000d, 0x00000000000002b3, 0x0000000000000001, 0x0000000000000008, 0x00000000000001fd, 0x0000000000000005, 0x0000000000005f56, 0x0000000000000369, 0x0000000000000005, 0x000000000000d048, 0x00000000000002cd, 0x0000000000000002, 0x0000000000000060, 0x000000000000028b, 0x0000000000000007, 0x0000000000477a79, 0x0000000000000339, 0x0000000000000004, 0x0000000000000c0a, 0x0000000000000000, 0x0000000000000000, 0x00007ffff7bcc760, 0x0000000000000000, 0x00007ffff7bcba00, 0x0000000000000000, 0x00007ffff7bcc680, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x007372656e6e6162};

long long compute(long long number)
{
    puts("banners");

    size_t i = 0;

    while (1) {
        if (get_idx[i] == number) {
            break;
        }
        i++;
    }

    return get_idx[i + 2];
}

int main(void)
{
    compute(1);
}

Let's compile it and send it to the binary. Don't foget to pad it.

After some output of "banners". We get the shell.

And then we can get the flag.

FLAG: ACS_IXIA_CTF{flip_of_a_coin}

Doing this write-up I realized that I made many silly mistakes, which could've been easily avoided. If I would've looked more closely in IDA and took some notes of the weirdness that I saw. I could've done it faster and better. But I didn't. I was sloppy and didn't pay attention to the details.

Often times when it comes to hunting for bugs it's the little details that matter. A hacker who can focus on details will discover great vulnerabilities.

Now, I know that this was a lesson for me, but I hope it was one for you too.