Welcome to another Hack the Box walkthrough. In this blog post, I have demonstrated how I owned the Artificial machine on Hack the Box. Hack The Box is a cybersecurity platform that helps you bridge knowledge gaps and prepares you for cyber security jobs.
You can also test and grow your penetration testing skills, from gathering information to reporting. If you are new to this blog, please do not forget to like, comment and subscribe to my YouTube channel and follow me on LinkedIn for more updates.About the Machine
Artificial is an easy Linux box centered on a web application that accepts user model uploads. The intended exploitation path leverages unsafe model processing + exposed build artifacts and backups to pivot from a web user to a local shell and, ultimately, to root via a backup/admin tool (Backrest).
Artificial is a great beginner-friendly box that ties together modern app concerns (ML model handling, containerized builds) with classic privilege escalation via misconfigured admin tooling and poor credential storage. It’s compact, instructive, and an excellent example of chaining lower-complexity issues into a complete compromise.
The first step in pwning the Artificial machine like I have always done in my previous writeups is to connect my Kali Linux terminal with Hack the Box server. To establish this connection, I ran the following command in the terminal:
Once the connection between my Kali Linux terminal and Hack the Box server has been established, I started the Artificial machine and I was assigned an IP address (10.10.11.74)
After been assigned 10.10.11.74, I decided to map the target machine IP address to the domain name. This way, I could access the service by name instead of by IP address by running:
I added 10.10.11.74 artificial.htb and closed the GNU interface by pressing and holding Ctrl + X. Then I performed reconnaissance using Nmap to find all the open port and services associated with the target machine. Using the following command, I found all the services and port running at 10.10.11.74 (artificial.htb):
From the Nmap scan, I found two open ports (Port 22/tcp and Port 80/tcp). Port 22/tcp has ssh service which means I have to get a reverse shell to the machine and Port 80/tcp has http service which means the machine is a web application which can be accessed on a webpage.
I visited 10.10.11.74 on my browser and was directed to the official Artificial webpage. The webpage has four hyperlinks: "WHY ARTIFICIAL", "REVIEWS", "LOGIN", "REGISTER".
The registration link allow us to register an account by providing our credentials like username, email address and password.
After registering an account, I proceeded to login. On the dashboard, there is an option to upload, manage and run AI models. Also, a short note with the following description was on the dashboard "Please ensure these requirements are installed when building your model, or use our Dockerfile to build the needed environment with ease."
The page included a short note with two links - requirements and Dockerfile, so I clicked both and downloaded the files to inspect how the service expects models to be built. The requirements.txt
simply contained::
The requirements.txt file contains the version number of tensorflow (tensorflow-cpu==2.13.1). The Dockerfile
I retrieved looked like this:
To get a feel for the build environment, I also built the image locally (using docker build -t my-tf-image .
) — the build completed using cached layers and produced a runnable image (localhost/my-tf-image:latest
).
It is important to use the dockerfile from the website to build the environment to be able to get a rebound shell. While searching the internet, I found a vulnerability in TensorFlow Remote Code Execution with Malicious Model and cloned the GitHub repository.
After cloning the repository, I navigation into the directory tensorflow-rce and opened the exploit.py file using the following command:
Inside the exploit.py file, I modified the IP address and the listening port default to my preferred option by checking the IP configuration using ifconfig command and setting my desired port number as well.
I modified the IP address and Port from default to mine and saved the file. Since Artificial website only allow .h5 file extension, I renamed the exploit.py to exploit.h5 and uploaded it to get a reverse shell.
After uploading the malicious model I started a netcat listener on port 6666
and waited for the server to process the file - a successful incoming connection would give me a remote shell and confirm arbitrary code execution during model loading by running the following command:
To spawn the reverse shell after uploading the exploit.h5 file, It is compulsory to click on "View Prediction" button.
After spinning up my listener (nc -lvnp 6666
) the malicious .h5
payload paid off - I got a reverse shell as the app
user:
I started by looking around the app
home directory for flags and obvious loot. There was no user.txt
in the usual places, so I continued to enumerate the project layout and landed in /home/app/app/instance
where I found a suspicious SQLite database:
Because the web app likely stores account data here, I pulled the file off the box to my attacking host. I used a quick HTTP transfer from the target back to me (I had a simple file server listening on :4444
):
Back on the target I opened the DB with sqlite3
and dumped the user
table by running:
I extracted Gael’s hash (c99175974b6e192936d97224638a34f8
) from users.db
into hash.txt
and ran John the Ripper with rockyou.txt
in Raw-md5
mode. The hash cracked quickly, revealing the password mattp005numbertwo
. Because the app stored unsalted MD5 hashes, offline cracking was trivial.
Gaining user access — SSH into gael
and capturing user.txt
With the recovered credentials the next step is to try logging in as Gael (and test credential reuse against other services) to escalate access and hunt for the user.txt
flag. With Gael’s cracked password in hand (mattp005numbertwo
), I attempted an SSH login to the box:
The client warned about a new host key (expected on a fresh HTB machine), so I accepted and continued. After entering the recovered password I was authenticated and dropped into an interactive shell as gael
:
A quick directory listing revealed the user flag in the home folder:
Hurray!!! I got the user flag! With user flag captured, the next phase is local enumeration for privilege escalation vectors (suid binaries, sudo rights, cronjobs, kernel exploits, and sensitive credentials).
Local enumeration — backups, secrets, and a handy plaintext password
After grabbing the user flag I continued local enumeration from gael
’s shell. A quick ls -al
in the home directory showed a few interesting quirks (history files redirected to /dev/null
, .ssh
present) and confirmed user.txt
was readable by root:gael
:
I moved on to /var/backups
(good place to check for system or application backups) and found backrest_backup.tar.gz
among several dump files:
Because gael
had privileges to read the backup, I spun up a quick HTTP server on the box and pulled the archive to my attacker host:
After extracting the archive (tar xvf backrest_backup.tar.gz -C /tmp/
) I inspected the extracted tree and noticed a few juicy artifacts: a backrest
binary, restic
, an install.sh
, a jwt-secret
file, an oplog.sqlite
DB and a .config
directory. These are all promising for further discovery and privilege escalation.
Inside the .config
I found an encoded credential string:
I base64-decoded that value and recovered the decoded hash:
I saved the hash in a hash file and attempted to crack the hash with john and it worked and I was able to obtain the plaintext using the following command:
Discovering an internal admin panel - using the stolen backup credentials
While poking around the system after recovering the cleartext password, I checked for listening services to find anything bound to 127.0.0.1
(services only reachable from the host):
That local-only listener looked interesting - services bound to loopback are often internal admin interfaces or dashboards that aren’t exposed to the network. Since I already had a shell as gael
, I accessed the service on 127.0.0.1:9898
(you can do this from the host directly or via SSH local port-forwarding if you want to view it from your attacker machine). The page presented a login form for Backrest 1.7.2.
I used the credentials recovered from the backup (username = backrest_root
, password !@#$%^
, the password we obtained by base64 → bcrypt cracking) and successfully authenticated to the dashboard. This confirmed a classic CTF pivot: a secret harvested from a backup granted access to an internal-only service that would otherwise be unreachable from the outside.
Abusing the Backrest admin panel — reading root.txt
via the backup tooling
Once I had access to the Backrest 1.7.2 dashboard I started poking the UI for functionality I could abuse. The dashboard exposed two obvious actions: Add Plan and Add Repo. I created a repository configuration that pointed directly at the host filesystem:
- Repo Name:
repo1
- Repository URI:
/opt
- Password:
boltech
After saving, the UI confirmed with “Added repo /opt” and showed repo actions: Run Command, Index Snapshots, Unlock Repo, Prune Now, Check Now, and Compute Stats.
The Run Command
feature is effectively a remote command runner for the backup tooling. From that prompt I issued two commands:
The panel executed /opt/backrest/restic backup /root -o sftp.args=-oBatchMode=yes
and created a snapshot of /root
. The output showed files and folders processed and reported snapshot 36564441 saved
.
Then I ran:
The panel executed /opt/backrest/restic dump latest /root/root.txt -o sftp.args=-oBatchMode=yes
and printed the contents of the file:
This dumped the root flag along with the content of the backup.
Hurray!!! I got the root flag. With that, the machine was officially pwned
If you enjoy reading my walkthrough, do not forget to like, comment, and subscribe to my YouTube channel and also connect with me on LinkedIn. Also, don't forget to turn on post notification on my YouTube channel and Medium to get notification as soon as I write.
Subscribe to my YouTube channel and Follow me on: LinkedIn | Medium | Twitter | Boltech Twitter | Buy Me a Coffee
0 Comments