Some time ago we took our first steps in the world of reverse engineering, learning about stack organization, how to execute a shellcode, how to write our own shellcodes, and how to execute a shell using shellcode. To perform all these tasks, we used GDB, a magnificent software for debugging our programs, but the reversing task became somewhat cumbersome. This time we will use Radare, focused from the ground up on reversing.
Radare is a really powerful software, composed of several elements:
- radare2: Hexadecimal editor and debugger
- rabin2: Extractor of info from binary executables
- rasm2: Assembler, disassembler from the CLI
- rahash2: Hash generator
- radiff2: Utility to search for differences using various algorithms
- rafind2: Pattern finder in a file
- ragg2: Binary compiler
- rarun2: Allows us to run the program in different environments, environment variables, arguments, directories…
There is an online book that can be really useful.
On the website itself, it is recommended to install from the repos as we will always get the latest version.
We install the bindings (integration libraries) for several programming languages, Valabind, SWIG, Ctypes, NodeJS, Dlang, Go:
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
Now for python, nodejs, ruby:
git clone https://github.com/radare/radare2-bindings
cd radare2-bindings
./configure –prefix=/usr
cd python
make
make install
We test the installation:
We install the hexadecimal editor ired:
sdb: key-value database similar to redis, used for internal operations of radare.
Now that we have everything we need, we proceed with the programming of a small crackme:
#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");
}
}
We compile the software:
We test it:
Crackme 0x00 Coded by Kr0m
Introduzca password: asd
ERROR: Password incorrecto!
Crackme 0x00 Coded by Kr0m
Introduzca password: 666-666
Ohu yeyesss Password Correcto!
Radare allows us to dump the strings of a binary:
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!
NOTE: The old school would do it through string :)
We open the binary in writeble mode, go to the program’s main and show the disassembled instructions:
[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
We are interested in modifying the conditional jump: jne 0x400714 to jump unconditionally to the correct pass part: jmp 0x400708, so we move to the memory position where the jump is:
[0x004006ad]> s 0x00400706
We can use this cheat sheet of quick commands, in our case we want to write assembler “by hand”
[0x00400706]> wa jmp 0x00400708
[0x00400706]> pd
,=< 0x00400706 750c jne 0x400714
,=< 0x00400706 eb00 jmp 0x400708
[0x00400706]> q
We run it again and Baaannnggg!!
Crackme 0x00 Coded by Kr0m
Introduzca password: asd
Ohu yeyesss Password Correcto!
As you can see, it has been really easy, just by modifying a small part of the code we have managed to redirect the flow of the program to where we are interested ;)