Ejercicios Reversing Ioli Crackmes

Los IOLI Crackmes son unos retos/ejercicios basicos de ingenieria inversa en los que hay que averiguar la contraseña que desbloquea a un programa.

Aqui dejo un Write up con la Solucion a los ejercicios IOLI Crackmes.
Con Radare2. (mas adelante rlos repetire con cutter.)

Indice:

1) Solucion crackme0x00 con radare
2) Solucion crackme0x00-clasico-linux
3) Solucion crackme0x01 con radare
4) Solucion crackme0x02 con radare
5) Solucion crackme0x03 con radare
6) Solucion crackme0x04 con radare
7) Solucion crackme0x05 con radare
8) Solucion crackme0x06 con radare

Referencias

https://dustri.org/b/defeating-ioli-with-radare2.html

crackme0x00 (radare)

jejo@medion:~/reversing/IOLI-crackme$ ./crackme0x00 
IOLI Crackme Level 0x00
Password: ????
Invalid Password!

Busco strings -z

jejo@medion:~/reversing/IOLI-crackme$ rabin2 -z crackme0x00 
[Strings]
nth paddr      vaddr      len size section type  string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0   0x00000568 0x08048568 24  25   .rodata ascii IOLI Crackme Level 0x00\n
1   0x00000581 0x08048581 10  11   .rodata ascii Password: 
2   0x0000058f 0x0804858f 6   7    .rodata ascii 250382
3   0x00000596 0x08048596 18  19   .rodata ascii Invalid Password!\n
4   0x000005a9 0x080485a9 15  16   .rodata ascii Password OK :)\n

Salida mas simple… ´-zqq´

jejo@medion:~/reversing/IOLI-crackme$ rabin2 -zqq crackme0x00 
IOLI Crackme Level 0x00\n
Password: 
250382
Invalid Password!\n
Password OK :)\n

El comando dentro de radare (interactivo) seria fs strings; f, iz , radare2 -c "fs strings; f " crackme0x00

jejo@em50l:~/reversing/IOLI-crackme$ radare2 -c "fs strings; f " crackme0x00 -Q
0x08048568 25 str.IOLI_Crackme_Level_0x00
0x08048581 11 str.Password:
0x0804858f 7 str.250382
0x08048596 19 str.Invalid_Password
0x080485a9 16 str.Password_OK_:

Probamos con 250382

jejo@medion:~/reversing/IOLI-crackme$ ./crackme0x00 
IOLI Crackme Level 0x00
Password: 250382
Password OK :)


Truco aaaa; pdc @main dejara la funcion Main en un codigo parecido a C Si lo retoco. casi tengo el codigo.

jejo@medion:~/reversing/IOLI-crackme$ radare2 -c "aaaa; pdc @main" crackme0x00 -Q
function main () {
       int printf("IOLI Crackme Level 0x00\n")
       int printf("Password: ")
       int scanf("%s")  //sym.imp.scanf ()
       dword [s2] = "250382"  //[0x804858f:4]=0x33303532 ; str.250382 ; const char *s2
       dword [esp] = eax        //const char *s1
                                                   
       int strcmp("", "250382")
       var = eax & eax
       if (!var) goto 0x8048480 //unlikely
       {
        loc_0x8048480:

Bueno no es perfecto. digamos que solo ha averiguado las primera s lineas de codigo.. Pero no esta mal.
Se puede intuir que compara una cadena con 250382 int strcmp("", "250382")




crackme0x00 (clasico linux)

jejo@medion:~/Escritorio/reversing/IOLI-crackme$ ./crackme0x00 
IOLI Crackme Level 0x00
Password: ????
Invalid Password!
jejo@medion:~/Escritorio/reversing/IOLI-crackme$ strings crackme0x00 
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
printf
strcmp
scanf
_IO_stdin_used
__libc_start_main
GLIBC_2.0
PTRh
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)
GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)

Probamos con 250382

jejo@medion:~/Escritorio/reversing/IOLI-crackme$ ./crackme0x00 
IOLI Crackme Level 0x00
Password: 250382
Password OK :)



crackme0x01 (radare)

  • r2 cackme0x01 abro el archivo.
  • aaaa analisis automatico con nombrado de funciones (autoname)
  • afl listado de funciones
  • pdf @ main desensamblado funcion main.
  • antes de la funcion scanf se le pasa a esp el parametro con el formato a leer del teclado. con ps @ 0x804854c (print string) listo el contenido de dicha posicion.
  • veo que compara el dato leido con 0x149a con ? 0x149a veo los posibles valores de este dato en sus distintos formatos.
