Esta pagina se ve mejor con JavaScript habilitado

Ingenieria inversa utilizando Radare

 ·  🎃 kr0m

Hace un tiempo dimos los primeros pasos en el mundo de la ingeniería inversa, como está organizada la pila, como ejecutar una shellcode, como escribir nuestras shellcodes y ejecución de una shell mediante shellcode. Para realizar todas las tareas enteriores utilizabamos GDB, un magnífico software para depurar nuestros porgramas pero la tarea de reversing se volvía un tanto pesada, esta vez utilizaremos Radare, enfocada desde los cimientos al reversing.

Radare es un software realmente potente, este se compone de varios elementos:

  • radare2: Editor hexadecimal y debugger
  • rabin2: Extractor de info de los ejecutables binarios
  • rasm2: Ensamblador, desensamblador desde la CLI
  • rahash2: Generador de hashes
  • radiff2: Utilidad para buscar diferencias utilizando varios algoritmos
  • rafind2: Buscador de patrones en un fichero
  • ragg2: Compilador de binarios
  • rarun2: Nos permite correr el programa en diferentes entornos, variables de entorno, argumentos, directorios…

Hay un libro online que nos puede resultar realmente útil.

En la propia web se recomienda instalar desde los repos ya que así obtendremos siempre la última versión.

cd /usr/src
git clone https://github.com/radare/radare2
cd radare2
sys/install.sh

Instalamos los bindings(librerias de integración) de varios lenguajes de programación, Valabind, SWIG, Ctypes, NodeJS, Dlang, Go:

emerge -av dev-lang/vala
ln -s /usr/bin/valac-0.24 /usr/bin/valac
cd ..
git clone https://github.com/radare/valabind
cd valabind
make
make install PREFIX=/usr

Ahora para python, nodejs, ruby:

cd ..
git clone https://github.com/radare/radare2-bindings
cd radare2-bindings
./configure –prefix=/usr
cd python
make
make install

Testeamos la instalación:

cd ../..
git clone https://github.com/radare/radare2-regressions
cd radare2-regressions
make

Instalamos el editor hexadecimal ired:

cd ..
git clone https://github.com/radare/ired
cd ired
make
make install PREFIX=/usr

sdb: base de datos clave-valor similar a redis, utilizada para operaciones internas de radare.

cd ..
git clone https://github.com/radare/sdb
cd sdb
make
make -C tests

Ahora que ya tenemos todo lo necesario procedemos con la programación de un pequeño crackme:

vi 00.c

#include<stdio.h>
int main(void){
    char str1[20];
    printf("Crackme 0x00 Coded by Kr0m\n");
    printf("Introduzca password: ");
    scanf("%s", str1);
    if (strcmp(str1, "666-666") == 0){
            printf("Ohu yeyesss Password Correcto!\n");
    } else {
            printf("ERROR: Password incorrecto!\n");
    }
}

Compilamos el software:

gcc 00.c -o 00

Lo probamos:

./00

Crackme 0x00 Coded by Kr0m
Introduzca password: asd
ERROR: Password incorrecto!
./00
Crackme 0x00 Coded by Kr0m
Introduzca password: 666-666
Ohu yeyesss Password Correcto!

Radare nos permite dumpear las cadenas de un binario:

rabin2 -z 00

vaddr=0x004007e8 paddr=0x000007e8 ordinal=000 sz=27 len=26 section=.rodata type=a string=Crackme 0x00 Coded by Kr0m
vaddr=0x00400803 paddr=0x00000803 ordinal=001 sz=22 len=21 section=.rodata type=a string=Introduzca password:
vaddr=0x0040081c paddr=0x0000081c ordinal=002 sz=8 len=7 section=.rodata type=a string=666-666
vaddr=0x00400828 paddr=0x00000828 ordinal=003 sz=31 len=30 section=.rodata type=a string=Ohu yeyesss Password Correcto!
vaddr=0x00400847 paddr=0x00000847 ordinal=004 sz=28 len=27 section=.rodata type=a string=ERROR: Password incorrecto!

