Este sitio utiliza cookies propias y de terceros. Si continúa navegando consideramos que acepta el uso de cookies. OK Más Información.

Ingeniería inversa con radare [Parte 1]

  • 0 Respuestas
  • 3824 Vistas

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado sadfud

  • *
  • Moderador
  • Mensajes: 182
  • Actividad:
    1.67%
  • Reputación 9
    • Ver Perfil
    • Blog
  • Skype: SadFud
« en: Septiembre 24, 2017, 03:34:53 am »
Buenas Underc0ders, este sera el primer post de un total entre 5 y 7 que tienen como objetivo enseñar como proceder en la ingenieria inversa con el framework radare2.


Lo primero que hay que hacer es instalar radare, las instrucciones de instalacion se encuentran en su repositorio de github.
https://github.com/radare/radare2

Para los vagos:
Código: Bash
  1. git clone https://github.com/radare/radare2
  2. cd radare2/sys
  3. chmod +x ./install.sh
  4. sudo ./install.sh

Antes de nada algunos recursos utiles:
Documentacion oficial de radare: https://radare.gitbooks.io/radare2book/content/
Informacion sobre arquitecturas e ingenieria inversa: https://www.aldeid.com/wiki/Category:Reverse-Engineering

En esta parte vamos a trabajar sobre la arquitectura x86, con sintaxis intel, dejo una chuleta con las instrucciones



El binario sobre el que trabajaremos en esta parte es el conocido IOLI crackme 0x00 (Podeis descargar todos los niveles aqui http://www113.zippyshare.com/v/UTjKTJfG/file.html )

En el archivo comprimido hay un archivo README.txt que nos da pistas sobre los niveles, en este nivel por ser el primero usaremos la ayuda que nos da.

Respecto a este nivel nos dice que las "strings son nuestras amigas".

Si bien esta seria de posts trataran exlusivamente sobre ingenieria inversa con radare2, sin usar ninguna otra cosa, me gustaria en este primer nivel resolverlo de varias sencillas maneras sin r2.

El primer metodo seria usando strings como nos indica el txt con
Código: Bash
  1. strings crackme0x00
. Output:
Código: Bash
  1. /lib/ld-linux.so.2
  2. __gmon_start__
  3. libc.so.6
  4. printf
  5. strcmp
  6. scanf
  7. _IO_stdin_used
  8. __libc_start_main
  9. GLIBC_2.0
  10. PTRh
  11. IOLI Crackme Level 0x00
  12. Password:
  13. 250382 #esta es la contraseña del primer nivel
  14. Invalid Password!
  15. Password OK :)
  16. GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)
  17. GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)
  18. GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)
  19. GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)
  20. GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)
  21. GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)
  22. GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)
  23. .symtab
  24. .strtab
  25. .shstrtab
  26. .interp
  27. .note.ABI-tag
  28. .gnu.hash
  29. .dynsym
  30. .dynstr
  31. .gnu.version
  32. .gnu.version_r
  33. .rel.dyn
  34. .rel.plt
  35. .init
  36. .text
  37. .fini
  38. .rodata
  39. .eh_frame
  40. .ctors
  41. .dtors
  42. .jcr
  43. .dynamic
  44. .got
  45. .got.plt
  46. .data
  47. .bss
  48. .comment
  49. crtstuff.c
  50. __CTOR_LIST__
  51. __DTOR_LIST__
  52. __JCR_LIST__
  53. completed.1
  54. __do_global_dtors_aux
  55. frame_dummy
  56. __CTOR_END__
  57. __DTOR_END__
  58. __FRAME_END__
  59. __JCR_END__
  60. __do_global_ctors_aux
  61. crackme0x00.c
  62. _GLOBAL_OFFSET_TABLE_
  63. __init_array_end
  64. __init_array_start
  65. _DYNAMIC
  66. data_start
  67. __libc_csu_fini
  68. _start
  69. __gmon_start__
  70. _Jv_RegisterClasses
  71. _fp_hw
  72. _fini
  73. __libc_start_main@@GLIBC_2.0
  74. _IO_stdin_used
  75. scanf@@GLIBC_2.0
  76. __data_start
  77. __dso_handle
  78. __libc_csu_init
  79. printf@@GLIBC_2.0
  80. __bss_start
  81. _end
  82. _edata
  83. strcmp@@GLIBC_2.0
  84. __i686.get_pc_thunk.bx
  85. main
  86. _init
  87.  

