This is a writeup for the Endless Christmas challenge, md5 hash 866c92038d6e9fc47db4424f71f6167a. It appeared in the X-MAS CTF, and it’s a Reverse challenge.
afl with Radare we can see there are calls to
execve, both happening in
main, a sign that this program creates (and maybe executes?) something else.
Putting a breakpoint just before the
execve happens will reveal what file is being loaded (looking into the rax register).
I went down 60 rabbit holes disassembling this binary further, but the best thing we can do at this point is change point of view, step out of Radare, and launch the binary by itself – it certainly doesn’t seem to be doing anything nasty up to this point.
It takes some time before any output is shown, so this may be a sign that some decoding happens. The program creates a good number of other binaries which all look identical, albeit different from the original one (as their size shows), but that are actually different upon closer inspection with their md5 hashes.
Opening one at random, we see that function names are different and more self-explanatory, but still not so helpful. Also, there are signs that this may be a scam, as
sym.encode_85 is never called (discover it by running
axt sym.encode_85). So it looks like it could be decoding the huge string the program stores (obtainable with a simple call to
strings) in base 85, but trying to manually decode it doesn’t yield much results. So far so bad. Uhm. Remember that all files are different, but they all look the same, and there is no immediate clue pointing at which should be the interesting one.
This is again a time in which you need to take a deep breath and consider stepping out of what you are currently doing. Launching the original binary with
ltrace reveals that several calls to
execve are made, and hints us at the fact that maybe only the last executed binary is interesting.
But how to discover its filename, since
ltrace only shows pointers? Let’s run it with
strace and find the relevant line amidst all the noise… There it is, right at the top of the window!
However, we soon realize that this is a scam again – there is no way to get to the successful “MERRY CHRISTMAS!” message. One significant hint is that the buffer that is read from input is never really used in any purposeful way. What the program does is scan a string of his own char by char,
xor each char with
0xd, and then check if
al is the same as
dl. This is never the case, and can never be, and in fact if we try to debug that routine, we see that the program always exits after the first iteration.
But we already have all that we need! Remember that the program xored each char of its string with
0xd – maybe that is the solution? Let’s write a small program to reproduce this behavior:
char str = "U @L^vi>n=i>R9;9<cR9ciR9;9<cR9ciR9;9<cR9ciR9;9<cR9ciRka9;p";
for (i=0; i<strlen(str); i++)
output[i] = str[i] ^ 13; //13 = 0xd
output[i] = '\0';
printf("\n %s \n\n", output);
And booom! We get the flag!