Crackme 6: ELF, no ptrace

Link: https://www.root-me.org/en/Challenges/Cracking/ELF-Ptrace (binary)

This program has some protections against debugging, and running it in a debugger fails immediately:

    $ /re/crackme/6/ch3.bin
    ############################################################
    ##        Bienvennue dans ce challenge de cracking        ##
    ############################################################

    Password : test

    Wrong password.

    $ gdb /re/crackme/6/ch3.bin
    GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
    [...]
    Reading symbols from /re/crackme/6/ch3.bin...(no debugging symbols found)...done.
    (gdb) r
    Starting program: /re/crackme/6/ch3.bin
    Debugger detecté ... Exit
    [Inferior 1 (process 534) exited with code 01]

Disassembling main in Hopper or gdb shows a copy of a string into the local variable at ebp - 0xc. Let’s call it secret.

    mov        dword [ebp-0xc], aKsuiealohgy ; "ksuiealohgy"

Then we see that if a call to ptrace fails, we stop the program:

    push       0x0
    push       0x1
    push       0x0
    push       0x0          ; argument "__request" for method ptrace
    call       ptrace       ; ptrace
    add        esp, 0x10
    test       eax, eax
    jns        loc_8048436

An easy way to skip this would be to replace this code with NOPs (no-ops) and the jump from a conditional to an unconditional jump.

Once we’ve bypassed this step, the control flow heads to a block where a password is read using fgets and stored in a local variable at ebp - 0x16.

    lea        eax, dword [ebp-0x16]
    push       eax          ; argument #1 for method _IO_fgets
    call       _IO_fgets    ; _IO_fgets

and we jump into some code right after a label named _notng:

    lea        eax, dword [_notng] ; _notng
    inc        eax
    jmp        eax

The beginning of notng is kind of strange, and gets to a HLT instruction which will stop the program:

    08048497         mov        eax, 0x8bea558a
    0804849c         inc        ebp
    0804849d         hlt

But here we’re going to eax + 1, so we can re-write the first byte as a NOP and ask Hopper to re-interpret the rest. Much better! We now have something that makes much more sense. Here’s our first byte, skipped:

    _notng:
    08048497         nop 

And the rest at 0x08048498 is now comparing the two local buffers. dl successively takes each byte of our input, and al the expected bytes. Here, if input[0] != secret[4] (’e’), we fail:

    08048498         mov        dl, byte [ebp-0x16]
    0804849b         mov        eax, dword [ebp-0xc]
    0804849e         add        eax, 0x4
    080484a1         mov        al, byte [eax]
    080484a3         cmp        dl, al
    080484a5         jne        sub_80484e4

Then input[1] (ebp - 0x16 + 1) is compared to secret[5] (‘a’)

    080484a7         mov        dl, byte [ebp-0x15]
    080484aa         mov        eax, dword [ebp-0xc]
    080484ad         add        eax, 0x5
    080484b0         mov        al, byte [eax]
    080484b2         cmp        dl, al
    080484b4         jne        sub_80484e4

Then input[2] to secret[1] (’s’) (notice the inc eax):

    080484b6         mov        dl, byte [ebp-0x14]
    080484b9         mov        eax, dword [ebp-0xc]
    080484bc         inc        eax
    080484bd         mov        al, byte [eax]
    080484bf         cmp        dl, al
    080484c1         jne        sub_80484e4

And finally input[3] to secret[10] (‘y’):

    080484c3         mov        dl, byte [ebp-0x13]
    080484c6         mov        eax, dword [ebp-0xc]
    080484c9         add        eax, 0xa
    080484cc         mov        al, byte [eax]
    080484ce         cmp        dl, al
    080484d0         jne        sub_80484e4

Let’s try it:

    $ /re/crackme/6/ch3.bin
    ############################################################
    ##        Bienvennue dans ce challenge de cracking        ##
    ############################################################
    
    Password : easy
    
    Good password !!!