Vemos que solo con listar las strings del binario conseguimos la contraseña valida, vamos a ver ahora como hacer lo mismo desde el modulo rabin2 de radare2: rabin2 -z crackme0x00
Con el comando rabin2 llamamos al modulo, con el flag -z buscamos strings en el binario. Obtenemos el siguiente resultado:

Código: Bash
  1. └──╼ $rabin2 -z crackme0x00
  2. vaddr=0x08048568 paddr=0x00000568 ordinal=000 sz=25 len=24 section=.rodata type=ascii string=IOLI Crackme Level 0x00\n
  3. vaddr=0x08048581 paddr=0x00000581 ordinal=001 sz=11 len=10 section=.rodata type=ascii string=Password:
  4. vaddr=0x0804858f paddr=0x0000058f ordinal=002 sz=7 len=6 section=.rodata type=ascii string=250382
  5. vaddr=0x08048596 paddr=0x00000596 ordinal=003 sz=19 len=18 section=.rodata type=ascii string=Invalid Password!\n
  6. vaddr=0x080485a9 paddr=0x000005a9 ordinal=004 sz=16 len=15 section=.rodata type=ascii string=Password OK :)\n
  7.  

De nuevo obtenemos la contraseña en texto plano a traves de un analisis estatico del binario.

Vamos a ver otra forma, ahora si usando exclusivamente radare2, de obtener la contraseña en texto plano sin debuggear el software y luego veremos como modificar el flujo de ejecuccion para que acepte cualquier contraseña como valida (crackear).

Lo primero que haremos sera ejecutar radare y analizar completamente el binario:
radare2 crackme0x00 -AA

Ahora dentro de radare con el comando 'S' (sin las comillas simples) listamos las secciones del binario. Documentación del comando https://radare.gitbooks.io/radare2book/content/basic_commands/sections.html
El formato del output que nos da es:
Numero de sección
Offset de inicio
Permisos de la seccion
Virtual adress (dirección virtual)
Size (tamaño)
Virtual size (tamaño virtual)
Nombre de la seccion

