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:
- 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 mycompute
function. - 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.