NOTA: La vieja escuela lo haría mediante string :)

Abrimos el binario en modo writeble, vamos al main del programa y mostramos las instrucciones desensambladas:

radare2 -w 00

[0x004005c0]> s sym.main
[0x004006ad]> pd

           0x004006c4    bfe8074000   mov edi, str.Crackme_0x00_Coded_by_Kr0m ; "Crackme 0x00 Coded by Kr0m" @ 0x4007e8
           0x004006c9    e882feffff   call sym.imp.puts
              0x00400550(unk) ; sym.imp.puts
           0x004006ce    bf03084000   mov edi, str.Introduzca_password: ; "Introduzca password: " @ 0x400803
           0x004006d3    b800000000   mov eax, 0
           0x004006d8    e893feffff   call sym.imp.printf
              0x00400570() ; sym.imp.printf
           0x004006dd    488d45e0     lea rax, qword [rbp - 0x20]
           0x004006e1    4889c6       mov rsi, rax
           0x004006e4    bf19084000   mov edi, 0x400819                ; "%s" @ 0x400819
           0x004006e9    b800000000   mov eax, 0
           0x004006ee    e8bdfeffff   call sym.imp.__isoc99_scanf
              0x004005b0() ; sym.imp.__isoc99_scanf
           0x004006f3    488d45e0     lea rax, qword [rbp - 0x20]
           0x004006f7    be1c084000   mov esi, str.666_666             ; "666-666" @ 0x40081c
           0x004006fc    4889c7       mov rdi, rax
           0x004006ff    e88cfeffff   call sym.imp.strcmp
              0x00400590() ; sym.imp.strcmp
           0x00400704    85c0         test eax, eax
       ,=< 0x00400706    750c         jne 0x400714
       |   0x00400708    bf28084000   mov edi, str.Ohu_yeyesss_Password_Correcto_ ; "Ohu yeyesss Password Correcto!" @ 0x400828
       |   0x0040070d    e83efeffff   call sym.imp.puts
       |      0x00400550() ; sym.imp.puts
      ,==< 0x00400712    eb0a         jmp 0x40071e
      |`-> 0x00400714    bf47084000   mov edi, str.ERROR:_Password_incorrecto_ ; "ERROR: Password incorrecto!" @ 0x400847
      |    0x00400719    e832feffff   call sym.imp.puts
      |       0x00400550() ; sym.imp.puts
      `--> 0x0040071e    488b55f8     mov rdx, qword [rbp - 8]
           0x00400722    64483314252. xor rdx, qword fs:[0x28]
     ,===< 0x0040072b    7405         je 0x400732
     |     0x0040072d    e82efeffff   call sym.imp.__stack_chk_fail
     |        0x00400560() ; sym.imp.__stack_chk_fail
     `---> 0x00400732    c9           leave

Nos interesa modificar el salto condicional: jne 0x400714 para que salte de forma incondicional a la parte del pass correcto: jmp 0x400708, para ello nos movemos a la posición de memoria donde está el salto:

[0x004006ad]> s 0x00400706

Podemos hacer uso de esta chuleta de comandos rápidos, en nuestro caso queremos escribir assembler “a pelo”

[0x00400706]> wa jmp 0x00400708
[0x00400706]> pd
 ,=< 0x00400706 750c jne 0x400714
 ,=< 0x00400706 eb00 jmp 0x400708
[0x00400706]> q

Rejecutamos y Baaannnggg!!

./00

Crackme 0x00 Coded by Kr0m
Introduzca password: asd
Ohu yeyesss Password Correcto!

Como veis ha sido realmente sencillo, tan solo modificando una pequeña parte del código hemos conseguido desviar el flujo del programa hacia donde nos interesa ;)

Si te ha gustado el artículo puedes invitarme a un RedBull aquí