IOLI Crackme 0x04 solution

Hello,

This is another IOLI crackme challenge solution.

root@kali:~/IOLI-crackme/bin-linux# r2 crackme0x04

[0x080483d0]> aaa
[ ] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* unctions (aan)
[x] Type matching analysis for all functions (afta)
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x080483d0]> afl
0x0804833c    1 23           sym._init
0x08048364    1 6            sym.imp.__libc_start_main
0x08048374    1 6            sym.imp.scanf
0x08048384    1 6            sym.imp.strlen
0x08048394    1 6            sym.imp.printf
0x080483a4    1 6            sym.imp.sscanf
0x080483b4    1 6            sym.imp.exit
0x080483d0    1 33           entry0
0x080483f4    3 33           fcn.080483f4
0x08048420    6 47           sym.__do_global_dtors_au
0x08048450    4 50           sym.frame_dummy
0x08048484    6 133          sym.check
0x08048509    1 92           sym.main
0x08048570    4 99           sym.__libc_csu_init
0x080485e0    1 5            sym.__libc_csu_fini
0x080485e5    1 4            sym.__i686.get_pc_thunk.bx
0x080485f0    4 35           sym.__do_global_ctors_aux
0x08048614    1 26           sym._fini
[0x080483d0]> pdf @main
-- main:
┌ (fcn) sym.main 92
│   sym.main (int argc, char **argv, char **envp);
│           ; var int local_78h @ ebp-0x78
│           ; var int local_4h @ esp+0x4
│           ; DATA XREF from entry0 (0x80483e7)
│           0x08048509      55             push ebp                    ; push word, doubleword or quadword onto the stack
│           0x0804850a      89e5           mov ebp, esp                ; moves data from src to dst
│           0x0804850c      81ec88000000   sub esp, 0x88               ; substract src and dst, stores result on dst
│           0x08048512      83e4f0         and esp, 0xfffffff0         ; binary and operation between src and dst, stores result on dst
│           0x08048515      b800000000     mov eax, 0                  ; moves data from src to dst
│           0x0804851a      83c00f         add eax, 0xf                ; adds src and dst, stores result on dst
│           0x0804851d      83c00f         add eax, 0xf                ; adds src and dst, stores result on dst
│           0x08048520      c1e804         shr eax, 4                  ; logic right shift (0 padding)
│           0x08048523      c1e004         shl eax, 4                  ; logic left shift (0 padding)
│           0x08048526      29c4           sub esp, eax                ; substract src and dst, stores result on dst
│           0x08048528      c704245e8604.  mov dword [esp], str.IOLI_Crackme_Level_0x04 ; [0x804865e:4]=0x494c4f49 ; "IOLI Crackme Level 0x04\n" ; moves data from src to dst; const char *format
│           0x0804852f      e860feffff     call sym.imp.printf         ; calls a subroutine, push eip into the stack (esp) ; int printf(const char *format)
│           0x08048534      c70424778604.  mov dword [esp], str.Password: ; [0x8048677:4]=0x73736150 ; "Password: " ; moves data from src to dst; const char *format
│           0x0804853b      e854feffff     call sym.imp.printf         ; calls a subroutine, push eip into the stack (esp) ; int printf(const char *format)
│           0x08048540      8d4588         lea eax, dword [local_78h]  ; load effective address
│           0x08048543      89442404       mov dword [local_4h], eax   ; moves data from src to dst
│           0x08048547      c70424828604.  mov dword [esp], 0x8048682  ; [0x8048682:4]=0x7325 ; moves data from src to dst; const char *format
│           0x0804854e      e821feffff     call sym.imp.scanf          ; calls a subroutine, push eip into the stack (esp) ; int scanf(const char *format)
│           0x08048553      8d4588         lea eax, dword [local_78h]  ; load effective address
│           0x08048556      890424         mov dword [esp], eax        ; moves data from src to dst
│           0x08048559      e826ffffff     call sym.check              ; calls a subroutine, push eip into the stack (esp)
│           0x0804855e      b800000000     mov eax, 0                  ; moves data from src to dst
│           0x08048563      c9             leave                       ; one byte alias for mov esp, ebp ; pop ebp
└           0x08048564      c3             ret                         ; return from subroutine. pop 4 bytes from esp and jump there.
[0x080483d0]> pdf @sym.check`
┌ (fcn) sym.check 133
│   sym.check (char *s);
│           ; var char *local_dh @ ebp-0xd
│           ; var unsigned int local_ch @ ebp-0xc
│           ; var unsigned int local_8h @ ebp-0x8
│           ; var int local_4h @ ebp-0x4
│           ; arg char *s @ ebp+0x8
│           ; var char *format @ esp+0x4
│           ; var int local_8h_2 @ esp+0x8
│           ; CALL XREF from sym.main (0x8048559)
│           0x08048484      55             push ebp                    ; push word, doubleword or quadword onto the stack
│           0x08048485      89e5           mov ebp, esp                ; moves data from src to dst
│           0x08048487      83ec28         sub esp, 0x28               ; '(' ; substract src and dst, stores result on dst
│           0x0804848a      c745f8000000.  mov dword [local_8h], 0     ; moves data from src to dst
│           0x08048491      c745f4000000.  mov dword [local_ch], 0     ; moves data from src to dst
│           ; CODE XREF from sym.check (0x80484f9)
│       ┌─> 0x08048498      8b4508         mov eax, dword [s]          ; [0x8:4]=-1 ; 8 ; moves data from src to dst
│       ╎   0x0804849b      890424         mov dword [esp], eax        ; moves data from src to dst; const char *s
│       ╎   0x0804849e      e8e1feffff     call sym.imp.strlen         ; calls a subroutine, push eip into the stack (esp) ; size_t strlen(const char *s)
│       ╎   0x080484a3      3945f4         cmp dword [local_ch], eax   ; compare two operands
│      ┌──< 0x080484a6      7353           jae 0x80484fb               ; jump short if above or equal (cf=0)
│      │╎   0x080484a8      8b45f4         mov eax, dword [local_ch]   ; moves data from src to dst
│      │╎   0x080484ab      034508         add eax, dword [s]          ; adds src and dst, stores result on dst
│      │╎   0x080484ae      0fb600         movzx eax, byte [eax]       ; move dst register size padding with zeroes
│      │╎   0x080484b1      8845f3         mov byte [local_dh], al     ; moves data from src to dst
│      │╎   0x080484b4      8d45fc         lea eax, dword [local_4h]   ; load effective address
|      │╎   0x080484b7      89442408       mov dword [local_8h_2], eax ; moves data from src to dst;   ...
│      │╎   0x080484bb      c74424043886.  mov dword [format], 0x8048638 ; [0x8048638:4]=0x50006425 ; moves data from src to dst; const char *format
│      │╎   0x080484c3      8d45f3         lea eax, dword [local_dh]   ; load effective address
│      │╎   0x080484c6      890424         mov dword [esp], eax        ; moves data from src to dst; const char *s
│      │╎   0x080484c9      e8d6feffff     call sym.imp.sscanf         ; calls a subroutine, push eip into the stack (esp) ; int sscanf(const char *s, const char *format,   ...)
│      │╎   0x080484ce      8b55fc         mov edx, dword [local_4h]   ; moves data from src to dst
│      │╎   0x080484d1      8d45f8         lea eax, dword [local_8h]   ; load effective address
│      │╎   0x080484d4      0110           add dword [eax], edx        ; adds src and dst, stores result on dst
│      │╎   0x080484d6      837df80f       cmp dword [local_8h], 0xf   ; compare two operands
│     ┌───< 0x080484da      7518           jne 0x80484f4               ; jump short if not equal/not zero (zf=0)
│     ││╎   0x080484dc      c704243b8604.  mov dword [esp], str.Password_OK ; [0x804863b:4]=0x73736150 ; "Password OK!\n" ; moves data from src to dst; const char *format
│     ││╎   0x080484e3      e8acfeffff     call sym.imp.printf         ; calls a subroutine, push eip into the stack (esp) ; int printf(const char *format)
│     ││╎   0x080484e8      c70424000000.  mov dword [esp], 0          ; moves data from src to dst; int status
│     ││╎   0x080484ef      e8c0feffff     call sym.imp.exit           ; calls a subroutine, push eip into the stack (esp) ; void exit(int status)
│     ││╎   ; CODE XREF from sym.check (0x80484da)
│     └───> 0x080484f4      8d45f4         lea eax, dword [local_ch]   ; load effective address
│      │╎   0x080484f7      ff00           inc dword [eax]             ; increment by 1
│      │└─< 0x080484f9      eb9d           jmp 0x8048498               ; jump
│      │    ; CODE XREF from sym.check (0x80484a6)
│      └──> 0x080484fb      c70424498604.  mov dword [esp], str.Password_Incorrect ; [0x8048649:4]=0x73736150 ; "Password Incorrect!\n" ; moves data from src to dst; const char *format
│           0x08048502      e88dfeffff     call sym.imp.printf         ; calls a subroutine, push eip into the stack (esp) ; int printf(const char *format)
│           0x08048507      c9             leave                       ; one byte alias for mov esp, ebp ; pop ebp
└           0x08048508      c3             ret                         ; return from subroutine. pop 4 bytes from esp and jump there.

Pay attention to these instructions:

│      │╎   0x080484d6      837df80f       cmp dword [local_8h], 0xf   ; compare two operands
│     ┌───< 0x080484da      7518           jne 0x80484f4               ; jump short if not equal/not zero (zf=0)
│     ││╎   0x080484dc      c704243b8604.  mov dword [esp], str.Password_OK ; [0x804863b:4]=0x73736150 ; "Password OK!\n" ; moves data from src to dst; const char *format
│     ││╎   0x080484e3      e8acfeffff     call sym.imp.printf         ; calls a subroutine, push eip into the stack (esp) ; int printf(const char *format)
│     ││╎   0x080484e8      c70424000000.  mov dword [esp], 0          ; moves data from src to dst; int status
│     ││╎   0x080484ef      e8c0feffff     call sym.imp.exit           ; calls a subroutine, push eip into the stack (esp) ; void exit(int status)

These section is where a number is compared to something and if true the password will be valid.
Something is compared against 15 (0xf).

Let’s find out which is the other operand.

│      └──> 0x080484fb      c70424498604.  mov dword [esp], str.Password_Incorrect ; [0x8048649:4]=0x73736150 ; "Password Incorrect!\n" ; moves data from src to dst; const char *format
│           0x08048502      e88dfeffff     call sym.imp.printf         ; calls a subroutine, push eip into the stack (esp) ; int printf(const char *format)
│           0x08048507      c9             leave                       ; one byte alias for mov esp, ebp ; pop ebp
└           0x08048508      c3             ret                         ; return from subroutine. pop 4 bytes from esp and jump there.

These section reminds me a loop.

What is being compared to 15 is the parameter of the app, in other words the password.

The functin strlen() gets the length of the password we input.
The function sscanf() gets characters from our password  “%s”, and then transform it to “%d”.
Using the loop for len times (our password length) these numbers are added together and compared with 0xf(15).

So, any number combinations that number by number added is 15 will be valid.

root@kali:~/IOLI-crackme/bin-linux# ./crackme0x04

IOLI Crackme Level 0x04
Password: 663
Password OK!