Código: Bash
  1. [00] . 0x00000154 -r-- va=0x08048154 sz=0x0013 vsz=0x0013 .interp
  2. [01] . 0x00000168 -r-- va=0x08048168 sz=0x0020 vsz=0x0020 .note.ABI_tag
  3. [02] . 0x00000188 -r-- va=0x08048188 sz=0x0030 vsz=0x0030 .hash
  4. [03] . 0x000001b8 -r-- va=0x080481b8 sz=0x0020 vsz=0x0020 .gnu.hash
  5. [04] . 0x000001d8 -r-- va=0x080481d8 sz=0x0070 vsz=0x0070 .dynsym
  6. [05] . 0x00000248 -r-- va=0x08048248 sz=0x0059 vsz=0x0059 .dynstr
  7. [06] . 0x000002a2 -r-- va=0x080482a2 sz=0x000e vsz=0x000e .gnu.version
  8. [07] . 0x000002b0 -r-- va=0x080482b0 sz=0x0020 vsz=0x0020 .gnu.version_r
  9. [08] . 0x000002d0 -r-- va=0x080482d0 sz=0x0008 vsz=0x0008 .rel.dyn
  10. [09] . 0x000002d8 -r-- va=0x080482d8 sz=0x0020 vsz=0x0020 .rel.plt
  11. [10] . 0x000002f8 -r-x va=0x080482f8 sz=0x0017 vsz=0x0017 .init
  12. [11] . 0x00000310 -r-x va=0x08048310 sz=0x0050 vsz=0x0050 .plt
  13. [12] * 0x00000360 -r-x va=0x08048360 sz=0x01e4 vsz=0x01e4 .text
  14. [13] . 0x00000544 -r-x va=0x08048544 sz=0x001a vsz=0x001a .fini
  15. [14] . 0x00000560 -r-- va=0x08048560 sz=0x0059 vsz=0x0059 .rodata
  16. [15] . 0x000005bc -r-- va=0x080485bc sz=0x0004 vsz=0x0004 .eh_frame
  17. [16] . 0x00000f0c -rw- va=0x08049f0c sz=0x0008 vsz=0x0008 .ctors
  18. [17] . 0x00000f14 -rw- va=0x08049f14 sz=0x0008 vsz=0x0008 .dtors
  19. [18] . 0x00000f1c -rw- va=0x08049f1c sz=0x0004 vsz=0x0004 .jcr
  20. [19] . 0x00000f20 -rw- va=0x08049f20 sz=0x00d0 vsz=0x00d0 .dynamic
  21. [20] . 0x00000ff0 -rw- va=0x08049ff0 sz=0x0004 vsz=0x0004 .got
  22. [21] . 0x00000ff4 -rw- va=0x08049ff4 sz=0x001c vsz=0x001c .got.plt
  23. [22] . 0x00001010 -rw- va=0x0804a010 sz=0x000c vsz=0x000c .data
  24. [23] . 0x0000101c -rw- va=0x0804a01c sz=0x0004 vsz=0x0004 .bss
  25. [24] . 0x0000101c ---- va=0x00000000 sz=0x01b9 vsz=0x01b9 .comment
  26. [25] . 0x000011d5 ---- va=0x00000000 sz=0x00db vsz=0x00db .shstrtab
  27. [26] . 0x00001738 ---- va=0x00000000 sz=0x0420 vsz=0x0420 .symtab
  28. [27] . 0x00001b58 ---- va=0x00000000 sz=0x0219 vsz=0x0219 .strtab
  29. [28] * 0x00000000 mr-x va=0x08048000 sz=0x05c0 vsz=0x05c0 LOAD0
  30. [29] . 0x00000f0c mrw- va=0x08049f0c sz=0x0110 vsz=0x0114 LOAD1
  31. [30] . 0x00000000 mrw- va=0x08048000 sz=0x0034 vsz=0x0034 ehdr
  32. [31] . 0x00100000 -rwx va=0x00100000 sz=0xf0000 vsz=0xf0000 esil.ram
  33.  

Esta información es bastante útil aunque para esta parte del curso no la usaremos.
Lo que vamos a hacer es desensamblar la funcion main. Pero antes de eso, ¿por que desensamblamos esa funcion y no otra?

Como hemos visto en el output de rabin2, y como en todos los crackmes hay una zona de chico bueno y chico malo, nos interesa por tanto saberen que funcion esta localizada la zona que nos da el OK, para ello usaremos el comando / Password que nos devuelve
Código: Bash
  1. Searching 8 bytes from 0x08048000 to 0x0804a020: 50 61 73 73 77 6f 72 64
  2. Searching 8 bytes in [0x8048000-0x804a020]
  3. hits: 3
  4. 0x08048581 hit0_0 .kme Level 0x00Password: %s250382Inv.
  5. 0x0804859e hit0_1 .250382Invalid Password!Password OK :.
  6. 0x080485a9 hit0_2 .alid Password!Password OK :). #esta es la linea que nos interesa
  7.  

Una vez sabemos la dirección donde esta la zona de 'chico bueno' le pedimos a r2 mas información sobre esa dirección con el comando axt: axt 0x080485a9
Código: Bash
  1. data 0x8048480 mov dword [esp], str.Password_OK_:__n in main; const char * format
  2.  

Una vez entendido el por que de desensamblar el main, usaremos el comando pdf (print disassembled function), comando completo pdf@sym.main

