This weekend’s Nuit du Hack provided 4 reverse engineering challenges which were required to be solved in order. I got through 1, 2, and 3 with a minimum of effort, but number 4 was the reverse engineering equivalent of the EVE Online learning cliff:
I’ll present my writeup of challenges 1, 2 and 3, as well as some notes on 4 which I was not able to solve during the time-frame allocated (another blog post – am keen to work on during the week).
Matroichka 1 is a warmup-grade challenge: opening it in IDA immediately reveals the key:
Entering this key spits out a base64 encoded output, which turns out to be the level 2 executable.
Matroichka 2 is a slightly more difficult – firstly, strlen() is performed against the key to ensure it’s the right length – instead of comparing the result of strlen against the correct answer, strlen’s return value is obfuscated as follows:
.text:0000000000400747 lea rdx, [rax+1] .text:000000000040074B mov rax, rdx .text:000000000040074E shl rax, 2 .text:0000000000400752 add rax, rdx .text:0000000000400755 shl rax, 2 .text:0000000000400759 add rax, rdx .text:000000000040075C add rax, rax .text:000000000040075F cmp rax, 1F8
This can be trivially brute-forced, or you can simply undo the maths (it’s not that difficult) – or if you own a copy of the Hex-Rays decompiler, I suppose you could just press F5.
There’s a whole stack of these checks, and they all look like this:
All of these checks are executed in order, and if you fail a check, [rbp-14h] is set to 0. A little bit of pen, paper and Python reveals the key to be “Pandi_panda”, which then gives you the third binary.
Matroichka 3 is a little more complex: immediately, we notice heavy use being made of the “_signal” function, and an odd “_kill” loop which tries to terminate the current process with a SIGSEGV:
Note that we’ve already got a signal handler set by “_signal”: therefore, when we give the process SIGSEGV via _kill, the SIGSEGV handler is executed.
The handler looks like this:
Note how it sets a new signal handler if the check (0x40083F) succeeds.
In a nutshell, the application tries to send 0x3FF SIGSEGV kills to itself – if it succeeds in handling one SIGSEGV, it sets the “next” signal handler. If a check fails – well, the new signal handler is simply never set, the process sends all 0x3FF signals to itself then exits.
Unlike Matroichka 2, manually reverse engineering this was annoying enough that I built a brute-force thingy.
From here, it’s simply a matter of taking each signal handler, sticking the maths part (after mov eax,[rbp+var_4], to mov eax,edx) into the brute force shell and letting it run: the “correct” result ends up in eax, which you can view in a debugger. Half an hour later, we get the key (“Did_you_like_signals?” – yes I did, this was an enjoyable diversion) and the stage 4 binary, and the fun really begins…