Write up on insinuator.netChallenge 01
Installing dependencies
sudo apt-get install cmake build-essential
Download the challenges
git clone git@github.com:bluec0re/reversing-radare2.git
cd reversing-radare2
Compile the challenges
mkdir build
cd build
cmake ..
make
The first challenge (compiled) is now in reversing-radare2/build/sources/challenge01/
.
You also have precompiled challenges in reversing-radare2/sources/challenge01/
.
In this post we will use the pre-compiled challenge challenge01
.
cd /opt
git clone git@github.com:radare/radare2.git
cd radare2
sys/install.sh
Back to reversing-radare2/sources/challenge01/
, we try to execute the
compiled binary :
./challenge01
##################################
# Challenge 1 #
# #
# (c) 2016 Timo Schmid #
##################################
Enter Password: qsmdlfk
Wrong!
To crack this challenge we will use radare2, to open the binary with radare2 we use the command :
r2 -d challenge01
Process with PID 15085 started...
= attach 15085 15085
bin.baddr 0x00400000
Using 0x400000
asm.bits 64
-- command not found: calc.exe
[0x7fdaa8972c30]>
The -d
is to start radare2 in debugger mode
We can list the entrypoints with the command ie
which stands for "info entrypoints".
[0x7fdaa8972c30]> ie
[Entrypoints]
vaddr=0x004007c0 paddr=0x000007c0 baddr=0x00400000 laddr=0x00000000 haddr=0x00000018 type=program
1 entrypoints
An entrypoint is the address from which the execution will start.
Here we can see that the entrypoint is 0x004007c0
.
To analyse the binary we run the command aaa
:
[0x7fdaa8972c30]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
= attach 15085 15085
15085
aaa
stands for "Analyze All Autoname functions after aa". This command will
analyze functions and bss.
Now that the analysis is done we can display the disassembly with pdf
"Print Disassembly".
This function will display the disassembly at the current address 0x7fdaa8972c30
:
[0x7fdaa8972c30]> pd
;-- rip:
0x7fdaa8972c30 4889e7 mov rdi, rsp
0x7fdaa8972c33 e8780d0000 call 0x7fdaa89739b0
0x7fdaa8972c38 4989c4 mov r12, rax
0x7fdaa8972c3b 8b0537502200 mov eax, dword [0x7fdaa8b97c78] ; [0x7fdaa8b97c78:4]=0
0x7fdaa8972c41 5a pop rdx
0x7fdaa8972c42 488d24c4 lea rsp, [rsp + rax*8]
0x7fdaa8972c46 29c2 sub edx, eax
0x7fdaa8972c48 52 push rdx
0x7fdaa8972c49 4889d6 mov rsi, rdx
0x7fdaa8972c4c 4989e5 mov r13, rsp
0x7fdaa8972c4f 4883e4f0 and rsp, 0xfffffffffffffff0
0x7fdaa8972c53 488b3de65322. mov rdi, qword [0x7fdaa8b98040] ; [0x7fdaa8b98040:8]=0
0x7fdaa8972c5a 498d4cd510 lea rcx, [r13 + rdx*8 + 0x10] ; 16
0x7fdaa8972c5f 498d5508 lea rdx, [r13 + 8] ; 8
But this is not interesting, we'd rather see the code of the main
function.
To do so we can use s main
to navigate to the main function (seek main).
[0x7fdaa8972c30]> s main
[0x0040091b]>
Notice how the current address has changed from 0x7fdaa8972c30
to 0x0040091b
With radare2 every command follows the same logic : the first letter defines the
type of the command (a for analyze, p for print, s for seek, i for info ...).
Then the second letter defines the subtype, and so on.
So when we typed ie
we used the subtype "entrypoint" of the commmand "info".
To get more info about the commands we can use and the subtypes available we can
use ?
. The command ?
lists the first level command available. Then we can
go deeper with i?
for instance, which shows that the commands iE
and iI
exist.
We could have used iI
to show info about the binary :
[0x0040091b]> iI
arch x86
binsz 6451
bintype elf
bits 64
canary false
class ELF64
crypto false
endian little
havecode true
intrp /lib64/ld-linux-x86-64.so.2
lang c
linenum true
lsyms true
machine AMD x86-64 architecture
maxopsz 16
minopsz 1
nx true
os linux
pcalign 0
pic false
relocs true
relro no
rpath NONE
static false
stripped false
subsys linux
va true
To enter visual mode we use the command V
.
The visual mode is like doing a pdf
(Print Disassembled Function) in vim.
You can go up and down with j
and k
. You can use p
and P
to cycle through
the different display modes.
So we seek the main function with s main
and enter visual mode with V
.
We can see the disassembled function :
[0x0040091b 1232 /reversing-radare2/sources/challenge01/challenge01]> pd $r @ main
/ (fcn) main 133
| main ();
| ; var int local_118h @ rbp-0x118
| ; var int local_110h @ rbp-0x110
| ; var int local_104h @ rbp-0x104
| ; var int local_100h @ rbp-0x100
| ; var int local_1h @ rbp-0x1
| ; DATA XREF from 0x004007dd (entry0)
| 0x0040091b 55 push rbp
| 0x0040091c 4889e5 mov rbp, rsp
| 0x0040091f 4881ec200100. sub rsp, 0x120
| 0x00400926 89bdfcfeffff mov dword [local_104h], edi
| 0x0040092c 4889b5f0feff. mov qword [local_110h], rsi
| 0x00400933 488995e8feff. mov qword [local_118h], rdx
| 0x0040093a b800000000 mov eax, 0
| 0x0040093f e872ffffff call sym.banner ;[1]
| 0x00400944 bfd70a4000 mov edi, str.Enter_Password: ; 0x400ad7 ; "Enter Password: "
| 0x00400949 b800000000 mov eax, 0
| 0x0040094e e81dfeffff call sym.imp.printf ;[2] ; int printf(const char *format)
| 0x00400953 488d8500ffff. lea rax, [local_100h]
| 0x0040095a 4889c6 mov rsi, rax
| 0x0040095d bfe80a4000 mov edi, str.255s ; 0x400ae8 ; "%255s"
| 0x00400962 b800000000 mov eax, 0
| 0x00400967 e844feffff call sym.imp.__isoc99_scanf ;[3]
| 0x0040096c c645ff00 mov byte [local_1h], 0
| 0x00400970 488d8500ffff. lea rax, [local_100h]
| 0x00400977 4889c7 mov rdi, rax
| 0x0040097a e870ffffff call sym.checkPassword ;[4]
| 0x0040097f 84c0 test al, al
| ,=< 0x00400981 740c je 0x40098f ;[5]
| | 0x00400983 bfee0a4000 mov edi, str.Password_accepted ; 0x400aee ; "Password accepted!"
| | 0x00400988 e8d3fdffff call sym.imp.puts ;[6] ; int puts(const char *s)
| ,==< 0x0040098d eb0a jmp 0x400999 ;[7]
| |`-> 0x0040098f bf010b4000 mov edi, str.Wrong ; 0x400b01 ; "Wrong!"
| | 0x00400994 e8c7fdffff call sym.imp.puts ;[6] ; int puts(const char *s)
The first line shows the command used to generate the current view : pd $r @ main
.
If you move up or down this line will change.
Looking at the disassembly we can see that first the banner is displayed with
the function banner
and the string "Enter Password: " is displayed with
printf
:
0x0040093f e872ffffff call sym.banner ;[1]
0x00400944 bfd70a4000 mov edi, str.Enter_Password: ; 0x400ad7 ; "Enter Password: "
0x00400949 b800000000 mov eax, 0
0x0040094e e81dfeffff call sym.imp.printf ;[2] ; int printf(const char *format)
From there the function scanf
is called to get the user input :
0x0040095a 4889c6 mov rsi, rax
0x0040095d bfe80a4000 mov edi, str.255s ; 0x400ae8 ; "%255s"
0x00400962 b800000000 mov eax, 0
0x00400967 e844feffff call sym.imp.__isoc99_scanf ;[3]
Then a function called checkPassword
is called and according to the result
of this function we are transported to the bad boy at address 0x00400a27
or the good boy at address 0x00400a1b
:
0x0040097a e870ffffff call sym.checkPassword ;[4]
0x0040097f 84c0 test al, al
0x00400981 740c je 0x40098f ;[5]
0x00400983 bfee0a4000 mov edi, str.Password_accepted ; 0x400aee ; "Password accepted!"
We could have seen this easily with radare2 graph mode.
When in visual mode, just press V
to enter graph mode and q
to quit it.
Once again we can use p
and P
to cycle through the display mode.
.-----------------------------------------.
| 0x40091b ;[gf] |
| 0x0040091b "./challenge01" |
| 0x0040091c "./challenge01" |
| 0x0040093f call sym.banner |
| 0x00400944 str.Enter_Password: |
| 0x0040094e call sym.imp.printf |
| 0x0040095d str.255s |
| 0x00400967 call sym.imp.__isoc99_scanf |
| 0x0040097a call sym.checkPassword |
`-----------------------------------------'
| |
| '------------------.
.----------------------------' |
| |
| |
.-----------------------------------------------. .-----------------------------------------------.
| 0x400983 ;[gi] | | 0x40098f ;[ge] |
| 0x00400983 str.Password_accepted | | 0x0040098f str.Wrong |
| 0x00400988 call sym.imp.puts "./challenge01" | | 0x00400994 call sym.imp.puts "./challenge01" |
`-----------------------------------------------' `-----------------------------------------------'
| |
'--------------------------------------. |
.------------'
|
|
.--------------------.
| [0x400999] ;[gh] |
`--------------------'
When in visual mode or graph mode we can still use radare2 commands.
To do so we just need to press :
to get a small terminal letting us type our commands.
So if we want to go to the checkPassword
function we can do :s sym.checkPassword
.
Then we hit Enter to return to the Visual mode.
Here is the graph disassembly for the checkPassword
function :
0x004008ef 55 push rbp
0x004008f0 4889e5 mov rbp, rsp
0x004008f3 4883ec20 sub rsp, 0x20
0x004008f7 48897de8 mov qword [local_18h], rdi
0x004008fb 48c745f8c30a. mov qword [local_8h], str.p4ssw0rd ; 0x400ac3 ; "p4ssw0rd"
0x00400903 488b45e8 mov rax, qword [local_18h]
0x00400907 becc0a4000 mov esi, str.n0p4ssw0rd ; 0x400acc ; "n0p4ssw0rd"
0x0040090c 4889c7 mov rdi, rax
0x0040090f e87cfeffff call sym.imp.strcmp ;[1] ; int strcmp(const char *s1, const char *s2)
0x00400914 85c0 test eax, eax
0x00400916 0f94c0 sete al
0x00400919 c9 leave
0x0040091a c3 ret
We can see that the function compares a string with "n0p4ssw0rd" and sets the result of the function accordingly.
So lets try to enter "n0p4ssw0rd" as the password !
First we restart the program with ood
(reopen current file in debug mode).
[0x004008ef]> ood
Wait event received by different pid 15085
Wait event received by different pid 15434
Process with PID 15474 started...
File dbg:///home/braincoke/Git/Crackme/reversing-radare2/sources/challenge01/challenge01 reopened in read-write mode
= attach 15474 15474
Unable to find filedescriptor 5
Unable to find filedescriptor 5
15474
[0x7fc5517bdc30]>
Then we "continue" the execution with dc
.
[0x7fc5517bdc30]> dc
##################################
# Challenge 1 #
# #
# (c) 2015 Timo Schmid #
##################################
Enter Password: n0p4ssw0rd
Password accepted!
[0x7fc5514bf748]>
That's it ! We cracked the binary !