Código: Bash
  1. [0x08048360]> pdf@main
  2.             ;-- main:
  3. / (fcn) main 127
  4. |   main ();
  5. |           ; var int local_18h @ ebp-0x18
  6. |           ; var int local_4h @ esp+0x4
  7. |              ; DATA XREF from 0x08048377 (entry0)
  8. |           0x08048414      55             push ebp
  9. |           0x08048415      89e5           mov ebp, esp
  10. |           0x08048417      83ec28         sub esp, 0x28               ; '('
  11. |           0x0804841a      83e4f0         and esp, 0xfffffff0
  12. |           0x0804841d      b800000000     mov eax, 0
  13. |           0x08048422      83c00f         add eax, 0xf
  14. |           0x08048425      83c00f         add eax, 0xf
  15. |           0x08048428      c1e804         shr eax, 4
  16. |           0x0804842b      c1e004         shl eax, 4
  17. |           0x0804842e      29c4           sub esp, eax
  18. |           0x08048430      c70424688504.  mov dword [esp], str.IOLI_Crackme_Level_0x00_n ; [0x8048568:4]=0x494c4f49 ; "IOLI Crackme Level 0x00\n" ; const char * format
  19. |           0x08048437      e804ffffff     call sym.imp.printf         ; int printf(const char *format)
  20. |           0x0804843c      c70424818504.  mov dword [esp], str.Password: ; hit0_0 ; [0x8048581:4]=0x73736150 ; "Password: " ; const char * format
  21. |           0x08048443      e8f8feffff     call sym.imp.printf         ; int printf(const char *format)
  22. |           0x08048448      8d45e8         lea eax, dword [local_18h]
  23. |           0x0804844b      89442404       mov dword [local_4h], eax
  24. |           0x0804844f      c704248c8504.  mov dword [esp], 0x804858c  ; [0x804858c:4]=0x32007325 ; "%s" ; const char * format
  25. |           0x08048456      e8d5feffff     call sym.imp.scanf          ; int scanf(const char *format)
  26. |           0x0804845b      8d45e8         lea eax, dword [local_18h]
  27. |           0x0804845e      c74424048f85.  mov dword [local_4h], str.250382 ; [0x804858f:4]=0x33303532 ; "250382"
  28. |           0x08048466      890424         mov dword [esp], eax        ; const char * s2
  29. |           0x08048469      e8e2feffff     call sym.imp.strcmp         ; int strcmp(const char *s1, const char *s2)
  30. |           0x0804846e      85c0           test eax, eax
  31. |       ,=< 0x08048470      740e           je 0x8048480
  32. |       |   0x08048472      c70424968504.  mov dword [esp], str.Invalid_Password__n ; [0x8048596:4]=0x61766e49 ; "Invalid Password!\n" ; const char * format
  33. |       |   0x08048479      e8c2feffff     call sym.imp.printf         ; int printf(const char *format)
  34. |      ,==< 0x0804847e      eb0c           jmp 0x804848c
  35. |      |`-> 0x08048480      c70424a98504.  mov dword [esp], str.Password_OK_:__n ; hit0_2 ; [0x80485a9:4]=0x73736150 ; "Password OK :)\n" ; const char * format
  36. |      |    0x08048487      e8b4feffff     call sym.imp.printf         ; int printf(const char *format)
  37. |      |       ; JMP XREF from 0x0804847e (main)
  38. |      `--> 0x0804848c      b800000000     mov eax, 0
  39. |           0x08048491      c9             leave
  40. \           0x08048492      c3             ret
  41.  

De nuevo nos volvemos a encontrar con la contraseña en texto plano.

Llegados a este punto ahora es cuando viene lo divertido, modificar el flujo de ejecuccion, osea, crackear el software. Al lio.

Salta a la vista que el programa compara dos registros (0x08048469, 0x0804846e) en uno esta la contraseña que valida el ejercicio y en el otro lo que nosotros hayamos introducido.
Por tanto la parte que nos interesa esta entre la direccion 0x0804846e y 0x08048480 donde se encuentra la string "Password OK :)".

A grandes rasgos lo que el software hace a partir de la direccion  0x0804846e es lo siguiente:
Compara la pwd introducida con la valida
Si son iguales salta a la direccion 0x08048480
En caso contrario llega hasta la direccion 0x0804847e que ejecuta un salto incondicional a  0x0804848c  y termina con la ejecuccion.

Lo que vamos a hacer es modificar ese "si es equivalente..." por un salto incondicional
Antes de nada, tenemos que entender el significado de la linea, mas concretamente de la segunda columna
 0x08048470      740e           je 0x8048480

