Jason Turley's Website

TryHackMe: Reverse Engineering Room Writeup

This is my writeup for the Reverse Engineering room created by ashu on TryHackMe. The room contains three “crackme” challenges that involve finding the correct passwords.

I have redacted these in my writeup, and encourage readers to solve these challenges on their own. Enjoy!


crackme1

When working with ELF binaries, I normally always start with running ltrace or strace.

This allows me to see:

In this case, the ltrace output shows the correct password (redacted below):

jason@lapras:/tmp$ ltrace ./crackme1.bin
puts("enter password"enter password
)                                                           = 15
\_\_isoc99\_scanf(0x7fd32ee008a3, 0x7ffffa955ef2, 0x7fd32e9ed8c0, 0x7ffff2161010hello
)   = 1
strcmp("hello", XXXXXX)                                                         = 4
puts("password is incorrect"password is incorrect
)                                                    = 22
+++ exited (status 0) +++

Run the crackme with the correct password to win:

jason@lapras:/tmp$ ./crackme1.bin
enter password
XXXXXX
password is correct

crackme2

For the second challenge, I again ran ltrace and strace, but the password was not shown.

So I opened the binary in gdb. Below is the disassembly output of the main() function:

jason@lapras:/tmp$ gdb -q crackme2.bin
Reading symbols from crackme2.bin...(no debugging symbols found)...done.
(gdb) disass main
Dump of assembler code for function main:
0x000000000000071a <+0>:     push   rbp
0x000000000000071b <+1>:     mov    rbp,rsp
0x000000000000071e <+4>:     sub    rsp,0x10
0x0000000000000722 <+8>:     mov    rax,QWORD PTR fs:0x28
0x000000000000072b <+17>:    mov    QWORD PTR \[rbp-0x8\],rax
0x000000000000072f <+21>:    xor    eax,eax
0x0000000000000731 <+23>:    lea    rdi,\[rip+0xec\]           # print "enter your password"
0x0000000000000738 <+30>:    call   0x5d0 <puts@plt>
0x000000000000073d <+35>:    lea    rax,\[rbp-0xc\]            # buffer for scanf to store our input
0x0000000000000741 <+39>:    mov    rsi,rax
0x0000000000000744 <+42>:    lea    rdi,\[rip+0xed\]           # "%d" format string for scanf
0x000000000000074b <+49>:    mov    eax,0x0
0x0000000000000750 <+54>:    call   0x5f0 <\_\_isoc99\_scanf@plt>
0x0000000000000755 <+59>:    mov    eax,DWORD PTR \[rbp-0xc\]  # our input stored here
0x0000000000000758 <+62>:    cmp    eax,0xXXXXX              # compare our input to the (redacted) value
0x000000000000075d <+67>:    jne    0x76d <main+83>          # branch if incorrect
0x000000000000075f <+69>:    lea    rdi,\[rip+0xd5\]           # print "password is valid"
0x0000000000000766 <+76>:    call   0x5d0 <puts@plt>
0x000000000000076b <+81>:    jmp    0x779 <main+95>          # branch if correct
0x000000000000076d <+83>:    lea    rdi,\[rip+0xd9\]           # print "password is incorrect"
0x0000000000000774 <+90>:    call   0x5d0 <puts@plt>
0x0000000000000779 <+95>:    mov    eax,0x0                  # return 0 for main
0x000000000000077e <+100>:   mov    rdx,QWORD PTR \[rbp-0x8\]
0x0000000000000782 <+104>:   xor    rdx,QWORD PTR fs:0x28
0x000000000000078b <+113>:   je     0x792 <main+120>
0x000000000000078d <+115>:   call   0x5e0 <\_\_stack\_chk\_fail@plt>
0x0000000000000792 <+120>:   leave
0x0000000000000793 <+121>:   ret
End of assembler dump.
(gdb)

I’ve marked the relevant assembly instructions with comments. (I got this idea from one of Chris Evans writeups). Let’s break down what this program is doing:

Since the correct password is hard coded in hex on line <+62>, I used gdb to print it in decimal (redacted below):

(gdb) b \*main+62
Breakpoint 1 at 0x758
(gdb) r
Starting program: /tmp/crackme2.bin
enter your password
LET ME IN
Breakpoint 1, 0x0000000008000758 in main ()

(gdb) p 0xXXXXX
$1 = XXXX

Run the program with this decimal value to win:

jason@lapras:/tmp$ ./crackme2.bin
enter your password
XXXXX
password is valid

crackme3

