Insinuator CrackMe - Part 1

11 March 2018

Write up on insinuator.netChallenge 01

Setting up the challenge

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.

Installing radare2

radare2radare2 documentation

cd /opt
git clone git@github.com:radare/radare2.git
cd radare2
sys/install.sh

Testing the challenge

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

Getting info with radare2

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

Radare2 visual mode

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!"

Radare2 graph mode

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.

checkPassword function

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 !

More info about this challenge