Simple crack me.

Information

  • category: reverse
  • points: 50

Description

Note: Enclose the flag with flag{}.

1 file : generic_crackme.bin

Writeup

Execute the program:

$ ./generic_crackme.bin
plz enter password plz:
hii
lolno

Mh… Using ltrace :

$ ltrace ./generic_crackme.bin                                                                                                                                             

puts("plz enter password plz:"plz enter password plz:
)                                                                                                                    = 24
fgets(hii
"hii\n", 100, 0x7f0f2442b860)                                                                                                                = 0x7ffffaa83bd0
puts("lolno"lolno
)                                                                                                                                      = 6
+++ exited (status 0) +++

Ok it doesn’t give the informations we need.

Let’s analyze the binary using radare2 :

# r2 -d generic_crackme.bin
[0x7fc214358100]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[Warning: Invalid range. Use different search.in=? or anal.in=dbg.maps.x
Warning: Invalid range. Use different search.in=? or anal.in=dbg.maps.x
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[TOFIX: aaft can't run in debugger mode.ions (aaft)
[x] Type matching analysis for all functions (aaft)
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x7fc214358100]> afl
0x561d89546060    1 46           entry0
0x561d89548fe0    1 4124         reloc.__libc_start_main
0x561d89546030    1 6            sym.imp.puts
0x561d89546040    1 6            sym.imp.__stack_chk_fail
0x561d89545000    3 404  -> 397  loc.imp._ITM_deregisterTMCloneTable
0x561d895451aa    5 32   -> 55   fcn.561d895451aa
0x561d89546050    1 6            sym.imp.fgets
0x561d8954621f    6 128          main
0x561d89546150    5 153  -> 60   entry.init0
0x561d89546100    5 65   -> 55   entry.fini0
0x561d89548ff8    1 4100         reloc.__cxa_finalize
0x561d89546090    4 41   -> 34   fcn.561d89546090
[0x7fc214358100]> s main
[0x561d8954621f]> pdf
/ (fcn) main 128
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_70h @ rbp-0x70
|           ; var int32_t var_8h @ rbp-0x8
|           ; DATA XREF from entry0 @ 0x561d89546081
|           0x561d8954621f      55             push rbp
|           0x561d89546220      4889e5         mov rbp, rsp
|           0x561d89546223      4883ec70       sub rsp, 0x70           ; 'p'
|           0x561d89546227      64488b042528.  mov rax, qword fs:[0x28] ; [0x28:8]=-1 ; '(' ; 40
|           0x561d89546230      488945f8       mov qword [var_8h], rax
|           0x561d89546234      31c0           xor eax, eax
|           0x561d89546236      488d3dc70d00.  lea rdi, str.plz_enter_password_plz: ; 0x561d89547004 ; "plz enter password plz:"
|           0x561d8954623d      e8eefdffff     call sym.imp.puts       ; int puts(const char *s)
|           0x561d89546242      488b15f72d00.  mov rdx, qword [reloc.stdin_64] ; [0x561d89549040:8]=0
|           0x561d89546249      488d4590       lea rax, [var_70h]
|           0x561d8954624d      be64000000     mov esi, 0x64           ; 'd' ; 100
|           0x561d89546252      4889c7         mov rdi, rax
|           0x561d89546255      e8f6fdffff     call sym.imp.fgets      ; char *fgets(char *s, int size, FILE *stream)
|           0x561d8954625a      488d4590       lea rax, [var_70h]
|           0x561d8954625e      4889c7         mov rdi, rax
|           0x561d89546261      e802ffffff     call 0x561d89546168
|           0x561d89546266      84c0           test al, al
|       ,=< 0x561d89546268      740e           je 0x561d89546278
|       |   0x561d8954626a      488d3dab0d00.  lea rdi, str.good_job_kthxbye ; 0x561d8954701c ; "good job kthxbye"
|       |   0x561d89546271      e8bafdffff     call sym.imp.puts       ; int puts(const char *s)
|      ,==< 0x561d89546276      eb0c           jmp 0x561d89546284
|      |`-> 0x561d89546278      488d3dae0d00.  lea rdi, str.lolno      ; 0x561d8954702d ; "lolno"
|      |    0x561d8954627f      e8acfdffff     call sym.imp.puts       ; int puts(const char *s)
|      |    ; CODE XREF from main @ 0x561d89546276
|      `--> 0x561d89546284      b800000000     mov eax, 0
|           0x561d89546289      488b4df8       mov rcx, qword [var_8h]
|           0x561d8954628d      6448330c2528.  xor rcx, qword fs:[0x28]
|       ,=< 0x561d89546296      7405           je 0x561d8954629d
|       |   0x561d89546298      e8a3fdffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|       `-> 0x561d8954629d      c9             leave
\           0x561d8954629e      c3             ret

Or visually :

We can see that before the puts("good job kthxbye"), the program calls a function 0x561d89546168 (I’m going to call this function flag) and if it returns 1 the program will print the good string. Let’s see what this function does :

[0x561d89546168]> pdf
p: Cannot find function at 0x561d89546168
[0x561d89546168]> pd
            ; CALL XREF from main @ 0x561d89546261
            0x561d89546168      55             push rbp
            0x561d89546169      4889e5         mov rbp, rsp
            0x561d8954616c      4883ec08       sub rsp, 8
            0x561d89546170      48897df8       mov qword [rbp - 8], rdi
            0x561d89546174      488b45f8       mov rax, qword [rbp - 8]
            0x561d89546178      0fb600         movzx eax, byte [rax]
            0x561d8954617b      0fbec0         movsx eax, al
            0x561d8954617e      89c7           mov edi, eax
            0x561d89546180      e8d4ffffff     call 0x561d89546159
            0x561d89546185      83f865         cmp eax, 0x65           ; 'e' ; 101
        ,=< 0x561d89546188      740a           je 0x561d89546194
        |   0x561d8954618a      b800000000     mov eax, 0
       ,==< 0x561d8954618f      e989000000     jmp 0x561d8954621d
       |`-> 0x561d89546194      488b45f8       mov rax, qword [rbp - 8]
       |    0x561d89546198      4883c001       add rax, 1
       |    0x561d8954619c      0fb600         movzx eax, byte [rax]
       |    0x561d8954619f      0fbec0         movsx eax, al
       |    0x561d895461a2      89c7           mov edi, eax
       |    0x561d895461a4      e8b0ffffff     call 0x561d89546159
       |    0x561d895461a9      83f870         cmp eax, 0x70           ; 'p' ; 112
       |,=< 0x561d895461ac      7407           je 0x561d895461b5
       ||   0x561d895461ae      b800000000     mov eax, 0
      ,===< 0x561d895461b3      eb68           jmp 0x561d8954621d
      ||`-> 0x561d895461b5      488b45f8       mov rax, qword [rbp - 8]
      ||    0x561d895461b9      4883c002       add rax, 2
      ||    0x561d895461bd      0fb600         movzx eax, byte [rax]
      ||    0x561d895461c0      0fbec0         movsx eax, al
      ||    0x561d895461c3      89c7           mov edi, eax
      ||    0x561d895461c5      e88fffffff     call 0x561d89546159
      ||    0x561d895461ca      83f868         cmp eax, 0x68           ; 'h' ; 104
      ||,=< 0x561d895461cd      7407           je 0x561d895461d6
      |||   0x561d895461cf      b800000000     mov eax, 0
     ,====< 0x561d895461d4      eb47           jmp 0x561d8954621d
     |||`-> 0x561d895461d6      488b45f8       mov rax, qword [rbp - 8]
     |||    0x561d895461da      4883c003       add rax, 3
     |||    0x561d895461de      0fb600         movzx eax, byte [rax]
     |||    0x561d895461e1      0fbec0         movsx eax, al
     |||    0x561d895461e4      89c7           mov edi, eax
     |||    0x561d895461e6      e86effffff     call 0x561d89546159
     |||    0x561d895461eb      83f868         cmp eax, 0x68           ; 'h' ; 104
     |||,=< 0x561d895461ee      7407           je 0x561d895461f7
     ||||   0x561d895461f0      b800000000     mov eax, 0
    ,=====< 0x561d895461f5      eb26           jmp 0x561d8954621d
    ||||`-> 0x561d895461f7      488b45f8       mov rax, qword [rbp - 8]
    ||||    0x561d895461fb      4883c004       add rax, 4
    ||||    0x561d895461ff      0fb600         movzx eax, byte [rax]
    ||||    0x561d89546202      0fbec0         movsx eax, al
    ||||    0x561d89546205      89c7           mov edi, eax
    ||||    0x561d89546207      e84dffffff     call 0x561d89546159
    ||||    0x561d8954620c      83f87a         cmp eax, 0x7a           ; 'z' ; 122
    ||||,=< 0x561d8954620f      7407           je 0x561d89546218
    |||||   0x561d89546211      b800000000     mov eax, 0
   ,======< 0x561d89546216      eb05           jmp 0x561d8954621d
   |||||`-> 0x561d89546218      b801000000     mov eax, 1
   `````--> 0x561d8954621d      c9             leave
            0x561d8954621e      c3             ret

We have multiple if on our input. If we try to write a pseudocode of this function we get:

int flag(char *string) == 0x561d89546168
{
    // somefunc() = 0x561d89546159
    if (somefunc(string[0]) == 'e')
        if(somefunc(string[1]) == 'p')
            if(somefunc(string[2]) == 'h')
                if(somefunc(string[3]) == 'h')
                    if(somefunc(string[4]) == 'z')
                        return 1;

    return 0;
}

Now what the function located at 0x561d89546159 (in our pseudocode somefunc) does :

[0x561d895461c5]> s 0x561d89546159
[0x561d89546159]> pd
            0x561d89546159      55             push rbp
            0x561d8954615a      4889e5         mov rbp, rsp
            0x561d8954615d      897dfc         mov dword [rbp - 4], edi
            0x561d89546160      8b45fc         mov eax, dword [rbp - 4]
            0x561d89546163      83c001         add eax, 1
            0x561d89546166      5d             pop rbp
            0x561d89546167      c3             ret

Psuedocode :

char somefunc(char c)
{
    return c + 1;
}

So what we have to do to print good job kthxbye ?

We need to take the string ephhz and substract to every character 1, in this way when the flag function will compare the result of somefunc char per char we will make all the if statements true:

“exploit.py” :

s = 'ephhz'
payload = ''
for i in range(0, len(s)):
    payload += chr(ord(s[i])-1)

print(payload)

Output : doggy

$ ./generic_crackme.bin
plz enter password plz:
doggy
good job kthxbye

Flag

flag{doggy}