The final crackme was an interesting one, and involved looping. Again, I launched gdb to get a look under the hood:

jason@lapras:/tmp$ gdb -q crackme3.bin
Reading symbols from crackme3.bin...(no debugging symbols found)...done.
(gdb) disass main
Dump of assembler code for function main:
0x000000000000071a <+0>:     push   rbp
0x000000000000071b <+1>:     mov    rbp,rsp
0x000000000000071e <+4>:     sub    rsp,0x30
0x0000000000000722 <+8>:     mov    rax,QWORD PTR fs:0x28
0x000000000000072b <+17>:    mov    QWORD PTR \[rbp-0x8\],rax
0x000000000000072f <+21>:    xor    eax,eax
0x0000000000000731 <+23>:    mov    WORD PTR \[rbp-0x23\],0x7a61
0x0000000000000737 <+29>:    mov    BYTE PTR \[rbp-0x21\],0x74
0x000000000000073b <+33>:    lea    rdi,\[rip+0x112\]           # print "enter your password"
0x0000000000000742 <+40>:    call   0x5d0 <puts@plt>
0x0000000000000747 <+45>:    lea    rax,\[rbp-0x20\]            # buffer for scanf to store our input
0x000000000000074b <+49>:    mov    rsi,rax
0x000000000000074e <+52>:    lea    rdi,\[rip+0x113\]           # 0x868
0x0000000000000755 <+59>:    mov    eax,0x0
0x000000000000075a <+64>:    call   0x5f0 <\_\_isoc99\_scanf@plt>
0x000000000000075f <+69>:    mov    DWORD PTR \[rbp-0x28\],0x0  # loop counter initialized to 0
0x0000000000000766 <+76>:    jmp    0x797 <main+125>
0x0000000000000768 <+78>:    mov    eax,DWORD PTR \[rbp-0x28\]
0x000000000000076b <+81>:    cdqe
0x000000000000076d <+83>:    movzx  edx,BYTE PTR \[rbp+rax\*1-0x20\]
0x0000000000000772 <+88>:    mov    eax,DWORD PTR \[rbp-0x28\]
0x0000000000000775 <+91>:    cdqe
0x0000000000000777 <+93>:    movzx  eax,BYTE PTR \[rbp+rax\*1-0x23\]
0x000000000000077c <+98>:    cmp    dl,al                     # compare two characters
0x000000000000077e <+100>:   je     0x793 <main+121>          # continue if equal
0x0000000000000780 <+102>:   lea    rdi,\[rip+0xe4\]
0x0000000000000787 <+109>:   call   0x5d0 <puts@plt>          # print "password is incorrect"
0x000000000000078c <+114>:   mov    eax,0x0                   # set 0 return value for main
0x0000000000000791 <+119>:   jmp    0x7ae <main+148>          # branch to exit code
0x0000000000000793 <+121>:   add    DWORD PTR \[rbp-0x28\],0x1  # increment loop counter by 1
0x0000000000000797 <+125>:   cmp    DWORD PTR \[rbp-0x28\],0x2  # check if loop count == 2
0x000000000000079b <+129>:   jle    0x768 <main+78>           # if not, branch to start of loop
0x000000000000079d <+131>:   lea    rdi,\[rip+0xdd\]            # if it is, you win
0x00000000000007a4 <+138>:   call   0x5d0 <puts@plt>          # print "password is valid"
0x00000000000007a9 <+143>:   mov    eax,0x0
0x00000000000007ae <+148>:   mov    rcx,QWORD PTR \[rbp-0x8\]
0x00000000000007b2 <+152>:   xor    rcx,QWORD PTR fs:0x28
0x00000000000007bb <+161>:   je     0x7c2 <main+168>
0x00000000000007bd <+163>:   call   0x5e0 <\_\_stack\_chk\_fail@plt>
0x00000000000007c2 <+168>:   leave
0x00000000000007c3 <+169>:   ret
End of assembler dump.

The program is essentially an implementation of strncmp. It loops to compare the first three characters of our input with the first three characters of the correct password.

The comparison is made on line <+98>

0x000000000000077c <+98>:    cmp    dl,al

It compares the value in register dl with register al. These are the lower halves of registers edx and eax, respectively.

I set a breakpoint on this line, and printed out the values stored in these registers on each loop iteration. This allowed me to piece together the correct three letter password.

Run the program with the correct password to win:

jason@lapras:/tmp$ ./crackme3.bin
enter your password
XXX
password is valid

Conclusion

I had a lot of fun with this room recommend it to anyone starting out in reverse engineering!