Nuit-du-hack-2016/Matriochka/Step-3

From aldeid
Jump to: navigation, search
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:

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:

Nuit-du-hack-2016-Matriochka-Step-3-main-graph-overview.png

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:

Nuit-du-hack-2016-Matriochka-Step-3-sub 4007FD-chain.png

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; // [email protected]

  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; // [email protected]

  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; // [email protected]

  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; // [email protected]

  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

blog comments powered by Disqus

Keywords: nuit-du-hack-2016 NDH2K16 challenge reversing