HackTheBox | Previse

I decided to start trying some of the boxes on HackTheBox for a change, instead of TryHackMe. In the past I've found these to be a bit more difficult generally than THM, so I opted to start with an easy one.

HackTheBox | Previse
Photo by Adi Goldstein / Unsplash

Introduction

I decided to start trying some of the boxes on HackTheBox for a change, instead of TryHackMe.  In the past I've found these to be a bit more difficult generally than THM, so I opted to start with an easy one.

I started in the usual way with a port scan to see what ports were open and listening.

Port Scan

# Nmap 7.92 scan initiated Thu Oct 21 18:56:23 2021 as: /snap/nmap/2536/bin/nmap -F -oN previse.nmap previse.htb
Nmap scan report for previse.htb
Host is up (0.031s latency).
Not shown: 98 closed tcp ports (conn-refused)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

The usual suspects here, so it was going to be a web application based exploit.  I added previse.htb to my /etc/hosts file so I wouldn't have to remember the IP address off by heart.

I tried to brute-force this login page with the username 'admin' but it didn't pay off.  I also ran a directory scan to see if there were any hidden files or folders.

Directory Scan

My initial directory scan did not reveal very much of interest.  Just the css and js asset files.  I ran a second scan for files with the .php prefix, as I noticed the homepage was called login.php.

