Nuit-du-hack-2016/Matriochka/Step-3
You are here: | Matriochka (step 3)
|
Description
This challenge is the 3rd stage of the Matriochka challenge. It is described as follows:
Can you help me? Recently, I found an executable binary. As I'm a true newbie, Certainly, to solve it, I will have difficulties. Keep in mind, the first step is quite easy. Maybe the last one will be quite tricky. Emulating it could be a good idea.
You must solve step 1 and step 2 first.
The challenge can be downloaded from the following mirror:
- (mirror) https://github.com/sebastiendamaye/public/raw/master/crackme/ecb4999fbfddea74ffa5b8bd22bf1a0a
File:
MD5 | ecb4999fbfddea74ffa5b8bd22bf1a0a |
---|---|
SHA1 | c1b306843328d37df2f029e1384a99359ba2a5cf |
SHA256 | d080cf9ece1d2ad692c8a90befcc74ac23a0e6466bb489504c040ed93a48cb4e |
Analysis
Running the binary
The program seems to expect an argument, a password:
$ ./stage3.bin Usage: ./stage3.bin <pass> $ ./stage3.bin oops Try again!
Main function overview
The main function starting at offset 0x4010F1 is structured as follows:
The program relies on Unix signals for its control flow. This is what we are going to analyze in the next sections.
Checking arguments
First of all, the program checks that an argument is passed to the program. If not, it jumps to the "Usage" section.
.text:00000000004010F1 ; int __cdecl main(int, char **, char **)
.text:00000000004010F1 main proc near
.text:00000000004010F1
.text:00000000004010F1 pass = qword ptr -20h
.text:00000000004010F1 num_args = dword ptr -14h
.text:00000000004010F1 count_i = dword ptr -8
.text:00000000004010F1 pid = dword ptr -4
.text:00000000004010F1
.text:00000000004010F1 push rbp
.text:00000000004010F2 mov rbp, rsp
.text:00000000004010F5 sub rsp, 20h
.text:00000000004010F9 mov [rbp+num_args], edi
.text:00000000004010FC mov [rbp+pass], rsi
.text:0000000000401100 cmp [rbp+num_args], 2
.text:0000000000401104 jz short loc_401121
.text:0000000000401106 mov rax, [rbp+pass]
.text:000000000040110A mov rax, [rax]
.text:000000000040110D mov rsi, rax
.text:0000000000401110 mov edi, offset format ; "Usage: %s <pass>\n"
.text:0000000000401115 mov eax, 0
.text:000000000040111A call _printf
.text:000000000040111F jmp short locret_40119D
Unix signals
loc_401121
Starting at offset 0x401121, the program calls 2 interesting functions. The 1st one (sub_4007FD) is actually the 1st node of a serie of Unix signals an the 2nd one (sub_401050) is the success message.
.text:0000000000401121 loc_401121:
.text:0000000000401121 mov rax, [rbp+pass]
.text:0000000000401125 add rax, 8
.text:0000000000401129 mov rax, [rax]
.text:000000000040112C mov edx, 3FFh ; n
.text:0000000000401131 mov rsi, rax ; src
.text:0000000000401134 mov edi, offset dest ; dest
.text:0000000000401139 call _strncpy
.text:000000000040113E mov eax, 0
.text:0000000000401143 call _getpid
.text:0000000000401148 mov [rbp+pid], eax
.text:000000000040114B mov esi, offset sub_4007FD ; handler
.text:0000000000401150 mov edi, SIGSEGV ; sig
.text:0000000000401155 call _signal
.text:000000000040115A mov esi, offset sub_401050 ; handler
.text:000000000040115F mov edi, SIGFPE ; sig
.text:0000000000401164 call _signal
.text:0000000000401169 mov [rbp+count_i], 0
.text:0000000000401170 jmp short loc_401185
sub_4007FD (1st character)
As described here, the signal function expects 2 parameters:
- sig: the signal code. Here, the signal used is SIGFPE (code 0x08), used for Signal Floating-Point Exception (e.g. zero divide or an operation resulting in overflow).
- func: the function that is called. Here, we can see that this is actually a chain of functions, as follows:
Now, if we analyze the code of the function, it rather looks complex (combination of imul, sar, sub) to make a computation based on the user input. Using the pseudo-code plugin (press F5) will help much. Here is the code it outputs:
void sub_4007FD()
{
signed int v0; // ecx@1
v0 = 1000 * dest;
if ( v0 / 68 > 999 && v0 / 68 <= 1000 )
signal(SIGSEGV, (__sighandler_t)handler);
}
It becomes easier to understand what is actually done. It checks that the 1st character of the user input is equal to 68 (letter "D"). If the test succeeds, the code jumps to the handler function at offset 0x40085C.
sub_40085C (2nd character)
Once again, the function looks complex to analyze and we can use the pseudo-code plugin to get the following output:
void handler()
{
signed int v0; // ecx@1
v0 = 1000 * byte_6040C1;
if ( v0 / 105 > 999 && v0 / 105 <= 1000 )
signal(11, (__sighandler_t)sub_4008C7);
}
This time, the code checks that the second character of the user input is equal to 105 (letter "i"). If the test is successfull, the code jumps to the next function sub_4008C7.
sub_4008C7 (3rd character)
Same here as previously. Below is the pseudo code:
void sub_4008C7()
{
signed int v0; // ecx@1
v0 = 1000 * byte_6040C2;
if ( v0 / 100 > 999 && v0 / 100 <= 1000 )
signal(11, sub_400926);
}
It checks that the 3rd character is equal to 100 (letter "d"). If successfull, the code jumps to sub_400926.
sub_400926 (4rd character)
Below is the pseudo code:
void sub_400926()
{
signed int v0; // ecx@1
v0 = 1000 * byte_6040C3;
if ( v0 / 95 > 999 && v0 / 95 <= 1000 )
signal(11, sub_40098A);
}
The code checks that the 4th character of the user input is equal to 95 ("_"). If successfull, it then jumps to sub_40098A.
And so on...
The exact same approach can be used to decode all other expected letters of the user input.
Solution
Below is the expected letters for each function:
Function | Expected value | Letter |
---|---|---|
sub_4007FD | 68 | D |
sub_40085C | 105 | i |
sub_4008C7 | 100 | d |
sub_400926 | 95 | _ |
sub_40098A | 121 | y |
sub_4009E8 | 111 | o |
sub_400A4C | 117 | u |
sub_400AB0 | 95 | _ |
sub_400B14 | 108 | l |
sub_400B73 | 105 | i |
sub_400BD7 | 107 | k |
sub_400C36 | 101 | e |
sub_400C95 | 95 | _ |
sub_400D0C | 115 | s |
sub_400D6B | 105 | i |
sub_400DCF | 103 | g |
sub_400E2E | 110 | n |
sub_400E8D | 97 | a |
sub_400EEC | 108 | l |
sub_400F4B | 115 | s |
sub_400FAA | 63 | ? |
Providing the program with this string leads to another base64 string, which will the next challenge (step4):
$ ./stage3.bin Did_you_like_signals? Good good! Now let's play a game... 6ydQg8QCWEBQg+wCWMNQg8QCWEBAUIPsAljDUIPEAliDwARQg+wCWMPo1v9m6wJmLujO/8P76znr AkiN6MP/w/rovv9m6wJmLvtm6gAAAAAAAeit/2bowv/NEGZmiBawAOie/8P66KX/zRDolP/D6z/o jv/D6wJmLrjAB+ic/80QZmb6jtjoef/DjsDof//NEOsCSI24AIDoZ/9m+o7Q6GD/w7wA8Ohl/80Q 6wFm66IxwOhm/80QZmb66wFm6Fv/w5CQkM0T+wboN//DuAAB6En/w5CQkI7A6DP/zRD6uwAA6Cr/ zRD7sDLoFv/DtAL6sQLoDf9mtQD66Ab/w/uKFrAA6wJIjegF/80QtgDrAmYuzRP76Pf+zRAH+uj9 [...SNIP...] AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
This time, it seems to be a DOS/MBR boot sector:
$ cat stage3.base64 | base64 -d > stage4 $ file stage4 stage4: DOS/MBR boot sector
Comments
Keywords: nuit-du-hack-2016 NDH2K16 challenge reversing