74 = je (jump if equal)
0e = bytes to jump (1 instruccion == 1 byte)

Por tanto el objetivo es que la linea anterior se convierta en
 0x08048470      eb0e           jmp 0x8048480

Vamos a hacerlo pues.

Para ello reabrimos el archivo en modo escritura con el comando oo+

Código: Bash
  1. [0x08048360]> oo+
  2. File crackme0x00 reopened in read-write mode
  3.  

A continuacion nos movemos a la direccion donde se encuentra el salto con s 0x08048470 y imprimimos las siguientes 8 instrucciones con el comando pd 8

Si todo ha salido bien deberia aparecer lo siguiente
Código: Bash
  1. [0x08048470]> pd 8
  2. |       ,=< 0x08048470      740e           je 0x8048480
  3. |       |   0x08048472      c70424968504.  mov dword [esp], str.Invalid_Password__n ; [0x8048596:4]=0x61766e49 ; "Invalid Password!\n" ; const char * format
  4. |       |   0x08048479      e8c2feffff     call sym.imp.printf         ; int printf(const char *format)
  5. |      ,==< 0x0804847e      eb0c           jmp 0x804848c
  6. |      |`-> 0x08048480      c70424a98504.  mov dword [esp], str.Password_OK_:__n ; hit0_2 ; [0x80485a9:4]=0x73736150 ; "Password OK :)\n" ; const char * format
  7. |      |    0x08048487      e8b4feffff     call sym.imp.printf         ; int printf(const char *format)
  8. |      |       ; JMP XREF from 0x0804847e (main)
  9. |      `--> 0x0804848c      b800000000     mov eax, 0
  10. |           0x08048491      c9             leave
  11.  

Para modificar la condicion usaremos el comando wx seguido de la nueva instruccion wx 0xeb

Listamos de nuevo 8 instrucciones y observamos como el flujo de ejecuccion se ha modificado

Código: Bash
  1. [0x08048470]> pd 8
  2. |       ,=< 0x08048470      eb0e           jmp 0x8048480
  3. |       |   0x08048472      c70424968504.  mov dword [esp], str.Invalid_Password__n ; [0x8048596:4]=0x61766e49 ; "Invalid Password!\n" ; const char * format
  4. |       |   0x08048479      e8c2feffff     call sym.imp.printf         ; int printf(const char *format)
  5. |      ,==< 0x0804847e      eb0c           jmp 0x804848c
  6. |      |`-> 0x08048480      c70424a98504.  mov dword [esp], str.Password_OK_:__n ; hit0_2 ; [0x80485a9:4]=0x73736150 ; "Password OK :)\n" ; const char * format
  7. |      |    0x08048487      e8b4feffff     call sym.imp.printf         ; int printf(const char *format)
  8. |      |       ; JMP XREF from 0x0804847e (main)
  9. |      `--> 0x0804848c      b800000000     mov eax, 0
  10. |           0x08048491      c9             leave
  11.  

Si necesitas ayuda, no dudes en mandar MP

 

¿Te gustó el post? COMPARTILO!



Malware Analysis "Policia Federal" primer parte

Iniciado por torrescrack

Respuestas: 0
Vistas: 3490
Último mensaje Junio 09, 2013, 08:23:02 pm
por torrescrack
Taller de Cracking desde 0 [Parte 1]

Iniciado por ANTRAX

Respuestas: 0
Vistas: 2682
Último mensaje Febrero 20, 2010, 02:34:08 am
por ANTRAX
Protección del software (Parte I)

Iniciado por CronuX

Respuestas: 7
Vistas: 4001
Último mensaje Marzo 21, 2010, 07:06:02 pm
por CronuX
Nueva versión de REMnux, la distribución Linux para el análisis e Ingeniería Inv

Iniciado por morodog

Respuestas: 0
Vistas: 2756
Último mensaje Abril 11, 2013, 10:58:44 am
por morodog
Reconociendo bucles en ingeniería reversa

Iniciado por LucaSthefano

Respuestas: 1
Vistas: 4532
Último mensaje Mayo 17, 2014, 09:35:29 am
por kasiko