/accounts.php         (Status: 302) [Size: 3994] [--> login.php]
/config.php           (Status: 200) [Size: 0]
/css                  (Status: 301) [Size: 308] [--> http://previse.htb/css/]
/download.php         (Status: 302) [Size: 0] [--> login.php]
/favicon.ico          (Status: 200) [Size: 15406]
/files.php            (Status: 302) [Size: 4914] [--> login.php]
/footer.php           (Status: 200) [Size: 217]
/header.php           (Status: 200) [Size: 980]
/index.php            (Status: 302) [Size: 2801] [--> login.php]
/index.php            (Status: 302) [Size: 2801] [--> login.php]
/js                   (Status: 301) [Size: 307] [--> http://previse.htb/js/]
/login.php            (Status: 200) [Size: 2224]
/logs.php             (Status: 302) [Size: 0] [--> login.php]
/logout.php           (Status: 302) [Size: 0] [--> login.php]
/nav.php              (Status: 200) [Size: 1248]
/server-status        (Status: 403) [Size: 276]
/status.php           (Status: 302) [Size: 2966] [--> login.php]
This proved to be fruitful

Most of the files simply redirected to the login.php file, but nav.php did not, so I had a look at that first.

Clicking on any of the links simply redirected me back to login.php.  I was trying various things in the browser dev tools, like editing and resending requests until eventually I decided it would be easier to load up BurpSuite.

To my surprise, when I attempted to access the accounts.php file through the Repeater tool, the actual admin page would render, before the redirect was followed.  This gave me an insight into what the accounts.php file's frontend looked like.

You've got to love burpsuite

Examining the HTML content of the response gave some clues as to what input the accounts.php file might be looking for in order to create an account.

        <form role="form" method="post" action="accounts.php">
            <div class="uk-margin">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: user"></span>
                    <input type="text" name="username" class="uk-input" id="username" placeholder="Username">
                </div>
            </div>
            <div class="uk-margin">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: lock"></span>
                    <input type="password" name="password" class="uk-input" id="password" placeholder="Password">
                </div>
            </div>
            <div class="uk-margin">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: lock"></span>
                    <input type="password" name="confirm" class="uk-input" id="confirm" placeholder="Confirm Password">
                </div>
            </div>
            <button type="submit" name="submit" class="uk-button uk-button-default">CREATE USER</button>
        </form>
What happens if we POST to accounts.php?

So it looks like in order to create an account I need to POST some data to accounts.php which includes username, password and confirm fields.

I created this request in BurpSuite and clicked on Send. Finally I have managed to create a user.

Exploring the Admin Area and Source Code

With my new user account created I could finally log in and explore the admin area of the application.

Always good when you have the source code

I took a look at the Files page and found a file called SiteBackup.zip available for download.

As the name suggested this zip file contained all the php source code for the application.

MySQL Credentials

The config.php file contained some login credentials for a MySQL server.  These credentials did not work against the SSH endpoint, with the user newguyor root though.  I gave up trying after 20 minutes of brute-forcing it with hydra.

<?php

function connectDB(){
    $host = 'localhost';
    $user = 'root';
    $passwd = '<redacted>';
    $db = 'previse';
    $mycon = new mysqli($host, $user, $passwd, $db);
    return $mycon;
}

?>

Further exploration of the code led me to a file called logs.php which contained the use of a function which is known to be "dangerous", called exec().  This function allows php to execute commands on the host system and then returns the results.

/////////////////////////////////////////////////////////////////////////////////////
//I tried really hard to parse the log delims in PHP, but python was SO MUCH EASIER//
/////////////////////////////////////////////////////////////////////////////////////

$output = exec("/usr/bin/python /opt/scripts/log_process.py {$_POST['delim']}");
echo $output;
EASIER perhaps, but not the most secure..

From looking at the php documentation, I learn that the first parameter passed to the exec() function is the command to execute.  I then notice that in this code, there is some unsanitized user input being inserted directly into the function.  The $_POST['delim'] parameter.

Exec() Exploit

I manage to find the page on the website which seems to make use of this logs.php file under the hood.  I click on "Submit" and inspect the request in BurpSuite.

In BurpSuite I can see where the delim parameter has been defined.  I modify this parameter to include an additional bash command using a semi-colon character. This character lets you execute multiple commands on a single line.

netcat to my own machine

Foothold

I set up a listener on my own machine on port 4444 and eventually I get a connection back.

gareth@enso:~/Desktop/Files/Previse$ nc -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 10.129.244.116 37402
whoami
www-data

I stabilise my shell using Python and then login to the MySQL database using the credentials I found earlier.

www-data@previse:/home$ mysql -u root -p previse
Enter password: 
mysql> select * from accounts;
+----+----------+------------------------------------+---------------------+
| id | username | password                           | created_at          |
+----+----------+------------------------------------+---------------------+
|  1 | m4lwhere | $1$🧂llol$<redacted> | 2021-05-27 18:18:36 |
|  3 | gareth   | $1$🧂llol$ZzLqiEgVUtVoDW74rJYqb1 | 2021-10-21 20:52:37 |
+----+----------+------------------------------------+---------------------+
2 rows in set (0.00 sec)
Time to heat up the GPU and get cracking

The accounts table has a salt which I recognise from the php code and a password hash.  I know from seeing the source code that the php crypt() function has been used, so I should be able to crack this hash using hashcat.

I find a user directory in /home called m4lwhere so I know this user exists in linux as well as in the MySQL database.

Horizontal Privilege Escalation

I load up hashcat and select the correct mode for a default crypt() hash, which was mode 500. This website has a great overview of the various hash types and corresponding mode numbers.

I saved the hash into a hash.txt file and started to crack the hash using the rockyou.txt wordlist.  It didn't take long before the password was cracked.

gareth@enso:~/Desktop/Files/Previse$ hashcat -m 500 hash.txt /usr/share/wordlists/rockyou.txt

Session..........: hashcat
Status...........: Running
Hash.Type........: md5crypt, MD5 (Unix), Cisco-IOS $1$ (MD5)
Hash.Target......: $1$🧂llol$<redacted>
Time.Started.....: Thu Oct 21 22:02:09 2021 (16 secs)
Time.Estimated...: Thu Oct 21 22:02:46 2021 (21 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:   380.0 kH/s (6.83ms) @ Accel:256 Loops:125 Thr:32 Vec:1
Recovered........: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.........: 6168576/14344385 (43.00%)
Rejected.........: 0/6168576 (0.00%)
Restore.Point....: 6168576/14344385 (43.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:750-875
Candidates.#1....: lionhead19 -> liloandzues21
Hardware.Mon.#1..: Temp: 63c Util: 83% Core:1594MHz Mem:2504MHz Bus:4

$1$🧂llol$<redacted>:<redacted>

I could then use this cracked password to su to the m4lwhere user and capture the user flag in the user.txt file.

www-data@previse:/home$ su m4lwhere
Password: 
m4lwhere@previse:/home$ cd m4lwhere/
m4lwhere@previse:~$ cat user.txt
<redacted>
m4lwhere@previse:~$ 

At this stage, I SSH directly into the box as the m4lwhere user, for an even more stable shell.

Vertical Privilege Escalation

The first thing I do is check if my user has anything it is allowed to run with sudo.  I saw there was a bash script called access_backup.sh in the /opt/script directory that I have permissions to run as the root user.

I read the contents of this script file and found the following:

#!/bin/bash

# We always make sure to store logs, we take security SERIOUSLY here

# I know I shouldnt run this as root but I cant figure it out programmatically on my account
# This is configured to run with cron, added to sudo so I can run as needed - we'll fix it later when there's time

gzip -c /var/log/apache2/access.log > /var/backups/$(date --date="yesterday" +%Y%b%d)_access.gz
gzip -c /var/www/file_access.log > /var/backups/$(date --date="yesterday" +%Y%b%d)_file_access.gz

I like how in the same breath the writer of this file says that they take security SERIOUSLY and then immediately follow by saying "I know I shouldn't run this as root".

In this script file I see that the "path injection" vulnerability is present. The script does not use an absolute path for the gzip or date binaries, meaning I can create my own version of these binaries and have this script run them as root instead.

SUID

Instead of x in the file permissions we set s for suid

Just to mix things up a bit, instead of just creating a reverse shell to my machine again as the root user, I decided to set the SUID bit on the /bin/bash binary.  SUID means "Set owner User ID up on execution" and effectively means that whoever runs bash will be running it as the owner of the binary, rather than as themselves.

Summary

The hardest part about this box was actually in the beginning, trying to get a foothold.  It took a while to figure out how to get it working and to create a user.  It was good to use BurpSuite to be able to see the content of the rendered page before the redirect took me back to the login page, and it felt quite realistic afterwards with the path towards root access.

The more HackTheBox boxes I do, hopefully the more easy they will become.