jejo@em50l:~/reversing/IOLI-crackme$ r2 crackme0x01 
 -- If you want to open the file in read-write mode, invoke r2 with '-w'
[0x08048330]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Finding function preludes
[x] Enable constraint types analysis for variables
[0x08048330]> afl
0x08048330    1 33           entry0
0x080482fc    1 6            sym.imp.__libc_start_main
0x08048380    6 47           sym.__do_global_dtors_aux
0x080483b0    4 50           sym.frame_dummy
0x080484e0    4 35           sym.__do_global_ctors_aux
0x080484d0    1 5            sym.__libc_csu_fini
0x08048504    1 26           sym._fini
0x08048460    4 99           sym.__libc_csu_init
0x080484d5    1 4            sym.__i686.get_pc_thunk.bx
0x080483e4    4 113          main
0x080482d4    1 23           sym._init
0x08048354    3 33           fcn.08048354
0x0804830c    1 6            sym.imp.scanf
0x0804831c    1 6            sym.imp.printf
[0x08048330]> pdf @main
 113: int main (int argc, char **argv, char **envp);
           ; var uint32_t var_4h @ ebp-0x4
           ; var int32_t var_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                ; 15
           0x080483f5      83c00f         add eax, 0xf                ; 15
           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, [var_4h]
           0x0804841b      89442404       mov dword [var_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 [var_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
[0x08048330]> ps @ 0x804854c
%d
[0x08048330]> ? 0x149a
int32   5274
uint32  5274
hex     0x149a
octal   012232
unit    5.2K
segment 0000:049a
string  "\x9a\x14"
fvalue: 5274.0
float:  0.000000f
double: 0.000000
binary  0b0001010010011010
trits   0t21020100
[0x08048330]> 


Luego el password es 5274

jejo@em50l:~/reversing/IOLI-crackme$ ./crackme0x01
IOLI Crackme Level 0x01
Password: ?
Invalid Password!
jejo@em50l:~/reversing/IOLI-crackme$ ./crackme0x01
IOLI Crackme Level 0x01
Password: 5274
Password OK :)



crackme0x02 (radare)

  • r2 cackme0x01 abro el archivo y ejecuto aaaa, analisis , pdf@main impresin y desensamblado funcion main.
jejo@medion:~/reversing/IOLI-crackme$ radare2 -c "aaaa;pdf@main" crackme0x02
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Finding function preludes
[x] Enable constraint types analysis for variables
 144: int main (int argc, char **argv, char **envp);
           ; var uint32_t var_ch @ ebp-0xc
           ; var signed int var_8h @ ebp-0x8
           ; var int32_t var_4h @ ebp-0x4
           ; var int32_t var_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                ; 15
           0x080483f5      83c00f         add eax, 0xf                ; 15
           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, [var_4h]
           0x0804841b      89442404       mov dword [var_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 [var_8h], 0x5a    ; 'Z' ; 90
           0x08048432      c745f4ec0100.  mov dword [var_ch], 0x1ec   ; 492
           0x08048439      8b55f4         mov edx, dword [var_ch]
           0x0804843c      8d45f8         lea eax, [var_8h]
           0x0804843f      0110           add dword [eax], edx
           0x08048441      8b45f8         mov eax, dword [var_8h]
           0x08048444      0faf45f8       imul eax, dword [var_8h]
           0x08048448      8945f4         mov dword [var_ch], eax
           0x0804844b      8b45fc         mov eax, dword [var_4h]
           0x0804844e      3b45f4         cmp eax, dword [var_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

El codigo a mirar (en el que hace los calculos del password) esta entre 0x0804842b justo despues de scanf y 0x08048451 justo antes de jne (salto condicional)

Luego:

  • s 0x08048451 Posicionado en la direccion 0x08048451
  • aeim ; aeip inicializo la pila de la MV y el contador de programa a la direccion anterior.
  • aesu 0x08048451 ejecuto hasta la direccion 0x08048451
  • afvd Visualizo variables argumentos locales. (variables internas a la fucnion (en pila))
[0x08048330]> s 0x0804842b
[0x0804842b]> aeim ; aeip 
[0x0804842b]> aesu 0x08048451
[0x0804844e]> afvd
type:signed int doesn't exist
var var_4h = 0x00177ffc = 0
var var_8h = 
var var_ch = 0x00177ff4 = 338724
var var_4h_2 = 0x00178004 = 0

Probemos con: 338724

jejo@medion:~/Escritorio/reversing/IOLI-crackme$ ./crackme0x02 
IOLI Crackme Level 0x02
Password: 338724
Password OK :)



crackme0x03 (radare)

  • radare2 -c "aaaa;pdf@main" crackme0x03
    -c es para pasarle comandos : aaaa, analisis , pdf@main impresin y desensamblado funcion main.
jejo@em50l:~/reversing/IOLI-crackme$ radare2 -c "aaaa;pdf@main" crackme0x03
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Finding function preludes
[x] Enable constraint types analysis for variables
 128: int main (int argc, char **argv, char **envp);
           ; var int32_t var_ch @ ebp-0xc
           ; var signed int var_8h @ ebp-0x8
           ; var int32_t var_4h @ ebp-0x4
           ; var int32_t var_4h_2 @ esp+0x4
           ; DATA XREF from entry0 @ 0x8048377
           0x08048498      55             push ebp
           0x08048499      89e5           mov ebp, esp
           0x0804849b      83ec18         sub esp, 0x18
           0x0804849e      83e4f0         and esp, 0xfffffff0
           0x080484a1      b800000000     mov eax, 0
           0x080484a6      83c00f         add eax, 0xf                ; 15
           0x080484a9      83c00f         add eax, 0xf                ; 15
           0x080484ac      c1e804         shr eax, 4
           0x080484af      c1e004         shl eax, 4
           0x080484b2      29c4           sub esp, eax
           0x080484b4      c70424108604.  mov dword [esp], str.IOLI_Crackme_Level_0x03 ; [0x8048610:4]=0x494c4f49 ; "IOLI Crackme Level 0x03\n" ; const char *format
           0x080484bb      e890feffff     call sym.imp.printf         ; int printf(const char *format)
           0x080484c0      c70424298604.  mov dword [esp], str.Password: ; [0x8048629:4]=0x73736150 ; "Password: " ; const char *format
           0x080484c7      e884feffff     call sym.imp.printf         ; int printf(const char *format)
           0x080484cc      8d45fc         lea eax, [var_4h]
           0x080484cf      89442404       mov dword [var_4h_2], eax
           0x080484d3      c70424348604.  mov dword [esp], 0x8048634  ; [0x8048634:4]=0x6425 ; const char *format
           0x080484da      e851feffff     call sym.imp.scanf          ; int scanf(const char *format)
           0x080484df      c745f85a0000.  mov dword [var_8h], 0x5a    ; 'Z' ; 90
           0x080484e6      c745f4ec0100.  mov dword [var_ch], 0x1ec   ; 492
           0x080484ed      8b55f4         mov edx, dword [var_ch]
           0x080484f0      8d45f8         lea eax, [var_8h]
           0x080484f3      0110           add dword [eax], edx
           0x080484f5      8b45f8         mov eax, dword [var_8h]
           0x080484f8      0faf45f8       imul eax, dword [var_8h]
           0x080484fc      8945f4         mov dword [var_ch], eax
           0x080484ff      8b45f4         mov eax, dword [var_ch]
           0x08048502      89442404       mov dword [var_4h_2], eax
           0x08048506      8b45fc         mov eax, dword [var_4h]
           0x08048509      890424         mov dword [esp], eax
           0x0804850c      e85dffffff     call sym.test
           0x08048511      b800000000     mov eax, 0
           0x08048516      c9             leave
           0x08048517      c3             ret
 [0x08048360]> 
[0x08048360]> s 0x080484df
[0x080484df]> aeim ; aeip
[0x080484df]> aesu 0x0804850c
[0x08048502]> afvd
type:signed int doesn't exist
var var_4h = 0x00177ffc = 0
var var_8h = 
var var_ch = 0x00177ff4 = 338724
var var_4h_2 = 0x00178004 = 338724

Probemos con 338724

jejo@em50l:~/reversing/IOLI-crackme$ ./crackme0x03 
IOLI Crackme Level 0x03
Password: 338724
Password OK!!! :)


Juguemos un poco mas con el programa.
Esta vez el cambio esta en la impresion.

[0x08048502]> pdf @sym.test
 42: sym.test (int32_t arg_8h, uint32_t arg_ch);
           ; arg int32_t arg_8h @ ebp+0x8
           ; arg uint32_t arg_ch @ ebp+0xc
           ; CALL XREF from main @ 0x804850c
           0x0804846e      55             push ebp
           0x0804846f      89e5           mov ebp, esp
           0x08048471      83ec08         sub esp, 8
           0x08048474      8b4508         mov eax, dword [arg_8h]
           0x08048477      3b450c         cmp eax, dword [arg_ch]
       ┌─< 0x0804847a      740e           je 0x804848a
          0x0804847c      c70424ec8504.  mov dword [esp], str.Lqydolg_Sdvvzrug ; [0x80485ec:4]=0x6479714c ; "Lqydolg#Sdvvzrug$"
          0x08048483      e88cffffff     call sym.shift
      ┌──< 0x08048488      eb0c           jmp 0x8048496
      ││   ; CODE XREF from sym.test @ 0x804847a
      │└─> 0x0804848a      c70424fe8504.  mov dword [esp], str.Sdvvzrug_RN ; [0x80485fe:4]=0x76766453 ; "Sdvvzrug#RN$$$#=,"
          0x08048491      e87effffff     call sym.shift
          ; CODE XREF from sym.test @ 0x8048488
      └──> 0x08048496      c9             leave
           0x08048497      c3             ret
[0x08048502]> q


Si intento simular el codigo de impresion. Parece que funciona Simulo desde la direccion 0x0804847c hasta la 0x08048488
s 0x0804847c ; aeim ; aeip ; aesu 0x08048488

[0x0804847c]> s 0x0804847c ; aeim ; aeip ; aesu 0x08048488 
^C[+] ESIL emulation interrupted at 0x00ac60af



crackme0x04 (radare)

  • radare2 -c "aaaa;pdf@main" crackme0x04
    -c es para pasarle comandos : aaaa, analisis , pdf@main impresin y desensamblado funcion main.
jejo@medion:~/Escritorio/reversing/IOLI-crackme$ radare2 -c "aaaa;pdf@main" crackme0x04
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Finding function preludes
[x] Enable constraint types analysis for variables
 92: int main (int argc, char **argv, char **envp);
           ; var int32_t var_78h @ ebp-0x78
           ; var int32_t var_4h @ esp+0x4
           ; DATA XREF from entry0 @ 0x80483e7
           0x08048509      55             push ebp
           0x0804850a      89e5           mov ebp, esp
           0x0804850c      81ec88000000   sub esp, 0x88
           0x08048512      83e4f0         and esp, 0xfffffff0
           0x08048515      b800000000     mov eax, 0
           0x0804851a      83c00f         add eax, 0xf                ; 15
           0x0804851d      83c00f         add eax, 0xf                ; 15
           0x08048520      c1e804         shr eax, 4
           0x08048523      c1e004         shl eax, 4
           0x08048526      29c4           sub esp, eax
           0x08048528      c704245e8604.  mov dword [esp], str.IOLI_Crackme_Level_0x04 ; [0x804865e:4]=0x494c4f49 ; "IOLI Crackme Level 0x04\n" ; const char *format
           0x0804852f      e860feffff     call sym.imp.printf         ; int printf(const char *format)
           0x08048534      c70424778604.  mov dword [esp], str.Password: ; [0x8048677:4]=0x73736150 ; "Password: " ; const char *format
           0x0804853b      e854feffff     call sym.imp.printf         ; int printf(const char *format)
           0x08048540      8d4588         lea eax, [var_78h]
           0x08048543      89442404       mov dword [var_4h], eax
           0x08048547      c70424828604.  mov dword [esp], 0x8048682  ; [0x8048682:4]=0x7325 ; const char *format
           0x0804854e      e821feffff     call sym.imp.scanf          ; int scanf(const char *format)
           0x08048553      8d4588         lea eax, [var_78h]
           0x08048556      890424         mov dword [esp], eax
           0x08048559      e826ffffff     call sym.check
           0x0804855e      b800000000     mov eax, 0
           0x08048563      c9             leave
           0x08048564      c3             ret
[0x080483d0]> 


Antes de nada veamos que tipo de cadena se introduce por la funcion scanf

[0x080483d0]> ps @0x8048682
%s

Esta vez es una cadena de texto s tipo string



Esta vez Vamos a practicar con la nueva interfaz Visual
si hago VV @sym.check
y pulso varias veces -
Vere el esquema decisiones de la funcion sym.check.
Nota: puedes moverte por la interfaz con la flechas del teclado.

[0x080483d0]> VV @sym.check

[0x08048484]> 0x8048484 # sym.check (char *s);  
                                     v                            

                                     └─┐ ┌───────────────────────────┐  
                                       │ │                           │  
                                 ┌────────────────────┐              
                                  0x8048498 [oc]
                                 └────────────────────┘              
                                         f t                         
                                         
                                         └──────┐                  
                        ┌────────────────┘        
                        
                    ┌────────────────────┐    ┌────────────────────┐ 
                    │  0x80484a8 [oe]    │    │  0x80484fb [oj]
                    └────────────────────┘    └────────────────────┘ 
                            f t                                      
                            
                            └──────┐                               
           ┌────────────────┘        
           
       ┌────────────────────┐    ┌────────────────────┐              
       │  0x80484dc [oh]    │    │  0x80484f4 [oi]
       └────────────────────┘    └────────────────────┘              
                                     v                               │  
                                     │                               │   
                                     └───────────────────────────────┘   

Se ve claramente que hay dos decisiones (ramas roja y verde)


En la primera se ve claramente como Comprueba la longitud y si la longitud no es correcta salta a password incorrect

[0x08048484]> 0x8048484 # sym.check (char *s); 
 ────────────────────────────────────────────────┐                                                                          
                                               │ │                                                                          
                             ┌────────────────────────────────────────┐                                         
                             │  0x8048498 [oc]                        │                                         
                             │ ; CODE XREF from sym.check @ 0x80484f9 │                                         
                             │ mov eax, dword [s]                     │                                         
                             │ ; const char *s                        │                                         
                             │ mov dword [esp], eax                   │                                         
                             │ ; size_t strlen(const char *s)         │                                         
                             │ call sym.imp.strlen;[ob]               │                                         
                             │ cmp dword [var_ch], eax                │                                         
                             │ jae 0x80484fb                          │                                         
                             └────────────────────────────────────────┘                                         
                                              f t                                                                        
                                              
                                              └───────────────────┐                                                    
      ┌───────────────────────────────────────┘                     
      
┌────────────────────────────────────────────────────────┐    ┌────────────────────────────────────────┐           
│  0x80484a8 [oe]                                        │    │  0x80484fb [oj]                        │           
│ mov eax, dword [var_ch]                                │    │ ; const char *format                   │           
│ add eax, dword [s]                                     │    │ ; CODE XREF from sym.check @ 0x80484a6 │           
│ movzx eax, byte [eax]                                  │    │ ; [0x8048649:4]=0x73736150             │           
│ mov byte [var_dh], al                                  │    │ ; "Password Incorrect!\n"              │           
│ lea eax, [var_4h]                                      │    │ mov dword [esp], str.Password_Incorrect│           
│ ;   ...                                                │    │ ; int printf(const char *format)       │           
│ mov dword [var_8h_2], eax                              │    │ call sym.imp.printf;[of]               │           
│ ; const char *format                                   │    │ leave                                  │           
│ ; [0x8048638:4]=0x50006425                             │    │ ret                                    │           
│ mov dword [format], 0x8048638                          │    └────────────────────────────────────────┘           
│ lea eax, [var_dh]                                      │                                                             
│ ; const char *s                                        │                                                             
│ mov dword [esp], eax                                   │                                                             
│ ; int sscanf(const char *s, const char *format,   ...) │                                                             
│ call sym.imp.sscanf;[od]                               │                                                    
│ mov edx, dword [var_4h]                                │                                                    
│ lea eax, [var_8h]                                      │                                                    
│ add dword [eax], edx                                   │                                                    
│ cmp dword [var_8h], 0xf                                │                                                    
│ jne 0x80484f4                                          │                                                    
└────────────────────────────────────────────────────────┘                                                    
    f t                                                                                                   
    

Aqui se ve claramente como Comprueba la longitud

call sym.imp.strlen;[ob]  
cmp dword [var_ch], eax  

La Variable longitud esta en la variable var_ch


Intento ver que valor coge la variable var_ch
Simulando desde 0x08048484 hasta 0x08048498 s 0x08048484 ; aeim ; aeip ; aesu 0x08048498

[0x080483d0]> pdb @sym.check
 133: sym.check (char *s);
           ; var char *var_dh @ ebp-0xd
           ; var uint32_t var_ch @ ebp-0xc
           ; var uint32_t var_8h @ ebp-0x8
           ; var int32_t var_4h @ ebp-0x4
           ; arg char *s @ ebp+0x8
           ; var char *format @ esp+0x4
           ; var int32_t var_8h_2 @ esp+0x8
           ; CALL XREF from main @ 0x8048559
           0x08048484      55             push ebp
           0x08048485      89e5           mov ebp, esp
           0x08048487      83ec28         sub esp, 0x28
           0x0804848a      c745f8000000.  mov dword [var_8h], 0
           0x08048491      c745f4000000.  mov dword [var_ch], 0
[0x080483d0]> s 0x08048484 ; aeim ; aeip ; aesu 0x08048498
[0x08048484]> afvd
var var_8h = 0x00177ff4 = 0
var var_ch = 0x00177ff0 = 0
arg s = 0x00178004 = ""
var var_dh = 0x00177fef = ""
var var_4h = 0x00177ff8 = 0
var var_8h_2 = 0x00177fdc = 0
var format = 0x00177fd8 = ""

Parece que toma el valor 0.
Luego si la longitud de cadena introducida anteriormente es cero: sale.
Parece que forma parte de un loop en el que se comprueban todos los caracteres del string.




Veamos la otra decision.

  
  ┌────────────────────────────────────────────────────────┐    
  │  0x80484a8 [oe]mov eax, dword [var_ch]                                │    
  add eax, dword [s]                                     │    
  movzx eax, byte [eax]                                  │    
  mov byte [var_dh], allea eax, [var_4h]                                      │    
  ;   ...mov dword [var_8h_2], eax; const char *format; [0x8048638:4]=0x50006425mov dword [format], 0x8048638lea eax, [var_dh]                                      │   
  ; const char *smov dword [esp], eax; int sscanf(const char *s, const char *format,   ...)call sym.imp.sscanf;[od]mov edx, dword [var_4h]                                │   
  lea eax, [var_8h]                                      │   
  add dword [eax], edxcmp dword [var_8h], 0xfjne 0x80484f4└────────────────────────────────────────────────────────┘       
  f t                                                                                                    
  
  └───────────────────────┐                          
  ┌───────────────┘                         
  
  ┌─────────────────────────────────────┐   ┌────────────────────────────────────────┐                                       
  │  0x80484dc [oh]                     │   │  0x80484f4 [oi]; const char *format                │   │ ; CODE XREF from sym.check @ 0x80484da; [0x804863b:4]=0x73736150          │   │ lea eax, [var_ch]                      │                                       
  ; "Password OK!\n"                  │   │ inc dword [eax]                        │                                       
  mov dword [esp], str.Password_OK    │   │ jmp 0x8048498; int printf(const char *format)    │   └────────────────────────────────────────┘                                       
  call sym.imp.printf;[of]v                                                                            
; int status
mov dword [esp], 0
; void exit(int status)
call sym.imp.exit;[og]
└─────────────────────────────────────┘       
  │                                              │                                                                            
  │                                              │                                                                            
  └──────────────────────────────────────────────┘                                       

Parece que llama a la funcion sscanfs (Read formatted data from string)
http://www.cplusplus.com/reference/cstdio/sscanf/


Para ver la dadena de formato que le pasa a la funcion sscanfs hago:
ps @0x8048638 : print string direccion @0x8048638

[0x08048484]> ps @0x8048638
%d


Veo que lee un numero decimal, suma su valor a la variable var_8h y lo compara con 0xf
y realiza un salto condicional jne (salto si no iguales / jump not equals)

lea eax, [var_8h]
add dword [eax], edx
cmp dword [var_8h], 0xf
jne 0x80484f4


Conclusion: parece que la suma de los digitos de la contraseña tienen que set 15 (0xf)


Comprobemos que funciona:

jejo@em50l:~/reversing/IOLI-crackme$ ./crackme0x04
IOLI Crackme Level 0x04
Password: 555
Password OK!
jejo@em50l:~/reversing/IOLI-crackme$ ./crackme0x04
IOLI Crackme Level 0x04
Password: 33333
Password OK!
jejo@em50l:~/reversing/IOLI-crackme$ ./crackme0x04
IOLI Crackme Level 0x04
Password: 555555
Password OK!
jejo@em50l:~/reversing/IOLI-crackme$ ./crackme0x04
IOLI Crackme Level 0x04
Password: 555loquetedelagana
Password OK!




crackme0x05 (radare)

  • radare2 -c "aaaa;VV@sym.check" ./crackme0x05
    Como es casi igual que el anterior vamos directos. -c es para pasarle comandos : aaaa, analisis , VV@sym.check Modo Visual funcion sym.check. Me desplazo con las flechas hasta el jne 0x804852b Y veo que el codigo es casi igual salvo que compara con 0x10 (16) y que la funcion en la que ivisualiza password correct se ha movido a sym.paralell
    Esto hace que sea mas dicifil localizar la zona del codigo en la que se comprueba la contraseña.

                                            v                                                    

                                           ┌┘                                                    
┌────────────────────────────────────────────┐                                                   
│                                          │ │                                                   
┌────────────────────────────────────────┐  
 0x80484dc [oc]; CODE XREF from sym.check @ 0x8048530mov eax, dword [s]                     │   
; const char *smov dword [esp], eax; size_t strlen(const char *s)call sym.imp.strlen;[ob]cmp dword [var_ch], eaxjae 0x8048532└────────────────────────────────────────┘   
f t     
  
└───────────────────┐     
┌───────────────────────────────────────┘                       
  
┌────────────────────────────────────────────────────────┐    ┌─────────────────────────────────────────┐   
│  0x80484ec [oe]                                        │    │  0x8048532 [oj]mov eax, dword [var_ch]                                │    │ ; const char *formatadd eax, dword [s]                                     │    │ ; CODE XREF from sym.check @ 0x80484eamovzx eax, byte [eax]                                  │    │ ; [0x8048679:4]=0x73736150mov byte [var_dh], al                                  │    │ ; "Password Incorrect!\n"lea eax, [var_4h]                                      │    │ mov dword [esp], str.Password_Incorrect;   ...                                                │    │ ; int printf(const char *format)mov dword [var_8h_2], eax                              │    │ call sym.imp.printf;[oi]; const char *format                                   │    │ leave; [0x8048668:4]=0x50006425                             │    │ retmov dword [format], 0x8048668                          │    └─────────────────────────────────────────┘ 
lea eax, [var_dh]                                      │  
; const char *smov dword [esp], eax; int sscanf(const char *s, const char *format,   ...)call sym.imp.sscanf;[od]mov edx, dword [var_4h]                                │  
lea eax, [var_8h]                                      │    
add dword [eax], edxcmp dword [var_8h], 0x10jne 0x804852b└────────────────────────────────────────────────────────┘   
f t                                                                                               

└───────────────────────────────────────────────────────────────────────────┐                   
└───────────┐                                                                 

│                ┌─────────────────────────┐                                           
│                │ [0x8048520]             
│                │ mov eax, dword [s]      
│                │ mov dword [esp], eax    
│                │ call sym.parell;[of]    
│                └─────────────────────────┘                                           
│                    v                                                                 
│                    │                                                                 
│                    └───────────────────────────┐                                     
│                                                │ ┌───────────────────────────────────┘                   
│                                                │ 
┌────────────────────────────────────────┐        
│  0x804852b [oh]; CODE XREF from sym.check @ 0x804851elea eax, [var_ch]                      │   
inc dword [eax]                        │   
jmp 0x80484dc└────────────────────────────────────────┘     
│                                              v                                                           
│                                              │                                                           
└──────────────────────────────────────────────┘  


Truco: si te fijas en call sym.parell;[of]
significa que tecleando of voy a la funcion sym.parell
Aunque tambien puedes ir a la funcion con el comando VV @sym.parell

[0x080483d0]> VV @sym.parell
[0x08048484]> 0x8048484 # sym.parell (char *s);  
            ┌────────────────────────────────────────────────────────┐                       
[0x8048484]                                            
68: sym.parell (char *s);                              
; var int32_t var_4h @ ebp-0x4                         
; arg char *s @ ebp+0x8                                
; var char *format @ esp+0x4                           
; var int32_t var_8h @ esp+0x8                         
; CALL XREF from sym.check @ 0x8048526                 
push ebp                                               
mov ebp, esp                                           
sub esp, 0x18                                          
lea eax, [var_4h]                                      
            │ ;   ...                                                
mov dword [var_8h], eax                                
            │ ; const char *format                                   
; [0x8048668:4]=0x50006425                             
mov dword [format], 0x8048668                          
mov eax, dword [s]                                     
            │ ; const char *s                                        
mov dword [esp], eax                                   
; int sscanf(const char *s, const char *format,   ...) 
call sym.imp.sscanf;[oa]                               
mov eax, dword [var_4h]                                
and eax, 1                                             
test eax, eax                                          
jne 0x80484c6                                          
            └────────────────────────────────────────────────────────┘                       
                    f t                                                                      
                    
                    └───────────────────────┐                                              
    ┌───────────────┘                         
    
┌─────────────────────────────────────┐   ┌─────────────────────────────────────────┐        
│  0x80484ae [oe]                     │   │  0x80484c6 [of]                         │        
│ ; const char *format                │   │ ; CODE XREF from sym.parell @ 0x80484ac │        
│ ; [0x804866b:4]=0x73736150          │   │ leave                                   │        
│ ; "Password OK!\n"                  │   │ ret                                     │        
│ mov dword [esp], str.Password_OK    │   └─────────────────────────────────────────┘        
│ ; int printf(const char *format)    │                                                      
│ call sym.imp.printf;[oc]            │                                                      
│ ; int status                        │                                                      
│ mov dword [esp], 0                  │                                                      
│ ; void exit(int status)             │                                                      
│ call sym.imp.exit;[od]              │                                                      
└─────────────────────────────────────┘                                                  

aqui tienes el password_OK



Comprobemos que funciona:

jejo@medion:~/Escritorio/reversing/IOLI-crackme$ ./crackme0x05
IOLI Crackme Level 0x05
Password: 88
Password OK!
jejo@medion:~/Escritorio/reversing/IOLI-crackme$ ./crackme0x05
IOLI Crackme Level 0x05
Password: 88loquesea
Password OK!




crackme0x06 (radare)

  • Esta vez tengo que tirar de debug: r2 -AA -d ./crackme0x06

db sym.imp.strncmp pongo un breakpoint en la funcion strcmp
dc ; drr debug continuar (saltara en el break potint) y debug muestro registros

Observo que con cada interaccion solo cambioa el registro A0 o eax Y parece que va apuntando a las variables del sistema

[0xf7fa4c70]> db sym.imp.strncmp
[0xf7fa4c70]> dc  ; drr 
IOLI Crackme Level 0x06
Password: 556
hit breakpoint at: 80483d8
 A0   eax 0xffbd339c  ([stack]) stack R W 0x435f534c (LS_COLORS=
 
[0x080483d8]> dc  ; drr 
hit breakpoint at: 80483d8
 A0   eax 0xffbd3988  ([stack]) stack R W 0x5353454c (LESSCLOSE=

Echandole un ojo a la funcin en la que esta el strcnmp veo que lo compara con la cadena LOL
En realidad compara con LOLO con un tamaño de 3 luego LOL

[0x080483d8]> pdf @sym.dummy
 102: sym.dummy (int32_t arg_ch);
       ; CALL XREF from sym.parell @ 0x8048547
   ......
     0x080484e6   c74424080300.  mov dword [var_8h_2], 3
     0x080484ee   c74424043887.  mov dword [var_4h_2], str.LOLO ; [0x8048738:4]=0x4f4c4f4c ; "LOLO"
     0x080484f6   8b0411         mov eax, dword [ecx + edx]
     0x080484f9   890424         mov dword [esp], eax
     0x080484fc   e8d7feffff     call sym.imp.strncmp; int strncmp(const char *s1, const char *s2, size_t n)
     0x08048501   85c0           test eax, eax
   └─<0x08048503   75bc           jne 0x80484c1
   ...... 
      0x08048519   c3             ret
[0x080483d8]> 


Probemos que funciona:

jejo@medion:~/Escritorio/reversing/IOLI-crackme$ LOL=? ./crackme0x06
IOLI Crackme Level 0x06
Password: 88
Password OK!



crackme0x07

crackme0x08

crackme0x09

Son iguales solo que con algunas funciones añadidas.
o compilados de forma distinta

Notas

Referencias

https://beginners.re/RE4B-EN.pdf

https://www.megabeets.net/a-journey-into-radare-2-part-1/ https://www.megabeets.net/a-journey-into-radare-2-part-2/

https://radare.gitbooks.io/radare2book/content/crackmes/ioli/intro.html
https://dustri.org/b/defeating-ioli-with-radare2.html
https://dustri.org/b/defeating-ioli-with-radare2-in-2017.html