IOLI Crackmes

Posted on

Lets download them

wget https://github.com/radareorg/radare2book/raw/master/crackmes/ioli/IOLI-crackme.tar.gz \
  && tar xvzf ./IOLI-crackme.tar.gz

crackme0x00

First lets see what happens when its ran.

% ./crackme0x00

IOLI Crackme Level 0x00
Password: 
Invalid Password!

Lets see where Password: is in the strings of the binary.

% strings ./crackme0x00 | grep -B1 -A1 Password

IOLI Crackme Level 0x00
Password: 
250382
Invalid Password!
Password OK :)
GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)

Alright, there is a number there, lets use that as the password.

%echo "250382" | ./crackme0x00

IOLI Crackme Level 0x00
Password: 
Password OK :)

crackme0x01

Moving on, lets see how this one behaves when executed.

% ./crackme0x01

IOLI Crackme Level 0x01
Password: 
Invalid Password!

Like last time lets looks at the =strings= of the binary.

% strings ./crackme0x01

Not so lucky this time, lets dig in a bit more with radare2

import r2pipe

f = "crackme0x01"
r = r2pipe.open(f)
r.cmd("aaa")
print(r.cmd("pdf@main"))
   / (fcn) main 113
   |   main (int argc, char **argv, char **envp);
   |           ; var unsigned int local_4h @ ebp-0x4
   |           ; var int local_4h_2 @ esp+0x4
   |           ; DATA XREF from entry0 (0x8048347)
   |           0x080483e4      55             push ebp
   |           0x080483e5      89e5           mov ebp, esp
   |           0x080483e7      83ec18         sub esp, 0x18
   |           0x080483ea      83e4f0         and esp, 0xfffffff0
   |           0x080483ed      b800000000     mov eax, 0
   |           0x080483f2      83c00f         add eax, 0xf
   |           0x080483f5      83c00f         add eax, 0xf
   |           0x080483f8      c1e804         shr eax, 4
   |           0x080483fb      c1e004         shl eax, 4
   |           0x080483fe      29c4           sub esp, eax
   |           0x08048400      c70424288504.  mov dword [esp], str.IOLI_Crackme_Level_0x01 ; [0x8048528:4]=0x494c4f49 ; "IOLI Crackme Level 0x01\n" ; const char *format
   |           0x08048407      e810ffffff     call sym.imp.printf         ; int printf(const char *format)
   |           0x0804840c      c70424418504.  mov dword [esp], str.Password: ; [0x8048541:4]=0x73736150 ; "Password: " ; const char *format
   |           0x08048413      e804ffffff     call sym.imp.printf         ; int printf(const char *format)
   |           0x08048418      8d45fc         lea eax, dword [local_4h]
   |           0x0804841b      89442404       mov dword [local_4h_2], eax
   |           0x0804841f      c704244c8504.  mov dword [esp], 0x804854c  ; [0x804854c:4]=0x49006425 ; const char *format
   |           0x08048426      e8e1feffff     call sym.imp.scanf          ; int scanf(const char *format)
   |           0x0804842b      817dfc9a1400.  cmp dword [local_4h], 0x149a
   |       ,=< 0x08048432      740e           je 0x8048442
   |       |   0x08048434      c704244f8504.  mov dword [esp], str.Invalid_Password ; [0x804854f:4]=0x61766e49 ; "Invalid Password!\n" ; const char *format
   |       |   0x0804843b      e8dcfeffff     call sym.imp.printf         ; int printf(const char *format)
   |      ,==< 0x08048440      eb0c           jmp 0x804844e
   |      ||   ; CODE XREF from main (0x8048432)
   |      |`-> 0x08048442      c70424628504.  mov dword [esp], str.Password_OK_: ; [0x8048562:4]=0x73736150 ; "Password OK :)\n" ; const char *format
   |      |    0x08048449      e8cefeffff     call sym.imp.printf         ; int printf(const char *format)
   |      |    ; CODE XREF from main (0x8048440)
   |      `--> 0x0804844e      b800000000     mov eax, 0
   |           0x08048453      c9             leave
   \           0x08048454      c3             ret

Here is the disassembly of the main function of the binary, notice the cmp dword [local_4h], 0x149a at 0x0804842b. This looks to be comparing 0x149a, but 0x149a is hex.

Using radare2 again, it can give us all other numeric values for 0x149a

r2 -c "? 0x149a" --

hex     0x149a
octal   012232
unit    5.2K
segment 0000:049a
int32   5274
string  "\x9a\x14"
binary  0b0001010010011010
fvalue: 5274.0
float:  0.000000f
double: 0.000000
trits   0t21020100

Now that we have all other numeric values for 0x149a lets try that int32 number.

% echo "5274" | ./crackme0x01

IOLI Crackme Level 0x01
Password: 
Password OK :)

crackme0x02

Lets start things off with looking at the output of =strings=.

% strings ./crackme0x02

Like last time nothing jumps out as potentially being the password, Lets review the main function in radare2 again.

import r2pipe

 f = "crackme0x02"
 r = r2pipe.open(f)
 r.cmd("aaa")
 print(r.cmd("pdf@main"))
   / (fcn) main 144
   |   main (int argc, char **argv, char **envp);
   |           ; var unsigned int local_ch @ ebp-0xc
   |           ; var signed int local_8h @ ebp-0x8
   |           ; var int local_4h @ ebp-0x4
   |           ; var int local_4h_2 @ esp+0x4
   |           ; DATA XREF from entry0 (0x8048347)
   |           0x080483e4      55             push ebp
   |           0x080483e5      89e5           mov ebp, esp
   |           0x080483e7      83ec18         sub esp, 0x18
   |           0x080483ea      83e4f0         and esp, 0xfffffff0
   |           0x080483ed      b800000000     mov eax, 0
   |           0x080483f2      83c00f         add eax, 0xf
   |           0x080483f5      83c00f         add eax, 0xf
   |           0x080483f8      c1e804         shr eax, 4
   |           0x080483fb      c1e004         shl eax, 4
   |           0x080483fe      29c4           sub esp, eax
   |           0x08048400      c70424488504.  mov dword [esp], str.IOLI_Crackme_Level_0x02 ; [0x8048548:4]=0x494c4f49 ; "IOLI Crackme Level 0x02\n" ; const char *format
   |           0x08048407      e810ffffff     call sym.imp.printf         ; int printf(const char *format)
   |           0x0804840c      c70424618504.  mov dword [esp], str.Password: ; [0x8048561:4]=0x73736150 ; "Password: " ; const char *format
   |           0x08048413      e804ffffff     call sym.imp.printf         ; int printf(const char *format)
   |           0x08048418      8d45fc         lea eax, dword [local_4h]
   |           0x0804841b      89442404       mov dword [local_4h_2], eax
   |           0x0804841f      c704246c8504.  mov dword [esp], 0x804856c  ; [0x804856c:4]=0x50006425 ; const char *format
   |           0x08048426      e8e1feffff     call sym.imp.scanf          ; int scanf(const char *format)
   |           0x0804842b      c745f85a0000.  mov dword [local_8h], 0x5a  ; 'Z' ; 90
   |           0x08048432      c745f4ec0100.  mov dword [local_ch], 0x1ec ; 492
   |           0x08048439      8b55f4         mov edx, dword [local_ch]
   |           0x0804843c      8d45f8         lea eax, dword [local_8h]
   |           0x0804843f      0110           add dword [eax], edx
   |           0x08048441      8b45f8         mov eax, dword [local_8h]
   |           0x08048444      0faf45f8       imul eax, dword [local_8h]
   |           0x08048448      8945f4         mov dword [local_ch], eax
   |           0x0804844b      8b45fc         mov eax, dword [local_4h]
   |           0x0804844e      3b45f4         cmp eax, dword [local_ch]
   |       ,=< 0x08048451      750e           jne 0x8048461
   |       |   0x08048453      c704246f8504.  mov dword [esp], str.Password_OK_: ; [0x804856f:4]=0x73736150 ; "Password OK :)\n" ; const char *format
   |       |   0x0804845a      e8bdfeffff     call sym.imp.printf         ; int printf(const char *format)
   |      ,==< 0x0804845f      eb0c           jmp 0x804846d
   |      ||   ; CODE XREF from main (0x8048451)
   |      |`-> 0x08048461      c704247f8504.  mov dword [esp], str.Invalid_Password ; [0x804857f:4]=0x61766e49 ; "Invalid Password!\n" ; const char *format
   |      |    0x08048468      e8affeffff     call sym.imp.printf         ; int printf(const char *format)
   |      |    ; CODE XREF from main (0x804845f)
   |      `--> 0x0804846d      b800000000     mov eax, 0
   |           0x08048472      c9             leave
   \           0x08048473      c3             ret

Here it looks it moves a value into the eax register at runtime and then jumps if not equal to the value, lets try to find that value of the eax register at runtime.

% echo "test" | \
  r2 -AAA ./crackme0x02 -d -c "db 0x0804844b" -c "dc" -c "dr"

eax = 0x00052b24
ebx = 0x00000000
ecx = 0x00000000
edx = 0x000001ec
esi = 0xf7ee0000
edi = 0xf7ee0000
esp = 0xff9c4410
ebp = 0xff9c4438
eip = 0x0804844b
eflags = 0x00000206
oeax = 0xffffffff

Now to get the int32 value of the eax register value.

% r2 -c "? 0x00052b24" -- | grep int32

int32   338724

Time to see if this was correct

% echo "338724" | ./crackme0x02

IOLI Crackme Level 0x02
Password: 
Password OK :)